Index: debug-testing/gli_proxy/DownloadPane.java
===================================================================
--- debug-testing/gli_proxy/DownloadPane.java	(revision 31879)
+++ debug-testing/gli_proxy/DownloadPane.java	(revision 31879)
@@ -0,0 +1,896 @@
+/**
+ *#########################################################################
+ *
+ * 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 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.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.file.WorkspaceTree;
+import org.greenstone.gatherer.greenstone.LocalGreenstone;
+import org.greenstone.gatherer.util.SafeProcess;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.download.URLConnectionManager;
+import org.greenstone.gatherer.download.Download;
+import org.greenstone.gatherer.download.DownloadScrollPane;
+import org.greenstone.gatherer.download.ServerInfoDialog;
+import org.greenstone.gatherer.util.XMLTools;
+import org.greenstone.gatherer.cdm.*;
+import org.greenstone.gatherer.gui.*;
+import org.w3c.dom.*;
+import org.xml.sax.*;
+import org.greenstone.gatherer.GAuthenticator;
+
+/**
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.1
+ */
+public class DownloadPane
+    extends JPanel {
+
+    static final private Dimension LABEL_SIZE = new Dimension(225, 25);
+    static final private Dimension TREE_SIZE = new Dimension(150, 500);
+    //static final private String CONTENTS[] = { "DOWNLOAD.MODE.WebDownload", "DOWNLOAD.MODE.MediaWikiDownload", "DOWNLOAD.MODE.OAIDownload", "DOWNLOAD.MODE.ZDownload" , "DOWNLOAD.MODE.SRWDownload"};
+    private String CONTENTS[] = null;
+
+    private boolean download_button_enabled = false;
+    private boolean ready = false;
+
+    private JPanel options_pane;
+    // TODO should use Vector to store all loaded downloads!!
+
+    private DesignTree tree;
+    private HashMap download_map;
+    private ServerInfoDialog server_info;
+    private JScrollPane list_scroll;
+    private DownloadScrollPane getter;
+    private String mode = null;
+    private TreePath previous_path;
+    //private String proxy_url = "";
+    private Properties proxy_urls = new Properties();
+    private Proxy proxyObject = null;
+	    
+    /** Main System code */
+    public DownloadPane() {
+	super();
+        JScrollPane scrol_tmp;
+        this.setComponentOrientation(Dictionary.getOrientation());
+	// TODO: Download the WDownload and the download panel fixed!!
+	getter = new DownloadScrollPane();
+        getter.start();
+	list_scroll = getter.getDownloadJobList();      
+        list_scroll.setComponentOrientation(Dictionary.getOrientation());
+
+	// TODO should use Vector to store all loaded downloads!!
+	String lang = Configuration.getLanguage();
+	download_map = new HashMap();
+
+	// run downloadinfo.pl -describeall, load the downloaders into the download_map, 
+	// and get back their list of names, which are of the form "<downloader>Download". 
+	// Store these names in the CONTENTS[] array as "DOWNLOAD.MODE.<downloader>Download", 
+	// with z3950 as a minor exception: DOWNLOAD.MODE.ZDownload.
+	ArrayList<String> downloaderNamesList = loadDownloadersInfo(lang);	
+	int size = downloaderNamesList.size();
+	CONTENTS = new String[size];
+	for(int i = 0; i < size; i++) {
+	    String downloadName = downloaderNamesList.get(i); // e.g. "WebDownload"	    
+	    CONTENTS[i] = "DOWNLOAD.MODE."+downloadName.replace("3950", ""); // A special case is Z3950Download,
+	                                 // which has to be stored in CONTENTS array as DOWNLOAD.MODE.ZDownload
+	}
+
+	// Creation
+	tree = new DesignTree();
+        tree.setComponentOrientation(Dictionary.getOrientation());
+	options_pane = new JPanel();
+        options_pane.setComponentOrientation(Dictionary.getOrientation());
+	
+	JButton clear_cache_button = new GLIButton(Dictionary.get("Mirroring.ClearCache"), Dictionary.get("Mirroring.ClearCache_Tooltip"));
+	clear_cache_button.setEnabled(true);
+	clear_cache_button.setMnemonic(KeyEvent.VK_C);
+
+	JButton download_button = new GLIButton(Dictionary.get("Mirroring.Download"), Dictionary.get("Mirroring.Download_Tooltip"));
+	download_button.setEnabled(true);
+	download_button.setMnemonic(KeyEvent.VK_D);
+
+	JButton information_button =  new GLIButton(Dictionary.get("Download.ServerInformation"), Dictionary.get("Download.ServerInformation_Tooltip"));
+	information_button.setEnabled(true);
+	information_button.setMnemonic(KeyEvent.VK_S);
+
+
+       	JButton preferences_button =  new GLIButton(Dictionary.get("Mirroring.Preferences"), Dictionary.get("Mirroring.Preferences_Tooltip"));
+	preferences_button.setEnabled(true);
+	preferences_button.setMnemonic(KeyEvent.VK_P);
+
+	// Connect
+	clear_cache_button.addActionListener(new ClearCacheListener());
+	download_button.addActionListener(new DownloadButtonListener());
+	preferences_button.addActionListener(new PreferencesButtonActionListener());
+	information_button.addActionListener(new InformationButtonActionListener());
+	tree.addTreeSelectionListener(new TreeListener());
+
+	// Add to Panel
+	JPanel button_pane = new JPanel();
+        button_pane.setComponentOrientation(Dictionary.getOrientation());
+	button_pane.setLayout(new GridLayout(1,4)); // GridLayout so button pane resizes with window-width
+	button_pane.setBorder(BorderFactory.createEtchedBorder());
+	button_pane.add(clear_cache_button);
+	button_pane.add(download_button);
+	button_pane.add(information_button);
+	button_pane.add(preferences_button);
+
+	JPanel tree_pane = new JPanel();
+        tree_pane.setComponentOrientation(Dictionary.getOrientation());
+	tree_pane.setLayout(new BorderLayout());
+        scrol_tmp = new JScrollPane(tree);
+        scrol_tmp.setComponentOrientation(Dictionary.getOrientation());
+       	tree_pane.add(scrol_tmp, BorderLayout.CENTER);
+	tree_pane.setPreferredSize(TREE_SIZE);
+ 
+
+	Color colour_two = Configuration.getColor("coloring.collection_tree_background", false);
+	options_pane.setBackground(colour_two);
+	options_pane.setBorder(BorderFactory.createEtchedBorder());
+
+
+	JScrollPane options_scroll_pane = new JScrollPane(options_pane);
+        options_scroll_pane.setComponentOrientation(Dictionary.getOrientation());
+	JSplitPane mode_pane = new JSplitPane();
+        mode_pane.setComponentOrientation(Dictionary.getOrientation());
+	mode_pane.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
+        if (Dictionary.getOrientation().isLeftToRight()){
+            mode_pane.add(tree_pane,JSplitPane.LEFT);
+            mode_pane.add(options_scroll_pane,JSplitPane.RIGHT); 
+            mode_pane.setDividerLocation(TREE_SIZE.width);
+        }else{
+            mode_pane.add(tree_pane,JSplitPane.RIGHT);
+            mode_pane.add(options_scroll_pane,JSplitPane.LEFT);
+            mode_pane.setDividerLocation(1-TREE_SIZE.width);
+        }
+		
+    
+	JPanel edit_pane = new JPanel();
+        edit_pane.setComponentOrientation(Dictionary.getOrientation());
+	edit_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(2,0,0,0), BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("Download Setting"), BorderFactory.createEmptyBorder(2,2,2,2))));
+	edit_pane.setLayout(new BorderLayout());
+	edit_pane.add(mode_pane,BorderLayout.CENTER);
+	edit_pane.add(button_pane,BorderLayout.PAGE_END);
+	
+	// Add to "this"
+	setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	setLayout(new GridLayout(2,1));
+	add(edit_pane);
+	add(list_scroll);
+
+	//set the mode to the first downloader in the list
+	mode = convertCONTENTStoMode(CONTENTS[0]); // e.g. Web
+	generateOptions(options_pane,(Download)download_map.get(mode));
+	previous_path = tree.getSelectionPath();
+    }
+
+    /** System Utilities */
+    public void modeChanged(int gli_mode) {
+	// do nothing at this stage - should we be renewing download options??
+    }
+
+    private void addHeader(String name, Color color, JPanel target_pane) {
+	JPanel header = new JPanel();
+        header.setComponentOrientation(Dictionary.getOrientation());
+	header.setBackground(color);
+	JPanel inner_pane = new JPanel();
+        inner_pane.setComponentOrientation(Dictionary.getOrientation());
+	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.setComponentOrientation(Dictionary.getOrientation());
+	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);
+	target_pane.add(header);
+    }
+
+    /** Supporting Functions */
+    private ArrayList<String> loadDownloadersInfo(String lang) {
+	Document document = null;
+	
+	try {
+	    if (Gatherer.isGsdlRemote) {
+		String output = Gatherer.remoteGreenstoneServer.getScriptOptions("downloadinfo.pl", "&describeall");
+		Reader reader = new StringReader(output);
+		document = XMLTools.parseXML(reader);
+	    }
+	    else {
+		ArrayList args_list = new ArrayList();
+		String args[] = null;
+		if(Configuration.perl_path != null) {
+		    args_list.add(Configuration.perl_path);
+		} else if(Utility.isWindows()) {
+		    args_list.add("Perl.exe");
+		} else {
+		    args_list.add("perl");
+		}
+		args_list.add("-S");
+		args_list.add(LocalGreenstone.getBinScriptDirectoryPath()+"downloadinfo.pl");
+		args_list.add("-describeall");
+		args_list.add("-xml");
+		args_list.add("-language");
+		args_list.add(lang);		
+		
+		// Create the process.
+		args = (String []) args_list.toArray(new String[0]);
+
+		SafeProcess process = new SafeProcess(args);
+		DebugStream.println("Getting Download Info: "+args_list);
+
+		// run the SafeProcess
+		int exitVal = process.runProcess();
+		if(exitVal != 0) {
+		    throw new Exception("*** Error running Download Info process, process exited with: "
+					+ exitVal);
+		}		
+		
+		// get the result and process it.
+		// This time we expect XML to have come out of the process std error stream.
+		String errStreamOutput = process.getStdError();
+		///System.err.println("*********\nDownload Pane data, got:\n" + errStreamOutput + "\n**********\n");
+		StringReader xmlStrReader = new StringReader(errStreamOutput);
+		document = XMLTools.parseXML(xmlStrReader);
+		xmlStrReader.close();
+		
+	    }
+
+            
+	}
+	catch (Exception error) {
+	    System.err.println("Failed when trying to parse downloadinfo.pl -describeall");
+	    error.printStackTrace();
+	}
+
+	if(document != null) {
+	    return parseXML(document.getDocumentElement());
+	}
+
+	return null;
+    }
+
+    private ArrayList<String> parseXML(Node root) {
+	ArrayList<String> downloaders = null;
+	Element downloadList = (Element)root;
+	int length = -1;
+	if(downloadList.hasAttribute("length")) {
+	    length = Integer.parseInt(downloadList.getAttribute("length"));
+	    downloaders = new ArrayList<String>(length);		
+	    
+	    for (Node node = downloadList.getFirstChild(); node != null; node = node.getNextSibling()) {
+		// goes through each <DownloadInfo> of describeAll
+		
+		String download_name = null;
+		
+		for(Node infoNode = node.getFirstChild(); 
+		    infoNode != null; infoNode = infoNode.getNextSibling()) {
+		    
+		    String node_name = infoNode.getNodeName();
+		    if(node_name.equalsIgnoreCase("Name")) { // <Name>WebDownload</Name>
+			download_name = XMLTools.getValue(infoNode); // e.g. WebDownload		
+		    }
+		    
+		    // At this top level of <DownloadInfo> elements,
+		    // skip all the downloaders that are Abstract, as these are pure superclasses		
+		    else if(node_name.equalsIgnoreCase("Abstract")) {
+			String isAbstract = XMLTools.getValue(infoNode);
+			
+			if(isAbstract.equalsIgnoreCase("no") && download_name != null) {
+			    downloaders.add(download_name);
+			    Download downloader = parseDownloadInfoXML(node); // parse the <DownloadInfo> node properly
+			    // now embedded references to abstract superclasses (embedded <DownloadInfo> nodes)
+			    // will be handled
+			    
+			    String shortName = download_name.replace("Download", ""); // e.g. "Web"
+			    download_map.put(shortName, downloader);
+			}
+		    }
+		}
+	    }
+	}
+
+	return downloaders;
+    }
+
+    private Download parseDownloadInfoXML(Node root) {
+
+	Download download = new Download();
+	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);
+		download.setName(name);
+	    }
+	    else if (node_name.equalsIgnoreCase("Desc")) {
+		download.setDescription(XMLTools.getValue(node));
+	    }
+	    else if (node_name.equalsIgnoreCase("Abstract")) {
+		download.setIsAbstract(XMLTools.getValue(node).equalsIgnoreCase(StaticStrings.YES_STR));
+	    }
+	    else if(node_name.equalsIgnoreCase("Arguments")) {
+		for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) {
+		    node_name = arg.getNodeName();
+                     if(node_name.equalsIgnoreCase("Option")) {
+			Argument argument = new Argument((Element)arg);
+			argument.parseXML((Element)arg);
+			argument.setValue(argument.getDefaultValue());
+			download.addArgument(argument);
+		     }
+		   
+		}
+	    }
+            else if(node_name.equalsIgnoreCase("DownloadInfo")) {
+                Download super_download = parseDownloadInfoXML(node);
+		download.setSuper(super_download);
+	    }
+	}
+
+	if(download.getName() != null) {
+	    return download;
+	}
+	return null;
+    }
+
+    /** Update the previous setup */
+    private boolean updateArguments(boolean checkRequired)
+    {
+	boolean cont = true;
+	for(int i = 0; i < options_pane.getComponentCount(); i++) {
+	   
+	    Component component = options_pane.getComponent(i);
+	    if(component instanceof ArgumentControl) {
+		cont = cont && ((ArgumentControl)component).updateArgument(checkRequired);
+	    }
+	}
+
+	if(cont){return true; }
+
+	return false;
+    }
+    
+    /** Generate Controls for Options */
+    /* at some stage we should think about which options should be shown for
+     * different modes. Currently, always show all options (unless hidden)*/
+    private void generateOptions(JPanel options_pane, ArgumentContainer data) {
+	options_pane.removeAll();
+	/** Create the current option panel */
+
+	ArrayList arguments = data.getArguments(true, false);
+      	int mode = Configuration.getMode();
+        ArrayList added_arguments = new ArrayList();
+     
+	for(int i = 0; i < arguments.size(); i++) {
+	    Argument argument = (Argument) arguments.get(i);
+
+	    if (argument.isHiddenGLI()) continue;
+	    ArgumentControl argument_control = new ArgumentControl(argument,false,null);
+	    added_arguments.add(argument_control);
+	}
+	
+
+       	options_pane.setLayout(new GridLayout(added_arguments.size(),1));
+        for(int i = 0; i <  added_arguments.size(); i++) { 
+	    options_pane.add((ArgumentControl)added_arguments.get(i));
+	    
+	}
+    }
+
+    /** Behaviour Functions */
+    public void afterDisplay() {
+	ready = true;        
+    }
+
+
+    public void gainFocus() {
+	if(!ready) {
+	    return;
+	}
+
+	// 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_enabled = true;
+	//download_button.setEnabled(download_button_enabled);
+    }
+
+
+
+    public void refresh(int refresh_reason, boolean ready)
+    {
+    }
+
+    /** Private classes */
+    /** 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();
+            this.setComponentOrientation(Dictionary.getOrientation());
+	    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("DOWNLOAD.MODE.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();
+		Gatherer.g_man.wait(true);
+
+		// type has the value DOWNLOAD.MODE.<downloader>Download,
+		// mode should then be of the form <downloader>
+		mode = convertCONTENTStoMode(type);
+		generateOptions(options_pane,(Download)download_map.get(mode));
+
+		tree.setSelectionPath(path);
+		previous_path = path;
+		repaint();
+
+		Gatherer.g_man.wait(false);
+	    }
+	}
+    }
+
+    private String convertCONTENTStoMode(String content) {
+	return content.replace("DOWNLOAD.MODE.", "").replace("ZDownload", "Z3950").replace("Download", "");
+    }
+
+    private class ClearCacheListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    // Retrieve the cache folder and delete it.
+	    Utility.delete(Utility.getCacheDir());
+	    // ...and refresh the node in the workspace tree to show it's all gone
+	    Gatherer.g_man.refreshWorkspaceTree(WorkspaceTree.DOWNLOADED_FILES_CHANGED);
+	}
+    }
+
+    private class DownloadButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+
+	    if(checkURL(true) && checkProxy() == true) {
+		
+		// Proxy settings are now set. Check that the url is not a redirect, else get
+		// redirect url (we do this step in order to avoid some unintuitive behaviour from wget)
+		Download current_download = (Download)download_map.get(mode);
+		
+		boolean noCheckCertificate = Configuration.get("general.no_check_certificate", true);		
+		Argument no_check_cert_arg = current_download.getArgument("no_check_certificate");
+		if(noCheckCertificate) {
+		    no_check_cert_arg.setValue("true");
+		    no_check_cert_arg.setAssigned(true);
+		} else {
+		    no_check_cert_arg.setValue("false");
+		    no_check_cert_arg.setAssigned(false); // only assigned Arguments have values
+		}
+
+		Argument arg_url = current_download.getArgument("url");
+		
+		if(arg_url != null) { // it's null for z3950 and possibly for other downloaders
+		    String url_str = arg_url.getValue();	
+			
+		    // No longer following URL redirects, since some of this has been taken care of by wget
+		    // For the rest, assume the user will get the URL right that they want to download from
+		    /*
+		      String redirect_url_str = getRedirectURL(url_str);
+		      
+		      // only update the Argument and its GUI ArgumentControl if the URL
+		      // has in fact changed
+		      if(!url_str.equals(redirect_url_str)) {
+		      arg_url.setValue(redirect_url_str);
+		      updateArgument(arg_url, redirect_url_str);
+		      }
+		    */
+		}
+		
+		getter.newDownloadJob((Download)download_map.get(mode) ,mode,proxy_url);
+	    }
+	}
+    }
+
+    /**
+     * The Java code here will retrieve the page at the given url. If the response code is 
+     * a redirect, it will get the redirect url so that wget may be called with the proper url. 
+     * This preprocessing of the URL is necessary because:
+     * Wget does not behave the way the browser does when faced with urls of the form
+     * http://www.englishhistory.net/tudor/citizens and if that page does not exist.
+     * The directory listing with a slash at the end (http://www.englishhistory.net/tudor/citizens/)
+     * does exist, however. In order to prevent wget from assuming that the root URL
+     * to traverse is http://www.englishhistory.net/tudor/ instead of the intended
+     * http://www.englishhistory.net/tudor/citizens/, we need give wget the redirect location
+     * that's returned when we initially make a request for http://www.englishhistory.net/tudor/citizens
+     * The proper url is sent back in the Location header, allowing us to bypass wget's 
+     * unexpected behaviour.
+     * This method ensures that urls like http://www.nzdl.org/niupepa also continue to work:
+     * there is no http://www.nzdl.org/niupepa/ page, because this url actually redirects to an 
+     * entirely different URL.
+     * @return the redirect url for the given url if any redirection is involved, or the
+     * url_str.
+     *
+     * Adding another useful URL on setting Java System Properties:
+     * https://stackoverflow.com/questions/12181843/using-java-to-download-files-from-a-https-url
+     */
+    private String getRedirectURL(String url_str) {
+	boolean noMoreRedirects = false;
+	boolean gotException = false;
+	final int TIMEOUT = 2 * 1000; // ms
+	
+	HttpURLConnection connection = null;
+	if(url_str.startsWith("http:") || url_str.startsWith("https:")) { // only test http urls
+	    try {
+		// URLConnectionManager class has special handling for https URLs,
+		// so you can control whether you want it to check an HTTPS site's security certificates for you or not
+		boolean noCheckCertificates = true;
+		connection = (HttpURLConnection)URLConnectionManager.getConnection(url_str, this.proxyObject, noCheckCertificates);
+		
+		// don't let it automatically follow redirects, since we want to
+		// find out whether we are dealing with redirects in the first place
+		connection.setInstanceFollowRedirects(false);
+		// Connection timeout: if we can't connect, like if the proxy is wrong, don't wait forever
+		// Read timeout: *idle time* when retrieving a link. Don't wait forever to retrieve a page (e.g. if page doesn't exist)
+		// https://stackoverflow.com/questions/6829801/httpurlconnection-setconnecttimeout-has-no-effect
+		connection.setConnectTimeout(TIMEOUT); 
+		connection.setReadTimeout(TIMEOUT); 
+		
+		// now check for whether we get a redirect response
+		// HTTP Codes 3xx are redirects, http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
+		int responseCode = connection.getResponseCode();
+		if(responseCode >= 300 && responseCode < 400) { 
+		    //String responseMsg = connection.getResponseMessage();
+
+		    // Get the Location header since this specifies the new location of the resource
+		    String location = connection.getHeaderField("Location");
+
+		    // this becomes the url that wget should download from
+		    url_str = location.trim();
+		} else {
+		   noMoreRedirects = true; 
+		}		
+		connection.disconnect();
+	    } catch(Exception e) {
+		gotException = true;
+		if(connection != null) {
+		    connection.disconnect();
+		}
+		System.err.println("Checking redirection. Tried to connect to "
+				   + url_str + ",\nbut got exception: " + e);
+	    }	    
+	} 
+
+	if(noMoreRedirects || gotException) {
+	    return url_str;
+	}
+	else { // continue checking for whether the new URL redirects elsewhere again
+	    return getRedirectURL(url_str);
+	}
+    }
+
+    
+    /** For a string-based Argument whose value has changed, this method
+     * updates the GUI ArgumentControl's value correspondingly. */
+    private void updateArgument(Argument arg, String value) {
+	for(int i = 0; i < options_pane.getComponentCount(); i++) {
+	    Component component = options_pane.getComponent(i);
+	    if(component instanceof ArgumentControl) {
+		ArgumentControl control = (ArgumentControl)component;
+		if(control.getArgument() == arg) {
+		    control.setValue(value);
+		    control.repaint();
+		}
+	    }
+	}
+    }
+
+    private boolean checkURL(boolean checkRequired){
+	
+	if (!updateArguments(checkRequired)){
+	    return false;
+	}
+
+	Download current_download = (Download)download_map.get(mode);
+	Argument arg_url = current_download.getArgument("url");
+	
+        if (arg_url == null) return true;
+ 
+	String url_str = arg_url.getValue();
+	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);
+	    return false;
+	}
+
+	return true;
+    }
+
+    
+    // TODO: https://arstechnica.com/civis/viewtopic.php?f=10&t=1281165
+    // "http or https to an https proxy?"
+    // About "CONNECT": https://daniel.haxx.se/docs/sshproxy.html
+    // "You need an SSH client that can issue CONNECT requests through the company HTTP proxy." Seems to imply http? Also uses it for ftp.
+    // https://forum.ivorde.com/set-up-ftp-proxy-via-command-line-in-linux-freebsd-t19733.html sets ftp_proxy to a http url.
+    // So it's seems to be just whatever protocol the proxy server has. When the proxy supports all three protocols
+    // (apparently the common case as per page below describing firefox prefs), then they wiki.archlinux sets the all three ftp_proxy/http_proxy/https_proxy to the same.
+    // See https://forums.freebsd.org/threads/57378/
+    // "I believe that ftp(1) only uses HTTP-type proxies for fetching URLs. I.e. you can't do traditional open->cd->get interactive style of FTP with it via a HTTP proxy. If you do something like ftp ftp://ftp.example.com/path/file, it should work with your proxy setup. For traditional interactive FTP, you need to be directly talking to the remote server or using the less common FTP proxy/gate functionality."
+    
+    // https://wiki.archlinux.org/index.php/Proxy_settings
+    // This does https_proxy = http_proxy, and explicitly prefixes "https://" to http_proxy.
+    // https://www.howtogeek.com/293213/how-to-configure-a-proxy-server-in-firefox/
+    /* Youâll usually want to click the âUse the proxy server for all protocolsâ option. Firefox will also use your HTTP proxy server for SSL-encrypted HTTPS connections and File Transfer Protocol (FTP) connections.
+Uncheck this box if you want to enter separate proxy servers for HTTP, HTTPS, and FTP connections. This isnât common.
+If youâre configuring a SOCKS proxy, leave the HTTP Proxy, SSL Proxy, and FTP Proxy boxes empty. Enter the address of the SOCKS proxy into the âSOCKS Hostâ and its port into the âPortâ box.
+    */
+    // DONE. TODO: Still need to read up on and test how to set wget proxy on windows
+    // Need to be on a windows machine that requires proxy, and get wget to work on cmdline
+    // If that works, then need to check https URLS also work.
+    // See https://superuser.com/questions/526710/how-to-set-http-proxy-address-for-wget-under-windows
+    private boolean checkProxy(){
+	 
+	//proxy_url = null;
+	proxy_urls.clear();
+	proxy_urls.setProperty("HTTP", "");
+	proxy_urls.setProperty("HTTPS", "");
+	proxy_urls.setProperty("FTP", "");
+	
+	Download current_download = (Download)download_map.get(mode);
+	
+        Argument arg = current_download.getArgument("proxy_on");
+  
+	if (arg == null) return true;
+	
+	// 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 = "";
+	    String address = proxy_host + ":" + proxy_port;
+	    
+            int count = 0;
+	    // Only for wget, need to avoid a second automatic authentication popup (first asks
+	    // the proxy authentication for wget, and the second will ask the same for the realm)
+	    // Once the authentication has been reused, it will set the GAuthenticator state back to REGULAR
+	    GAuthenticator.setMode(GAuthenticator.DOWNLOAD);
+	    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) {
+		return false;
+	    }
+
+	    // https://askubuntu.com/questions/664777/systemwide-proxy-settings-in-ubuntu
+	    // http://www.rgagnon.com/javadetails/java-0085.html
+	    // how-do-i-make-httpurlconnection-use-a-proxy
+	    // https://stackoverflow.com/questions/8030908/how-to-check-if-proxy-is-working-in-java
+	    proxyObject = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxy_host, Integer.parseInt(proxy_port)));
+
+	    if(user_pass.indexOf("@") != -1) {
+	   
+		   arg.setValue("true"); // proxy_on argument
+		   arg.setAssigned(true);
+		   
+		   arg = current_download.getArgument("proxy_host");
+		   arg.setValue(proxy_host);
+		   arg.setAssigned(true);
+		   
+		   arg = current_download.getArgument("proxy_port");
+		   arg.setValue(proxy_port);
+		   arg.setAssigned(true);
+
+		
+		// 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 following can (using ps) - actually the environment stuff didn't work for windows, so lets go back to this
+		/*if (Utility.isWindows()) {
+	    
+		   arg = current_download.getArgument("user_name");
+		   arg.setValue(user_pass.substring(0, user_pass.indexOf("@")));
+		   arg.setAssigned(true);
+
+		   arg = current_download.getArgument("user_password");
+		   arg.setValue(user_pass.substring(user_pass.indexOf("@") + 1));
+		   arg.setAssigned(true);
+		  }
+		 
+	       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+"/";
+		   
+ 	       /*}*/
+		
+	       return true;
+	    }
+	    else{
+		// unset proxy_on argument
+		arg = current_download.getArgument("proxy_on");
+		arg.setValue("false"); 
+		arg.setAssigned(false);
+		return false;
+	    }
+
+	} else {
+	    // unset proxy_on argument
+	    arg = current_download.getArgument("proxy_on");
+	    arg.setValue("false"); 
+	    arg.setAssigned(false);
+	}
+	
+	return true;
+    }
+
+    /*
+    private class PreferencesButtonActionListener
+    implements ActionListener {
+    public void actionPerformed(ActionEvent event) {
+    new Preferences(Preferences.CONNECTION_PREFS);
+    }
+    }*/
+    
+    private class InformationButtonActionListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    //turn off the check for find argument
+	    Download current_download = (Download)download_map.get(mode);
+
+            if (!checkProxy() || !checkURL(false) )return;
+
+	    if(server_info != null) {
+		server_info.dispose();
+	    }
+	    
+	    Argument arg_url = current_download.getArgument("url");
+	    String str_url = "";
+	    if( arg_url!= null && arg_url.isAssigned()) {
+		str_url = arg_url.getValue();	    
+		/*
+		String redirected_url = getRedirectURL(str_url); // work out the real URL
+		if(!str_url.equals(redirected_url)) {
+		    arg_url.setValue(redirected_url);
+		}
+		*/
+	    }
+
+	    boolean noCheckCertificate = Configuration.get("general.no_check_certificate", true);
+	    Argument no_check_cert_arg = current_download.getArgument("no_check_certificate");
+	    if(noCheckCertificate) {		
+		no_check_cert_arg.setValue("true");
+		no_check_cert_arg.setAssigned(true);
+	    } else {
+		no_check_cert_arg.setValue("false");
+		no_check_cert_arg.setAssigned(false); // only assigned Arguments have values
+	    }
+
+ 	    server_info = new ServerInfoDialog(str_url ,proxy_url, mode,(Download)download_map.get(mode));
+ 	    
+	}
+    }
+
+     private class PreferencesButtonActionListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    new Preferences(Preferences.CONNECTION_PREFS);
+	}
+    }
+}
Index: debug-testing/gli_proxy/Gatherer.java
===================================================================
--- debug-testing/gli_proxy/Gatherer.java	(revision 31879)
+++ debug-testing/gli_proxy/Gatherer.java	(revision 31879)
@@ -0,0 +1,1754 @@
+/**
+*#########################################################################
+*
+* 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.FedoraInfo;
+import org.greenstone.gatherer.collection.CollectionManager;
+import org.greenstone.gatherer.feedback.ActionRecorderDialog;
+import org.greenstone.gatherer.feedback.Base64;
+import org.greenstone.gatherer.file.FileManager;
+import org.greenstone.gatherer.file.FileAssociationManager;
+import org.greenstone.gatherer.file.RecycleBin;
+import org.greenstone.gatherer.greenstone.Classifiers;
+import org.greenstone.gatherer.greenstone.LocalGreenstone;
+import org.greenstone.gatherer.greenstone.LocalLibraryServer;
+import org.greenstone.gatherer.greenstone.Plugins;
+import org.greenstone.gatherer.greenstone3.ServletConfiguration;
+import org.greenstone.gatherer.gui.GUIManager;
+import org.greenstone.gatherer.gui.URLField;
+import org.greenstone.gatherer.gui.WarningDialog;
+import org.greenstone.gatherer.gui.FedoraLogin;
+import org.greenstone.gatherer.metadata.FilenameEncoding;
+import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
+import org.greenstone.gatherer.util.GS3ServerThread;
+import org.greenstone.gatherer.util.JarTools;
+import org.greenstone.gatherer.util.SafeProcess;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+
+
+/** 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
+{    
+	/** The name of the GLI. */
+	static final public String PROGRAM_NAME = "Greenstone Librarian Interface";
+	/** The current version of the GLI.
+		* Note: the gs3-release-maker relies on this variable being declared
+		* in a line which matches this java regex:
+		* ^(.*)String\s*PROGRAM_VERSION\s*=\s*"trunk";
+		* If change the declaration and it no longer matches the regex, please
+		* change the regex in the gs3-release-maker code and in this message
+		*/
+
+	static final public String PROGRAM_VERSION = "trunk";
+
+	static private Dimension size = new Dimension(800, 540);
+	static public RemoteGreenstoneServer remoteGreenstoneServer = null;
+
+	/** Has the exit flag been set? */
+	static final public int EXIT_THEN_RESTART= 2;
+	static public boolean exit = false;
+	static public int exit_status = 0;
+
+	static private String gli_directory_path = null;
+	static private String gli_user_directory_path = null;
+
+	static public String client_operating_system = null;
+
+	/** All of the external applications that must exit before we close the Gatherer. */
+	static private Vector apps = new Vector();
+	static private String non_standard_collect_directory_path = null;
+	static public String open_collection_file_path = null;
+	static public String gsdlsite_collecthome = "";
+	/** A public reference to the FileAssociationManager. */
+	static public FileAssociationManager assoc_man;
+	/** A public reference to the CollectionManager. */
+	static public CollectionManager c_man;
+	/** A public reference to the RecycleBin. */
+	static public RecycleBin recycle_bin;
+	/** 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;
+
+	/** We are using the GLI for GS3 */
+	static public boolean GS3 = false;
+
+	static public boolean isApplet = false;
+	static public boolean isGsdlRemote = false;
+	static public boolean isLocalLibrary = false;
+
+	/* TODO: If we're using local GLI, collections are built locally. If we're using client-GLI
+	* and it contains a gs2build folder in it, then localBuild will also be true (if this is not
+	* turned off in Preferences). If we're remote and this is turned off in Prefs, build remotely. */
+	/*static public boolean buildingLocally = true;*/
+	/** If we're using local GLI, we can always download. If we're using client-GLI, we can only
+	* download if we have a gs2build folder inside it. And if we don't turn off downloadEnabling
+	* in the preferences.
+	*/
+	static public boolean isDownloadEnabled = true;
+
+	// 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;
+
+	//////kk added////////  
+	static public String cgiBase="";
+	/////////////////
+
+	/** 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);
+	}
+
+	static private URL default_gliserver_url=null;
+
+	public Gatherer(String[] args) 
+	{
+		// Display the version to make error reports a lot more useful
+		System.err.println("Version: " + PROGRAM_VERSION + "\n");
+
+		JarTools.initialise(this); 
+
+		GetOpt go = new GetOpt(args);
+
+		// Remember the GSDLOS value
+		client_operating_system = go.client_operating_system;
+
+		// 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());
+		}
+
+		// Are we using a remote Greenstone?
+		if (go.use_remote_greenstone) {
+			isGsdlRemote = true;
+
+			// We don't have a local Greenstone!
+			go.gsdl3_path=null;
+			go.gsdl3_src_path=null;
+
+			// Don't set go.gsdl_path to null, since gdsl_path may still be set 
+			// if we have a client-gli containing gs2build folder. 
+			// However, keep track of whether we can download.
+			if(go.gsdl_path == null) {
+				isDownloadEnabled = false;
+			}
+
+			// We have to use our own collect directory since we can't use the Greenstone one
+			setCollectDirectoryPath(getGLIUserDirectoryPath() + "collect" + File.separator);
+		}
+		// We have a local Greenstone. OR we have a gs2build folder inside 
+		// the client-GLI folder (with which the Download panel becomes enabled) 
+		if(isDownloadEnabled) {
+			LocalGreenstone.setDirectoryPath(go.gsdl_path);
+		}
+
+		// Users may specify a non-standard collect directory (eg. when running one GLI in a network environment)
+		// Processing of custom non-standard collect directory passed into gli now happens in init()
+		//if (go.collect_directory_path != null) { setCollectDirectoryPath(go.collect_directory_path); }
+
+		// More special code for running with a remote Greenstone
+		if (isGsdlRemote) {
+			if (go.fedora_info.isActive()) {
+				Configuration.TEMPLATE_CONFIG_XML = "xml/" + Configuration.FEDORA_CONFIG_PREFIX + "configRemote.xml";
+			}
+			else {
+				Configuration.TEMPLATE_CONFIG_XML = "xml/configRemote.xml";
+			}
+
+			Configuration.CONFIG_XML = "configRemote.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);
+			}
+		}
+		else {	    
+			if (go.fedora_info.isActive()) {
+				Configuration.TEMPLATE_CONFIG_XML = "xml/" + Configuration.FEDORA_CONFIG_PREFIX + Configuration.CONFIG_XML;
+			}
+			// else, the CONFIG_XML uses the default config file, which is for the local GS server
+		}
+
+		init(go.gsdl_path, go.gsdl3_path, go.gsdl3_src_path, 
+		go.fedora_info,
+		go.local_library_path, go.library_url_string, 
+		go.gliserver_url_string, go.debug, go.perl_path, go.no_load, go.filename, go.site_name,
+		go.servlet_path, go.collect_directory_path);
+	}
+
+
+	public void init(String gsdl_path, String gsdl3_path, String gsdl3_src_path, 
+	FedoraInfo fedora_info,
+	String local_library_path,
+	String library_url_string, String gliserver_url_string, boolean debug_enabled,
+	String perl_path, boolean no_load, String open_collection, 
+	String site_name, String servlet_path, String collect_directory_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());
+		}
+
+		// Delete plugins.dat and classifiers.dat files from previous versions of the GLI (no longer used)
+		File plugins_dat_file = new File(Gatherer.getGLIUserDirectoryPath() + "plugins.dat");
+		if (plugins_dat_file.exists()) {
+			System.err.println("Deleting plugins.dat file...");
+			Utility.delete(plugins_dat_file);
+		}
+		File classifiers_dat_file = new File(Gatherer.getGLIUserDirectoryPath() + "classifiers.dat");
+		if (classifiers_dat_file.exists()) {
+			System.err.println("Deleting classifiers.dat file...");
+			Utility.delete(classifiers_dat_file);
+		}
+
+		try {
+			// Load GLI config file
+			new Configuration(getGLIUserDirectoryPath(), gsdl_path, gsdl3_path, gsdl3_src_path, site_name,
+			fedora_info);
+			
+			// Check we know where Perl is
+			Configuration.perl_path = perl_path;
+			if (isGsdlRemote && !isDownloadEnabled && 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());
+				}
+			}
+
+			// 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.")
+			    && !java_vendor.equals("Oracle Corporation")) {
+				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();
+			}
+
+			if (fedora_info.isActive()) {
+
+			    // if we have either a remote GS 2/3 server, or if we are dealing with a 
+			    // local GS2, or else if it's a local GS3 but with fedora installed elsewhere, 
+			    // we ask for fedora login details now
+			    File fedora_webapp = new File(gsdl3_src_path+File.separator+"packages"+File.separator+"tomcat"+File.separator+"webapps"+File.separator+"fedora");
+			    
+			    if(isGsdlRemote || !GS3 || !fedora_webapp.exists()) {
+				popupFedoraInfo();
+			    }
+
+			    // else if we have a local GS3 with fedora installed within it, we'll be starting 
+			    // up fedora further below, together with the local tomcat
+			}
+			
+			// the no_load flag to GLI is processed at the end of handling open_collection_file_path
+			open_collection_file_path = open_collection;
+			if (open_collection_file_path == null) {
+				open_collection_file_path = Configuration.getString(
+				"general.open_collection"+Configuration.gliPropertyNameSuffix(), true);
+			}
+			
+			initCollectDirectoryPath(); 
+			
+			if (no_load || (isGsdlRemote && open_collection_file_path.equals(""))) {
+				open_collection_file_path = null;
+			}
+			
+			// Finally, we're ready to find out the version of the remote Greenstone server 
+			if(isGsdlRemote) {
+				// instantiate the RemoteGreenstoneServer object first
+				remoteGreenstoneServer = new RemoteGreenstoneServer();
+
+				// Set up proxy
+				setProxy();
+				// Now we set up an Authenticator
+				Authenticator.setDefault(new GAuthenticator());
+
+				int greenstoneVersion = 2;
+				requestGLIServerURL();
+				gliserver_url_string = Configuration.gliserver_url.toString();
+				
+				greenstoneVersion = remoteGreenstoneServer.getGreenstoneVersion();
+				// Display the version to make error reports a lot more useful
+				System.err.println("Remote Greenstone server version: " + greenstoneVersion);
+				if(greenstoneVersion == -1) { // remote server not running
+					Gatherer.exit();
+				}
+				if(greenstoneVersion >= 3) {
+					this.GS3 = true;
+					Configuration.prepareForGS3();
+				} 
+				
+				if(fedora_info.isActive()) { 
+					// when GS server is remote, FEDORA_HOME resides on the remote server side,
+					// but we know the library URL from user-provided information
+					library_url_string = fedora_info.getLibraryURL();
+				} else {
+					library_url_string = remoteGreenstoneServer.getLibraryURL(Configuration.gliserver_url.toString());
+				}
+				// write it into the config file
+				Configuration.setString("general.library_url", true, library_url_string);
+			}
+			else { // local greenstone: add shutdown hooks to forcibly stop the server on irregular termination
+			    // And start up the local library server, if that's what we want
+
+			    // The Java virtual machine shuts down in response to two kinds of events:
+			    // - The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
+			    // - The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.
+			    // https://coderanch.com/t/328888/java/Killing-process-spawned-Runtime-exec
+			    // So here we add a shutdown hook to take care of Ctrl-C situations where GLI is irregularly terminated
+			    // Sadly, the shutdownhook never gets called on Windows, whether GS2 or GS3,
+			    // when a Ctrl-C is sent to the DOS prompt that launched GLI. Because GLI on Windows
+			    // currently waits to respond to a Ctrl-C until AFTER GLI is already (properly) exited
+			    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+				    public void run() {
+					
+					if(Gatherer.exit != true) { // unexpected termination, such as Ctrl-C won't set Gatherer.exit
+					    // so still need to at least issue the call to stop any running GS server
+					    
+					    System.err.println("ShutDownHook called...");
+					    System.err.println("Attempting to forcibly terminate the GS server...");
+
+					    if (GS3) { // issue the ant call to stop any running GS3
+						// (tomcat and networked Derby Server) by calling GS3ServerThread.stopServer()
+						GS3ServerThread.stopServer();
+					    } else { // issue the call to stop any running GS2 local library server
+						if (LocalLibraryServer.isRunning() == true) {
+						    LocalLibraryServer.forceStopServer();
+						}
+					    }
+					}
+				    }
+				}));
+					
+			    
+				if (!GS3) {		
+					isLocalLibrary = LocalLibraryServer.start(gsdl_path, local_library_path);				
+					
+				}
+				else { // local GS3, start the local tomcat
+				    
+					GS3ServerThread thread = new GS3ServerThread(gsdl3_src_path, "restart");
+					thread.start();
+	
+
+
+					// If fedora installed inside this local GS3, then ask for fedora login details now.
+					if (fedora_info.isActive()) { 
+					    File fedora_webapp = new File(gsdl3_src_path+File.separator+"packages"+File.separator+"tomcat"+File.separator+"webapps"+File.separator+"fedora");
+					    
+					    if(fedora_webapp.exists()) {
+						System.err.println("**** Waiting for the local Greenstone server to start up fedora...");
+						popupFedoraInfo();
+					    }
+					}
+				}
+				// else web library: GS server is local, but doesn't use the webserver included with GS2
+			}
+			
+			// 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
+			// It is not necessary if an independent GSI was launched and the user hasn't pressed Enter Library yet
+			DebugStream.println("Configuration.library_url = " + Configuration.library_url);
+			if (Configuration.library_url == null) {
+				if(isLocalLibrary) {
+					if(!LocalLibraryServer.isURLPending()) {
+						missingEXEC();
+					}
+					// else LocalLibraryServer is expecting a URL soon, so don't need to display the dialog
+				} else { // GS2 webLibrary or GS3 or remote Greenstone
+					missingEXEC();
+				}
+			}
+
+			// The "-gliserver_url" option overwrites anything in the config files
+			if (gliserver_url_string != null && gliserver_url_string.length() > 0) {
+				try {
+					System.err.println("Setting gliserver_url to " + gliserver_url_string + "...");
+					Configuration.gliserver_url = new URL(gliserver_url_string);
+				}
+				catch (MalformedURLException error) {
+					DebugStream.printStackTrace(error);
+				}
+			}
+
+			// If we're using a remote Greenstone we need to know where the gliserver script is
+			DebugStream.println("Configuration.gliserver_url = " + Configuration.gliserver_url);
+
+			if (GS3) {
+				// Load Greenstone 3 servlet configuration
+				if (isGsdlRemote){
+					servlet_config = new ServletConfiguration(Configuration.gli_user_directory_path);
+				}else{
+					servlet_config= new ServletConfiguration(gsdl3_path);
+				}
+			}
+
+			if (GS3 && Configuration.servlet_path == null) {
+				Configuration.servlet_path = servlet_config.getServletPath(Configuration.site_name);
+			}
+			
+			// ensure that a directory called 'cache' exists in the GLI user directory  
+			File user_cache_dir = new File(Gatherer.getGLIUserCacheDirectoryPath());
+			System.err.println("User cache dir: " + Gatherer.getGLIUserCacheDirectoryPath());
+			if (!user_cache_dir.exists() && !user_cache_dir.mkdir()) {
+				System.err.println("Warning: Unable to make directory: " + user_cache_dir);
+			}
+
+
+			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();
+				}
+			}
+
+
+			// Check for ImageMagick - dependent on perl_path
+			if (Gatherer.isGsdlRemote) {
+				DebugStream.println("Not checking for ImageMagick.");
+			}
+			else if (!(new ImageMagickTest()).found()) {
+				// Time for a warning message
+				missingImageMagick();
+			}
+			
+			// Check for PDFBox
+			if (Gatherer.isGsdlRemote) {
+				DebugStream.println("Not checking for PDFBox.");
+			}
+			else {			    
+				String gs_dir = gsdl_path; // for GS3, pdf-box is in gs2build/ext (not in GS3/ext), for GS2 it's also in GS2/ext
+			    File pdfboxExtensionFolder = new File(gs_dir+File.separator+"ext"+File.separator+"pdf-box");
+			    if (!(pdfboxExtensionFolder.exists() && pdfboxExtensionFolder.isDirectory())) {
+				// The user doesn't have PDFBox, inform them of it
+				String zipExtension = Utility.isWindows() ? "zip" : "tar.gz";
+				missingPDFBox(zipExtension, pdfboxExtensionFolder.getParent());
+			    }
+			}
+
+			// Check that the local can support multiple filename encodings
+			//System.err.println("#### Java identifies current Locale as (file.encoding): "
+			//	+ System.getProperty("file.encoding"));
+			if(System.getProperty("file.encoding").equals("UTF-8")){
+				// If the locale is UTF-8, Java will interpret all filename bytes as UTF-8, 
+				// which is a destructive process as it will convert characters not recognised
+				// by UTF-8 into the invalid character, rather than preserving the bytecodes.
+				// This has the effect that non-UTF8 encoded filenames on a system set to a 
+				// UTF-8 locale are not 'seen' by Java (if they contain non-ASCII characters).
+				multipleFilenameEncodingsNotSupported();		
+				FilenameEncoding.MULTIPLE_FILENAME_ENCODINGS_SUPPORTED = false; 
+				FilenameEncoding.URL_FILE_SEPARATOR = File.separator;
+			} else {
+				FilenameEncoding.MULTIPLE_FILENAME_ENCODINGS_SUPPORTED = true;
+				FilenameEncoding.URL_FILE_SEPARATOR = "/"; // URL file separator is always "/" 
+			}
+			
+			// 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);
+				}
+			}
+
+			// At this point (which is where this code originally used to be), we can set up the proxy for the
+			// non-remote case. The remote Greenstone server would already have setup its proxy when required.
+			if(!isGsdlRemote) {
+				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();
+			// Create Recycle Bin
+			recycle_bin = new RecycleBin();
+
+			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();
+				}
+			}
+			
+			
+		} 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);
+
+		// Get a list of the core Greenstone classifiers and plugins
+		Classifiers.loadClassifiersList(null);
+		Plugins.loadPluginsList(null);
+
+		// Users may specify a non-standard collect directory (eg. when running one GLI in a network environment)
+		// Set to any custom collection directory provided to gli. This happens if gli was run as:
+		// ./gli.sh -collectdir </full/path/to/custom/collect>
+		if(collect_directory_path != null) {
+
+		    // create a version of the collect_dir_path without a file-separator at end
+		    String collectDir = collect_directory_path; 
+		    if(collectDir.endsWith(File.separator)) {
+			collectDir = collectDir.substring(0, collectDir.length()-1); // remove file separator at end
+		    }
+
+		    // update .gli/config.xml to contain the version of the path without file-separator at end
+		    if(collect_directory_path.equals(getDefaultGSCollectDirectoryPath(false))) {
+			Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(), 
+						true, "");
+		    } else {
+			Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(), 
+						true, collectDir);
+		    }
+
+		    // set non_standard_collect_directory_path variable. Ensures file_separator at end
+		    Gatherer.setCollectDirectoryPath(collect_directory_path); 
+
+		    // Use version of path without file-separator at end to set collecthome in gsdlsite(3).cfg
+		    if(collectDir != null) {
+			collectDir = "\""+collectDir+"\"";
+		    }
+		    Utility.updatePropertyConfigFile(getGsdlSiteConfigFile(), "collecthome", collectDir);
+		    // if gsdlsite.cfg does not exist (if using server.exe for instance), the above method will just return
+		}
+
+		// If using a remote Greenstone we need to download the collection configurations now
+		if (Gatherer.isGsdlRemote) {
+			if (remoteGreenstoneServer.downloadCollectionConfigurations().equals("")) {
+				// !! Something went wrong downloading the collection configurations
+				System.err.println("Error: Could not download collection configurations.");
+				if(!Gatherer.isApplet) { // don't close the browser if it is an applet!
+					System.exit(0);
+				}
+			}
+		}
+	}
+
+	
+	/** Returns the correct version of the (local or remote) Greenstone server if init() has already been called. */
+	public static int serverVersionNumber() { 
+		return GS3 ? 3 : 2;
+	} 
+
+	/** Returns "Server: version number" if init() has already been called. */
+	public static String getServerVersionAsString() { 
+		return "Server: v" + serverVersionNumber();
+	} 
+
+	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 && Configuration.screen_size.width > 0) {
+			size.width = Configuration.screen_size.width;
+		}
+		if (size.height < 480) {
+			size.height = 480;
+		}
+		else if (size.height > Configuration.screen_size.height && Configuration.screen_size.height > 0) {
+			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);
+		}
+
+		// Get a list of the core Greenstone classifiers and plugins
+		/*Classifiers.loadClassifiersList(null);
+	Plugins.loadPluginsList(null);
+
+	// If using a remote Greenstone we need to download the collection configurations now
+	if (Gatherer.isGsdlRemote) {
+		if (remoteGreenstoneServer.downloadCollectionConfigurations().equals("")) {
+		// !! Something went wrong downloading the collection configurations
+		System.err.println("Error: Could not download collection configurations.");
+		System.exit(0);
+		}
+	}*/
+
+		// If there was a collection left open last time, reopen it	
+		if (open_collection_file_path == null || new File(Gatherer.open_collection_file_path).isDirectory()) {
+			
+			//the menu bar items, file and edit, are disabled from the moment of their creation. if there is no left-over collection from the last session, enable them; otherwise it's disabled until the collection finishes loading. They will be enabled in collectionManager.java
+			setMenuBarEnabled(true);
+		} else {
+
+			// If there was a collection left open last time, reopen it
+			c_man.openCollectionFromLastTime();
+		}
+	}
+
+	public static void setMenuBarEnabled(boolean enabled) {
+		g_man.menu_bar.file.setEnabled(enabled);
+		g_man.menu_bar.edit.setEnabled(enabled);
+	}
+
+	/** 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
+	*/
+	static public void exit(int new_exit_status)
+	{
+		DebugStream.println("In Gatherer.exit()...");
+		exit = true;
+		if (new_exit_status != 0) {
+			// default exit_status is already 0 
+			// only remember a new exit status if it is non-trivial
+			exit_status = new_exit_status;
+		}
+
+		// Save the file associations
+		if (assoc_man != null) {
+			assoc_man.save();
+			assoc_man = null;
+		}
+
+		// Get the gui to deallocate
+		if(g_man != null) {
+			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();
+		}
+
+		// If we're using a remote Greenstone server we need to make sure that all jobs have completed first
+		if (isGsdlRemote) {
+			remoteGreenstoneServer.exit();
+		} else if (GS3) { // stop the local tomcat web server when running GS3
+		    // can't call ant stop from its own thread - what if GLI has exited by then?
+		    // issue call to ant stop from the main GLI thread
+		    //GS3ServerThread thread = new GS3ServerThread(Configuration.gsdl_path, "stop");
+		    //thread.start();
+
+		    GS3ServerThread.stopServer();
+		    
+		}
+
+		// 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(exit_status);
+			}
+		}
+		else {
+			JOptionPane.showMessageDialog(g_man, Dictionary.get("General.Outstanding_Processes"), Dictionary.get("General.Outstanding_Processes_Title"), JOptionPane.ERROR_MESSAGE);
+			g_man.setVisible(false);
+		}
+	}
+
+	static public void exit()
+	{
+		exit(0);
+	}
+
+	/** Returns the path of the current collect directory. */
+	static public String getCollectDirectoryPath()
+	{
+		if (non_standard_collect_directory_path != null) {
+			return non_standard_collect_directory_path;
+		}
+		
+		return getDefaultGSCollectDirectoryPath(true); // file separator appended
+		
+	}
+	
+	// if we need to know whether the local server we are running is server.exe vs apache web server
+	static public boolean isPersistentServer() {
+		return (!isGsdlRemote && LocalLibraryServer.isPersistentServer());
+	}
+
+	/** Returns the path of the Greenstone "collect" directory. */
+	static public String getDefaultGSCollectDirectoryPath(boolean appendSeparator) {
+		String colDir;
+		if (GS3) {
+			colDir = getSitesDirectoryPath() + Configuration.site_name + File.separator + "collect";			
+		}
+		else {
+			colDir = Configuration.gsdl_path + "collect";
+		}
+		
+		if(appendSeparator) {
+			colDir += File.separator;
+		}
+		return colDir;
+	}	
+
+	/** 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);
+		}
+	}
+
+
+	public static void initCollectDirectoryPath() {		
+		String defaultColdir = getDefaultGSCollectDirectoryPath(false); // no file separator at end
+		String coldir = defaultColdir;
+		// If local GS and opening a collection outside the standard GS collect folder,
+		// need to open the non-standard collect folder that the collection resides in
+		if (!isGsdlRemote 
+		    && !open_collection_file_path.startsWith(defaultColdir))
+		{  
+			File collectFolder = null;
+			
+			if(!open_collection_file_path.equals("")) {
+				if(!open_collection_file_path.endsWith("gli.col")) { // then it's a collect folder
+					collectFolder = new File(open_collection_file_path);
+				} else {
+					// the filepath is a gli.col file. To get the collect folder: the 1st level up
+					// is the collection folder, 2 two levels up is the containing collect folder
+					collectFolder = new File(open_collection_file_path).getParentFile().getParentFile();
+				}	
+				
+				// Need to deal with colgroups as well: while there's an etc/collect.cfg
+				// in the current collectFolder, move one level up
+				String cfg_file = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
+				if(new File(collectFolder.getAbsolutePath()+File.separator+cfg_file).exists()) { // colgroup
+					collectFolder = collectFolder.getParentFile();		    
+				}
+
+				// Inform the user that their collecthome is non-standard (not inside GS installation)
+				nonStandardCollectHomeMessage(collectFolder.getAbsolutePath(), defaultColdir); // display message
+			}		
+			
+			if(collectFolder == null || !collectFolder.exists()) {
+				// if GLI config file specified no collectDir (open_collection_file_path is "")
+				// OR if dealing with a local server but the collectdir no longer exists, 
+				// use the default greenstone collect directory, and write that to affected files
+				
+				open_collection_file_path = defaultColdir;		// default GS collect dir
+				// Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(), true, "");
+			} else { // use the coldir value specified in the flags to GLI or from the last GLI session				
+				coldir = collectFolder.getAbsolutePath();
+			}			
+			// set it as the current folder
+			setCollectDirectoryPath(coldir); // will ensure the required file separator at end
+		}
+		
+		if(!isGsdlRemote) {
+			// LocalLibraryServer would  already have set glisite.cfg to the correct collecthome for server.exe
+			// Here we set collecthome in gsdl(3)site.cfg for the GS2 apache web server and GS3 tomcat server
+			String gsdlsitecfg = getGsdlSiteConfigFile();			
+			// update the gsdlsite config file and store the old value for use when we exit GLI
+			if(coldir.equals(defaultColdir)) {				
+				gsdlsite_collecthome = Utility.updatePropertyConfigFile(
+				gsdlsitecfg, "collecthome", null);
+			} else {
+				gsdlsite_collecthome = Utility.updatePropertyConfigFile(
+				gsdlsitecfg, "collecthome", "\""+coldir+"\""); // no file separator
+				// if gsdlsite.cfg does not exist (if using server.exe for instance), the above method will just return
+			}
+		}		
+	}
+
+	/** depending on the version of GS being run, return the path to the current GS' installation's gsdl(3)site.cfg */
+	public static String getGsdlSiteConfigFile() {
+		if(Gatherer.GS3) { // web/WEB-INF/cgi/gsdl3site.cfg
+			return Configuration.gsdl3_path + File.separator + "WEB-INF" 
+			+ File.separator + "cgi" + File.separator + "gsdl3site.cfg";
+		} else { // cgi-bin/gsdlsite.cfg
+		    String gsdlarch = System.getenv("GSDLARCH");
+		    if(gsdlarch == null) {
+			gsdlarch = "";
+		    }
+		    return Configuration.gsdl_path /* + File.separator */
+			+ "cgi-bin" + File.separator + client_operating_system+gsdlarch + File.separator + "gsdlsite.cfg";
+		}
+	}
+
+	public static void collectDirectoryHasChanged(
+	String oldCollectPath, String newCollectPath, final Component container) 
+	{		
+		if(oldCollectPath.equals(newCollectPath)) {
+			return; // nothing to be done
+		}
+		
+		// Will use a busy cursor if the process of changing the collect directory takes more 
+		// than half a second/500ms. See http://www.catalysoft.com/articles/busyCursor.html
+		Cursor originalCursor = container.getCursor();
+		java.util.TimerTask timerTask = new java.util.TimerTask() {
+			public void run() {
+				// set the cursor on the container:
+				container.setCursor(new Cursor(Cursor.WAIT_CURSOR));
+			}
+		};
+		java.util.Timer timer = new java.util.Timer(); 
+		
+		try {
+			timer.schedule(timerTask, 500);
+			
+			// first save any open collection in the old location, then close it
+			if(Gatherer.c_man.getCollection() != null) {
+				Gatherer.g_man.saveThenCloseCurrentCollection(); // close the current collection first
+			}
+			
+			// change to new collect path
+			if(newCollectPath.equals(getDefaultGSCollectDirectoryPath(true))) {
+				Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(), 
+				true, "");
+			} else {
+				Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(), 
+				true, newCollectPath);
+			}
+			Gatherer.setCollectDirectoryPath(newCollectPath);
+			
+
+			// refresh the Documents in Greenstone Collections
+			//WorkspaceTreeModel.refreshGreenstoneCollectionsNode();
+			Gatherer.g_man.refreshWorkspaceTreeGreenstoneCollections();
+			
+			// The web server needs to be told where a new (non-standard) collecthome home is.
+			// The web server reads collecthome from cgi-bin/<OS>/gsdlsite.cfg, where the property
+			// collecthome can be specified if a non-standard collecthome is to be used. If no 
+			// such property is specified in the file, then it assumes the standard GS collecthome.
+			// This method does nothing for a remote Greenstone.	
+			if(Gatherer.isGsdlRemote) {
+				return;
+			}	
+			
+			// non-destructive update of gsdl(3)site.cfg (comments preserved)
+			String collectDir = Gatherer.getCollectDirectoryPath();
+			//collectDir = "\"" + collectDir.substring(0, collectDir.length()-1) + "\""; // remove file separator at end	
+			collectDir = collectDir.substring(0, collectDir.length()-1); // remove file separator at end
+			if(collectDir != null) {
+				collectDir = "\""+collectDir+"\"";
+			}
+			Utility.updatePropertyConfigFile(getGsdlSiteConfigFile(), "collecthome", collectDir);
+			// if gsdlsite.cfg does not exist (if using server.exe for instance), the above method will just return
+			
+			if(!Gatherer.GS3 && Gatherer.isLocalLibrary) {
+				// for Images in the collection to work, the apache web server 
+				// configuration's COLLECTHOME should be updated on collectdir change. 
+				// Does nothing for server.exe at the moment
+
+				LocalLibraryServer.reconfigure();
+			}
+		} finally { // Note try-finally section without catch:
+			// "Java's finally clause is guaranteed to be executed even when
+			// an exception is thrown and not caught in the current scope."
+			// See http://www.catalysoft.com/articles/busyCursor.html
+			// the following code fragment is guaranteed to restore the original
+			// cursor now the custom actionPerformed() processing is complete, regardless
+			// of whether the processing method terminates normally or throws an exception
+			// and regardless of where in the call stack the exception is caught.			
+			
+			timer.cancel();
+			container.setCursor(originalCursor);
+		}
+	}
+
+
+	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) {
+
+	    // Do not do configGS3Server for a GS3 solr collection. Not at present at least, when we're stopping
+	    // and starting the GS3 server from GLI for solr cols, since this function clears the solr.xml file.
+	    /*if(Gatherer.c_man.isSolrCollection()) {
+		return;
+		}*/
+
+		if (Configuration.library_url == null){
+			System.out.println("Error: you have not provided the Greenstone Library address.");  
+			return;
+
+		} 
+		
+		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(java.net.ConnectException connectException) {
+			JOptionPane.showMessageDialog(g_man, Dictionary.get("Preferences.Connection.Library_Path_Connection_Failure", Configuration.library_url.toString()), Dictionary.get("General.Warning"), JOptionPane.WARNING_MESSAGE);
+			DebugStream.println(connectException.getMessage());
+		}
+		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
+	*/
+	static 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.");
+		}
+	}
+
+
+	static public void spawnApplication(String command)
+	{
+		ExternalApplication app = new ExternalApplication(command);
+		apps.add(app);
+		app.start();
+	}
+
+	static public void spawnApplication(String command, String ID)
+	{
+		ExternalApplication app = new ExternalApplication(command, ID);
+		apps.add(app);
+		app.start();
+	}
+
+	static public void spawnApplication(String[] commands, String ID)
+	{
+		ExternalApplication app = new ExternalApplication(commands, ID);
+		apps.add(app);
+		app.start();
+	}
+
+	static public void terminateApplication(String ID) {
+		for(int i = 0; i < apps.size(); i++) {
+			ExternalApplication app = (ExternalApplication)apps.get(i);
+			if(app.getID() != null && app.getID().equals(ID)) {
+				app.stopExternalApplication();
+				apps.remove(app);
+			}
+		}
+	}
+
+
+	/** 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
+	*/    
+	static 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;
+		String configPropertyName = "general.library_url"+Configuration.gliPropertyNameSuffix();
+
+		if (GS3) {
+			// Warning dialog with no cancel button and no "turn off warning" checkbox 
+			dialog = new WarningDialog("warning.MissingEXEC", Dictionary.get("MissingEXEC_GS3.Title"), Dictionary.get("MissingEXEC_GS3.Message"), configPropertyName, false, false);
+		} else { // local case
+			dialog = new WarningDialog("warning.MissingEXEC", Dictionary.get("MissingEXEC.Title"), Dictionary.get("MissingEXEC.Message"), configPropertyName, false);
+		}
+
+		JTextField field = new URLField.Text(Configuration.getColor("coloring.editable_foreground", false), Configuration.getColor("coloring.editable_background", false));
+
+		// Set the default library URL to the tomcat server and port number
+		// specified in the build.properties located in the gsdl3_src_path 
+		if (GS3) {
+			String host = "localhost";
+			String port = "8383";
+			
+			File buildPropsFile = new File(Configuration.gsdl3_src_path + File.separator + "build.properties");
+			if(buildPropsFile.exists()) {
+				Properties props = new Properties();
+				try{
+					props.load(new FileInputStream(buildPropsFile));
+					host = props.getProperty("tomcat.server", host); 
+					port = props.getProperty("tomcat.port", port);
+				}catch(Exception e){
+					DebugStream.println("Could not load build.properties file");
+					System.err.println("Could not load build.properties file");
+				}
+				props = null;
+			}
+			String defaultURL = "http://"+host+":"+port+"/"+"greenstone3";
+			field.setText(defaultURL);
+			field.selectAll();
+		}
+		dialog.setValueField(field);
+		dialog.display();
+		dialog.dispose();
+		dialog = null;
+
+		String library_url_string = Configuration.getString(configPropertyName, true);
+		if (!library_url_string.equals("")) {
+			try {
+				// WarningDialog does not allow invalid URLs, so the following is ignored:
+				// make sure the URL the user provided contains the http:// prefix
+				// and then save the corrected URL
+				if(!library_url_string.startsWith("http://") 
+						&& !library_url_string.startsWith("https://")) {
+					library_url_string = "http://"+library_url_string;
+					Configuration.setString(configPropertyName, true, configPropertyName);
+				}
+				Configuration.library_url = new URL(library_url_string);
+			}
+			catch (MalformedURLException exception) {
+				DebugStream.printStackTrace(exception);
+			}
+		}
+	}
+
+
+
+	/** Prints a warning message about a missing library path, which means the final collection cannot be previewed in the Gatherer.
+	*/
+	static private void popupFedoraInfo() {
+
+		FedoraLogin dialog = new FedoraLogin("Fedora Login", false);
+
+		if (Configuration.library_url == null) {
+			
+			String library_url_string = dialog.getLibraryURL();
+			if (!library_url_string.equals("")) {
+				try {
+					Configuration.library_url = new URL(library_url_string);
+				}
+				catch (MalformedURLException exception) {
+					DebugStream.printStackTrace(exception);
+				}
+			}
+		}
+		
+		boolean showLogin = true;
+		do {
+			if(!dialog.loginRequested()) { // user pressed cancel to exit the FedoraLogin dialog
+				System.exit(0);
+			} else {
+				showLogin = dialog.loginRequested();
+				String hostname = dialog.getHostname();
+				String port     = dialog.getPort();
+				String username = dialog.getUsername();
+				String password = dialog.getPassword();
+				String protocol = dialog.getProtocol();
+				
+				Configuration.fedora_info.setHostname(hostname);
+				Configuration.fedora_info.setPort(port);
+				Configuration.fedora_info.setUsername(username);
+				Configuration.fedora_info.setPassword(password);
+				Configuration.fedora_info.setProtocol(protocol);
+				
+				String ping_url_str = protocol + "://" + hostname + ":" + port + "/fedora";
+				String login_str = username + ":" + password;
+				
+				String login_encoding = Base64.encodeBytes(login_str.getBytes());
+				
+				try {
+					URL ping_url = new URL(ping_url_str);
+					URLConnection uc = ping_url.openConnection();
+					uc.setRequestProperty  ("Authorization", "Basic " + login_encoding);
+					// Attempt to access some content ...
+					InputStream content = (InputStream)uc.getInputStream();
+					
+					// if no exception occurred in the above, we would have come here:
+					showLogin = false;
+					dialog.dispose();
+				}
+				catch (Exception exception) {
+					// TODO: move into dictionary
+					String[] errorMessage = {"Failed to connect to the Fedora server.", "It might not be running, or",
+						"incorrect username and/or password."};
+					dialog.setErrorMessage(errorMessage);
+					//DebugStream.printStackTrace(exception);
+					// exception occurred, show the dialog again (do this after printing to
+					// debugStream, else the above does not get done for some reason).
+					dialog.setVisible(true);
+				}
+			} 
+		} while(showLogin);
+
+		dialog = null; // no more need of the dialog
+		
+		// Now we are connected.
+	}
+
+
+
+	static private void requestGLIServerURL()
+	{
+		WarningDialog dialog;
+		String[] defaultURLs = {
+			"http://localhost:8080/greenstone3/cgi-bin/gliserver.pl", 
+			"http://localhost:8080/gsdl/cgi-bin/gliserver.pl"
+		};
+
+		// Warning dialog with no cancel button and no "turn off warning" checkbox 
+		// (since user-input of the gliserver script is mandatory)
+		dialog = new WarningDialog("warning.MissingGLIServer", Dictionary.get("MissingGLIServer.Title"), Dictionary.get("MissingGLIServer.Message"), "general.gliserver_url", false, false); 
+
+		dialog.setValueField(new URLField.DropDown(Configuration.getColor("coloring.editable_foreground", false), 
+		Configuration.getColor("coloring.editable_background", false), 
+		defaultURLs, "general.gliserver_url", 
+		"general.open_collection"+Configuration.gliPropertyNameSuffix(), 
+		"gliserver.pl")); 
+
+		if (Gatherer.default_gliserver_url!=null){
+			dialog.setValueField(Gatherer.default_gliserver_url.toString());
+		}
+
+		// A WarningDialog cannot always be made to respond (let alone to exit the program) on close. We
+		// handle the response of this particular WarningDialog here: a URL for gliserver.pl is a crucial
+		// piece of user-provided data. Therefore, if no URL was entered for gliserver.pl, it'll exit safely.
+		dialog.addWindowListener(new WindowAdapter() {
+			public void windowClosing(WindowEvent e) {
+				Gatherer.exit();
+			}
+		});
+		
+		dialog.display();
+		dialog.dispose();
+		dialog = null;
+
+		
+		String gliserver_url_string = Configuration.getString("general.gliserver_url", true);
+		if (!gliserver_url_string.equals("")) {
+			try {
+				Configuration.gliserver_url = new URL(gliserver_url_string);
+				Configuration.setString("general.gliserver_url", true, gliserver_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 private void missingGSDL() {
+		WarningDialog dialog = new WarningDialog("warning.MissingGSDL", Dictionary.get("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 private void missingImageMagick() {
+		WarningDialog dialog = new WarningDialog("warning.MissingImageMagick", Dictionary.get("MissingImageMagick.Title"), Dictionary.get("MissingImageMagick.Message"), null, false);
+		dialog.display();
+		dialog.dispose();
+		dialog = null;
+	}
+
+    	/** Prints a message informing the user where they can get PDFBox from to process PDF files of v1.5 and greater */
+    static private void missingPDFBox(String zipExtension, String extFolder) {
+	// point to the correct version of the PDFBox extension for this Greenstone release
+	String releaseTag = "";
+	if(!PROGRAM_VERSION.equals("trunk")) { // assume it's a release version
+	    releaseTag = "main/tags/"+PROGRAM_VERSION+"/";
+	}
+
+	WarningDialog dialog = new WarningDialog("warning.MissingPDFBox", Dictionary.get("MissingPDFBox.Title"), Dictionary.get("MissingPDFBox.Message", new String[]{releaseTag, zipExtension, extFolder}), 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 private void missingPERL() {
+		WarningDialog dialog = new WarningDialog("warning.MissingPERL", Dictionary.get("MissingPERL.Title"), Dictionary.get("MissingPERL.Message"), null, false);
+		dialog.display();
+		dialog.dispose();
+		dialog = null;
+	}
+
+    /** Prints a message informing the user that their collecthome is non-standard (not inside GS installation) */
+    static private void nonStandardCollectHomeMessage(String open_collection_file_path, String defaultColDir) {
+	WarningDialog dialog = new WarningDialog("warning.NonStandardCollectHome", Dictionary.get("NonStandardCollectHome.Title"), Dictionary.get("NonStandardCollectHome.Message", new String[]{open_collection_file_path, defaultColDir}), null, false);
+		dialog.display();
+		dialog.dispose();
+		dialog = null;
+	}
+
+	/** Prints a warning message about the OS not supporting multiple filename encodings.  */
+	static private void multipleFilenameEncodingsNotSupported() {	
+		WarningDialog dialog = new WarningDialog("warning.NoEncodingSupport", 
+		Dictionary.get("NoEncodingSupport.Title"), 
+		Dictionary.get("NoEncodingSupport.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)) {
+			    // These are Java properties, therefore see
+			    // https://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html
+			    // https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html
+			    // https://stackoverflow.com/questions/14243590/proxy-settings-in-java
+
+			    // Not sure what proxyType is. And proxySet ceased to exist since JDK 6 or before
+				System.setProperty("http.proxyType", "4");
+				System.setProperty("http.proxyHost", Configuration.getString("general.HTTP_proxy_host", true));
+				System.setProperty("http.proxyPort", Configuration.getString("general.HTTP_proxy_port", true));
+				//System.setProperty("http.proxySet", "true");
+				
+				System.setProperty("https.proxyHost", Configuration.getString("general.HTTPS_proxy_host", true));
+				System.setProperty("https.proxyPort", Configuration.getString("general.HTTPS_proxy_port", true));
+
+				System.setProperty("ftp.proxyHost", Configuration.getString("general.FTP_proxy_host", true));
+				System.setProperty("ftp.proxyPort", Configuration.getString("general.FTP_proxy_port", true));
+				
+			} else {
+				System.setProperty("http.proxyHost", "");
+				System.setProperty("http.proxyPort", "");
+				//System.setProperty("http.proxySet", "false");
+				System.setProperty("https.proxyHost", "");
+				System.setProperty("https.proxyPort", "");
+				System.setProperty("ftp.proxyHost", "");
+				System.setProperty("ftp.proxyPort", "");
+			}
+		} catch (Exception error) {
+			DebugStream.println("Error in Gatherer.initProxy(): " + error);
+			DebugStream.printStackTrace(error);
+		}
+	}
+
+	
+	/** 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 voluntarily 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. */
+	static private class ExternalApplication
+	extends Thread {
+		private SafeProcess process = null;
+		/** The initial command string given to this sub-process. */
+		private String command = null;
+		private String[] commands = null;
+
+		private String ID = null;
+
+		/** Constructor.
+	* @param command The initial command <strong>String</strong>.
+	*/
+		public ExternalApplication(String command) {
+			this.command = command;
+		}
+
+		public ExternalApplication(String[] commands) {
+			this.commands = commands;
+		}
+
+		public ExternalApplication(String command, String ID) {
+			this.command = command;
+			this.ID = ID;
+		}
+
+		public ExternalApplication(String[] commands, String ID) {
+			this.commands = commands;
+			this.ID = ID;
+		}
+		
+		public String getID() { 
+			return ID; 
+		}
+
+		/** 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++) {						
+						// get rid of any quotes around parameters in file associations
+						if(commands[i].startsWith("\"") || commands[i].startsWith("\'")) {
+						    commands[i] = commands[i].substring(1);
+						}
+						if(commands[i].endsWith("\"") || commands[i].endsWith("\'")) {
+						    commands[i] = commands[i].substring(0, commands[i].length()-1);
+						}
+
+						if (i>0) {
+						    whole_command.append(" ");
+						}
+						whole_command.append(commands[i]);		    
+					}
+					DebugStream.println("Running " + whole_command.toString());
+					process = new SafeProcess(commands);
+				}
+				else {
+					DebugStream.println("Running " + command);
+					process = new SafeProcess(command);
+				}
+				process.runProcess();
+			}
+			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) {
+				// In my opinion (DB) there is no need to exit here,
+				// the 'run' method ending naturally brings this
+				// thread to an end.  In fact it is potentially
+				// dangerous to exit here, as the main thread in the
+				// Gatherer class may be stopped prematurely.  As it so
+				// happens the point at which the ExternalApplication thread
+				// is asked to stop (Back in the main Gatherer thread) is after
+				// various configuration files have been saved.
+				// 
+				// A similar argument holds for BrowserApplication thread below.
+				System.exit(exit_status);
+			}
+		}
+		public void stopExternalApplication() {
+			if(process != null) {
+			    SafeProcess.log("*** stopExternalApplication called.");
+			    process.cancelRunningProcess();
+			}
+		}
+	}
+	/** 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. */
+	static private class BrowserApplication
+	extends Thread {
+		private SafeProcess 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);
+
+					process = new SafeProcess(new_commands);
+					int exitCode = process.runProcess();
+					if (exitCode != 0) { // if Netscape or mozilla was not open
+						DebugStream.println("couldn't do remote, trying original command");
+						printArray(commands);
+						process = null;
+						process = new SafeProcess(commands); // try the original command
+						process.runProcess();
+					}
+				} 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());
+					process = new SafeProcess(commands);
+					process.runProcess();
+				}
+			}
+			
+			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(exit_status);
+			}
+		}
+		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) {
+			    SafeProcess.log("*** stopBrowserApplication called.");
+			    process.cancelRunningProcess();
+			}
+		}
+	}
+
+
+	private class ImageMagickTest
+	{
+		public boolean found()
+		{
+		    // at this stage, GLI has already sourced setup.bash, and the necessary
+		    // env variables will be available to the perl process we're about to launch
+		    boolean found = false;
+
+		    
+			    // run the command `/path/to/perl -S gs-magick.pl identify -version`
+			    ArrayList cmd_list = new ArrayList();
+			    if (!Gatherer.isGsdlRemote) {
+				if(Configuration.perl_path != null) {
+				    cmd_list.add(Configuration.perl_path);
+				} else {
+				    System.err.println("***** ImageMagickTest Warning: Perl_path not set, calling 'perl' instead.");
+				    cmd_list.add("perl");
+				}
+				cmd_list.add("-S");
+			    }
+			    cmd_list.add("gs-magick.pl");
+			    if(Utility.isWindows()) {
+				cmd_list.add("identify.exe");
+			    } else {
+				cmd_list.add("identify");
+			    }
+			    cmd_list.add("-version");
+
+			    String[] command_parts = (String[]) cmd_list.toArray(new String[0]);
+
+			    String cmd_str = "";
+			    for(int i = 0; i < command_parts.length; i++) {
+			    	cmd_str += command_parts[i] + " ";
+			    }
+			    DebugStream.println("***** Running ImageMagickTest command: " + cmd_str);
+			   
+			    SafeProcess image_magick_process = new SafeProcess(command_parts);
+			    int exitValue = image_magick_process.runProcess(); // default process iostream handling
+			    //new way of detection of ImageMagick
+			    // Inspect the standard output of the process and seach for two particular occurrences: Version and ImageMagick.
+			    String output = image_magick_process.getStdOutput().toLowerCase();
+			    if (output.indexOf("version") != -1 || output.indexOf("imagemagick") != -1) {
+				found = true;
+			    } // else found var remains false	
+			    
+			    return found;
+			    //return (image_magick_process.exitValue() == 0);
+			    
+		}
+	}
+
+
+	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 {
+			    SafeProcess perl_process = new SafeProcess(command);
+			    int exitValue = perl_process.runBasicProcess();
+			    return (exitValue == 0);
+			}
+			catch (Exception exception) {
+				return false;
+			}
+		}
+
+		public String toString() {
+			return command[0];
+		}
+	}
+	
+}
Index: debug-testing/gli_proxy/Preferences.java
===================================================================
--- debug-testing/gli_proxy/Preferences.java	(revision 31879)
+++ debug-testing/gli_proxy/Preferences.java	(revision 31879)
@@ -0,0 +1,1240 @@
+/**
+ *#########################################################################
+ *
+ * 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.remote.RemoteGreenstoneServer;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.GAuthenticator;
+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 HTTP = "HTTP";
+    static final public String HTTPS = "HTTPS";
+    static final public String FTP = "FTP";
+    
+    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 chdir_button;
+    private JButton ok_button;
+    private JCheckBox show_file_size_checkbox;
+    private JCheckBox no_check_certificate_checkbox; // Set no_check_certificate when retrieving https URLs that have no (valid) certificate
+    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 JCheckBox workflow_format;
+    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 JSpinner http_proxy_port_field;
+    private JSpinner https_proxy_port_field;
+    private JSpinner ftp_proxy_port_field;
+    private JTabbedPane tab_pane;
+    private JTextArea mode_description_textarea;
+    private JTextField font_field;
+    private JTextField gliserver_url_field;
+    private JTextField library_path_field;
+    private JTextField program_field;
+    private JTextField http_proxy_host_field;
+    private JTextField https_proxy_host_field;
+    private JTextField ftp_proxy_host_field;
+    private JTextField collect_dir_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);
+	setTitle(Dictionary.get("Preferences"));
+	setJMenuBar(new SimpleMenuBar("preferences"));
+
+	// Creation
+	JPanel content_pane = (JPanel) getContentPane();
+        content_pane.setComponentOrientation(Dictionary.getOrientation());
+	tab_pane = new JTabbedPane();
+        tab_pane.setComponentOrientation(Dictionary.getOrientation());
+	JPanel general_preferences = createGeneralPreferences();
+        general_preferences.setComponentOrientation(Dictionary.getOrientation());
+	tab_pane.addTab(Dictionary.get("Preferences.General"), null, general_preferences, Dictionary.get("Preferences.General_Tooltip")); 
+	tab_pane.addTab(Dictionary.get("Preferences.Mode"), null, createModePreferences(), Dictionary.get("Preferences.Mode_Tooltip"));
+	//	tab_pane.addTab(Dictionary.get("Preferences.Workflow"), null, createWorkflowPreferences(), Dictionary.get("Preferences.Workflow_Tooltip")); 
+	JPanel connection_preferences = createConnectionPreferences();
+        connection_preferences.setComponentOrientation(Dictionary.getOrientation());
+	tab_pane.addTab(Dictionary.get("Preferences.Connection"), null, connection_preferences, Dictionary.get("Preferences.Connection_Tooltip")); 
+	tab_pane.addTab(Dictionary.get("Preferences.Warnings"), null, createWarningPreferences(), Dictionary.get("Preferences.Warnings_Tooltip")); 
+	
+	JPanel button_pane = new JPanel();
+        button_pane.setComponentOrientation(Dictionary.getOrientation());
+	ok_button = new GLIButton(Dictionary.get("General.OK"), Dictionary.get("General.OK_Tooltip"));
+	
+	apply_button = new GLIButton(Dictionary.get("General.Apply"), Dictionary.get("General.Apply_Tooltip"));
+	
+	cancel_button = new GLIButton(Dictionary.get("General.Cancel"), Dictionary.get("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);
+        button_pane.setComponentOrientation(Dictionary.getOrientation());
+        
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(tab_pane, BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+        content_pane.setComponentOrientation(Dictionary.getOrientation());
+        
+	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.setComponentOrientation(Dictionary.getOrientation());
+	program_pane.setPreferredSize(ROW_SIZE);
+	JLabel program_label = new JLabel(Dictionary.get("Preferences.Connection.ProgramCommand"));
+	program_label.setPreferredSize(LABEL_SIZE);
+	program_label.setComponentOrientation(Dictionary.getOrientation());
+        
+	program_field = new JTextField(Configuration.getPreviewCommand());
+	program_field.setCaretPosition(0);
+	program_field.setToolTipText(Dictionary.get("Preferences.Connection.ProgramCommand_Tooltip"));
+	program_field.setComponentOrientation(Dictionary.getOrientation());
+        
+	JPanel library_path_pane = new JPanel();
+	library_path_pane.setPreferredSize(ROW_SIZE);
+        library_path_pane.setComponentOrientation(Dictionary.getOrientation());
+	JLabel library_path_label = new JLabel();
+	library_path_label.setPreferredSize(LABEL_SIZE);
+        library_path_label.setComponentOrientation(Dictionary.getOrientation());
+	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);
+        library_path_field.setComponentOrientation(Dictionary.getOrientation());
+	if (Gatherer.GS3) {
+	    library_path_label.setText(Dictionary.get("Preferences.Connection.Library_Path_GS3"));
+	    library_path_field.setToolTipText(Dictionary.get("Preferences.Connection.Library_Path_Tooltip_GS3"));
+	} else {
+	    library_path_label.setText(Dictionary.get("Preferences.Connection.Library_Path"));
+	    library_path_field.setToolTipText(Dictionary.get("Preferences.Connection.Library_Path_Tooltip"));
+	}
+	    
+	// Disable this field when using the applet, as it is automatically determined
+	library_path_label.setEnabled(!Gatherer.isApplet);
+	library_path_field.setEnabled(!Gatherer.isApplet);
+
+	JPanel gliserver_url_pane = null;
+	JLabel gliserver_url_label = null;
+	if (Gatherer.isGsdlRemote && !Gatherer.GS3) {
+	    gliserver_url_pane = new JPanel();
+	    gliserver_url_pane.setPreferredSize(ROW_SIZE);
+	    gliserver_url_label = new JLabel(Dictionary.get("Preferences.Connection.GLIServer_URL"));
+	    gliserver_url_label.setPreferredSize(LABEL_SIZE);
+            gliserver_url_label.setComponentOrientation(Dictionary.getOrientation());
+	    String gliserver_url_string = "";
+	    if (Configuration.gliserver_url != null) {
+		gliserver_url_string = Configuration.gliserver_url.toString();
+	    }
+	    gliserver_url_field = new JTextField(gliserver_url_string);
+            gliserver_url_field.setComponentOrientation(Dictionary.getOrientation());
+	    gliserver_url_field.setCaretPosition(0);
+	    gliserver_url_field.setToolTipText(Dictionary.get("Preferences.Connection.GLIServer_URL_Tooltip"));
+	   
+	    // Disable this field when using the applet, as it is automatically determined
+	    gliserver_url_label.setEnabled(!Gatherer.isApplet);
+	    gliserver_url_field.setEnabled(!Gatherer.isApplet);
+	}
+
+	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_pane.setComponentOrientation(Dictionary.getOrientation());
+	    site_label = new JLabel(Dictionary.get("Preferences.Connection.Site"));
+	    site_label.setPreferredSize(LABEL_SIZE);
+            site_label.setComponentOrientation(Dictionary.getOrientation());
+	    // what should we do if Gatherer.servlet_config.getSites() is null?
+	    site_combobox = new JComboBox(Gatherer.servlet_config.getSites().toArray());
+	    site_combobox.setOpaque(false);
+	    site_combobox.setToolTipText(Dictionary.get("Preferences.Connection.Site_Tooltip"));
+	    site_combobox.setComponentOrientation(Dictionary.getOrientation());
+            
+	    servlet_pane = new JPanel();
+	    servlet_pane.setPreferredSize(ROW_SIZE);
+            servlet_pane.setComponentOrientation(Dictionary.getOrientation());
+            
+	    servlet_label = new JLabel(Dictionary.get("Preferences.Connection.Servlet"));
+	    servlet_label.setPreferredSize(LABEL_SIZE);
+            servlet_label.setComponentOrientation(Dictionary.getOrientation());
+	    servlet_combobox = new JComboBox();
+	    servlet_combobox.setOpaque(false);
+            servlet_combobox.setComponentOrientation(Dictionary.getOrientation());
+	    // 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.setToolTipText(Dictionary.get("Preferences.Connection.Servlet_Tooltip2"));
+		//servlet_combobox.setModel(new DefaultComboBoxModel());
+		servlet_combobox.setEnabled(false);
+	    } else {
+		///ystem.err.println(ArrayTools.objectArrayToString(servlet_options.toArray()));
+
+		servlet_combobox.setModel(new DefaultComboBoxModel(servlet_options.toArray()));
+		servlet_combobox.setToolTipText(Dictionary.get("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;
+		    }
+		}
+		
+	    }
+	}
+
+	JPanel collect_dir_pane = new JPanel();
+        collect_dir_pane.setComponentOrientation(Dictionary.getOrientation());
+	collect_dir_pane.setPreferredSize(ROW_SIZE);
+	JLabel collect_dir_label = new JLabel(Dictionary.get("Preferences.Connection.CollectDirectory"));
+	collect_dir_label.setPreferredSize(LABEL_SIZE);
+	collect_dir_label.setComponentOrientation(Dictionary.getOrientation());
+	collect_dir_field = new JTextField(Gatherer.getCollectDirectoryPath());
+	//collect_dir_field = new JTextField(Configuration.getString("general.open_collection"+Configuration.gliPropertyNameSuffix(), true));
+	collect_dir_field.setCaretPosition(0);
+	collect_dir_field.setToolTipText(Dictionary.get("Preferences.Connection.CollectDirectory_Tooltip"));
+	collect_dir_field.setEditable(false);
+	JButton chdir_button = new GLIButton(Dictionary.get("General.CD"), Dictionary.get("General.CD_Tooltip"));
+	chdir_button.addActionListener(new ChangeDirListener());
+	if(Gatherer.isGsdlRemote) { // disable changing directories for client GLI
+	    chdir_button.setEnabled(false);
+	}
+
+	boolean no_check_cert_enabled = Configuration.get("general.no_check_certificate", true); // pass true to look in general rather than collection specific config file
+	
+	boolean currently_enabled = Configuration.get("general.use_proxy", true);
+	// Creation
+	JPanel connection_pane = new JPanel();
+        connection_pane.setComponentOrientation(Dictionary.getOrientation());
+	no_check_certificate_checkbox = new JCheckBox(Dictionary.get("Preferences.Connection.No_Check_Certificate"));
+	no_check_certificate_checkbox.setToolTipText(Dictionary.get("Preferences.Connection.No_Check_Certificate_Tooltip"));
+	no_check_certificate_checkbox.setSelected(no_check_cert_enabled);
+	no_check_certificate_checkbox.setComponentOrientation(Dictionary.getOrientation());        
+	no_check_certificate_checkbox.setPreferredSize(ROW_SIZE);
+	
+	use_proxy_checkbox = new JCheckBox(Dictionary.get("Preferences.Connection.Use_Proxy"));
+	use_proxy_checkbox.setSelected(currently_enabled);
+	use_proxy_checkbox.setComponentOrientation(Dictionary.getOrientation());        
+	use_proxy_checkbox.setPreferredSize(ROW_SIZE);
+	
+	
+	// Connection
+	no_check_certificate_checkbox.addActionListener(new NoCheckCertificateListener());
+	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.LINE_START);
+	program_pane.add(program_field, BorderLayout.CENTER);
+
+	library_path_pane.setLayout(new BorderLayout());
+	library_path_pane.add(library_path_label, BorderLayout.LINE_START);
+	library_path_pane.add(library_path_field, BorderLayout.CENTER);
+
+	if (Gatherer.isGsdlRemote && !Gatherer.GS3) {
+	    gliserver_url_pane.setLayout(new BorderLayout());
+	    gliserver_url_pane.add(gliserver_url_label, BorderLayout.LINE_START);
+	    gliserver_url_pane.add(gliserver_url_field, BorderLayout.CENTER);
+	}
+
+	if (Gatherer.GS3) {
+	    site_pane.setLayout(new BorderLayout());
+	    site_pane.add(site_label, BorderLayout.LINE_START);
+	    site_pane.add(site_combobox, BorderLayout.CENTER);
+
+	    servlet_pane.setLayout(new BorderLayout());
+	    servlet_pane.add(servlet_label, BorderLayout.LINE_START);
+	    servlet_pane.add(servlet_combobox, BorderLayout.CENTER);
+	}
+
+	collect_dir_pane.setLayout(new BorderLayout());
+	collect_dir_pane.add(collect_dir_label, BorderLayout.LINE_START);
+	collect_dir_pane.add(collect_dir_field, BorderLayout.CENTER);
+	collect_dir_pane.add(chdir_button, BorderLayout.LINE_END);
+
+
+	connection_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	//connection_pane.setLayout(new GridLayout(13,1,0,2));
+	connection_pane.setLayout(new GridLayout(10,1,0,2));
+	connection_pane.add(program_pane);
+	connection_pane.add(library_path_pane);
+	if (Gatherer.isGsdlRemote && !Gatherer.GS3) {
+	    connection_pane.add(gliserver_url_pane);
+	}
+	if (Gatherer.GS3) {
+	    connection_pane.add(site_pane);
+	    connection_pane.add(servlet_pane);
+	}
+	connection_pane.add(collect_dir_pane);
+
+	connection_pane.add(no_check_certificate_checkbox);
+	connection_pane.add(use_proxy_checkbox);
+	
+	// set up the proxy host and port fields for each of http, https and ftp	
+        setupProxyHostPane(HTTP, connection_pane, currently_enabled, http_proxy_host_field, http_proxy_port_field);
+	setupProxyHostPane(HTTPS, connection_pane, currently_enabled, https_proxy_host_field, https_proxy_port_field);
+	setupProxyHostPane(FTP, connection_pane, currently_enabled, ftp_proxy_host_field, ftp_proxy_port_field);
+
+	return connection_pane;
+    }
+
+    private JPanel createGeneralPreferences() {
+	JPanel general_pane = new JPanel();
+        general_pane.setComponentOrientation(Dictionary.getOrientation());
+	// 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.hasAttribute(StaticStrings.GLI_ATTRIBUTE) 
+		&& (language_element.getAttribute(StaticStrings.GLI_ATTRIBUTE)).equalsIgnoreCase(StaticStrings.TRUE_STR)) 
+	       || (language_element.hasAttribute(StaticStrings.MDS_ATTRIBUTE) 
+		   && (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();
+        email_pane.setComponentOrientation(Dictionary.getOrientation());
+
+        JLabel email_label = new JLabel(Dictionary.get("Preferences.General.Email"));
+        email_label.setComponentOrientation(Dictionary.getOrientation());
+	email_label.setPreferredSize(LABEL_SIZE);
+	
+        email_field = new EmailField(Configuration.getColor("coloring.error_background", false));
+	email_field.setText(Configuration.getEmail());
+	email_field.setToolTipText(Dictionary.get("Preferences.General.Email_Tooltip"));
+	email_field.setComponentOrientation(Dictionary.getOrientation());
+	// Font selection
+	JPanel font_pane = new JPanel();
+        font_pane.setComponentOrientation(Dictionary.getOrientation());
+	
+        JLabel font_label = new JLabel(Dictionary.get("Preferences.General.Font"));
+        font_label.setComponentOrientation(Dictionary.getOrientation());
+	font_label.setPreferredSize(LABEL_SIZE);
+	
+        font_field = new JTextField(Configuration.getString("general.font", true));
+	font_field.setToolTipText(Dictionary.get("Preferences.General.Font_Tooltip"));
+	font_field.setComponentOrientation(Dictionary.getOrientation());
+        
+	// Extracted metadata
+	view_extracted_metadata_checkbox = new JCheckBox(Dictionary.get("Preferences.General.View_Extracted_Metadata"));
+	view_extracted_metadata_checkbox.setSelected(false);
+        view_extracted_metadata_checkbox.setComponentOrientation(Dictionary.getOrientation());
+	
+        if (Configuration.get("general.view_extracted_metadata", Configuration.COLLECTION_SPECIFIC)) {
+	    view_extracted_metadata_checkbox.setSelected(true);
+	}
+	view_extracted_metadata_checkbox.setToolTipText(Dictionary.get("Preferences.General.View_Extracted_Metadata_Tooltip"));
+        view_extracted_metadata_checkbox.setComponentOrientation(Dictionary.getOrientation());
+        
+	// Show file sizes
+	show_file_size_checkbox = new JCheckBox(Dictionary.get("Preferences.General.Show_File_Size"));
+	show_file_size_checkbox.setSelected(false);
+        show_file_size_checkbox.setComponentOrientation(Dictionary.getOrientation());
+        
+	if (Configuration.get("general.show_file_size", Configuration.COLLECTION_SPECIFIC)) {
+	    show_file_size_checkbox.setSelected(true);
+	}
+	show_file_size_checkbox.setToolTipText(Dictionary.get("Preferences.General.Show_File_Size_Tooltip"));
+	
+	// Language
+	JPanel language_pane = new JPanel();
+        language_pane.setComponentOrientation(Dictionary.getOrientation());
+
+        JLabel language_label = new JLabel(Dictionary.get("Preferences.General.Interface_Language"));
+        language_label.setComponentOrientation(Dictionary.getOrientation());
+	language_label.setPreferredSize(LABEL_SIZE);
+	
+	language_combobox = new JComboBox(dictionary_model.toArray());
+	language_combobox.setOpaque(false);
+	language_combobox.setToolTipText(Dictionary.get("Preferences.General.Interface_Language_Tooltip"));
+	language_combobox.setComponentOrientation(Dictionary.getOrientation());
+        
+	// Try to locate and select the current language
+	// Else default to English
+	String language_code = Configuration.getLanguage();
+	int defaultIndex = 0;
+	DictionaryEntry defaultEntry = null;
+
+	int b = 0;
+	for (; b < language_combobox.getItemCount(); b++) {
+	    DictionaryEntry entry = (DictionaryEntry) language_combobox.getItemAt(b);
+	    if (language_code.equalsIgnoreCase(entry.getLocale().getLanguage())) {
+		language_combobox.setSelectedIndex(b);
+		break;
+	    } else if (entry.getLocale().getLanguage().equalsIgnoreCase("en")) { // store English as fallback
+		defaultIndex = b;
+		defaultEntry = entry;
+	    }
+	}
+	// if we cycled through and couldn't find the chosen language to load, 
+	// then we set the Preferences' and Configuration's language to English
+	if (b == language_combobox.getItemCount()) {
+	    language_combobox.setSelectedIndex(defaultIndex);
+	    Configuration.setLocale("general.locale", true, defaultEntry.getLocale());
+	    System.err.println("*** GLI doesn't yet support the language: " + language_code 
+			       + " and has therefore defaulted to: " + Configuration.getLanguage());
+	}
+
+	// Layout
+	email_pane.setLayout(new BorderLayout());
+	email_pane.add(email_label, BorderLayout.LINE_START);
+	email_pane.add(email_field, BorderLayout.CENTER);
+
+	language_pane.setLayout(new BorderLayout());
+	language_pane.add(language_label, BorderLayout.LINE_START);
+	language_pane.add(language_combobox, BorderLayout.CENTER);
+
+	font_pane.setLayout(new BorderLayout());
+	font_pane.add(font_label, BorderLayout.LINE_START);
+	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;
+    }
+
+    private void setupProxyHostPane(String protocol, JPanel connection_pane, boolean isEnabled,
+				    JTextField proxy_host_field, JSpinner proxy_port_field)
+    {
+	final Dimension WIDER_LABEL_SIZE = new Dimension(180, 25);
+	final Dimension NARROWER_LABEL_SIZE = new Dimension(60, 25);
+	final Dimension WIDER_ROW_SIZE = new Dimension(480, 25);
+	final Dimension NARROWER_ROW_SIZE = new Dimension(120, 25);
+	
+	JPanel proxy_host_pane = new JPanel();
+        proxy_host_pane.setComponentOrientation(Dictionary.getOrientation());
+	proxy_host_pane.setPreferredSize(WIDER_ROW_SIZE);
+        
+	JLabel proxy_host_label = new JLabel(Dictionary.get("Preferences.Connection."+protocol+"_Proxy_Host"));
+        proxy_host_label.setComponentOrientation(Dictionary.getOrientation());
+	proxy_host_label.setPreferredSize(WIDER_LABEL_SIZE);
+	
+	proxy_host_field = new JTextField(Configuration.getString("general."+protocol+"_proxy_host", true));
+	proxy_host_field.setEnabled(isEnabled);
+	proxy_host_field.setToolTipText(Dictionary.get("Preferences.Connection."+protocol+"_Proxy_Host_Tooltip"));
+	proxy_host_field.setComponentOrientation(Dictionary.getOrientation());
+        
+	JPanel proxy_port_pane = new JPanel();
+        proxy_port_pane.setComponentOrientation(Dictionary.getOrientation());
+	proxy_port_pane.setPreferredSize(NARROWER_ROW_SIZE);
+        
+	JLabel proxy_port_label = new JLabel(Dictionary.get("Preferences.Connection."+protocol+"_Proxy_Port"));
+	proxy_port_label.setPreferredSize(NARROWER_LABEL_SIZE);
+        proxy_port_label.setComponentOrientation(Dictionary.getOrientation());
+	
+	String port_value = Configuration.getString("general."+protocol+"_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(isEnabled);
+	proxy_port_field.setToolTipText(Dictionary.get("Preferences.Connection."+protocol+"_Proxy_Port_Tooltip"));
+
+
+	// Since the actual object member vars were null when this method is called
+	// need to ensure they are assigned the correct value now, else those refs will remain null
+	if(protocol.equals(HTTP)) {
+	    http_proxy_host_field = proxy_host_field;
+	    http_proxy_port_field = proxy_port_field;
+	} else if (protocol.equals(HTTPS)) {
+	    https_proxy_host_field = proxy_host_field;
+	    https_proxy_port_field = proxy_port_field;
+	} else if(protocol.equals(FTP)) {
+	    ftp_proxy_host_field = proxy_host_field;
+	    ftp_proxy_port_field = proxy_port_field;
+	} 
+	
+	proxy_host_pane.setLayout(new BorderLayout());
+	proxy_host_pane.add(proxy_host_label, BorderLayout.LINE_START);
+	proxy_host_pane.add(proxy_host_field, BorderLayout.CENTER);
+
+	proxy_port_pane.setLayout(new BorderLayout());
+	proxy_port_pane.add(proxy_port_label, BorderLayout.LINE_START);
+	proxy_port_pane.add(proxy_port_field, BorderLayout.CENTER);
+
+	//connection_pane.add(proxy_host_pane);
+	//connection_pane.add(proxy_port_pane);
+
+	JPanel proxy_panel = new JPanel();
+	proxy_panel.setLayout(new BorderLayout());	
+	proxy_panel.add(proxy_host_pane, BorderLayout.WEST);
+	proxy_panel.add(proxy_port_pane, BorderLayout.CENTER);
+
+	connection_pane.add(proxy_panel);
+    }
+    
+
+    /** Generate the controls for altering the detail mode.
+     * @return a JPanel of controls
+     */
+    private JPanel createModePreferences() {
+	// Create Controls
+	JPanel mode_panel = new JPanel();
+        mode_panel.setComponentOrientation(Dictionary.getOrientation());
+	
+        JPanel button_panel = new JPanel();
+        button_panel.setComponentOrientation(Dictionary.getOrientation());
+	
+        ButtonGroup mode_button_group = new ButtonGroup();
+	
+        assistant_mode_radio_button = new JRadioButton(Dictionary.get("Preferences.Mode.Assistant"));
+	assistant_mode_radio_button.setOpaque(false);
+        assistant_mode_radio_button.setComponentOrientation(Dictionary.getOrientation());
+	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);
+        expert_mode_radio_button.setComponentOrientation(Dictionary.getOrientation());
+	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);
+        librarian_mode_radio_button.setComponentOrientation(Dictionary.getOrientation());
+	mode_button_group.add(librarian_mode_radio_button);
+	
+	
+        mode_description_textarea = new JTextArea();
+        mode_description_textarea.setComponentOrientation(Dictionary.getOrientation());
+	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.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);
+	listener = null;
+	// Layout
+	button_panel.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	button_panel.setLayout(new GridLayout(3,1,2,2));
+	button_panel.add(assistant_mode_radio_button);
+	button_panel.add(librarian_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);
+        warning_preferences_check_list.setComponentOrientation(Dictionary.getOrientation());
+
+	// 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.setComponentOrientation(Dictionary.getOrientation());
+	warning_preferences_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	warning_preferences_pane.setLayout(new BorderLayout());
+        JScrollPane scrol_tmp = new JScrollPane(warning_preferences_check_list);
+        scrol_tmp.setComponentOrientation(Dictionary.getOrientation());
+	warning_preferences_pane.add(scrol_tmp, 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();
+        workflow_preferences_pane.setComponentOrientation(Dictionary.getOrientation());
+	
+        JPanel checklist_pane = new JPanel();
+        checklist_pane.setComponentOrientation(Dictionary.getOrientation());
+	
+        JLabel title_label = new JLabel(Dictionary.get("Preferences.Workflow.Title"));
+        title_label.setComponentOrientation(Dictionary.getOrientation());
+	title_label.setPreferredSize(ROW_SIZE);
+	
+	workflow_download = new JCheckBox(Dictionary.get("GUI.Download")+" - "+Dictionary.get("GUI.Download_Tooltip"));
+        workflow_download.setComponentOrientation(Dictionary.getOrientation());
+	workflow_download.setSelected(Configuration.get("workflow.download", false) && Gatherer.isDownloadEnabled);
+	workflow_download.setPreferredSize(ROW_SIZE);
+	
+	workflow_gather = new JCheckBox(Dictionary.get("GUI.Gather")+" - "+Dictionary.get("GUI.Gather_Tooltip"));
+	workflow_gather.setSelected(Configuration.get("workflow.gather", false));
+	workflow_gather.setPreferredSize(ROW_SIZE);
+	workflow_gather.setComponentOrientation(Dictionary.getOrientation());
+        
+	workflow_enrich = new JCheckBox(Dictionary.get("GUI.Enrich")+" - "+Dictionary.get("GUI.Enrich_Tooltip"));
+	workflow_enrich.setSelected(Configuration.get("workflow.enrich", false));
+	workflow_enrich.setPreferredSize(ROW_SIZE);
+	workflow_enrich.setComponentOrientation(Dictionary.getOrientation());
+        
+	workflow_design = new JCheckBox(Dictionary.get("GUI.Design")+" - "+Dictionary.get("GUI.Design_Tooltip"));
+	workflow_design.setSelected(Configuration.get("workflow.design", false));
+	workflow_design.setPreferredSize(ROW_SIZE);
+	workflow_design.setComponentOrientation(Dictionary.getOrientation());
+        
+	workflow_create = new JCheckBox(Dictionary.get("GUI.Create")+" - "+Dictionary.get("GUI.Create_Tooltip"));
+	workflow_create.setSelected(Configuration.get("workflow.create", false));
+	workflow_create.setPreferredSize(ROW_SIZE);
+	workflow_create.setComponentOrientation(Dictionary.getOrientation());
+        
+	workflow_format = new JCheckBox(Dictionary.get("GUI.Format")+" - "+Dictionary.get("GUI.Format_Tooltip"));
+	workflow_format.setSelected(Configuration.get("workflow.format", false));
+	workflow_format.setPreferredSize(ROW_SIZE);
+	workflow_format.setComponentOrientation(Dictionary.getOrientation());
+        
+	JPanel predefined_pane = new JPanel();
+        predefined_pane.setComponentOrientation(Dictionary.getOrientation());
+	
+        JLabel predefined_label = new JLabel(Dictionary.get("Preferences.Workflow.Predefined.Label"));
+        predefined_label.setComponentOrientation(Dictionary.getOrientation());
+	
+        JComboBox predefined_combobox = new JComboBox(predefined); 
+	predefined_combobox.setOpaque(false);
+	// 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);
+	}
+	if (Configuration.get("workflow.format", true)) {
+	    checklist_pane.add(workflow_format);
+	}
+	
+	predefined_pane.setLayout(new BorderLayout(5,0));
+	predefined_pane.add(predefined_label, BorderLayout.LINE_START);
+	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 ChangeDirListener implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    JFileChooser chooser = new JFileChooser(collect_dir_field.getText());
+	    chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+	    int returnVal = chooser.showOpenDialog(Preferences.this);
+	    if(returnVal == JFileChooser.APPROVE_OPTION) {
+		collect_dir_field.setText(chooser.getSelectedFile().getAbsolutePath() + File.separator);
+	    } // else collect_dir_field text remains as it is
+	}
+    }
+
+    private class OKButtonListener
+	implements ActionListener {
+	private boolean close;
+	public OKButtonListener(boolean close) {
+	    this.close = close;
+	}
+
+	private void setProxyHostForProtocol(String protocol,
+					     JTextField proxy_host_field,
+					     JSpinner proxy_port_field)
+	{
+	    if(proxy_host_field == null) {
+		System.err.println("@@@ proxy_host_field is NULL !!!");
+	    }
+	    
+	    Configuration.setString("general."+protocol+"_proxy_host", true, proxy_host_field.getText());
+	    Configuration.setString("general."+protocol+"_proxy_port", true, proxy_port_field.getValue() + "");
+	}
+	
+	public void actionPerformed(ActionEvent event)
+	{
+	    // Several options requiring restarting the GLI to apply: 
+	    // interface font, interface language, changed gliserver url or library url
+	    boolean restart_required = false;
+	    boolean keep_collection_open = false;
+	    String restart_message = "";
+
+	    
+	    // 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 old_library_url = (Configuration.library_url == null) ? null : Configuration.library_url.toString();
+	    String library_url_string = library_path_field.getText();
+	    if(old_library_url != null && !old_library_url.equals(library_url_string)) {
+
+		// If the server is remote and the library path's been changed, then GLI client needs restart
+		// If the server is local, GLI is going to work with the collection of GSDLPath anyway, 
+		// even if the library path for previewing has changed
+		if (Gatherer.isGsdlRemote) {
+		    restart_required = true;
+		    restart_message = Dictionary.get("Preferences.General.Manual_Restart_Required");
+		    
+		}
+		if(Gatherer.c_man.getCollection() != null) {
+		    // if the gliserver url has changed while a collection is open, 
+		    // close the open collection of the old library URL
+		    Gatherer.g_man.saveThenCloseCurrentCollection();
+		    Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(), true, "");
+		}
+	    }
+	    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"+Configuration.gliPropertyNameSuffix(), 
+				    true, library_url_string);
+
+	    if (Gatherer.isGsdlRemote && !Gatherer.GS3) {
+		String old_gliserver_url = Configuration.gliserver_url.toString(); 
+		String gliserver_url_string = gliserver_url_field.getText();
+		if(!old_gliserver_url.equals(gliserver_url_string)) {
+		    restart_required = true;
+		    restart_message = Dictionary.get("Preferences.General.Manual_Restart_Required");
+
+		    if(Gatherer.c_man.getCollection() != null) {
+			// if the gliserver url has changed while a collection is open, 
+			// close the open collection of the old gliserver URL
+			Gatherer.g_man.saveThenCloseCurrentCollection();
+			Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(), true, "");
+		    }
+		}
+		if (gliserver_url_string.equals("")) {
+		    Configuration.gliserver_url = null;
+		}
+		else {
+		    try {
+			Configuration.gliserver_url = new URL(gliserver_url_string);
+		    }
+		    catch (MalformedURLException exception) {
+			DebugStream.printStackTrace(exception);
+		    }
+		}
+		Configuration.setString("general.gliserver_url", true, gliserver_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());
+	    setProxyHostForProtocol(HTTP, http_proxy_host_field, http_proxy_port_field);
+	    setProxyHostForProtocol(HTTPS, https_proxy_host_field, https_proxy_port_field);
+	    setProxyHostForProtocol(FTP, ftp_proxy_host_field, ftp_proxy_port_field);
+	    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());
+
+
+	    // 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;
+		restart_message = Dictionary.get("Preferences.General.Restart_Required");
+
+	    }
+
+	    // GLI interface language
+	    String current_lang = Configuration.getLanguage();
+	    if (!current_lang.equals(((DictionaryEntry) language_combobox.getSelectedItem()).getLocale().getLanguage())) {
+	      // need to save the collection before changing the locale otherwise it stuffs the metadata names up
+	      if(Gatherer.c_man.getCollection() != null) {
+		  Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(), true, Gatherer.c_man.getLoadedCollectionColFilePath());
+		  Gatherer.g_man.saveThenCloseCurrentCollection();
+		  keep_collection_open = true;
+		}
+
+		Configuration.setLocale("general.locale", Configuration.GENERAL_SETTING, ((DictionaryEntry) language_combobox.getSelectedItem()).getLocale());
+		restart_required = true;
+		restart_message = Dictionary.get("Preferences.General.Restart_Required");
+	    }
+
+	    // Inform the user that a restart is required, if necessary
+	    if (restart_required) {
+		JOptionPane.showMessageDialog(Gatherer.g_man, restart_message, 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 (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 && !Gatherer.isGsdlRemote) {
+		// shut down the collection
+		System.err.println("shutting down the 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());
+// 	    Configuration.set("workflow.format", false, workflow_format.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());
+// 	    Gatherer.g_man.workflowUpdate("Format", workflow_format.isSelected());
+
+	    // Always save configuration changes immediately (in case the GLI crashes)
+	    Configuration.save();
+	    if (Gatherer.isGsdlRemote && Gatherer.GS3 && site_changed ){
+		Gatherer.remoteGreenstoneServer.downloadCollectionConfigurations();
+	    }
+	    // Refresh the GLI to account for the configuration changes
+	    Gatherer.refresh(Gatherer.PREFERENCES_CHANGED);
+
+	    // If proxy is on but proxy details are incomplete, then can't continue 
+	    if (use_proxy_checkbox.isSelected()
+		&& http_proxy_host_field.getText().equals("")
+		&& https_proxy_host_field.getText().equals("")
+		&& ftp_proxy_host_field.getText().equals("")) {
+		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("Preferences.Connection.Proxy_Host_Missing"),
+					      Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+	    } else {
+		// Hide dialog
+		if (close) {
+		    self.dispose();
+		}
+	    }
+
+		// collect directory change
+	    String newCollectPath = collect_dir_field.getText();
+	    if(!newCollectPath.endsWith(File.separator)) {
+		newCollectPath += File.separator;
+	    }
+		// wait cursor will display while changing the collect directory, need to work out what component to
+		// display it on: main GLI frame or Preferences window, depending on if OK or Apply was pressed
+		Container container = close ? Gatherer.g_man.getContentPane() : Preferences.this.getContentPane();
+	    Gatherer.collectDirectoryHasChanged(Gatherer.getCollectDirectoryPath(), 
+				newCollectPath, container);
+			// will tell the server that the collect directory has changed and that
+			// the workspace needs to be refreshed (Documents in Greenstone Collections)	   
+		
+	    if (restart_required) {
+	      if (keep_collection_open) {
+		Gatherer.g_man.exitNoCollectionSave(Gatherer.EXIT_THEN_RESTART);
+	      } else {
+		Gatherer.g_man.exit(Gatherer.EXIT_THEN_RESTART);
+	      }
+	    }
+	}
+    }
+
+    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 {
+		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"));
+		workflow_format.setSelected(element.getEnabled("format"));
+	    }
+	}
+    }
+
+
+    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("The site changed to = "+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) {
+		    ///ystem.err.println("no servlets for this site");
+		    servlet_combobox.setModel(new DefaultComboBoxModel());
+		    servlet_combobox.setToolTipText(Dictionary.get("Preferences.Connection.Servlet_Tooltip2"));
+		    servlet_combobox.setEnabled(false);
+
+		} else {
+		    ///ystem.err.println(ArrayTools.objectArrayToString(servlet_options.toArray()));
+		    servlet_combobox.setModel(new DefaultComboBoxModel(servlet_options.toArray()));
+		    servlet_combobox.setToolTipText(Dictionary.get("Preferences.Connection.Servlet_Tooltip"));
+		    servlet_combobox.setEnabled(true);
+		}
+		if (Gatherer.isGsdlRemote){
+		    // Close the current collection, remove the lock on this file, ask to login to the new site, then download collection configurations of the site.
+		    if (Gatherer.c_man.getCollection()!=null){
+			File lock_file = new File(Gatherer.c_man.getLoadedCollectionDirectoryPath() + "gli.lck");
+			Gatherer.remoteGreenstoneServer.deleteCollectionFile(Gatherer.c_man.getLoadedCollectionName(),lock_file);
+			Gatherer.g_man.closeCurrentCollection();
+		    }
+		    Configuration.site_name=site;
+		    Gatherer.remoteGreenstoneServer.set_remote_greenstone_server_authentication_to_null();
+		    Gatherer.remoteGreenstoneServer.downloadCollectionConfigurations();
+		}
+	    }
+	}    
+    }
+
+    private class NoCheckCertificateListener implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    boolean isEnabled = no_check_certificate_checkbox.isSelected();
+	    Configuration.set("general.no_check_certificate", true, isEnabled);
+	    boolean no_check_cert_enabled = Configuration.get("general.no_check_certificate", 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.
+	    http_proxy_host_field.setEnabled(enabled);
+	    http_proxy_port_field.setEnabled(enabled);
+	    https_proxy_host_field.setEnabled(enabled);
+	    https_proxy_port_field.setEnabled(enabled);
+	    ftp_proxy_host_field.setEnabled(enabled);
+	    ftp_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: debug-testing/gli_proxy/dictionary.properties
===================================================================
--- debug-testing/gli_proxy/dictionary.properties	(revision 31879)
+++ debug-testing/gli_proxy/dictionary.properties	(revision 31879)
@@ -0,0 +1,1188 @@
+#*******************
+#** Language Orientation Property
+Component.Orientation:LTR
+
+#*******************
+#
+#***** AboutDialog *****
+AboutDialog.Acknowledgement:Acknowledgements for proprietary programs, packages or classes...
+AboutDialog.Date:(November 2009)
+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:'qfslib' 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.Item9:'New folder', 'delete' and 'help' icons from the Dropline Neu! icon set by Silvestre Herrera, available from http://art.gnome.org/
+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-2009 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.Bad_Integer:<html>The argument '{0}' requires an integer value,<br>but no integer can be parsed from {1}.</html>
+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.Required_Argument:The argument '{0}' must be given a value.
+CDM.ArgumentConfiguration.Title:Configuring Arguments
+CDM.BuildTypeManager.Title:Select the Indexer
+CDM.BuildTypeManager.mg:MG
+CDM.BuildTypeManager.mg_Description:This is the original indexer used by Greenstone, developed mainly by Alistair Moffat and described in the classic book Managing Gigabytes. It does section level indexing, and searches can be boolean or ranked (not both at once). For each index specified in the collection, a separate index file is created. For phrase searching, Greenstone does an "AND" search on all the terms, then scans the resulting hits to see if the phrase is present. It has been extensively tested on very large collections (many GB of text).
+CDM.BuildTypeManager.mgpp:MGPP
+CDM.BuildTypeManager.mgpp_Description:This new version of MG (MG plus plus) was developed by the New Zealand Digital Library Project. It does word level indexing, which allows fielded, phrase and proximity searching to be handled by the indexer. Boolean searches can be ranked. Only a single index file is created for a Greenstone collection: document/section levels and text/metadata fields are all handled by one index file. For collections with many indexes, this results in a smaller collection size than using MG. For large collections, searching may be a bit slower due to the index being word level rather than section level.
+CDM.BuildTypeManager.lucene:Lucene
+CDM.BuildTypeManager.lucene_Description:Lucene was developed by the Apache Software Foundation. It handles field and proximity searching, but only at a single level (e.g. complete documents or individual sections, but not both). Therefore document and section indexes for a collection require two separate index files. It provides a similar range of search functionality to MGPP with the addition of single-character wildcards, range searching and sorting of search results by metadata fields. It was added to Greenstone to facilitate incremental collection building, which MG and MGPP can't provide.
+CDM.BuildTypeManager.Current_Type:Indexer in use: {0}
+CDM.BuildTypeManager.Change:Change...
+CDM.BuildTypeManager.Change_Tooltip:Change the indexer used by this collection
+CDM.ClassifierManager.Add:Add Classifier...
+CDM.ClassifierManager.Add_Tooltip:Use the specified classifier with this collection
+CDM.ClassifierManager.Assigned:Assigned Classifiers
+CDM.ClassifierManager.Classifier:Select classifier to add
+CDM.ClassifierManager.Classifier_Str:classifier
+CDM.ClassifierManager.Classifier_List_XML_Parse_Failed:Unable to get the list of classifiers using classinfo.pl -listall.
+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.Remove:Remove Classifier
+CDM.ClassifierManager.Remove_Tooltip:Remove the selected classifier from the list
+CDM.DatabaseTypeManager.Change:Change...
+CDM.DatabaseTypeManager.Change_Tooltip:Change the type of database used by this collection
+CDM.DatabaseTypeManager.Current_Type:Database in use: {0}
+CDM.DatabaseTypeManager.Title:Select the Database
+CDM.DatabaseTypeManager.gdbm:GDBM
+CDM.DatabaseTypeManager.gdbm_Description: GDBM (or GNU Database Manager) is a simple flat-file database engine which Greenstone uses as the default database for new collections.
+CDM.DatabaseTypeManager.jdbm:JDBM
+CDM.DatabaseTypeManager.jdbm_Description: JDBM (or Java Database Manager) is essentially a Java implementation of GDBM. Consider using this database engine combined with the Lucene indexer if you are wanting to create a pure Java run-time.
+CDM.DatabaseTypeManager.sqlite:SQLITE
+CDM.DatabaseTypeManager.sqlite_Description: SQLite is a simple relational database engine. It can be used in Greenstone to provide experimental advanced searching features that are not possible with the other database engines. To enable these features add "sqlform" to the list of SearchTypes in the Format Features section of the Format tab. 
+CDM.FormatManager.Add:Add Format
+CDM.FormatManager.Add_Tooltip:Add the specified format command 
+CDM.FormatManager.AllFeatures:All Features
+CDM.FormatManager.AllParts:All Components
+CDM.FormatManager.Default_Warning:Are you sure you want to reset the format statement to its default?
+CDM.FormatManager.Default:Reset to Default
+CDM.FormatManager.Default_Tooltip:Reset the selected format command to its default value 
+CDM.FormatManager.Editor:HTML Format String
+CDM.FormatManager.Editor_Tooltip:Enter or edit the format command
+CDM.FormatManager.Editor_Disabled_Tooltip:Click 'Add Format' to add this format command to your collection.
+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.Default:Reset to Default
+CDM.FormatManager.Default_Tooltip:Reset the selected variable to its default
+CDM.FormatManager.Insert_Variable:Insert Variable...
+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
+CDM.FormatManager.Variable_Tooltip:Insert one of the predefined variables into the selected format command
+CDM.FormatManager.MessageBox:XML Validation 
+CDM.FormatManager.MessageBox_Tooltip:XML Template validation Message 
+CDM.General.Access:This collection should be publicly accessible
+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.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' image:
+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' image:
+CDM.General.Icon_Collection_Small_Tooltip:The URL of the image to display on the library's home page for this collection
+CDM.General.Image_Copy_Failed:An error has occurred which prevents the image you selected being copied.\nPlease try manually copying the image:\n{0}\n to the images folder of your collection:\n{1}
+CDM.General.Image_Filter:Images (gifs, jpgs and pngs)
+CDM.GUI.Classifiers:Browsing Classifiers
+CDM.GUI.Formats:Format Features
+CDM.GUI.General:General
+CDM.GUI.Indexes:Search Indexes
+CDM.GUI.Macros:Collection Specific Macros
+CDM.GUI.Plugins:Document Plugins
+CDM.GUI.Root:CDM_ROOT
+CDM.GUI.SearchMetadata:Search
+CDM.GUI.Subcollections:Partition Indexes
+CDM.GUI.SuperCollection:Cross-Collection Search
+CDM.GUI.Translation:Translate Text
+CDM.GUI.DepositorMetadata:Depositor Metadata
+CDM.HelpButton:Help for this screen
+CDM.HelpButton_Tooltip:Open up the GLI help for this screen
+CDM.IndexManager.Add_Index:Add Index
+CDM.IndexManager.Add_Index_Tooltip:Add the specified index
+CDM.IndexManager.Allfields_Index:Add combined searching over all assigned indexes (allfields)
+CDM.IndexManager.Default_Index_Indicator:[Default Index]
+CDM.IndexManager.Index_Exists:That index has already been assigned for this collection.
+CDM.IndexManager.Indexes:Assigned Indexes
+CDM.IndexManager.Level:Indexing level:
+CDM.IndexManager.Level_Tooltip:Textual unit on which index is based
+CDM.IndexManager.Add_All:Add All
+CDM.IndexManager.Add_All_Tooltip:Add a separate index for every source
+CDM.IndexManager.Edit_Index:Edit Index
+CDM.IndexManager.Edit_Index_Tooltip:Modify the selected index
+CDM.IndexManager.New_Index:New Index
+CDM.IndexManager.New_Index_Tooltip:Add a new index
+CDM.IndexManager.Remove_Index:Remove Index
+CDM.IndexManager.Remove_Index_Tooltip:Remove the selected index
+CDM.IndexManager.Replace_Index:Replace Index
+CDM.IndexManager.Replace_Index_Tooltip:Update the selected index
+CDM.IndexManager.Select_All:Select All
+CDM.IndexManager.Select_All_Tooltip:Select all index sources
+CDM.IndexManager.Select_None:Select None
+CDM.IndexManager.Select_None_Tooltip:Deselect all index sources
+CDM.IndexManager.Set_Default:Set Default Index
+CDM.IndexManager.Set_Default_Tooltip:Make the selected index the default index
+CDM.IndexManager.Source:Include in index:
+CDM.IndexManager.Source_Tooltip:The metadata elements to build the index on
+CDM.IndexManager.Text_Source:Full text
+CDM.IndexManager.Text_Source_Tooltip:Include the full text of the documents in the index
+CDM.IndexingManager.Accent_fold:Accent fold
+CDM.IndexingManager.Accent_fold_Tooltip:Generate an accent-folded index, which enables searching for words ignoring accents.
+CDM.IndexingManager.Casefold:Casefold
+CDM.IndexingManager.Casefold_Tooltip:Generate a case-folded index, which enables case-insensitive searching.
+CDM.IndexingManager.Options:Indexing options:
+CDM.IndexingManager.Separate_cjk:CJK Text Segmentation
+CDM.IndexingManager.Separate_cjk_Tooltip:<html>Segment CJK (Chinese, Japanese, Korean) text. Currently involves inserting a space between each CJK character.<br> This is necessary for searching in CJK text unless the text has been segmented into words already.</html>
+CDM.IndexingManager.Stem:Stem
+CDM.IndexingManager.Stem_Tooltip:<html>Generate a stemmed index, which enables searching on word stems. <br>For example, searching for "farm" will also match "farms" "farming" "farmers" (useful for English and French only).</html>
+CDM.LanguageManager.Add_Tooltip:Add an index partition based on the specified languages
+CDM.LanguageManager.Assigned_Languages:Assigned Language Partitions
+CDM.LanguageManager.Default_Language:Default Language
+CDM.LanguageManager.LanguageMetadata:Language Metadata:
+CDM.LanguageManager.LanguageMetadata_Tooltip:The metadata element to use to determine a document's language
+CDM.LanguageManager.Remove_Tooltip:Remove the selected language partition from the list
+CDM.LanguageManager.Replace_Tooltip:Replace the selected partition with a new one based on the ticked languages
+CDM.LanguageManager.Selector:Languages to add: 
+CDM.LanguageManager.Selector_Tooltip:The languages to build an index partition on
+CDM.LanguageManager.Set_Default:Set Default
+CDM.LanguageManager.Set_Default_Tooltip:Make the selected language partition the default
+CDM.LevelManager.Document:document
+CDM.LevelManager.Section:section
+CDM.LevelManager.Paragraph:paragraph
+CDM.LevelManager.Level_Title:Indexing Levels
+CDM.LevelManager.Default:Default
+CDM.LevelManager.Default_Tooltip:Default level in reader's interface
+CDM.MacrosManager.Editor_Tooltip:Edit macros here
+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.QuickAdd:Add Plugin
+CDM.PlugInManager.Add_Tooltip:Use the specified plugin with this collection
+CDM.PlugInManager.Assigned:Assigned Plugins
+CDM.PlugInManager.Configure:Configure Plugin...
+CDM.PlugInManager.Configure_Tooltip:Change the options of the selected plugin
+CDM.PlugInManager.Ignore:Don't Add Plugin
+CDM.PlugInManager.Ignore_Tooltip:Don't add any plugins to this collection.
+CDM.PlugInManager.PlugIn:Select plugin to add:
+CDM.PlugInManager.PlugIn_Tooltip:The plugins available for use in the 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_List_XML_Parse_Failed:Unable to get the list of plugins using pluginfo.pl -listall.
+CDM.PluginManager.Plugin_Suggestion_Prompt:None of the plugins in this collection are expected to process the file "{0}" directly. (However, it may be included in the collection if it belongs to another file, for example, an image in a web page.) The following plugins may be able 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.SearchMetadataManager.Component:Item in search menu
+CDM.SearchMetadataManager.Component_Name:Display text
+CDM.SearchMetadataManager.Type_index:Index
+CDM.SearchMetadataManager.Type_level:Level
+CDM.SearchMetadataManager.Type_partition:Partition
+CDM.SearchMetadataManager.Type_language:Language Partition
+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.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.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.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.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.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.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.Translation:Translated Text
+CDM.TranslationManager.Translation_Tooltip:Enter the translation of the string here
+CDM.DepositorMetadataManager.Warning:At least one metadata element should be selected.
+#*******************
+#
+#***** 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.No_Collection_Loaded:No collection loaded
+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
+#***************************
+#
+#******ScheduldBuilt******
+ScheduleBuilt.Message:The scheduling of this collection has been altered. 
+ScheduleBuilt.Title:Collection Scheduling Result
+#***************************
+#
+#***** CollectionManager *****
+CollectionManager.Schedule_Failed:An error has occurred and the collection could not be scheduled for periodic building. 
+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_Collection:Creating collection
+CollectionManager.Creating_Collection_Please_Wait:Creating collection, please wait...
+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.Schedule_Ready_Title:Scheduling State. 
+CollectionManager.Build_Not_Moved:The building directory could not be moved. Try building again, or exit GLI and the server, and then restart GLI and try building again - this should fix the problem.
+CollectionManager.Index_Not_Deleted:The index directory could not be deleted. Try exiting GLI and the server, and then restart GLI and try building again - this should fix the problem.
+CollectionManager.Install_Exception:Exception detected during collection install:\n{0}\nMost likely caused by Windows or Local Library holding locks on files.\nPlease make sure that none of the collection source files\nare opened in external applications, then rebuild.
+#*****************************
+#
+#***** CollectionPopupMenu *****
+CollectionPopupMenu.Delete:Delete
+CollectionPopupMenu.New_Dummy_Doc:New dummy document
+CollectionPopupMenu.New_Folder:New folder
+CollectionPopupMenu.Refresh:Refresh folder view
+CollectionPopupMenu.Rename:Rename
+CollectionPopupMenu.Replace:Replace...
+#*******************************
+#
+#***** CreatePane *****
+CreatePane.Schedule_Progress:Schedule Progress
+CreatePane.Schedule:Schedule Options
+CreatePane.Schedule_Tooltip:Options for the scheduling of automatic collection formation
+CreatePane.Schedule_Build:Schedule Action
+CreatePane.Schedule_Build_Tooltip:Schedule automatic collection formation
+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.Minimal_Build:Minimal Rebuild
+CreatePane.Minimal_Build_Tooltip:Faster, as only the parts of the collection building process that are necessary are performed
+CreatePane.Minimal_Build_Not_Required:Rebuilding is not required because you have not added any files to the collection,\nedited metadata, or changed options in the Design pane.\n(To force a rebuild, choose "Complete Rebuild" and press the "Build Collection" button.)
+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, and Scheduling Options
+CreatePane.Preview_Collection:Preview Collection
+CreatePane.Preview_Collection_Tooltip:Preview the 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_Fedora_Delete:Error trying to purge collection from Fedora.
+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
+DeleteCollectionPrompt.Cannot_Delete_Open_Collection_Tooltip:Cannot delete collection {0}, since it is currently open
+#**********************
+#
+#***** 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
+
+#*******************
+#
+#***** Download *****
+DOWNLOAD.MODE.Root:Download_Root
+DOWNLOAD.MODE.WebDownload:Web
+DOWNLOAD.MODE.MediaWikiDownload:MediaWiki
+DOWNLOAD.MODE.OAIDownload:OAI
+DOWNLOAD.MODE.ZDownload:Z39.50
+DOWNLOAD.MODE.SRWDownload:SRU
+
+Download.ServerInformation:Server Information
+Download.ServerInformation_Tooltip:Download some information about the server, and check that a connection can be made
+
+#********************
+#
+#***** EnrichPane *****
+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.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.InheritedMetadata_Tooltip:Click this icon to visit the folder where this inherited piece of metadata was assigned
+EnrichPane.ManageMetadataSets:Manage Metadata Sets...
+EnrichPane.ManageMetadataSets_Tooltip:Change the metadata sets used by the collection
+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.NotOneFileOnlyMetadataSelected:This piece of metadata does not apply only to this file, and cannot be edited.
+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
+ExplodeMetadataPrompt.Plugin:Plugin to use for exploding
+#***********************
+#
+#****** ReplaceSrcWithHTMLPrompt *******
+ReplaceSrcWithHTMLPrompt.ReplaceSrc:Replace with HTML version
+ReplaceSrcWithHTMLPrompt.ReplaceSrc_Tooltip:Replace this source document with the HTML version Greenstone generates.
+ReplaceSrcWithHTMLPrompt.Instructions:Replacing a document with its generated HTML version will allow you to edit the HTML file and rebuild the collection in future with these edits intact. This is an irreversible process and the original document(s) thus replaced will be removed from the collection.
+ReplaceSrcWithHTMLPrompt.Failed_Title:Replacing with HTML Failed.
+ReplaceSrcWithHTMLPrompt.Failed_ReplaceSrc:The document(s) {0} could not be replaced with an HTML version.
+ReplaceSrcWithHTMLPrompt.NotSrcReplaceable:This file-type can not be replaced with an HTML version.
+ReplaceSrcWithHTMLPrompt.Successful_ReplaceSrc:All selected documents successfully replaced with their HTML versions.
+ReplaceSrcWithHTMLPrompt.Successful_Title:Replacing with Generated HTML Versions Complete.
+ReplaceSrcWithHTMLPrompt.Title:Replace Source Documents with HTML Files
+ReplaceSrcWithHTMLPrompt.Plugin:Plugin to use for exploding
+#***********************
+#
+#****** 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.Install:CD/DVD will install some files when used (faster)
+WriteCDImagePrompt.Install_Tooltip:Produces a self-installing CD-ROM that installs the library server (and optionally all the collection files) onto the host machine. 
+WriteCDImagePrompt.NoInstall:CD/DVD will not install any files when used
+WriteCDImagePrompt.NoInstall_Tooltip:Produces a CD-ROM that runs the library directly from the CD-ROM without installing anything on the host machine.
+WriteCDImagePrompt.Instructions:Export one or more collections to a self-installing Windows CD/DVD image (although this works on any platform, the CD/DVD image that is created only runs under Windows).
+WriteCDImagePrompt.Progress_Label:Copying Files. This could take some time...
+WriteCDImagePrompt.Size_Label:Estimated size: 
+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:Folder name
+ExportAsPrompt.Export_Name_Tooltip:The name of the folder in the Greenstone tmp directory where the exported collection will be saved.
+ExportAsPrompt.Export:Export collection
+ExportAsPrompt.Export_Tooltip:Export the selected collection in the chosen file format into the designated directory
+ExportAsPrompt.Failed_ExportOne:The collection {0} could not be exported.
+ExportAsPrompt.Failed_Details:See {1} for details
+ExportAsPrompt.Failed_Title:Export Failed
+ExportAsPrompt.Instructions:Export files in a collection into another format.
+ExportAsPrompt.Progress_Label:Exporting Files. This could take some time...
+ExportAsPrompt.Successful_ExportOne:The collection {0} has been exported.
+ExportAsPrompt.Successful_Details:Files exported to: {1}
+ExportAsPrompt.Successful_Title:Export Complete
+ExportAsPrompt.Title:Export Collection
+ExportAsPrompt.SaveAs:Export to
+ExportAsPrompt.SaveAs_Tooltip:Select the format you want to export to
+ExportAsPrompt.Cancel:Cancel
+ExportAsPrompt.Cancel_Tooltip:Cancel the exporting process
+ExportAsPrompt.Browse:Browse
+ExportAsPrompt.Browse_Tooltip:Choose a xsl file
+ExportAsPrompt.ApplyXSL:Apply XSL file to {0}
+ExportAsPrompt.ApplyXSL_Tooltip:Use a xsl file to convert the exported files.
+ExportAsPrompt.MARCXMLGroup:Group marc records
+ExportAsPrompt.MARCXMLGroup_Tooltip:Export all marc records to a single file.
+ExportAsPrompt.MappingXML:Apply the mapping file
+ExportAsPrompt.MappingXML_Tooltip:Use a mapping file for converting the exported files.
+#
+#***** Inherited Metadata *****
+ExtractedMetadata.Message:The selected file or folder contains extracted metadata, but it is currently hidden. To view extracted metadata go to the "File" menu and select "Preferences". In the "General" properties sheet select "View Extracted Metadata", then click "Ok".
+ExtractedMetadata.Title:This File/Folder Has Hidden Extracted Metadata
+#
+#***** FileActions *****
+FileActions.Calculating_Size:Calculating total size of selected files
+FileActions.ChooseDestinationDirectory:Choose destination directory
+FileActions.Copying:Copying {0}
+FileActions.Could_Not_Delete:Could not delete {0}
+FileActions.Cyclic_Path:Cannot copy {0}: the destination folder is a subfolder of the source folder.
+FileActions.Deleting:Deleting {0}
+FileActions.Directories_Selected:{0} folders selected
+FileActions.Directory_Selected:1 folder selected
+FileActions.File_Already_Exists_No_Create:The file '{0}' 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.Folder_Does_Not_Exist:This folder no longer exists, it may have been renamed or deleted
+FileActions.File_Exists:{0} already exists in the destination folder. Overwrite it?
+FileActions.File_Move_Error_Message:Could not move {0} to\n{1}.
+FileActions.File_Not_Deleted_Message:{0}\nThe file named above can not be deleted. \nPlease check that you don't have the file open\nin an external program, then try again. 
+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_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.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.Moving:Moving {0}
+FileActions.No_Activity:No action requested
+FileActions.Read_Not_Permitted_Message:Could not read {0}.
+FileActions.Read_Only:Files from the workspace are read only and cannot be deleted.
+FileActions.Replacing:Replacing {0}
+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.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
+FileActions.File_Permission_Detail:\n\nNote: In general, the Greenstone Librarian Interface needs write permission for the Greenstone home folder, \nwhich is {0}.\nPlease grant 'Full Control' for this folder (and all subfolders) to the current user ({1}) and try again.\n\n(Alternatively, re-install Greenstone into a location where you have "Full Control" already,\n such as a your home folder or "My Documents".)
+
+#************************
+#
+#******* 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.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 selected association from the existing associations
+FileAssociationDialog.Replace:Replace
+FileAssociationDialog.Replace_Tooltip:Replace the selected association with the new association details
+#*******************
+#
+#******Filter***************
+Filter.0:HTM & HTML
+Filter.1:XML
+Filter.2:Text Files
+Filter.3:Images
+Filter.4:PDF
+Filter.5:Office Documents
+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.CD:Change Dir...
+General.CD_Tooltip:Browse to a different collect directory
+General.ChooseCollectDirectory:Choose your collect directory...
+General.Close:Close
+General.Close_Tooltip:Close this dialog box
+General.Edit:Edit Value
+General.Error:Error
+General.LLS_Not_Started:You've launched the Greenstone server, but not pressed its Enter Library button yet.\nOnce you've done this, press Preview Collection in the Librarian Interface again to view the collection.
+General.LLS_Not_Started_Title:Local Library Server not started yet.
+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.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.Reconfigure:Reconfigure your web server manually
+General.Review_Output:Please review output below:
+General.Redo:Redo
+General.Redo_Tooltip:Restore the last undo
+General.Save:Save
+General.Undo:Undo
+General.Undo_Tooltip:Undo the last edit
+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.BadArgument:Argument {0} is invalid.
+GShell.BadArgumentValue:Argument {0} has an invalid value.
+GShell.BadPluginOptions:The bad argument occurred in plugin {0}.
+GShell.BadClassifierOptions:The bad argument occurred in classifier {0}.
+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.Schedule.ScheduleBegun1:**************** Schedule Started ***************
+GShell.Schedule.ScheduleComplete1:**************** Schedule Finished *************
+GShell.Schedule.ScheduleDelete:*********** Deleting Existing Scheduling ***** 
+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.Import.SegmentProcessing:Processing segment {0-segment number}.
+GShell.Import.SegmentProcessingError:Error processing segment {0-segment number}.
+GShell.Import.Warning:{0-plugin name} Warning:
+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 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.Format:Format
+GUI.Format_Tooltip:Design the appearance of your collection
+GUI.Gather:Gather
+GUI.Gather_Tooltip:Select the files to include in your collection
+GUI.CollectHome.title:The collect directory has changed
+GUI.CollectHome.message:The collect directory value has been changed from:
+GUI.CollectHome.to:to:
+GUI.CollectHome.dir:{0}
+GUI.CollectHome.gli:Do you want the Librarian Interface to remember the new collect directory?
+GUI.CollectHome.server:Do you want the Greenstone Server to remember the new collect directory?
+GUI.CollectHome.resetToDefault:No, reset to default
+GUI.CollectHome.leaveAtDefault:No, leave at default
+GUI.CollectHome.reset:Reset to default
+
+#***************
+#
+#***** HELP *****
+Help.Contents:Contents
+Help.Title:Librarian Interface Help Pages
+#****************************
+#
+#***** Invalid Metadata ******
+InvalidMetadata.Message:This metadata element is restricted to the pre-defined set of values. Please choose one from the existing values.
+InvalidMetadata.Title:Invalid Metadata
+#***************************
+#
+#***** LegacyCollection
+LegacyCollection.Message:You are about to load a collection that has not been created by the GLI. Existing metadata will be imported into the Dublin Core metadata set. Original metadata files will be saved in a folder called import.bak.
+LegacyCollection.Title:Loading External Collection
+#***************************
+#
+#***** 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.Copy_Collection:Copy this collection to...
+Menu.Edit:Edit
+Menu.Edit_Copy:Copy ({0}-c)
+Menu.Edit_Cut:Cut ({0}-x)
+Menu.Edit_Paste:Paste ({0}-v)
+Menu.Edit_Config:Edit collectionConfig.xml
+Menu.Expand:Open Folder
+Menu.Explode_Metadata_Database:Explode metadata database
+Menu.Replace_SrcDoc_With_HTML:Replace with HTML version
+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.Move_Collection:Move this collection to...
+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
+#**********************************
+#
+#***** MetadataSetDialog**********
+MetadataSetDialog.Title:Manage Metadata Sets
+MetadataSetDialog.Add_Title:Add Metadata Set
+MetadataSetDialog.Current_Sets:Assigned Metadata Sets
+MetadataSetDialog.Available_Sets:Available Metadata Sets
+MetadataSetDialog.Add:Add...
+MetadataSetDialog.Add_Tooltip:Add a new metadata set to the collection
+MetadataSetDialog.New_Set:New...
+MetadataSetDialog.New_Set_Tooltip:Create a new metadata set
+MetadataSetDialog.Add_Set:Add
+MetadataSetDialog.Add_Set_Tooltip:Add the selected metadata set to the collection
+MetadataSetDialog.Browse:Browse...
+MetadataSetDialog.Browse_Tooltip:Add a new metadata set to the collection
+MetadataSetDialog.Edit:Edit...
+MetadataSetDialog.Edit_Tooltip:Edit the selected metadata set
+MetadataSetDialog.Remove:Remove
+MetadataSetDialog.Remove_Tooltip:Remove the selected metadata set from the collection
+MetadataSetDialog.Elements:Elements in selected Metadata Set
+
+#****************************************
+#
+#***** MetadataSetNamespaceClash warning***
+MetadataSetNamespaceClash.Title:Metadata Set Namespace Clash
+MetadataSetNamespaceClash.Message:The metadata set you have chosen to add ({0}) has the same namespace as one already in the collection ({1}). If you add this new set, the old one will be deleted and the new one added in its place. Any assigned metadata values will be transferred to the new set if it contains the appropriate elements.
+#*********************************************
+#
+#******** 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.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.Log_Title:Download Log
+Mirroring.DownloadJob.Pause:Pause
+Mirroring.DownloadJob.Pause_Tooltip:Pause this download
+Mirroring.DownloadJob.Stop:Stop
+Mirroring.DownloadJob.Stop_Tooltip:Stop this download job if it is currently running
+Mirroring.DownloadJob.Stopped:Stopped
+Mirroring.DownloadJob.Stopped_Tooltip:This download has been stopped
+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.Warning_No_Valid_Certificate:WARNING: Can't download from a site that doesn't have a (valid) security certificate.
+Mirroring.DownloadJob.Enable_NoCheckCertificate:Enable 'No certificate checking' in Preferences > Connection to download insecurely from 'https' URLs. 
+Mirroring.DownloadJob.Waiting:Waiting to start
+Mirroring.DownloadJob.Waiting_User:Waiting for user action
+Mirroring.Invalid_URL:The URL entered is not valid. Please correct.
+Mirroring.Invalid_URL_Title:Invalid URL
+Mirroring.Preferences:Configure Proxy...
+Mirroring.Preferences_Tooltip:Enable proxy and/or edit proxy settings
+#*********************
+#
+#***** 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 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 Windows Local Library Server, "library.cgi" for other web servers).
+MissingEXEC.Title:Missing Greenstone Library Address
+#***** Missing EXEC_GS3 *****
+MissingEXEC_GS3.Message:Please enter the Greenstone 3 library URL. 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://".
+MissingEXEC_GS3.Title:Greenstone 3 Library URL
+#***** Missing GLIServer *****
+MissingGLIServer.Message:Enter the address of the remote Greenstone "gliserver.pl" script in the text field below. Remember that a valid URL must start with the protocol "http://" and end with "gliserver.pl".
+MissingGLIServer.Title:Specify GLI Server 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
+#******* MissingImageMagick ********
+MissingImageMagick.Message:Warning! The Librarian Interface failed to locate an appropriate version of ImageMagick. Images can be included in collections but no image processing functionality will be available, such as converting images to a different type, or generating thumbnails. 
+MissingImageMagick.Title:Missing ImageMagick
+#******* MissingPDFBox ********
+MissingPDFBox.Message:To process PDF documents version 1.5 and above, download the PDFBox extension from \nhttp://svn.greenstone.org/{0}gs2-extensions/pdf-box/trunk/pdf-box-java.{1}\nInstall it by unzipping it into your {2} folder. Then configure your PDFPlugin with pdfbox_conversion turned on.
+MissingPDFBox.Title:Missing PDFBox extension
+#******** Multiple filename encodings not supported *******
+NoEncodingSupport.Message:Your locale seems to be in UTF-8. Non-UTF-8 filenames are not supported by your setup.
+NoEncodingSupport.Title:No Filename Encoding Support
+#******** Non-standard collect home *******
+NonStandardCollectHome.Message:Your current collect home {0} is located outside of your Greenstone installation and is not its default collect directory at {1}. To work with the collect directory of your choice, go to File > Preferences > Connection and set the Collect Directory field to a folder.
+NonStandardCollectHome.Title:Non-standard collect home
+#*****************************
+#
+#***** New Session *****
+NewCollectionPrompt.Base_Collection:Base this collection on:
+NewCollectionPrompt.Base_Collection_Tooltip:Select an existing collection to base the new collection on
+NewCollectionPrompt.ChooseACollection:Choose a collection
+NewCollectionPrompt.Collection_Description:Description of content:
+NewCollectionPrompt.Collection_Name:Collection folder:
+NewCollectionPrompt.Collection_Scope_Personal:This is a personal collection
+NewCollectionPrompt.Collection_Scope_Personal_Tooltip:The collection can be edited by the person who created it and users in the "all-collections-editor" group.
+NewCollectionPrompt.Collection_Scope_Shared:This is not a personal collection
+NewCollectionPrompt.Collection_Scope_Shared_Tooltip:The collection can be edited by users in the "all-collections-editor" group.
+NewCollectionPrompt.Error:Error in new collection.
+NewCollectionPrompt.Instructions:To create a new collection fill out the fields below.
+NewCollectionPrompt.NewCollection:-- New Collection --
+NewCollectionPrompt.OtherCollections:-- Other Collections... --
+NewCollectionPrompt.Select:Select
+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
+#**********************
+#
+#******* OldWGET *******
+NoPluginExpectedToProcessFile.Message:None of Greenstone's plugins are expected to process the file "{0}" directly. (However, it may be included in the collection if it belongs to another file, for example, an image in a web page.) 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
+#***********************
+#
+#***** OpenCollectionDialog *****
+OpenCollectionDialog.Available_Collections:Available Collections
+OpenCollectionDialog.Description:Collection Description
+OpenCollectionDialog.Open:Open
+OpenCollectionDialog.Open_Tooltip:Load the selected collection into the Librarian Interface
+OpenCollectionDialog.Title:Open Greenstone Collection
+#**********************
+#
+#***** FormatConversionDialog *****
+FormatConversionDialog.Accept_All:Accept All
+FormatConversionDialog.Accept_All_Tooltip:Closes this dialog, accepting the default Greenstone3 format statements that have been automatically produced for the current and any subsequent Greenstone2 format statements.
+FormatConversionDialog.Cancel_Or_Accept_All:One or more Greenstone3 format statements contains invalid XML.\nEither press Cancel to correct the XML.\nOr press OK to store the Greenstone3 format statements as-is, albeit inactive.\nYou can later use the Format tab to revisit the format statements if you want to update their syntax.
+FormatConversionDialog.Cancel_Or_Continue_Next:Either press Cancel to go back and re-edit the XML.\nOr press OK to store the current XML as-is, albeit inactive, and continue on to the next statement.\nYou can later use the Format tab to revisit this format statement if you want to update its syntax.
+FormatConversionDialog.Cancel_Tooltip:Cancels out of opening the collection and closes this dialog, discarding any changes made in the dialog.
+FormatConversionDialog.Error_GS3_Format:Error in Greenstone3 format statement.
+FormatConversionDialog.GS2_Text_Tooltip:Greenstone2 format statement.
+FormatConversionDialog.GS3_Text_Tooltip:Greenstone3 format statement, must be XML to be active in Greenstone.
+FormatConversionDialog.Invalid_XML:Invalid XML.
+FormatConversionDialog.Invalid_XML_Warning_Title:Cancel or Continue?
+FormatConversionDialog.Next:Next
+FormatConversionDialog.Next_Tooltip:Inspect the next Greenstone3 format statement that has been automatically converted from a Greenstone2 format statement.
+FormatConversionDialog.Reconvert:Reconvert
+FormatConversionDialog.Reconvert_Tooltip:Converts the text that is currently in the Greenstone2 format text area into a Greenstone3 format statement.
+FormatConversionDialog.Tidy_Done:Tidy done.
+FormatConversionDialog.Tidy_Failed:Tidy failed.
+FormatConversionDialog.Title:Convert Greenstone2 format statements to Greenstone3
+FormatConversionDialog.XHTML_Tidy:XHTML Tidy
+FormatConversionDialog.XHTML_Tidy_Tooltip:Will run HTML Tidy over the Greenstone3 format statement to try to fix up obvious XHTML errors.
+FormatConversionDialog.XML_Still_Invalid:XML is still invalid.
+
+#***** ConfigFileEditor *****
+ConfigFileEditor.Tooltip:Greenstone 3 collection configuration XML editor.
+ConfigFileEditor.Save_Tooltip:Save changes and close.
+ConfigFileEditor.Cancel_Tooltip:Close without saving.
+
+#**********************
+#
+#***** Options Pane inside CreatePane *****
+OptionsPane.Cancelled: - cancelled
+OptionsPane.LogHistory:Log history
+OptionsPane.Successful: - successful
+OptionsPane.Scheduled: - scheduled
+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.GLIServer_URL:Greenstone gliserver URL:
+Preferences.Connection.GLIServer_URL_Tooltip:The URL of the Greenstone "gliserver" CGI script
+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.Library_Path_Connection_Failure:Failed to connect. Check that the Greenstone server at {0} is running.
+Preferences.Connection.CollectDirectory:Collect Directory:
+Preferences.Connection.CollectDirectory_Tooltip:The path to the collect directory you want to work with.
+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.No_Check_Certificate: No certificate checking (effective on 'https' URLs)
+Preferences.Connection.No_Check_Certificate_Tooltip:Tick to download even from 'https' URLs that don't have a (valid) security certificate.
+Preferences.Connection.HTTP_Proxy_Host:HTTP Proxy Host:
+Preferences.Connection.HTTP_Proxy_Host_Tooltip:The address of your HTTP proxy server
+Preferences.Connection.HTTP_Proxy_Port:Port:
+Preferences.Connection.HTTP_Proxy_Port_Tooltip:The port number of your HTTP proxy server
+Preferences.Connection.HTTPS_Proxy_Host:HTTPS Proxy Host:
+Preferences.Connection.HTTPS_Proxy_Host_Tooltip:The address of your HTTPS proxy server
+Preferences.Connection.HTTPS_Proxy_Port:Port:
+Preferences.Connection.HTTPS_Proxy_Port_Tooltip:The port number of your HTTPS proxy server
+Preferences.Connection.FTP_Proxy_Host:FTP Proxy Host:
+Preferences.Connection.FTP_Proxy_Host_Tooltip:The address of your FTP proxy server
+Preferences.Connection.FTP_Proxy_Port:Port:
+Preferences.Connection.FTP_Proxy_Port_Tooltip:The port number of your FTP proxy server
+Preferences.Connection.Proxy_Host_Missing:Enter a value for at least one proxy host or turn off Use Proxy Connection in the Connection tab.
+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 loading a new interface language.
+Preferences.General.Manual_Restart_Required:Please restart the GLI client to take the changed connection settings into account.
+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, and building collections.
+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.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
+
+ShowPreviousCollection.Title:Preview the collection previously built
+ShowPreviousCollection.Message:An error has occurred and the collection could not be created.You are previewing the collection that was built previously. 
+#**********************
+#
+#***** Remote Greenstone Server *****
+RemoteGreenstoneServer.Authentication_Message:Please enter your Greenstone username and password:
+RemoteGreenstoneServer.Authentication_Message_gs3:Please enter your Greenstone username and password at site:
+RemoteGreenstoneServer.Error:An error has occurred on the remote Greenstone server while performing this operation:\n{0-Error message}
+RemoteGreenstoneServer.Error_Title:Remote Greenstone Server Error
+RemoteGreenstoneServer.Progress:Remote Greenstone Server Progress: 
+RemoteGreenstoneServer.Steal_Lock_Message:This collection is currently locked by user '{0-User name}'.\nDo you want to steal control of this lock file (not recommended, as work may be lost)?
+#**********************
+#
+#***** Rename Prompt *****
+RenamePrompt.Name:Name:
+RenamePrompt.Title:Rename file/folder
+#**********************
+#
+#***** Replace Prompt *****
+ReplacePrompt.Title:Replace file with ...
+#**********************
+#
+#***** 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 {0} seconds. Do you\nwish to wait for another {0} seconds?
+Server.StartUpTimeOut:The greenstone local library has not responded to the\nstart command for {0} seconds. Do you\nwish to wait for another {0} seconds?
+Server.Reconfigure:You just changed collecthome.\nAs GLI didn't start your webserver, it can't reconfigure this automatically.\nPlease reconfigure your server manually to work with the change to collecthome.
+#
+#***** Sources *****
+Source.General:General
+#**********************
+#
+#***** 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******
+
+GEMS.Title:Greenstone Editor for Metadata Sets
+GEMS.OpenMetadataSetPrompt.Title:Open Metadata Set
+GEMS.OpenMetadataSetPrompt.Open_Tooltip:Open the selected metadata set
+GEMS.Set_Description:Metadata set description
+GEMS.OpenMetadataSetPrompt.Open:Open
+GEMS.OpenMetadataSetPrompt.Available_Sets:Available metadata sets
+GEMS.DeleteMetadataSetPrompt.Title:Delete Metadata Set
+GEMS.DeleteMetadataSetPrompt.Delete_Tooltip:Delete the selected metadata set
+GEMS.DeleteMetadataSetPrompt.Delete:Delete
+GEMS.DeleteMetadataSetPrompt.Available_Sets:Available metadata sets
+GEMS.DeleteMetadataSetPrompt.Confirm_Delete:Please tick the box to confirm metadata set deletion.
+GEMS.DeleteMetadataSetPrompt.No_Set:No metadata set selected
+GEMS.Confirm_Removal:Are you sure you wish to remove this {0}?
+GEMS.Confirm_Removal_Title:Confirm Removal
+GEMS.Attribute:Attribute
+GEMS.Popup.AddElement:Add Element
+GEMS.Popup.DeleteElement:Delete Element
+GEMS.Popup.AddSubElement:Add Subelement
+GEMS.Popup.DeleteSubElement:Delete Subelement
+GEMS.NewMetadataSetPrompt.Title:New Metadata Set
+GEMS.NewMetadataSetPrompt.Instructions:To create a new metadata set fill out the fields below:
+GEMS.NewMetadataSetPrompt.Base_MetadataSet:Base this metadata set on:
+GEMS.NewMetadataSetPrompt.Metadata_Title:Metadata set title:
+GEMS.NewMetadataSetPrompt.Metadata_Namespace:Metadata set namespace:
+GEMS.NewMetadataSetPrompt.New_Metadata:-- New Metadata Set --
+GEMS.NewMetadataSetPrompt.Title_Error_Message:A new metadata set must have a Title
+GEMS.NewMetadataSetPrompt.Title_Error:No Title Specified
+GEMS.NewMetadataSetPrompt.Namespace_Error_Message:A new metadata set must have a namespace
+GEMS.NewMetadataSetPrompt.Namespace_Error:No Namespace Specified
+GEMS.SelectedLanguage:Add attributes for language:
+GEMS.Language:--Choose Language--
+GEMS.LanguageDependent:Language dependent attributes
+GEMS.Attribute_Table:Attributes
+GEMS.Attribute_Deletion_Error:Attribute Deletion Error
+GEMS.Attribute_Deletion_Error_Message:This attribute is required and cannot be deleted
+GEMS.Add_Lang_Depend_Attr_Error:Attribute Addition Error
+GEMS.Add_Lang_Depend_Attr_Error_Message:No "language-dependent" attribute is provided, please add this attribute.
+GEMS.Attribute_Edition_Error:Attribute Edition Error
+GEMS.Attribute_Edition_Error_Message:This attribute is required and cannot be empty
+GEMS.Confirm_Save:This metadata set has been changed, would you like to save it?
+GEMS.Confirm_Save_Title:Save Metadata Set
+GEMS.Confirm_DeleteElement:Are you sure you wish to delete element {0}?
+GEMS.Confirm_DeleteElement_Title:Delete Element
+GEMS.File_Deletion_Error_Message:This file cannot be deleted
+GEMS.File_Deletion_Error:File Deletion Error
+GEMS.Namespace_Conflict_Message:Warning: this namespace has been used by another metadata set. Continue?
+GEMS.Namespace_Conflict:Namespace Conflict
+GEMS.Move_Up:Move Up
+GEMS.Move_Down:Move Down
+GEMS.Cannot_Undo:(this action cannot be undone)
+
+GEMS.AttributeTable.Name:Name
+GEMS.AttributeTable.Language:Language
+GEMS.AttributeTable.Value:Value
+GEMS.NewMetadataElementNamePrompt.Title:New Element
+GEMS.NewMetadataElementNamePrompt.Name:Please enter a name for the new element
+GEMS.NewMetadataElementNamePrompt.SubTitle:New Subelement
+GEMS.NewMetadataElementNamePrompt.SubName:Please enter a name for the new subelement
+GEMS.NewMetadataElementNamePrompt.Name_Error_Message:An element with this name already exists.
+GEMS.NewMetadataElementNamePrompt.Name_Error:Element Name Error
+GEMS.NewMetadataElementNamePrompt.EmptyName_Error_Message:A new element must have a name.
+
+
+GEMS.No_Set_Loaded:No metadata set is loaded. Please use File->New to create a new set, or File->Open to open an existing set.
