<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>onejar/.version</filename>
    </added>
    <added>
      <filename>onejar/OneJar.class</filename>
    </added>
    <added>
      <filename>onejar/OneJar.java</filename>
    </added>
    <added>
      <filename>onejar/com/simontuffs/onejar/Boot$1.class</filename>
    </added>
    <added>
      <filename>onejar/com/simontuffs/onejar/Boot$2.class</filename>
    </added>
    <added>
      <filename>onejar/com/simontuffs/onejar/Boot$3.class</filename>
    </added>
    <added>
      <filename>onejar/com/simontuffs/onejar/IProperties.class</filename>
    </added>
    <added>
      <filename>onejar/com/simontuffs/onejar/IProperties.java</filename>
    </added>
    <added>
      <filename>onejar/detectloader.mf</filename>
    </added>
    <added>
      <filename>onejar/extloader.mf</filename>
    </added>
    <added>
      <filename>onejar/wrap/wraploader.jar</filename>
    </added>
    <added>
      <filename>platform/libquaqua.jnilib</filename>
    </added>
    <added>
      <filename>platform/quaqua.jar</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -218,6 +218,10 @@
       &lt;tarfileset dir=&quot;${dest.dir}&quot; prefix=&quot;${app.name}.app/Contents/Resources/Java&quot;&gt;
         &lt;include name=&quot;${BINARY}&quot; /&gt;
       &lt;/tarfileset&gt;
+      &lt;tarfileset dir=&quot;${packaging}&quot; prefix=&quot;${app.name}.app/Contents/Resources/Java&quot;&gt;
+      	&lt;include name=&quot;quaqua.jar&quot; /&gt;
+	&lt;include name=&quot;libquaqua.jnilib&quot; /&gt;
+      &lt;/tarfileset&gt;
     &lt;/tar&gt;
     &lt;delete file=&quot;/tmp/MRJApp.properties&quot; /&gt;
   &lt;/target&gt;</diff>
      <filename>build.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,6 @@
 Manifest-Version: 1.0
-Ant-Version: Apache Ant 1.6.5
-Created-By: 1.5.0_06-64 (&quot;Apple Computer, Inc.&quot;)
+Ant-Version: Apache Ant 1.7.0
+Created-By: 1.4.2_04-b05 (Sun Microsystems Inc.)
 Main-Class: com.simontuffs.onejar.Boot
-One-Jar-Expand: expand,doc
+One-Jar-Expand: expand,doc,file.txt
 </diff>
      <filename>onejar/META-INF/MANIFEST.MF</filename>
    </modified>
    <modified>
      <diff>@@ -1,3 +1,2 @@
 Manifest-Version: 1.0
 Main-Class: com.simontuffs.onejar.Boot
-One-Jar-Expand: expand,doc</diff>
      <filename>onejar/boot-manifest.mf</filename>
    </modified>
    <modified>
      <diff></diff>
      <filename>onejar/com/simontuffs/onejar/Boot.class</filename>
    </modified>
    <modified>
      <diff>@@ -1,245 +1,552 @@
-/*
- * Copyright (c) 2004, P. Simon Tuffs (simon@simontuffs.com)
- * All rights reserved.
- *
- * See full license at http://one-jar.sourceforge.net/one-jar-license.txt
- * This license is also included in the distributions of this software
- * under doc/one-jar-license.txt
- */	 
-
-package com.simontuffs.onejar;
-
-import java.io.InputStream;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.Properties;
-import java.util.jar.Attributes;
-import java.util.jar.JarFile;
-import java.util.jar.JarInputStream;
-import java.util.jar.Manifest;
-
-/**
- * Run a java application which requires multiple support jars from inside
- * a single jar file.
- * 
- * &lt;p&gt;
- * Developer time JVM properties:
- * &lt;pre&gt;
- *   -Done-jar.main-class={name}  Use named class as main class to run. 
- *   -Done-jar.record[=recording] Record loaded classes into &quot;recording&quot; directory.
- *                                Flatten jar-names into directory tree suitable 
- * 								  for use as a classpath.
- *   -Done-jar.jar-names          Record loaded classes, preserve jar structure
- *   -Done-jar.verbose            Run the JarClassLoader in verbose mode.
- * &lt;/pre&gt;
- * @author simon@simontuffs.com (&lt;a href=&quot;http://www.simontuffs.com&quot;&gt;http://www.simontuffs.com&lt;/a&gt;)
- */
-public class Boot {
-	
-	/**
-	 * The name of the manifest attribute which controls which class 
-	 * to bootstrap from the jar file.  The boot class can
-	 * be in any of the contained jar files.
-	 */
-	public final static String BOOT_CLASS = &quot;Boot-Class&quot;;
-	
-	public final static String MANIFEST = &quot;META-INF/MANIFEST.MF&quot;;
-	public final static String MAIN_JAR = &quot;main/main.jar&quot;;
-
-	public final static String WRAP_CLASS_LOADER = &quot;Wrap-Class-Loader&quot;;
-    public final static String WRAP_DIR = &quot;wrap&quot;;
-	public final static String WRAP_JAR = &quot;/&quot; + WRAP_DIR + &quot;/wraploader.jar&quot;;
-
-	public final static String PROPERTY_PREFIX = &quot;one-jar.&quot;;
-	public final static String MAIN_CLASS = PROPERTY_PREFIX + &quot;main-class&quot;;
-	public final static String RECORD = PROPERTY_PREFIX + &quot;record&quot;;
-	public final static String JARNAMES = PROPERTY_PREFIX + &quot;jar-names&quot;;
-	public final static String VERBOSE = PROPERTY_PREFIX + &quot;verbose&quot;;
-	public final static String INFO = PROPERTY_PREFIX + &quot;info&quot;;
-	
-	protected static boolean info, verbose;
-
-	// Singleton loader.
-	protected static JarClassLoader loader = null;
-	
-	public static JarClassLoader getClassLoader() {
-		return loader;
-	}
-    
-    public static void setClassLoader(JarClassLoader $loader) {
-        if (loader != null) throw new RuntimeException(&quot;Attempt to set a second Boot loader&quot;);
-        loader = $loader;
-    }
-
-	protected static void VERBOSE(String message) {
-		if (verbose) System.out.println(&quot;Boot: &quot; + message);
-	}
-
-	protected static void WARNING(String message) {
-		System.err.println(&quot;Boot: Warning: &quot; + message); 
-	}
-	
-	protected static void INFO(String message) {
-		if (info) System.out.println(&quot;Boot: Info: &quot; + message);
-	}
-
-    public static void main(String[] args) throws Exception {
-    	run(args);
-    }
-    
-    public static void run(String args[]) throws Exception {
-    	
-		if (false) {
-			// What are the system properties.
-	    	Properties props = System.getProperties();
-	    	Enumeration _enum = props.keys();
-	    	
-	    	while (_enum.hasMoreElements()) {
-	    		String key = (String)_enum.nextElement();
-	    		System.out.println(key + &quot;=&quot; + props.get(key));
-	    	}
-		}
-	    	
-    	// Is the main class specified on the command line?  If so, boot it.
-    	// Othewise, read the main class out of the manifest.
-		String mainClass = null, recording = null;
-		boolean record = false, jarnames = false;
-
-		{
-			// Default properties are in resource 'one-jar.properties'.
-			Properties properties = new Properties();
-			String props = &quot;/one-jar.properties&quot;;
-			InputStream is = Boot.class.getResourceAsStream(props); 
-			if (is != null) {
-				INFO(&quot;loading properties from &quot; + props);
-				properties.load(is);
-			}
-				 
-			// Merge in anything in a local file with the same name.
-			props = &quot;file:one-jar.properties&quot;;
-			is = Boot.class.getResourceAsStream(props);
-			if (is != null) {
-				INFO(&quot;loading properties from &quot; + props);
-				properties.load(is);
-			} 
-			// Set system properties only if not already specified.
-			Enumeration _enum = properties.propertyNames();
-			while (_enum.hasMoreElements()) {
-				String name = (String)_enum.nextElement();
-				if (System.getProperty(name) == null) {
-					System.setProperty(name, properties.getProperty(name));
-				}
-			}
-		}		
-		// Process developer properties:
-		mainClass = System.getProperty(MAIN_CLASS);
-		if (System.getProperties().containsKey(RECORD)) {
-			record = true;
-			recording = System.getProperty(RECORD);
-			if (recording.length() == 0) recording = null;
-    	} 
-		if (System.getProperties().containsKey(JARNAMES)) {
-			record = true;
-			jarnames = true;
-		}
-		
-		if (System.getProperties().containsKey(VERBOSE)) {
-			verbose = true;
-            info = true;
-		} 
-		if (System.getProperties().containsKey(INFO)) {
-			info = true;
-		} 
-
-		// If no main-class specified, check the manifest of the main jar for
-		// a Boot-Class attribute.
-		if (mainClass == null) {
-	    	// Hack to obtain the name of this jar file.
-	    	String jar = System.getProperty(PROPERTY_PREFIX + &quot;jarname&quot;); 
-            if (jar == null) jar = System.getProperty(JarClassLoader.JAVA_CLASS_PATH);
-
-            // Fix from 'eleeptg' for OS-X problems: extract first entry from classpath 
-            // 'test.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/.compatibility/14compatibility.jar' 
-            if ((jar!=null) &amp;&amp; (jar.indexOf(System.getProperty(&quot;path.separator&quot;)) &gt; 0)) 
-                jar = jar.substring(0, jar.indexOf(System.getProperty(&quot;path.separator&quot;))); 
-            
-	    	JarFile jarFile = new JarFile(jar);
-	    	Manifest manifest = jarFile.getManifest();
-			Attributes attributes = manifest.getMainAttributes();
-			mainClass = attributes.getValue(BOOT_CLASS);
-		}
-		
-		if (mainClass == null) {
-			// Still don't have one (default).  One final try: look for a jar file in a
-			// main directory.  There should be only one, and it's manifest 
-			// Main-Class attribute is the main class.  The JarClassLoader will take
-			// care of finding it.
-			InputStream is = Boot.class.getResourceAsStream(&quot;/&quot; + MAIN_JAR);
-			if (is != null) {
-				JarInputStream jis = new JarInputStream(is);
-				Manifest manifest = jis.getManifest();
-				Attributes attributes = manifest.getMainAttributes();
-				mainClass = attributes.getValue(Attributes.Name.MAIN_CLASS);
-			}
-		}
-	
-		// Do we need to create a wrapping classloader?  Check for the
-		// presence of a &quot;wrap&quot; directory at the top of the jar file.
-		URL url = Boot.class.getResource(WRAP_JAR);
-		
-		if (url != null) {
-			// Wrap class loaders.
-			JarClassLoader bootLoader = new JarClassLoader(WRAP_DIR);
-			bootLoader.setRecord(record);
-			bootLoader.setFlatten(!jarnames);
-			bootLoader.setRecording(recording);
-			bootLoader.setInfo(info);
-            bootLoader.setVerbose(verbose);
-			bootLoader.load(null);
-			
-			// Read the &quot;Wrap-Class-Loader&quot; property from the wraploader jar file.
-			// This is the class to use as a wrapping class-loader.
-			JarInputStream jis = new JarInputStream(Boot.class.getResourceAsStream(WRAP_JAR));
-			String wrapLoader = jis.getManifest().getMainAttributes().getValue(WRAP_CLASS_LOADER);
-			if (wrapLoader == null) {
-				WARNING(url + &quot; did not contain a &quot; + WRAP_CLASS_LOADER + &quot; attribute, unable to load wrapping classloader&quot;);
-			} else {
-				INFO(&quot;using &quot; + wrapLoader);
-				Class jarLoaderClass = bootLoader.loadClass(wrapLoader);
-				Constructor ctor = jarLoaderClass.getConstructor(new Class[]{ClassLoader.class});
-				loader = (JarClassLoader)ctor.newInstance(new Object[]{bootLoader});
-			}
-				
-		} else {
-			INFO(&quot;using JarClassLoader&quot;);
-			loader = new JarClassLoader(Boot.class.getClassLoader());
-		}
-		loader.setRecord(record);
-		loader.setFlatten(!jarnames);
-		loader.setRecording(recording);
-        loader.setInfo(info);
-		loader.setVerbose(verbose);
-		mainClass = loader.load(mainClass);
-        
-        if (mainClass == null) throw new Exception(&quot;main class was not found (fix: add main/main.jar with a Main-Class manifest attribute, or specify -D&quot; + MAIN_CLASS + &quot;)&quot;);
-
-    	// Guard against the main.jar pointing back to this
-    	// class, and causing an infinite recursion.
-        String bootClass = Boot.class.getName();
-    	if (mainClass.equals(Boot.class.getName()))
-    		throw new Exception(&quot;main class would cause infinite recursion: check main.jar/META-INF/MANIFEST.MF/Main-Class attribute: &quot; + mainClass);
-    	
-		// Set the context classloader in case any classloaders delegate to it.
-		// Otherwise it would default to the sun.misc.Launcher$AppClassLoader which
-		// is used to launch the jar application, and attempts to load through
-		// it would fail if that code is encapsulated inside the one-jar.
-		Thread.currentThread().setContextClassLoader(loader);
-        
-    	Class cls = loader.loadClass(mainClass);
-    	
-    	Method main = cls.getMethod(&quot;main&quot;, new Class[]{String[].class}); 
-    	main.invoke(null, new Object[]{args});
-    }
-}
+/*
+ * Copyright (c) 2004, P. Simon Tuffs (simon@simontuffs.com)
+ * All rights reserved.
+ *
+ * See the full license at http://www.simontuffs.com/one-jar/one-jar-license.html
+ * This license is also included in the distributions of this software
+ * under doc/one-jar-license.txt
+ */	 
+
+package com.simontuffs.onejar;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+/**
+ * Run a java application which requires multiple support jars from inside
+ * a single jar file.
+ * 
+ * &lt;p&gt;
+ * Developer time JVM properties:
+ * &lt;pre&gt;
+ *   -Done-jar.main.class={name}  Use named class as main class to run. 
+ *   -Done-jar.record[=recording] Record loaded classes into &quot;recording&quot; directory.
+ *                                Flatten jar.names into directory tree suitable 
+ * 								  for use as a classpath.
+ *   -Done-jar.jar.names          Record loaded classes, preserve jar structure
+ *   -Done-jar.verbose            Run the JarClassLoader in verbose mode.
+ * &lt;/pre&gt;
+ * @author simon@simontuffs.com (&lt;a href=&quot;http://www.simontuffs.com&quot;&gt;http://www.simontuffs.com&lt;/a&gt;)
+ */
+public class Boot {
+	
+    /**
+	 * The name of the manifest attribute which controls which class 
+	 * to bootstrap from the jar file.  The boot class can
+	 * be in any of the contained jar files.
+	 */
+	public final static String BOOT_CLASS = &quot;Boot-Class&quot;;
+    public final static String ONE_JAR_CLASSLOADER = &quot;One-Jar-Class-Loader&quot;;
+    public final static String ONE_JAR_MAIN_CLASS = &quot;One-Jar-Main-Class&quot;;
+	
+	public final static String MANIFEST = &quot;META-INF/MANIFEST.MF&quot;;
+	public final static String MAIN_JAR = &quot;main/main.jar&quot;;
+
+	public final static String WRAP_CLASS_LOADER = &quot;Wrap-Class-Loader&quot;;
+    public final static String WRAP_DIR = &quot;wrap&quot;;
+	public final static String WRAP_JAR = &quot;/&quot; + WRAP_DIR + &quot;/wraploader.jar&quot;;
+
+    // System properties.
+	public final static String PROPERTY_PREFIX = &quot;one-jar.&quot;;
+	public final static String P_MAIN_CLASS = PROPERTY_PREFIX + &quot;main.class&quot;;
+	public final static String P_RECORD = PROPERTY_PREFIX + &quot;record&quot;;
+	public final static String P_JARNAMES = PROPERTY_PREFIX + &quot;jar.names&quot;;
+	public final static String P_VERBOSE = PROPERTY_PREFIX + &quot;verbose&quot;;
+	public final static String P_INFO = PROPERTY_PREFIX + &quot;info&quot;;
+    public final static String P_STATISTICS = PROPERTY_PREFIX + &quot;statistics&quot;;
+    public final static String P_SHOW_PROPERTIES = PROPERTY_PREFIX + &quot;show.properties&quot;;
+    public final static String P_JARPATH = PROPERTY_PREFIX + &quot;jar.path&quot;;
+    public final static String P_ONE_JAR_CLASS_PATH = PROPERTY_PREFIX + &quot;class.path&quot;;
+    public final static String P_JAVA_CLASS_PATH = &quot;java.class.path&quot;;
+    public final static String P_PATH_SEPARATOR = &quot;|&quot;;
+    public final static String P_EXPAND_DIR = PROPERTY_PREFIX + &quot;expand.dir&quot;;
+    
+    // Command-line arguments
+    public final static String HELP = &quot;--one-jar-help&quot;;
+    public final static String VERSION = &quot;--one-jar-version&quot;;
+    
+    public final static String[] HELP_PROPERTIES = {
+        P_MAIN_CLASS, &quot;Specifies the name of the class which should be executed \n(via public static void main(String[])&quot;, 
+        P_RECORD,     &quot;true:  Enables recording of the classes loaded by the application&quot;,
+        P_JARNAMES,   &quot;true:  Recorded classes are kept in directories corresponding to their jar names.\n&quot; + 
+                      &quot;false: Recorded classes are flattened into a single directory.  \nDuplicates are ignored (first wins)&quot;,
+        P_VERBOSE,    &quot;true:  Print verbose classloading information&quot;, 
+        P_INFO,       &quot;true:  Print informative classloading information&quot;, 
+        P_STATISTICS, &quot;true:  Shows statistics about the One-Jar Classloader&quot;,
+        P_JARPATH,    &quot;Full path of the one-jar file being executed.  \nOnly needed if java.class.path does not contain the path to the jar, e.g. on Max OS/X.&quot;,
+        P_ONE_JAR_CLASS_PATH,    &quot;Extra classpaths to be added to the execution environment.  \nUse platform independent path separator '&quot; + P_PATH_SEPARATOR + &quot;'&quot;,
+        P_EXPAND_DIR, &quot;Directory to use for expanded files.&quot;,
+        P_SHOW_PROPERTIES, &quot;true:  Shows the JVM system properties.&quot;,
+    };
+	
+    public final static String[] HELP_ARGUMENTS = {
+        HELP,       &quot;Shows this message, then exits.&quot;,
+        VERSION,    &quot;Shows the version of One-JAR, then exits.&quot;, 
+    };
+    
+	protected static boolean info, verbose, statistics;
+    protected static String myJarPath;
+    
+    protected static long startTime = System.currentTimeMillis();
+    protected static long endTime = 0;
+    
+
+	// Singleton loader.  This must not be changed once it is set, otherwise all
+    // sorts of nasty class-cast exceptions will ensue.  Hence we control 
+    // access to it strongly.
+	private static JarClassLoader loader = null;
+	
+    
+	/**
+     * This method provides access to the bootstrap One-JAR classloader which 
+     * is needed in the URL connection Handler when opening streams relative
+     * to classes.  
+     * @return
+	 */
+    public synchronized static JarClassLoader getClassLoader() {
+		return loader;
+	}
+    
+    /**
+     * This is the single point of entry for setting the &quot;loader&quot; member.  It checks to 
+     * make sure programming errors don't call it more than once.
+     * @param $loader
+     */
+    public synchronized static void setClassLoader(JarClassLoader $loader) {
+        if (loader != null) throw new RuntimeException(&quot;Attempt to set a second Boot loader&quot;);
+        loader = $loader;
+        setProperties(loader);
+    }
+
+	protected static void VERBOSE(String message) {
+		if (verbose) System.out.println(&quot;Boot: &quot; + message);
+	}
+    
+	protected static void WARNING(String message) {
+		System.err.println(&quot;Boot: Warning: &quot; + message); 
+	}
+	
+	protected static void INFO(String message) {
+		if (info) System.out.println(&quot;Boot: Info: &quot; + message);
+	}
+    
+    protected static void PRINTLN(String message) {
+        System.out.println(&quot;Boot: &quot; + message);
+    }
+
+    public static void main(String[] args) throws Exception {
+    	run(args);
+    }
+    
+    public static void run(String args[]) throws Exception {
+		
+        processArgs(args);
+        
+    	// Is the main class specified on the command line?  If so, boot it.
+    	// Othewise, read the main class out of the manifest.
+		String mainClass = null;
+		
+		{
+			// Default properties are in resource 'one-jar.properties'.
+			Properties properties = new Properties();
+			String props = &quot;/one-jar.properties&quot;;
+			InputStream is = Boot.class.getResourceAsStream(props); 
+			if (is != null) {
+				INFO(&quot;loading properties from &quot; + props);
+				properties.load(is);
+			}
+				 
+			// Merge in anything in a local file with the same name.
+			props = &quot;file:one-jar.properties&quot;;
+			is = Boot.class.getResourceAsStream(props);
+			if (is != null) {
+				INFO(&quot;loading properties from &quot; + props);
+				properties.load(is);
+			} 
+			
+			// Set system properties only if not already specified.
+			Enumeration _enum = properties.propertyNames();
+			while (_enum.hasMoreElements()) {
+				String name = (String)_enum.nextElement();
+				if (System.getProperty(name) == null) {
+					System.setProperty(name, properties.getProperty(name));
+				}
+			}
+		}		
+        if (Boolean.valueOf(System.getProperty(P_SHOW_PROPERTIES, &quot;false&quot;)).booleanValue()) {
+            // What are the system properties.
+            Properties props = System.getProperties();
+            String keys[] = (String[])props.keySet().toArray(new String[]{});
+            Arrays.sort(keys);
+            
+            for (int i=0; i&lt;keys.length; i++) {
+                String key = keys[i];
+                System.out.println(key + &quot;=&quot; + props.get(key));
+            }
+        }
+		// Process developer properties:
+		mainClass = System.getProperty(P_MAIN_CLASS);
+
+        // Pick some things out of the top-level JAR file.
+        String jar = getMyJarPath();
+        JarFile jarFile = new JarFile(jar);
+        Manifest manifest = jarFile.getManifest();
+        Attributes attributes = manifest.getMainAttributes();
+        String bootLoaderName = attributes.getValue(ONE_JAR_CLASSLOADER);
+        
+		// If no main-class specified, check the manifest of the main jar for
+		// a Boot-Class attribute.
+		if (mainClass == null) {
+            mainClass = attributes.getValue(ONE_JAR_MAIN_CLASS);
+            if (mainClass == null) {
+                mainClass = attributes.getValue(BOOT_CLASS);
+                if (mainClass != null) {
+                    WARNING(&quot;The manifest attribute &quot; + BOOT_CLASS + &quot; is deprecated in favor of the attribute &quot; + ONE_JAR_MAIN_CLASS);
+                }
+            } 
+		}
+        
+		if (mainClass == null) {
+			// Still don't have one (default).  One final try: look for a jar file in a
+			// main directory.  There should be only one, and it's manifest 
+			// Main-Class attribute is the main class.  The JarClassLoader will take
+			// care of finding it.
+			InputStream is = Boot.class.getResourceAsStream(&quot;/&quot; + MAIN_JAR);
+			if (is != null) {
+				JarInputStream jis = new JarInputStream(is);
+				Manifest mainmanifest = jis.getManifest();
+                jis.close();
+				mainClass = mainmanifest.getMainAttributes().getValue(Attributes.Name.MAIN_CLASS);
+			} else {
+			    // There is no main jar. Warning.
+                WARNING(&quot;Unable to locate &quot; + MAIN_JAR + &quot; in the JAR file &quot; + getMyJarPath());
+            }
+		}
+	
+		// Do we need to create a wrapping classloader?  Check for the
+		// presence of a &quot;wrap&quot; directory at the top of the jar file.
+		URL url = Boot.class.getResource(WRAP_JAR);
+		
+		if (url != null) {
+			// Wrap class loaders.
+            final JarClassLoader bootLoader = getBootLoader(bootLoaderName);
+            setProperties(bootLoader);
+			bootLoader.load(null);
+			
+			// Read the &quot;Wrap-Class-Loader&quot; property from the wraploader jar file.
+			// This is the class to use as a wrapping class-loader.
+            InputStream is = Boot.class.getResourceAsStream(WRAP_JAR);
+            if (is != null) {
+    			JarInputStream jis = new JarInputStream(is);
+    			final String wrapLoader = jis.getManifest().getMainAttributes().getValue(WRAP_CLASS_LOADER);
+                jis.close();
+    			if (wrapLoader == null) {
+    				WARNING(url + &quot; did not contain a &quot; + WRAP_CLASS_LOADER + &quot; attribute, unable to load wrapping classloader&quot;);
+    			} else {
+    				INFO(&quot;using &quot; + wrapLoader);
+                    JarClassLoader wrapped = getWrapLoader(bootLoader, wrapLoader);
+                    if (wrapped == null) {
+                        WARNING(&quot;Unable to instantiate &quot; + wrapLoader + &quot; from &quot; + WRAP_DIR + &quot;: using default JarClassLoader&quot;);
+                        wrapped = getBootLoader(null);
+                    }
+                    setClassLoader(wrapped);
+    			}
+            }
+		} else {
+            setClassLoader(getBootLoader(bootLoaderName, Boot.class.getClassLoader()));
+            INFO(&quot;using JarClassLoader: &quot; + getClassLoader().getClass().getName());
+		}
+        setProperties(loader);
+        
+		mainClass = loader.load(mainClass);
+        
+        if (mainClass == null &amp;&amp; !loader.isExpanded()) 
+            throw new Exception(getMyJarName() + &quot; main class was not found (fix: add main/main.jar with a Main-Class manifest attribute, or specify -D&quot; + P_MAIN_CLASS + &quot;=&lt;your.class.name&gt;), or use &quot; + ONE_JAR_MAIN_CLASS + &quot; in the manifest&quot;);
+
+        if (mainClass != null) {
+        	// Guard against the main.jar pointing back to this
+        	// class, and causing an infinite recursion.
+            String bootClass = Boot.class.getName();
+        	if (bootClass.equals(mainClass))
+        		throw new Exception(getMyJarName() + &quot; main class (&quot; + mainClass + &quot;) would cause infinite recursion: check main.jar/META-INF/MANIFEST.MF/Main-Class attribute: &quot; + mainClass);
+        	
+    		// Set the context classloader in case any classloaders delegate to it.
+    		// Otherwise it would default to the sun.misc.Launcher$AppClassLoader which
+    		// is used to launch the jar application, and attempts to load through
+    		// it would fail if that code is encapsulated inside the one-jar.
+    		Thread.currentThread().setContextClassLoader(loader);
+            
+        	Class cls = loader.loadClass(mainClass);
+            
+            endTime = System.currentTimeMillis();
+            showTime();
+            
+        	Method main = cls.getMethod(&quot;main&quot;, new Class[]{String[].class}); 
+        	main.invoke(null, new Object[]{args});
+        }
+    }
+
+    public static void showTime() {
+        long endtime = System.currentTimeMillis();
+        if (statistics) {
+            PRINTLN(&quot;Elapsed time: &quot; + (endtime - startTime) + &quot;ms&quot;);
+        }
+    }
+    
+    public static void setProperties(IProperties jarloader) {
+        INFO(&quot;setProperties(&quot; + jarloader + &quot;)&quot;);
+        if (getProperty(P_RECORD)) {
+            jarloader.setRecord(true);
+            jarloader.setRecording(System.getProperty(P_RECORD));
+        } 
+        if (getProperty(P_JARNAMES)) {
+            jarloader.setRecord(true);
+            jarloader.setFlatten(false);
+        }
+        if (getProperty(P_VERBOSE)) {
+            jarloader.setVerbose(true);
+            jarloader.setInfo(true);
+            verbose = true;
+        } 
+        if (getProperty(P_INFO)) {
+            jarloader.setInfo(true);
+            info = true;
+        } 
+        
+        statistics = getProperty(P_STATISTICS);
+    }
+    
+    public static boolean getProperty(String key) {
+        return Boolean.valueOf(System.getProperty(key, &quot;false&quot;)).booleanValue();
+    }
+    
+    public static String getMyJarName() {
+        String name = getMyJarPath();
+        int last = name.lastIndexOf(&quot;/&quot;);
+        if (last &gt;= 0) {
+            name = name.substring(last+1); 
+        }
+        return name;
+    }
+    
+    public static String getMyJarPath() {
+        if (myJarPath != null) {
+            return myJarPath;
+        }
+        myJarPath = System.getProperty(P_JARPATH); 
+        if (myJarPath == null) {
+            try {
+                // Hack to obtain the name of this jar file.
+                String jarname = System.getProperty(P_JAVA_CLASS_PATH);
+                // Open each Jar file looking for this class name.  This allows for
+                // JVM's that place more than the jar file on the classpath.
+                String jars[] =jarname.split(System.getProperty(&quot;path.separator&quot;));
+                for (int i=0; i&lt;jars.length; i++) {
+                    jarname = jars[i];
+                    VERBOSE(&quot;Checking &quot; + jarname + &quot; as One-Jar file&quot;);
+                    // Allow for URL based paths, as well as file-based paths.  File
+                    InputStream is = null;
+                    try {
+                        is = new URL(jarname).openStream();
+                    } catch (MalformedURLException mux) {
+                        // Try a local file.
+                        try {
+                            is = new FileInputStream(jarname);
+                        } catch (IOException iox) {
+                            // Ignore..., but it isn't good to have bad entries on the classpath.
+                            continue;
+                        }
+                    }
+                    ZipEntry entry = findJarEntry(new JarInputStream(is), Boot.class.getName().replace('.', '/') + &quot;.class&quot;);
+                    if (entry != null) {
+                        myJarPath = jarname;
+                        break;
+                    } else {
+                        // One more try as a Zip file: supports launch4j on Windows.
+                        entry = findZipEntry(new ZipFile(jarname), Boot.class.getName().replace('.', '/') + &quot;.class&quot;);
+                        if (entry != null) {
+                            myJarPath = jarname;
+                            break;
+                        }
+                    }
+                }
+            } catch (Exception x) {
+                x.printStackTrace();
+                WARNING(&quot;jar=&quot; + myJarPath + &quot; loaded from &quot; + P_JAVA_CLASS_PATH + &quot; (&quot; + System.getProperty(P_JAVA_CLASS_PATH) + &quot;)&quot;);
+            }
+        }
+        if (myJarPath == null) {
+            throw new IllegalArgumentException(&quot;Unable to locate &quot; + Boot.class.getName() + &quot; in the java.class.path: consider using -D&quot; + P_JARPATH + &quot; to specify the one-jar filename.&quot;);
+        }
+        // Normalize those annoying DOS backslashes.
+        myJarPath = myJarPath.replace('\\', '/');
+        return myJarPath;
+    }
+    
+    public static JarEntry findJarEntry(JarInputStream jis, String name) throws IOException {
+        JarEntry entry;
+        while ((entry = jis.getNextJarEntry()) != null) {
+            if (entry.getName().equals(name)) {
+                return entry;
+            }
+        }
+        return null;
+    }
+    
+    public static ZipEntry findZipEntry(ZipFile zip, String name) throws IOException {
+        Enumeration entries = zip.entries();
+        while (entries.hasMoreElements()) {
+            ZipEntry entry = (ZipEntry) entries.nextElement();
+            VERBOSE((&quot;findZipEntry(): entry=&quot; + entry.getName()));
+            if (entry.getName().equals(name)) 
+                return entry;
+        }
+        return null;
+    }
+    
+    public static int firstWidth(String[] table) {
+        int width = 0;
+        for (int i=0; i&lt;table.length; i+=2) {
+            if (table[i].length() &gt; width) width = table[i].length();
+        }
+        return width;
+    }
+    
+    public static String pad(String indent, String string, int width) {
+        StringBuffer buf = new StringBuffer();
+        buf.append(indent);
+        buf.append(string);
+        for (int i=0; i&lt;width-string.length(); i++) {
+            buf.append(&quot; &quot;);
+        }
+        return buf.toString();
+    }
+    
+    public static String wrap(String indent, String string, int width) {
+        String padding = pad(indent, &quot;&quot;, width);
+        string = string.replaceAll(&quot;\n&quot;, &quot;\n&quot; + padding);
+        return string;
+    }
+
+    public static void processArgs(String args[]) throws Exception {
+        // Check for arguments which matter to us.  Process them, but pass them through to the
+        // application too. (TODO: maybe make this passthrough optional).
+        Set arguments = new HashSet(Arrays.asList(args));
+        if (arguments.contains(HELP)) {
+            int width = firstWidth(HELP_ARGUMENTS);
+            // Width of first column
+            
+            System.out.println(&quot;One-Jar uses the following command-line arguments&quot;);
+            for (int i=0; i&lt;HELP_ARGUMENTS.length; i++) {
+                System.out.print(pad(&quot;    &quot;, HELP_ARGUMENTS[i++], width+1));
+                System.out.println(wrap(&quot;    &quot;, HELP_ARGUMENTS[i], width+1));
+            }
+            System.out.println();
+            
+            width = firstWidth(HELP_PROPERTIES);
+            System.out.println(&quot;One-Jar uses the following VM properties (-D&lt;property&gt;=&lt;true|false|string&gt;)&quot;);
+            for (int i=0; i&lt;HELP_PROPERTIES.length; i++) {
+                System.out.print(pad(&quot;    &quot;, HELP_PROPERTIES[i++], width+1));
+                System.out.println(wrap(&quot;    &quot;, HELP_PROPERTIES[i], width+1));
+            }
+            System.out.println();
+            System.exit(0);
+        } else if (arguments.contains(VERSION)) {
+            InputStream is = Boot.class.getResourceAsStream(&quot;/.version&quot;);
+            if (is != null) {
+                BufferedReader br = new BufferedReader(new InputStreamReader(is)); 
+                String version = br.readLine();
+                br.close();
+                System.out.println(&quot;One-JAR version &quot; + version);
+            } else {
+                System.out.println(&quot;Unable to determine One-JAR version (missing /.version resource in One-JAR archive)&quot;);
+            }
+            System.exit(0);
+        }
+    }
+    
+    protected static JarClassLoader getBootLoader(final String loader) {
+        JarClassLoader bootLoader = (JarClassLoader)AccessController.doPrivileged(
+                new PrivilegedAction() {
+                    public Object run() {
+                        if (loader != null) {
+                            try {
+                                Class cls = Class.forName(loader);
+                                Constructor ctor = cls.getConstructor(new Class[]{String.class});
+                                return ctor.newInstance(new Object[]{WRAP_DIR});
+                            } catch (Exception x) {
+                                WARNING(&quot;Unable to instantiate &quot; + loader + &quot;: &quot; + x + &quot; continuing using default &quot; + JarClassLoader.class.getName());
+                            }
+                        }
+                        return new JarClassLoader(WRAP_DIR);
+                    }
+                }
+            );
+        return bootLoader;
+    }
+    
+    protected static JarClassLoader getBootLoader(final String loader, ClassLoader parent) {
+        return (JarClassLoader)AccessController.doPrivileged(
+            new PrivilegedAction() {
+                public Object run() {
+                    if (loader != null) {
+                        try {
+                            Class cls = Class.forName(loader);
+                            Constructor ctor = cls.getConstructor(new Class[]{ClassLoader.class});
+                            return ctor.newInstance(new Object[]{Boot.class.getClassLoader()});
+                        } catch (Exception x) {
+                            WARNING(&quot;Unable to instantiate &quot; + loader + &quot;: &quot; + x + &quot; continuing using default &quot; + JarClassLoader.class.getName());
+                        }
+                    }
+                    return new JarClassLoader(Boot.class.getClassLoader());
+                }
+            }
+        );        
+    }
+    
+    protected static JarClassLoader getWrapLoader(final ClassLoader bootLoader, final String wrapLoader) {
+        return ((JarClassLoader)AccessController.doPrivileged(
+            new PrivilegedAction() {
+                public Object run() {
+                    try {
+                        Class jarLoaderClass = bootLoader.loadClass(wrapLoader);
+                        Constructor ctor = jarLoaderClass.getConstructor(new Class[]{ClassLoader.class});
+                        return ctor.newInstance(new Object[]{bootLoader});
+                    } catch (Throwable t) {
+                        WARNING(t.toString());
+                    }
+                    return null;
+                }
+            }));
+    }
+
+    public static long getEndTime() {
+        return endTime;
+    }
+
+    public static long getStartTime() {
+        return startTime;
+    }
+    
+}</diff>
      <filename>onejar/com/simontuffs/onejar/Boot.java</filename>
    </modified>
    <modified>
      <diff></diff>
      <filename>onejar/com/simontuffs/onejar/Handler$1.class</filename>
    </modified>
    <modified>
      <diff></diff>
      <filename>onejar/com/simontuffs/onejar/Handler.class</filename>
    </modified>
    <modified>
      <diff>@@ -1,49 +1,55 @@
-/*
- * Copyright (c) 2004, P. Simon Tuffs (simon@simontuffs.com)
- * All rights reserved.
- *
- * See full license at http://one-jar.sourceforge.net/one-jar-license.txt
- * This license is also included in the distributions of this software
- * under doc/one-jar-license.txt
- */
-
-package com.simontuffs.onejar;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.URLStreamHandler;
-
-/**
- * @author simon@simontuffs.com
- *
- */
-public class Handler extends URLStreamHandler {
-
-	/**
-	 * This procol name must match the name of the package in which this class
-	 * lives.
-	 */
-	public static String PROTOCOL = &quot;onejar&quot;;
-
-	protected int len = PROTOCOL.length()+1;
-	
-	/** 
-	 * @see java.net.URLStreamHandler#openConnection(java.net.URL)
-	 */
-	protected URLConnection openConnection(URL u) throws IOException {
-		final String resource = u.toString().substring(len);
-		return new URLConnection(u) {
-			public void connect() {
-			}
-			public InputStream getInputStream() {
-				// Use the Boot classloader to get the resource.  There
-				// is only one per one-jar.
-				JarClassLoader cl = Boot.getClassLoader();
-				return cl.getByteStream(resource);
-			}
-		};
-	}
-
-}
+/*
+ * Copyright (c) 2004, P. Simon Tuffs (simon@simontuffs.com)
+ * All rights reserved.
+ *
+ * See the full license at http://one-jar.sourceforge.net/one-jar-license.html
+ * This license is also included in the distributions of this software
+ * under doc/one-jar-license.txt
+ */
+
+package com.simontuffs.onejar;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.FileNameMap;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+/**
+ * @author simon@simontuffs.com
+ *
+ */
+public class Handler extends URLStreamHandler {
+
+	/**
+	 * This procol name must match the name of the package in which this class
+	 * lives.
+	 */
+	public static String PROTOCOL = &quot;onejar&quot;;
+
+	/** 
+	 * @see java.net.URLStreamHandler#openConnection(java.net.URL)
+	 */
+	protected URLConnection openConnection(final URL u) throws IOException {
+		final String resource = u.getPath();
+		return new URLConnection(u) {
+			public void connect() {
+			}
+            public String getContentType() {
+                FileNameMap fileNameMap = java.net.URLConnection.getFileNameMap();
+                String contentType = fileNameMap.getContentTypeFor(resource);
+                if (contentType == null) 
+                    contentType = &quot;text/plain&quot;;
+                return contentType;
+            }
+			public InputStream getInputStream() {
+				// Use the Boot classloader to get the resource.  There
+				// is only one per one-jar.
+				JarClassLoader cl = Boot.getClassLoader();
+				return cl.getByteStream(resource);
+			}
+		};
+	}
+    
+}</diff>
      <filename>onejar/com/simontuffs/onejar/Handler.java</filename>
    </modified>
    <modified>
      <diff></diff>
      <filename>onejar/com/simontuffs/onejar/JarClassLoader$1.class</filename>
    </modified>
    <modified>
      <diff></diff>
      <filename>onejar/com/simontuffs/onejar/JarClassLoader$ByteCode.class</filename>
    </modified>
    <modified>
      <diff></diff>
      <filename>onejar/com/simontuffs/onejar/JarClassLoader.class</filename>
    </modified>
    <modified>
      <diff>@@ -1,931 +1,1058 @@
-/*
- * Copyright (c) 2004, P. Simon Tuffs (simon@simontuffs.com)
- * All rights reserved.
- *
- * See full license at http://one-jar.sourceforge.net/one-jar-license.txt
- * This license is also included in the distributions of this software
- * under doc/one-jar-license.txt
- */
-
-/**
- * Many thanks to the following for their contributions to One-Jar:
- * 
- * Contributor: Christopher Ottley &lt;xknight@users.sourceforge.net&gt;
- * Contributor: Thijs Sujiten (www.semantica.nl)
- * Contributor: Gerold Friedmann
- */
-
-package com.simontuffs.onejar;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.security.CodeSource;
-import java.security.ProtectionDomain;
-import java.security.cert.Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.jar.Attributes;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.jar.JarInputStream;
-import java.util.jar.Manifest;
-import java.util.jar.Attributes.Name;
-
-/**
- * Loads classes from pre-defined locations inside the jar file containing this
- * class.  Classes will be loaded from jar files contained in the following 
- * locations within the main jar file (on the classpath of the application 
- * actually, which when running with the &quot;java -jar&quot; command works out to be
- * the same thing).
- * &lt;ul&gt;
- * &lt;li&gt;
- *   /lib	Used to contain library jars.
- * &lt;/li&gt;
- * &lt;li&gt;
- *   /main	Used to contain a default main jar.
- * &lt;/li&gt;
- * &lt;/ul&gt; 
- * @author simon@simontuffs.com (&lt;a href=&quot;http://www.simontuffs.com&quot;&gt;http://www.simontuffs.com&lt;/a&gt;)
- */
-public class JarClassLoader extends ClassLoader {
-    
-    public final static String JAVA_CLASS_PATH = &quot;java.class.path&quot;;
-    public final static String LIB_PREFIX = &quot;lib/&quot;;
-    public final static String BINLIB_PREFIX = &quot;binlib/&quot;;
-    public final static String MAIN_PREFIX = &quot;main/&quot;;
-    public final static String RECORDING = &quot;recording&quot;;
-    public final static String TMP = &quot;tmp&quot;;
-    public final static String UNPACK = &quot;unpack&quot;;
-    public final static String EXPAND = &quot;One-Jar-Expand&quot;;
-    public final static String CLASS = &quot;.class&quot;;
-    
-    public final static String JAVA_PROTOCOL_HANDLER = &quot;java.protocol.handler.pkgs&quot;;
-    
-    protected String name;
-    
-    static {
-        // Add our 'onejar:' protocol handler, but leave open the 
-        // possibility of a subsequent class taking over the 
-        // factory.  TODO: (how reasonable is this?)
-        String handlerPackage = System.getProperty(JAVA_PROTOCOL_HANDLER);
-        if (handlerPackage == null) handlerPackage = &quot;&quot;;
-        if (handlerPackage.length() &gt; 0) handlerPackage = &quot;|&quot; + handlerPackage;
-        handlerPackage = &quot;com.simontuffs&quot; + handlerPackage;
-        System.setProperty(JAVA_PROTOCOL_HANDLER, handlerPackage);
-        
-    }
-    
-    protected String PREFIX() {
-        return &quot;JarClassLoader: &quot;;
-    }
-    
-    protected String NAME() {
-        return (name != null? &quot;'&quot; + name + &quot;' &quot;: &quot;&quot;);
-    }
-    
-    protected void VERBOSE(String message) {
-        if (verbose) System.out.println(PREFIX() + NAME() + message);
-    }
-    
-    protected void WARNING(String message) {
-        System.err.println(PREFIX() + &quot;Warning: &quot; + NAME() + message); 
-    }
-    
-    protected void INFO(String message) {
-        if (info) System.out.println(PREFIX() + &quot;Info: &quot; + NAME() + message);
-    }
-    
-    // Synchronize for thread safety.  This is less important until we
-    // start to do lazy loading, but it's a good idea anyway.
-    protected Map byteCode = Collections.synchronizedMap(new HashMap());
-    protected Map pdCache = Collections.synchronizedMap(new HashMap());
-    protected Map binLibPath = Collections.synchronizedMap(new HashMap());
-    protected Set jarNames = Collections.synchronizedSet(new HashSet());
-    
-    protected boolean record = false, flatten = false, unpackFindResource = false;
-    protected boolean verbose = false, info = false;
-    protected String recording = RECORDING;
-    
-    protected String jarName, mainJar, wrapDir;
-    protected boolean delegateToParent;
-    
-    protected class ByteCode {
-		public ByteCode(String $name, String $original, byte $bytes[], String $codebase, Manifest $manifest) {
-            name = $name;
-            original = $original;
-            bytes = $bytes;
-            codebase = $codebase;
-			manifest = $manifest;
-        }
-        public byte bytes[];
-        public String name, original, codebase;
-		public Manifest manifest;
-    }
-    
-    
-    /**
-     * Create a non-delegating but jar-capable classloader for bootstrap
-     * purposes.
-     * @param $wrap  The directory in the archive from which to load a 
-     * wrapping classloader.
-     */
-    public JarClassLoader(String $wrap) {
-        wrapDir = $wrap;
-        delegateToParent = wrapDir == null;
-    }
-    
-    /**
-     * The main constructor for the Jar-capable classloader.
-     * @param $record	If true, the JarClassLoader will record all used classes
-     * 					into a recording directory (called 'recording' by default)
-     *				 	The name of each jar file will be used as a directory name
-     *					for the recorded classes.
-     * @param $flatten  Whether to flatten out the recorded classes (i.e. eliminate
-     * 					the jar-file name from the recordings).
-     * 
-     * Example: Given the following layout of the one-jar.jar file
-     * &lt;pre&gt;
-     *    /
-     *    /META-INF
-     *    | MANIFEST.MF
-     *    /com
-     *      /simontuffs
-     *        /onejar
-     *          Boot.class
-     *          JarClassLoader.class
-     *    /main
-     *        main.jar
-     *        /com
-     *          /main
-     *            Main.class 
-     *    /lib
-     *        util.jar
-     *          /com
-     *            /util
-     *              Util.clas
-     * &lt;/pre&gt;
-     * The recording directory will look like this:
-     * &lt;ul&gt;
-     * &lt;li&gt;flatten=false&lt;/li&gt;
-     * &lt;pre&gt;
-     *   /recording
-     *     /main.jar
-     *       /com
-     *         /main
-     *            Main.class
-     *     /util.jar
-     *       /com
-     *         /util
-     *            Util.class
-     * &lt;/pre&gt;
-     *
-     * &lt;li&gt;flatten = true&lt;/li&gt;
-     * &lt;pre&gt;
-     *   /recording
-     *     /com
-     *       /main
-     *          Main.class
-     *       /util
-     *          Util.class
-     *   
-     * &lt;/ul&gt;
-     * Flatten mode is intended for when you want to create a super-jar which can
-     * be launched directly without using one-jar's launcher.  Run your application
-     * under all possible scenarios to collect the actual classes which are loaded,
-     * then jar them all up, and point to the main class with a &quot;Main-Class&quot; entry
-     * in the manifest.  
-     *       
-     */
-    public JarClassLoader(ClassLoader parent) {
-        super(parent);
-        delegateToParent = true;
-        // System.out.println(PREFIX() + this + &quot; parent=&quot; + parent + &quot; loaded by &quot; + this.getClass().getClassLoader());
-    }
-    
-    public String load(String mainClass) {
-        // Hack: if there is a one-jar.jarname property, use it.
-        String jarname = System.getProperty(Boot.PROPERTY_PREFIX + &quot;jarname&quot;);
-        return load(mainClass, jarname);
-    }
-    
-    public String load(String mainClass, String jarName) {
-        if (record) {
-            new File(recording).mkdirs();
-        }
-        try {
-            if (jarName == null) {
-                // Hack to get the lib directory entries.   We know we are being
-                // loaded out of a jar file, so there is only one jar-file on the
-                // classpath: ours!  So we open it.
-                jarName = System.getProperty(JAVA_CLASS_PATH);
-
-                // Fix from 'eleeptg' for OS-X problems: extract first entry from classpath 
-                // 'test.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/.compatibility/14compatibility.jar' 
-                if ((jarName!=null) &amp;&amp; (jarName.indexOf(System.getProperty(&quot;path.separator&quot;)) &gt; 0)) 
-                    jarName = jarName.substring(0, jarName.indexOf(System.getProperty(&quot;path.separator&quot;))); 
-                
-            }
-            JarFile jarFile = new JarFile(jarName);
-            Enumeration _enum = jarFile.entries();
-            Manifest manifest = jarFile.getManifest();
-            String expandPaths[] = null;
-            // TODO: Allow a destination directory (relative or absolute) to 
-            // be specified like this:
-            // One-Jar-Expand: build=../expanded
-            String expand = manifest.getMainAttributes().getValue(EXPAND);
-            if (expand != null) {
-                VERBOSE(EXPAND + &quot;=&quot; + expand);
-                expandPaths = expand.split(&quot;,&quot;);
-            }
-            boolean mainfound = false;
-            while (_enum.hasMoreElements()) {
-                JarEntry entry = (JarEntry)_enum.nextElement();
-                if (entry.isDirectory()) continue;
-                
-                // The META-INF/MANIFEST.MF file can contain a property which names
-                // directories in the JAR to be expanded (comma separated). For example:
-                // One-Jar-Expand: build,tmp,webapps
-                boolean expanded = false;
-                String name = entry.getName();
-                if (expandPaths != null) {
-                    // TODO: Can't think of a better way to do this right now.  
-                    // This code really doesn't need to be optimized anyway.
-                    for (int i=0; i&lt;expandPaths.length; i++) {
-                        if (name.startsWith(expandPaths[i])) {
-                            File dest = new File(name);
-                            // Override if ZIP file is newer than existing.
-                            if (!dest.exists() || dest.lastModified() &lt; entry.getTime()) {
-                                INFO(&quot;Expanding &quot; + name);
-                                if (dest.exists()) INFO(&quot;Update because lastModified=&quot; + new Date(dest.lastModified()) + &quot;, entry=&quot; + new Date(entry.getTime()));
-                                dest.getParentFile().mkdirs();
-                                VERBOSE(&quot;using jarFile.getInputStream(&quot; + entry + &quot;)&quot;);
-                                InputStream is = jarFile.getInputStream(entry);
-                                FileOutputStream os = new FileOutputStream(dest); 
-                                copy(is, os);
-                                is.close();
-                                os.close();
-                            } else {
-                                VERBOSE(name + &quot; already expanded&quot;);
-                            }
-                            expanded = true;
-                            break;
-                        }
-                    }
-                }
-                if (expanded) continue;
-                
-                String jar = entry.getName();
-                if (wrapDir != null &amp;&amp; jar.startsWith(wrapDir) || jar.startsWith(LIB_PREFIX) || jar.startsWith(MAIN_PREFIX)) {
-                    if (wrapDir != null &amp;&amp; !entry.getName().startsWith(wrapDir)) continue;
-                    // Load it! 
-                    INFO(&quot;caching &quot; + jar);
-                    VERBOSE(&quot;using jarFile.getInputStream(&quot; + entry + &quot;)&quot;);
-                    {
-                        // Note: loadByteCode consumes the input stream, so make sure its scope
-                        // does not extend beyond here.
-                        InputStream is = jarFile.getInputStream(entry);
-                        if (is == null) 
-                            throw new IOException(&quot;Unable to load resource /&quot; + jar + &quot; using &quot; + this);
-						loadByteCode(is, jar, manifest);
-                    }
-                    
-                    // Do we need to look for a main class?
-                    if (jar.startsWith(MAIN_PREFIX)) {
-                    	mainfound = true;
-                        if (mainClass == null) {
-                            JarInputStream jis = new JarInputStream(jarFile.getInputStream(entry));
-                            Manifest m = jis.getManifest();
-                            // Is this a jar file with a manifest?
-                            if (m != null) {
-                                mainClass = jis.getManifest().getMainAttributes().getValue(Attributes.Name.MAIN_CLASS);
-                                mainJar = jar;
-                            }
-                        } else if (mainJar != null) {
-                            WARNING(&quot;A main class is defined in multiple jar files inside &quot; + MAIN_PREFIX + mainJar + &quot; and &quot; + jar);
-                            WARNING(&quot;The main class &quot; + mainClass + &quot; from &quot; + mainJar + &quot; will be used&quot;);
-                        }
-                    } 
-                } else if (wrapDir == null &amp;&amp; name.startsWith(UNPACK)) {
-                    // Unpack into a temporary directory which is on the classpath of
-                    // the application classloader.  Badly designed code which relies on the
-                    // application classloader can be made to work in this way.
-                    InputStream is = this.getClass().getResourceAsStream(&quot;/&quot; + jar);
-                    if (is == null) throw new IOException(jar);
-                    // Make a sentinel.
-                    File dir = new File(TMP);
-                    File sentinel = new File(dir, jar.replace('/', '.'));
-                    if (!sentinel.exists()) {
-                        INFO(&quot;unpacking &quot; + jar + &quot; into &quot; + dir.getCanonicalPath());
-						loadByteCode(is, jar, TMP, manifest);
-                        sentinel.getParentFile().mkdirs();
-                        sentinel.createNewFile();
-                    }
-                } else if (name.endsWith(CLASS)) {
-                    // A plain vanilla class file rooted at the top of the jar file.
-					loadBytes(entry, jarFile.getInputStream(entry), &quot;/&quot;, null, manifest);
-                } else {
-                    // A resource? 
-                   INFO(&quot;resource: &quot; + jarFile.getName() + &quot;!&quot; + entry.getName());
-                }
-                if (!mainfound &amp;&amp; mainClass == null) {
-                	// One last try to determine a main class.
-                	mainClass = manifest.getMainAttributes().getValue(Attributes.Name.MAIN_CLASS);
-                }
-            }
-            // If mainClass is still not defined, return null.  The caller is then responsible
-            // for determining a main class.
-            
-        } catch (IOException iox) {
-            System.err.println(&quot;Unable to load resource: &quot; + iox);
-            iox.printStackTrace(System.err);
-        }
-        return mainClass;
-    }
-    
-	protected void loadByteCode(InputStream is, String jar, Manifest man) throws IOException {
-		loadByteCode(is, jar, null, man);
-    }
-    
-	protected void loadByteCode(InputStream is, String jar, String tmp, Manifest man) throws IOException {
-        JarInputStream jis = new JarInputStream(is);
-        JarEntry entry = null;
-        // TODO: implement lazy loading of bytecode.
-        while ((entry = jis.getNextJarEntry()) != null) {
-            if (entry.isDirectory()) continue;
-			loadBytes(entry, jis, jar, tmp, man);
-        }
-    }
-    
-	protected void loadBytes(JarEntry entry, InputStream is, String jar, String tmp, Manifest man) throws IOException {
-        String entryName = entry.getName().replace('/', '.');
-        int index = entryName.lastIndexOf('.');
-        String type = entryName.substring(index+1);
-        
-        // Because we are doing stream processing, we don't know what
-        // the size of the entries is.  So we store them dynamically.
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        copy(is, baos);
-        
-        if (tmp != null) {
-            // Unpack into a temporary working directory which is on the classpath.
-            File file = new File(tmp, entry.getName());
-            file.getParentFile().mkdirs();
-            FileOutputStream fos = new FileOutputStream(file);
-            fos.write(baos.toByteArray());
-            fos.close();
-            
-        } else {
-            // If entry is a class, check to see that it hasn't been defined
-            // already.  Class names must be unique within a classloader because
-            // they are cached inside the VM until the classloader is released.
-            byte[] bytes = baos.toByteArray();
-            if (type.equals(&quot;class&quot;)) {
-                if (alreadyCached(entryName, jar, bytes)) return;
-				byteCode.put(entryName, new ByteCode(entryName, entry.getName(), bytes, jar, man));
-                VERBOSE(&quot;cached bytes for class &quot; + entryName);
-            } else {
-                // Another kind of resource.  Cache this by name, and also prefixed
-                // by the jar name.  Don't duplicate the bytes.  This allows us
-                // to map resource lookups to either jar-local, or globally defined.
-                String localname = jar + &quot;/&quot; + entryName;
-				byteCode.put(localname, new ByteCode(localname, entry.getName(), bytes, jar, man));
-                // Keep a set of jar names so we can do multiple-resource lookup by name
-                // as in findResources().
-                jarNames.add(jar);
-                VERBOSE(&quot;cached bytes for local name &quot; + localname);
-                // Only keep the first non-local entry: this is like classpath where the first
-                // to define wins.  
-                if (alreadyCached(entryName, jar, bytes)) return;
-
-                byteCode.put(entryName, new ByteCode(entryName, entry.getName(), bytes, jar, man));
-                VERBOSE(&quot;cached bytes for entry name &quot; + entryName);
-                
-            }
-        }
-    }
-    
-    protected boolean classPool = false;
-    
-    /**
-     * Locate the named class in a jar-file, contained inside the
-     * jar file which was used to load &lt;u&gt;this&lt;/u&gt; class.
-     */
-    protected Class findClass(String name) throws ClassNotFoundException {
-        // Make sure not to load duplicate classes.
-        Class cls = findLoadedClass(name);
-        if (cls != null) return cls;
-        
-        // Look up the class in the byte codes.
-        // Translate path?
-        VERBOSE(&quot;findClass(&quot; + name + &quot;)&quot;);
-        String cache = name + CLASS;
-        ByteCode bytecode = (ByteCode)byteCode.get(cache);
-        if (bytecode != null) {
-            VERBOSE(&quot;found &quot; + name + &quot; in codebase '&quot; + bytecode.codebase + &quot;'&quot;);
-            if (record) {
-                record(bytecode);
-            }
-            // Use a protectionDomain to associate the codebase with the
-            // class.
-            ProtectionDomain pd = (ProtectionDomain)pdCache.get(bytecode.codebase);
-            if (pd == null) {
-                ProtectionDomain cd = JarClassLoader.class.getProtectionDomain();
-                URL url = cd.getCodeSource().getLocation();
-                try {
-                    url = new URL(&quot;jar:&quot; + url + &quot;!/&quot; + bytecode.codebase);
-                } catch (MalformedURLException mux) {
-                    mux.printStackTrace(System.out);    			
-                }
-                
-                CodeSource source = new CodeSource(url, (Certificate[])null);
-                pd = new ProtectionDomain(source, null, this, null);
-                pdCache.put(bytecode.codebase, pd);
-            }
-            
-            // Do it the simple way.
-            byte bytes[] = bytecode.bytes;
-			
-			int i = name.lastIndexOf('.');
-			if (i != -1) {
-				String pkgname = name.substring(0, i);
-				// Check if package already loaded.
-				Package pkg = getPackage(pkgname);
-				Manifest man = bytecode.manifest;
-				if (pkg != null) {
-					// Package found, so check package sealing.
-					if (pkg.isSealed()) {
-						// Verify that code source URL is the same.
-						if (!pkg.isSealed()) {
-							throw new SecurityException(&quot;sealing violation: package &quot; + pkgname + &quot; is sealed&quot;);
-						}
-
-					} else {
-						// Make sure we are not attempting to seal the package
-						// at this code source URL.
-						if ((man != null) &amp;&amp; isSealed(pkgname, man)) {
-							throw new SecurityException(&quot;sealing violation: can't seal package &quot; + pkgname + &quot;: already loaded&quot;);
-						}
-					}
-				} else {
-					if (man != null) {
-						definePackage(pkgname, man);
-					} else {
-						definePackage(pkgname, null, null, null, null, null, null, null);
-					}
-				}
-			}
-			
-            return defineClass(name, bytes, pd);
-        }
-        VERBOSE(name + &quot; not found&quot;);
-        throw new ClassNotFoundException(name);
-        
-    }
-    
-    private boolean isSealed(String name, Manifest man) {
-		String path = name.replace('.', '/').concat(&quot;/&quot;);
-		Attributes attr = man.getAttributes(path);
-		String sealed = null;
-		if (attr != null) {
-			sealed = attr.getValue(Name.SEALED);
-		}
-		if (sealed == null) {
-			if ((attr = man.getMainAttributes()) != null) {
-				sealed = attr.getValue(Name.SEALED);
-			}
-		}
-		return &quot;true&quot;.equalsIgnoreCase(sealed);
-	}
-
-    /**
-	 * Defines a new package by name in this ClassLoader. The attributes
-	 * contained in the specified Manifest will be used to obtain package
-	 * version and sealing information. For sealed packages, the additional URL
-	 * specifies the code source URL from which the package was loaded.
-	 * 
-	 * @param name
-	 *            the package name
-	 * @param man
-	 *            the Manifest containing package version and sealing
-	 *            information
-	 * @param url
-	 *            the code source url for the package, or null if none
-	 * @exception IllegalArgumentException
-	 *                if the package name duplicates an existing package either
-	 *                in this class loader or one of its ancestors
-	 * @return the newly defined Package object
-	 */
-	protected Package definePackage(String name, Manifest man) throws IllegalArgumentException {
-		String path = name.replace('.', '/').concat(&quot;/&quot;);
-		String specTitle = null, specVersion = null, specVendor = null;
-		String implTitle = null, implVersion = null, implVendor = null;
-		String sealed = null;
-		URL sealBase = null;
-
-		Attributes attr = man.getAttributes(path);
-		if (attr != null) {
-			specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
-			specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
-			specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
-			implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
-			implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
-			implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
-			sealed = attr.getValue(Name.SEALED);
-		}
-		attr = man.getMainAttributes();
-		if (attr != null) {
-			if (specTitle == null) {
-				specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
-			}
-			if (specVersion == null) {
-				specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
-			}
-			if (specVendor == null) {
-				specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
-			}
-			if (implTitle == null) {
-				implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
-			}
-			if (implVersion == null) {
-				implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
-			}
-			if (implVendor == null) {
-				implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
-			}
-			if (sealed == null) {
-				sealed = attr.getValue(Name.SEALED);
-			}
-		}
-		return definePackage(name, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor, sealBase);
-	}
-	
-    protected Class defineClass(String name, byte[] bytes, ProtectionDomain pd) throws ClassFormatError {
-        // Simple, non wrapped class definition.
-        return defineClass(name, bytes, 0, bytes.length, pd);
-    }
-    
-    protected void record(ByteCode bytecode) {
-        String fileName = bytecode.original;
-        // Write out into the record directory.
-        File dir = new File(recording, flatten? &quot;&quot;: bytecode.codebase);
-        File file = new File(dir, fileName);
-        if (!file.exists()) {
-            file.getParentFile().mkdirs();
-            VERBOSE(&quot;&quot; + file);
-            try {
-                FileOutputStream fos = new FileOutputStream(file);
-                fos.write(bytecode.bytes);
-                fos.close();
-                
-            } catch (IOException iox) {
-                System.err.println(PREFIX() + &quot;unable to record &quot; + file + &quot;: &quot; + iox);
-            }
-            
-        }
-    }
-    
-    /**
-     * Overriden to return resources from the appropriate codebase.
-     * There are basically two ways this method will be called: most commonly
-     * it will be called through the class of an object which wishes to 
-     * load a resource, i.e. this.getClass().getResourceAsStream().  Before
-     * passing the call to us, java.lang.Class mangles the name.  It 
-     * converts a file path such as foo/bar/Class.class into a name like foo.bar.Class, 
-     * and it strips leading '/' characters e.g. converting '/foo' to 'foo'.
-     * All of which is a nuisance, since we wish to do a lookup on the original
-     * name of the resource as present in the One-Jar jar files.  
-     * The other way is more direct, i.e. this.getClass().getClassLoader().getResourceAsStream().
-     * Then we get the name unmangled, and can deal with it directly. 
-     *
-     * The problem is this: if one resource is called /foo/bar/data, and another 
-     * resource is called /foo.bar.data, both will have the same mangled name, 
-     * namely 'foo.bar.data' and only one of them will be visible.  Perhaps the
-     * best way to deal with this is to store the lookup names in mangled form, and
-     * simply issue warnings if collisions occur.  This is not very satisfactory,
-     * but is consistent with the somewhat limiting design of the resource name mapping
-     * strategy in Java today.
-     */
-    public InputStream getByteStream(String resource) {
-        
-        InputStream result = null;
-        // Look up without resolving first.  This allows jar-local 
-        // resolution to take place.
-        ByteCode bytecode = (ByteCode)byteCode.get(resource);
-        if (bytecode == null) {
-            // Try again with a resolved name.
-            bytecode = (ByteCode)byteCode.get(resolve(resource));
-        }
-        if (bytecode != null) result = new ByteArrayInputStream(bytecode.bytes);
-        // Special case: if we are a wrapping classloader, look up to our
-        // parent codebase.  Logic is that the boot JarLoader will have 
-        // delegateToParent = false, the wrapping classloader will have 
-        // delegateToParent = true;
-        if (result == null &amp;&amp; delegateToParent) {
-            result = ((JarClassLoader)getParent()).getByteStream(resource);
-        }
-        VERBOSE(&quot;getByteStream(&quot; + resource + &quot;) -&gt; &quot; + result);
-        return result;
-    }
-    
-    /**
-     * Resolve a resource name.  Look first in jar-relative, then in global scope.
-     * @param resource
-     * @return
-     */
-    protected String resolve(String $resource) {
-        
-        if ($resource.startsWith(&quot;/&quot;)) $resource = $resource.substring(1);
-        $resource = $resource.replace('/', '.');
-        String resource = null;
-        String caller = getCaller();
-        ByteCode callerCode = (ByteCode)byteCode.get(caller + &quot;.class&quot;);
-        
-        if (callerCode != null) {
-            // Jar-local first, then global.
-            String tmp = callerCode.codebase + &quot;/&quot; + $resource;
-            if (byteCode.get(tmp) != null) {
-                resource = tmp; 
-            } 
-        }
-        if (resource == null) {
-            // One last try.
-            if (byteCode.get($resource) == null) {
-                resource = null; 
-            } else {
-                resource = $resource;
-            }
-        }
-        VERBOSE(&quot;resource &quot; + $resource + &quot; resolved to &quot; + resource);
-        return resource;
-    }
-    
-    protected boolean alreadyCached(String name, String jar, byte[] bytes) {
-        // TODO: check resource map to see how we will map requests for this
-        // resource from this jar file.  Only a conflict if we are using a
-        // global map and the resource is defined by more than
-        // one jar file (default is to map to local jar).
-        ByteCode existing = (ByteCode)byteCode.get(name);
-        if (existing != null) {
-            // If bytecodes are identical, no real problem.  Likewise if it's in
-            // META-INF.
-            if (!Arrays.equals(existing.bytes, bytes) &amp;&amp; !name.startsWith(&quot;/META-INF&quot;)) {
-                INFO(existing.name + &quot; in &quot; + jar + &quot; is hidden by &quot; + existing.codebase + &quot; (with different bytecode)&quot;);
-            } else {
-                VERBOSE(existing.name + &quot; in &quot; + jar + &quot; is hidden by &quot; + existing.codebase + &quot; (with same bytecode)&quot;);
-            }
-            return true;
-        }
-        return false;
-    }
-    
-    
-    protected String getCaller() {
-        StackTraceElement[] stack = new Throwable().getStackTrace();
-        // Search upward until we get to a known class, i.e. one with a non-null
-        // codebase.
-        String caller = null;
-        for (int i=0; i&lt;stack.length; i++) {
-            if (byteCode.get(stack[i].getClassName() + &quot;.class&quot;) != null) {
-                caller = stack[i].getClassName();
-                break;
-            }
-        }
-        return caller;
-    }
-    
-    /**
-     * Sets the name of the used  classes recording directory.
-     * 
-     * @param $recording A value of &quot;&quot; will use the current working directory 
-     * (not recommended).  A value of 'null' will use the default directory, which
-     * is called 'recording' under the launch directory (recommended).
-     */
-    public void setRecording(String $recording) {
-        recording = $recording;
-        if (recording == null) recording = RECORDING;
-    }
-    
-    public String getRecording() {
-        return recording;
-    }
-    
-    public void setRecord(boolean $record) {
-        record = $record;
-    }
-    public boolean getRecord() {
-        return record;
-    }
-    
-    public void setFlatten(boolean $flatten) {
-        flatten = $flatten;
-    }
-    public boolean isFlatten() {
-        return flatten;
-    }
-    
-    public void setVerbose(boolean $verbose) {
-        verbose = $verbose;
-        if (verbose) info = true;
-    }
-    
-    public boolean getVerbose() {
-        return verbose;
-    }
-    
-    public void setInfo(boolean $info) {
-        info = $info;
-    }
-    public boolean getInfo() {
-        return info;
-    }
-    
-    /* (non-Javadoc)
-     * @see java.lang.ClassLoader#findResource(java.lang.String)
-     */
-    protected URL findResource(String $resource) {
-        try {
-            INFO(&quot;findResource(&quot; + $resource + &quot;)&quot;);
-            // Do we have the named resource in our cache?  If so, construct a 
-            // 'onejar:' URL so that a later attempt to access the resource
-            // will be redirected to our Handler class, and thence to this class.
-            String resource = resolve($resource);
-            if (resource != null) {
-                // We know how to handle it.
-                INFO(&quot;findResource() found: &quot; + $resource);
-                return new URL(Handler.PROTOCOL + &quot;:&quot; + resource); 
-            }
-            INFO(&quot;findResource(): unable to locate &quot; + $resource);
-            // If all else fails, return null.
-            return null;
-        } catch (MalformedURLException mux) {
-            WARNING(&quot;unable to locate &quot; + $resource + &quot; due to &quot; + mux);
-        }
-        return null;
-        
-    }
-    
-    public Enumeration findResources(String name) throws IOException {
-        INFO(&quot;findResources(&quot; + name + &quot;)&quot;);
-        INFO(&quot;findResources: looking in &quot; + jarNames);
-        Iterator iter = jarNames.iterator();
-        final List resources = new ArrayList();
-        // Mangle name to match our dot separated format.  This still 
-        // seems a bit flakey to me.  TODO: revisit.
-        name = name.replace('/', '.');
-        while (iter.hasNext()) {
-            String resource = iter.next().toString() + &quot;/&quot; + name;
-            if (byteCode.containsKey(resource)) {
-                resources.add(new URL(Handler.PROTOCOL + &quot;:&quot; + resource));
-            }
-        }
-        final Iterator ri = resources.iterator();
-        return new Enumeration() {
-            public boolean hasMoreElements() {
-                return ri.hasNext();
-            }
-            public Object nextElement() {
-                return ri.next();
-            }
-        };
-    }
-    
-    /**
-     * Utility to assist with copying InputStream to OutputStream.  All
-     * bytes are copied, but both streams are left open.
-     * @param in Source of bytes to copy.
-     * @param out Destination of bytes to copy.
-     * @throws IOException
-     */
-    protected void copy(InputStream in, OutputStream out) throws IOException {
-        byte[] buf = new byte[1024];
-        while (true) {
-            int len = in.read(buf);
-            if (len &lt; 0) break;
-            out.write(buf, 0, len);
-        }
-    }
-    
-    public String toString() {
-        return super.toString() + (name != null? &quot;(&quot; + name + &quot;)&quot;: &quot;&quot;);
-    }
-    
-    /**
-     * Returns name of the classloader.
-     * @return
-     */
-    public String getName() {
-        return name;
-    }
-    
-    /**
-     * Sets name of the classloader.  Default is null.
-     * @param string
-     */
-    public void setName(String string) {
-        name = string;
-    }
-    
-    
-    /**
-     * If the system specific library exists in the JAR, expand it and return the path
-     * to the expanded library to the caller. Otherwise return null so the caller
-     * searches the java.library.path for the requested library.
-     *
-     *
-     * @author Christopher Ottley
-     * @param name the (system specific) name of the requested library
-     * @return the full pathname to the requested library, or null
-     * @see Runtime#loadLibrary()
-     * @since 1.2
-     */
-    protected String findLibrary(String name) {
-        String result = null; // By default, search the java.library.path for it
-        
-        String binlibPrefix = &quot;&quot;;
-        String binlibSuffix = &quot;&quot;;
-        
-        String osName = System.getProperties().getProperty(&quot;os.name&quot;);
-        
-        /* Possible values 
-         AIX
-         Digital Unix
-         FreeBSD
-         HP UX
-         Irix
-         Linux
-         Mac OS
-         MPE/iX
-         Netware 4.11
-         OS/2
-         Solaris
-         Windows 2000
-         Windows 95
-         Windows 98
-         Windows NT
-         Windows XP
-         */
-        
-        if (osName.toLowerCase().startsWith(&quot;windows&quot;)) {
-            binlibPrefix = &quot;&quot;;
-            binlibSuffix = &quot;.dll&quot;;
-        } else if (osName.toLowerCase().startsWith(&quot;mac&quot;)) {
-            binlibPrefix = &quot;lib&quot;;
-            binlibSuffix = &quot;.jnilib&quot;;
-        } else { // Assume Linux/Unix
-            binlibPrefix = &quot;lib&quot;;
-            binlibSuffix = &quot;.so&quot;;
-        }
-        String osPrefixedName = binlibPrefix + name;
-        
-        String resourcePath = BINLIB_PREFIX + osPrefixedName + binlibSuffix;
-        
-        // If it isn't in the map, try to expand to temp and return the full path
-        // otherwise, remain null so the java.library.path is searched.
-        
-        // If it has been expanded already and in the map, return the expanded value
-        if (binLibPath.get(resourcePath) != null) {
-            result = (String)binLibPath.get(resourcePath);
-        } else {
-            
-            // See if it's a resource in the JAR that can be extracted
-            try {
-                InputStream is = this.getClass().getResourceAsStream(&quot;/&quot; + resourcePath);
-                File tempNativeLib = File.createTempFile(osPrefixedName + &quot;-&quot;, binlibSuffix);
-                FileOutputStream os = new FileOutputStream(tempNativeLib);
-                copy(is, os);
-                os.close();
-                
-                tempNativeLib.deleteOnExit();
-                
-                binLibPath.put(resourcePath, tempNativeLib.getPath());
-                
-                result = tempNativeLib.getPath();
-                if (result != null) {
-                    VERBOSE(&quot;Found &quot; + result + &quot; in native binary library &quot; + resourcePath);
-                }
-            } catch(Throwable e)  {
-                // Couldn't load the library
-                // Return null by default to search the java.library.path
-            }
-            
-        }
-        
-        return result;
-    }
-}
+/*
+ * Copyright (c) 2004-2007, P. Simon Tuffs (simon@simontuffs.com)
+ * All rights reserved.
+ *
+ * See the full license at http://www.simontuffs.com/one-jar/one-jar-license.html
+ * This license is also included in the distributions of this software
+ * under doc/one-jar-license.txt
+ */
+
+/**
+ * Many thanks to the following for their contributions to One-Jar:
+ * 
+ * Contributor: Christopher Ottley &lt;xknight@users.sourceforge.net&gt;
+ * Contributor: Thijs Sujiten (www.semantica.nl)
+ * Contributor: Gerold Friedmann
+ */
+
+package com.simontuffs.onejar;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.CodeSource;
+import java.security.ProtectionDomain;
+import java.security.cert.Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+import java.util.jar.Attributes.Name;
+
+/**
+ * Loads classes from pre-defined locations inside the jar file containing this
+ * class.  Classes will be loaded from jar files contained in the following 
+ * locations within the main jar file (on the classpath of the application 
+ * actually, which when running with the &quot;java -jar&quot; command works out to be
+ * the same thing).
+ * &lt;ul&gt;
+ * &lt;li&gt;
+ *   /lib	Used to contain library jars.
+ * &lt;/li&gt;
+ * &lt;li&gt;
+ *   /main	Used to contain a default main jar.
+ * &lt;/li&gt;
+ * &lt;/ul&gt; 
+ * @author simon@simontuffs.com (&lt;a href=&quot;http://www.simontuffs.com&quot;&gt;http://www.simontuffs.com&lt;/a&gt;)
+ */
+public class JarClassLoader extends ClassLoader implements IProperties {
+    
+    public static final String DOT_CONFIRM = &quot;.onejar.confirm&quot;;
+    public final static String LIB_PREFIX = &quot;lib/&quot;;
+    public final static String BINLIB_PREFIX = &quot;binlib/&quot;;
+    public final static String MAIN_PREFIX = &quot;main/&quot;;
+    public final static String RECORDING = &quot;recording&quot;;
+    public final static String TMP = &quot;tmp&quot;;
+    public final static String UNPACK = &quot;unpack&quot;;
+    public final static String EXPAND = &quot;One-Jar-Expand&quot;;
+    public final static String EXPAND_TMP = &quot;One-Jar-Expand-Tmp&quot;;
+    public final static String EXPAND_DIR = &quot;One-Jar-Expand-Dir&quot;;
+    public final static String SHOW_EXPAND = &quot;One-Jar-Show-Expand&quot;;
+    public final static String CONFIRM_EXPAND = &quot;One-Jar-Confirm-Expand&quot;;
+    public final static String CLASS = &quot;.class&quot;;
+    
+    public final static String NL = System.getProperty(&quot;line.separator&quot;);
+    
+    public final static String JAVA_PROTOCOL_HANDLER = &quot;java.protocol.handler.pkgs&quot;;
+    
+    protected String name;
+    protected boolean noExpand, expanded;
+    protected ClassLoader externalClassLoader;
+    
+    static {
+        // Add our 'onejar:' protocol handler, but leave open the 
+        // possibility of a subsequent class taking over the 
+        // factory.  TODO: (how reasonable is this?)
+        String handlerPackage = System.getProperty(JAVA_PROTOCOL_HANDLER);
+        if (handlerPackage == null) handlerPackage = &quot;&quot;;
+        if (handlerPackage.length() &gt; 0) handlerPackage = &quot;|&quot; + handlerPackage;
+        handlerPackage = &quot;com.simontuffs&quot; + handlerPackage;
+        System.setProperty(JAVA_PROTOCOL_HANDLER, handlerPackage);
+        
+    }
+    
+    protected String PREFIX() {
+        return &quot;JarClassLoader: &quot;;
+    }
+    
+    protected String NAME() {
+        return (name != null? &quot;'&quot; + name + &quot;' &quot;: &quot;&quot;);
+    }
+    
+    protected void VERBOSE(String message) {
+        if (verbose) System.out.println(PREFIX() + NAME() + message);
+    }
+    
+    protected void WARNING(String message) {
+        System.err.println(PREFIX() + &quot;Warning: &quot; + NAME() + message); 
+    }
+    
+    protected void INFO(String message) {
+        if (info) System.out.println(PREFIX() + &quot;Info: &quot; + NAME() + message);
+    }
+    
+    protected void PRINTLN(String message) {
+        System.out.println(message);
+    }
+    
+    protected void PRINT(String message) {
+        System.out.print(message);
+    }
+    
+    // Synchronize for thread safety.  This is less important until we
+    // start to do lazy loading, but it's a good idea anyway.
+    protected Map byteCode = Collections.synchronizedMap(new HashMap());
+    protected Map pdCache = Collections.synchronizedMap(new HashMap());
+    protected Map binLibPath = Collections.synchronizedMap(new HashMap());
+    protected Set jarNames = Collections.synchronizedSet(new HashSet());
+    
+    protected boolean record = false, flatten = false, unpackFindResource = false;
+    protected boolean verbose = false, info = false;
+    protected String recording = RECORDING;
+    
+    protected String jarName, mainJar, wrapDir;
+    protected boolean delegateToParent;
+    
+    protected static class ByteCode {
+		public ByteCode(String $name, String $original, ByteArrayOutputStream baos, String $codebase, Manifest $manifest) {
+            name = $name;
+            original = $original;
+            bytes = baos.toByteArray();
+            codebase = $codebase;
+			manifest = $manifest;
+        }
+        public byte bytes[];
+        public String name, original, codebase;
+		public Manifest manifest;
+    }
+    
+    
+    /**
+     * Create a non-delegating but jar-capable classloader for bootstrap
+     * purposes.
+     * @param $wrap  The directory in the archive from which to load a 
+     * wrapping classloader.
+     */
+    public JarClassLoader(String $wrap) {
+        wrapDir = $wrap;
+        delegateToParent = wrapDir == null;
+        init();
+    }
+    
+    /**
+     * The main constructor for the Jar-capable classloader.
+     * @param $record	If true, the JarClassLoader will record all used classes
+     * 					into a recording directory (called 'recording' by default)
+     *				 	The name of each jar file will be used as a directory name
+     *					for the recorded classes.
+     * @param $flatten  Whether to flatten out the recorded classes (i.e. eliminate
+     * 					the jar-file name from the recordings).
+     * 
+     * Example: Given the following layout of the one-jar.jar file
+     * &lt;pre&gt;
+     *    /
+     *    /META-INF
+     *    | MANIFEST.MF
+     *    /com
+     *      /simontuffs
+     *        /onejar
+     *          Boot.class
+     *          JarClassLoader.class
+     *    /main
+     *        main.jar
+     *        /com
+     *          /main
+     *            Main.class 
+     *    /lib
+     *        util.jar
+     *          /com
+     *            /util
+     *              Util.clas
+     * &lt;/pre&gt;
+     * The recording directory will look like this:
+     * &lt;ul&gt;
+     * &lt;li&gt;flatten=false&lt;/li&gt;
+     * &lt;pre&gt;
+     *   /recording
+     *     /main.jar
+     *       /com
+     *         /main
+     *            Main.class
+     *     /util.jar
+     *       /com
+     *         /util
+     *            Util.class
+     * &lt;/pre&gt;
+     *
+     * &lt;li&gt;flatten = true&lt;/li&gt;
+     * &lt;pre&gt;
+     *   /recording
+     *     /com
+     *       /main
+     *          Main.class
+     *       /util
+     *          Util.class
+     *   
+     * &lt;/ul&gt;
+     * Flatten mode is intended for when you want to create a super-jar which can
+     * be launched directly without using one-jar's launcher.  Run your application
+     * under all possible scenarios to collect the actual classes which are loaded,
+     * then jar them all up, and point to the main class with a &quot;Main-Class&quot; entry
+     * in the manifest.  
+     *       
+     */
+    public JarClassLoader(ClassLoader parent) {
+        super(parent);
+        delegateToParent = true;
+        init();
+        // System.out.println(PREFIX() + this + &quot; parent=&quot; + parent + &quot; loaded by &quot; + this.getClass().getClassLoader());
+    }
+    
+    /**
+     * Common initialization code: establishes a classloader for delegation
+     * to one-jar.class.path resources.
+     */
+    protected void init() {
+        String classpath = System.getProperty(Boot.P_ONE_JAR_CLASS_PATH);
+        if (classpath != null) {
+            String tokens[] = classpath.split(&quot;\\&quot; + Boot.P_PATH_SEPARATOR);
+            List list = new ArrayList();
+            for (int i=0; i&lt;tokens.length; i++) {
+                String path = tokens[i];
+                try {
+                    list.add(new URL(path));
+                } catch (MalformedURLException mux) {
+                    // Try a file:/// prefix and an absolute path.
+                    try {
+                        list.add(new URL(&quot;file:///&quot; + new File(path).getAbsolutePath()));
+                    } catch (MalformedURLException ignore) {
+                        Boot.WARNING(&quot;Unable to parse external path: &quot; + path);
+                    }
+                }
+            }
+            URL urls[] = (URL[])list.toArray(new URL[0]);
+            Boot.INFO(&quot;external URLs=&quot; + Arrays.asList(urls));
+            externalClassLoader = new URLClassLoader(urls);
+        }
+    }
+    
+    public String load(String mainClass) {
+        // Hack: if there is a one-jar.jarname property, use it.
+        String jarname = Boot.getMyJarPath();
+        return load(mainClass, jarname);
+    }
+    
+    public String load(String mainClass, String jarName) {
+        if (record) {
+            new File(recording).mkdirs();
+        }
+        try {
+            if (jarName == null) {
+                jarName = Boot.getMyJarPath();
+            }
+            JarFile jarFile = new JarFile(jarName);
+            Enumeration _enum = jarFile.entries();
+            Manifest manifest = jarFile.getManifest();
+            String expandPaths[] = null;
+            // TODO: Allow a destination directory (relative or absolute) to 
+            // be specified like this:
+            // One-Jar-Expand: build=../expanded
+            String expand = manifest.getMainAttributes().getValue(EXPAND);
+            String expandtmp = manifest.getMainAttributes().getValue(EXPAND_TMP);
+            String expanddir = System.getProperty(Boot.P_EXPAND_DIR);
+            if (expanddir == null) expanddir = manifest.getMainAttributes().getValue(EXPAND_DIR);
+            boolean shouldExpand = true;
+            File tmpdir = new File(&quot;.&quot;);
+            if (expandtmp != null &amp;&amp; Boolean.valueOf(expandtmp).booleanValue()) {
+                if (expanddir != null) {
+                    tmpdir = new File(expanddir);
+                } else {
+                    File tmpfile = File.createTempFile(&quot;one-jar&quot;, &quot;.tmp&quot;);
+                    tmpfile.deleteOnExit();
+                    tmpdir = new File(tmpfile.getParentFile() + &quot;/&quot; + new File(jarName).getName() + &quot;/expand&quot;);
+                }
+            }
+            if (noExpand == false &amp;&amp; expand != null) {
+                expanded = true;
+                VERBOSE(EXPAND + &quot;=&quot; + expand);
+                expandPaths = expand.split(&quot;,&quot;);
+                boolean getconfirm = Boolean.TRUE.toString().equals(manifest.getMainAttributes().getValue(CONFIRM_EXPAND));
+                if (getconfirm) {
+                    String answer = getConfirmation(tmpdir);
+                    if (answer == null) answer = &quot;n&quot;;
+                    answer = answer.trim().toLowerCase();
+                    if (answer.startsWith(&quot;q&quot;)) {
+                        PRINTLN(&quot;exiting without expansion.&quot;);
+                        // Indicate (expected) failure with a non-zero return code.
+                        System.exit(1);
+                    } else if (answer.startsWith(&quot;n&quot;)) {
+                        shouldExpand = false;
+                    }
+                }
+            }
+            boolean showexpand = Boolean.TRUE.toString().equals(manifest.getMainAttributes().getValue(SHOW_EXPAND));
+            if (showexpand) {
+                PRINTLN(&quot;Expanding to: &quot; + tmpdir.getAbsolutePath());
+            }
+            while (_enum.hasMoreElements()) {
+                JarEntry entry = (JarEntry)_enum.nextElement();
+                if (entry.isDirectory()) continue;
+                
+                // The META-INF/MANIFEST.MF file can contain a property which names
+                // directories in the JAR to be expanded (comma separated). For example:
+                // One-Jar-Expand: build,tmp,webapps
+                String name = entry.getName();
+                if (expandPaths != null) {
+                    // TODO: Can't think of a better way to do this right now.  
+                    // This code really doesn't need to be optimized anyway.
+                    if (shouldExpand &amp;&amp; shouldExpand(expandPaths, name)) {
+                        File dest = new File(tmpdir, name);
+                        // Override if ZIP file is newer than existing.
+                        if (!dest.exists() || dest.lastModified() &lt; entry.getTime()) {
+                            String msg = &quot;Expanding:  &quot; + name;
+                            if (showexpand) {
+                                PRINTLN(msg);
+                            } else {
+                                INFO(msg);
+                            }
+                            if (dest.exists()) INFO(&quot;Update because lastModified=&quot; + new Date(dest.lastModified()) + &quot;, entry=&quot; + new Date(entry.getTime()));
+                            File parent = dest.getParentFile();
+                            if (parent != null) {
+                                parent.mkdirs();
+                            }
+                            VERBOSE(&quot;using jarFile.getInputStream(&quot; + entry + &quot;)&quot;);
+                            InputStream is = jarFile.getInputStream(entry);
+                            FileOutputStream os = new FileOutputStream(dest); 
+                            copy(is, os);
+                            is.close();
+                            os.close();
+                        } else {
+                            String msg = &quot;Up-to-date: &quot; + name;
+                            if (showexpand) {
+                                PRINTLN(msg);
+                            } else {
+                                VERBOSE(msg);
+                            }
+                        }
+                    }
+                }
+                
+                String jar = entry.getName();
+                if (wrapDir != null &amp;&amp; jar.startsWith(wrapDir) || jar.startsWith(LIB_PREFIX) || jar.startsWith(MAIN_PREFIX)) {
+                    if (wrapDir != null &amp;&amp; !entry.getName().startsWith(wrapDir)) continue;
+                    // Load it! 
+                    INFO(&quot;caching &quot; + jar);
+                    VERBOSE(&quot;using jarFile.getInputStream(&quot; + entry + &quot;)&quot;);
+                    {
+                        // Note: loadByteCode consumes the input stream, so make sure its scope
+                        // does not extend beyond here.
+                        InputStream is = jarFile.getInputStream(entry);
+                        if (is == null) 
+                            throw new IOException(&quot;Unable to load resource /&quot; + jar + &quot; using &quot; + this);
+						loadByteCode(is, jar, manifest);
+                    }
+                    
+                    // Do we need to look for a main class?
+                    if (jar.startsWith(MAIN_PREFIX)) {
+                        if (mainClass == null) {
+                            JarInputStream jis = new JarInputStream(jarFile.getInputStream(entry));
+                            Manifest m = jis.getManifest();
+                            jis.close();
+                            // Is this a jar file with a manifest?
+                            if (m != null) {
+                                mainClass = jis.getManifest().getMainAttributes().getValue(Attributes.Name.MAIN_CLASS);
+                                mainJar = jar;
+                            }
+                        } else if (mainJar != null) {
+                            WARNING(&quot;A main class is defined in multiple jar files inside &quot; + MAIN_PREFIX + mainJar + &quot; and &quot; + jar);
+                            WARNING(&quot;The main class &quot; + mainClass + &quot; from &quot; + mainJar + &quot; will be used&quot;);
+                        }
+                    } 
+                } else if (wrapDir == null &amp;&amp; name.startsWith(UNPACK)) {
+                    // Unpack into a temporary directory which is on the classpath of
+                    // the application classloader.  Badly designed code which relies on the
+                    // application classloader can be made to work in this way.
+                    InputStream is = this.getClass().getResourceAsStream(&quot;/&quot; + jar);
+                    if (is == null) throw new IOException(jar);
+                    // Make a sentinel.
+                    File dir = new File(TMP);
+                    File sentinel = new File(dir, jar.replace('/', '.'));
+                    if (!sentinel.exists()) {
+                        INFO(&quot;unpacking &quot; + jar + &quot; into &quot; + dir.getCanonicalPath());
+						loadByteCode(is, jar, TMP, manifest);
+                        sentinel.getParentFile().mkdirs();
+                        sentinel.createNewFile();
+                    }
+                } else if (name.endsWith(CLASS)) {
+                    // A plain vanilla class file rooted at the top of the jar file.
+					loadBytes(entry, jarFile.getInputStream(entry), &quot;/&quot;, null, manifest);
+                } else {
+                    // A resource? 
+                   INFO(&quot;resource: &quot; + jarFile.getName() + &quot;!/&quot; + entry.getName());
+                }
+            }
+            // If mainClass is still not defined, return null.  The caller is then responsible
+            // for determining a main class.
+            
+        } catch (IOException iox) {
+            System.err.println(&quot;Unable to load resource: &quot; + iox);
+            iox.printStackTrace(System.err);
+        }
+        return mainClass;
+    }
+
+    public static boolean shouldExpand(String expandPaths[], String name) {
+        for (int i=0; i&lt;expandPaths.length; i++) {
+            if (name.startsWith(expandPaths[i])) return true;
+        }
+        return false;
+    }        
+
+	protected void loadByteCode(InputStream is, String jar, Manifest man) throws IOException {
+		loadByteCode(is, jar, null, man);
+    }
+    
+	protected void loadByteCode(InputStream is, String jar, String tmp, Manifest man) throws IOException {
+        JarInputStream jis = new JarInputStream(is);
+        JarEntry entry = null;
+        // TODO: implement lazy loading of bytecode.
+        while ((entry = jis.getNextJarEntry()) != null) {
+            if (entry.isDirectory()) continue;
+			loadBytes(entry, jis, jar, tmp, man);
+        }
+    }
+    
+	protected void loadBytes(JarEntry entry, InputStream is, String jar, String tmp, Manifest man) throws IOException {
+        String entryName = entry.getName().replace('/', '.');
+        int index = entryName.lastIndexOf('.');
+        String type = entryName.substring(index+1);
+        
+        // agattung: patch (for one-jar 0.95)
+        // add package handling to avoid NullPointer exceptions
+        // after calls to getPackage method of this ClassLoader
+        int index2 = entryName.lastIndexOf('.', index-1);
+        if (index2 &gt; -1) {
+            String packageName = entryName.substring(0, index2);
+            if (getPackage(packageName) == null) {
+                definePackage(packageName, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, null);
+            }
+        }
+        // end patch
+        
+        // Because we are doing stream processing, we don't know what
+        // the size of the entries is.  So we store them dynamically.
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        copy(is, baos);
+        
+        if (tmp != null) {
+            // Unpack into a temporary working directory which is on the classpath.
+            File file = new File(tmp, entry.getName());
+            file.getParentFile().mkdirs();
+            FileOutputStream fos = new FileOutputStream(file);
+            fos.write(baos.toByteArray());
+            fos.close();
+            
+        } else {
+            // If entry is a class, check to see that it hasn't been defined
+            // already.  Class names must be unique within a classloader because
+            // they are cached inside the VM until the classloader is released.
+            if (type.equals(&quot;class&quot;)) {
+                if (alreadyCached(entryName, jar, baos)) return;
+				byteCode.put(entryName, new ByteCode(entryName, entry.getName(), baos, jar, man));
+                VERBOSE(&quot;cached bytes for class &quot; + entryName);
+            } else {
+                // Another kind of resource.  Cache this by name, and also prefixed
+                // by the jar name.  Don't duplicate the bytes.  This allows us
+                // to map resource lookups to either jar-local, or globally defined.
+                String localname = jar + &quot;/&quot; + entryName;
+				byteCode.put(localname, new ByteCode(localname, entry.getName(), baos, jar, man));
+                // Keep a set of jar names so we can do multiple-resource lookup by name
+                // as in findResources().
+                jarNames.add(jar);
+                VERBOSE(&quot;cached bytes for local name &quot; + localname);
+                // Only keep the first non-local entry: this is like classpath where the first
+                // to define wins.  
+                if (alreadyCached(entryName, jar, baos)) return;
+
+                byteCode.put(entryName, new ByteCode(entryName, entry.getName(), baos, jar, man));
+                VERBOSE(&quot;cached bytes for entry name &quot; + entryName);
+                
+            }
+        }
+    }
+    
+    protected boolean classPool = false;
+    
+    /**
+     * Locate the named class in a jar-file, contained inside the
+     * jar file which was used to load &lt;u&gt;this&lt;/u&gt; class.
+     */
+    protected Class findClass(String name) throws ClassNotFoundException {
+        // Delegate to external paths first
+        Class cls = null;
+        if (externalClassLoader != null) {
+            try {
+            return externalClassLoader.loadClass(name);
+            } catch (ClassNotFoundException cnfx) {
+                // continue...
+            }
+        }
+
+        // Make sure not to load duplicate classes.
+        cls = findLoadedClass(name);
+        if (cls != null) return cls;
+        
+        // Look up the class in the byte codes.
+        // Translate path?
+        VERBOSE(&quot;findClass(&quot; + name + &quot;)&quot;);
+        String cache = name + CLASS;
+        ByteCode bytecode = (ByteCode)byteCode.get(cache);
+        if (bytecode != null) {
+            VERBOSE(&quot;found &quot; + name + &quot; in codebase '&quot; + bytecode.codebase + &quot;'&quot;);
+            if (record) {
+                record(bytecode);
+            }
+            // Use a protectionDomain to associate the codebase with the
+            // class.
+            ProtectionDomain pd = (ProtectionDomain)pdCache.get(bytecode.codebase);
+            if (pd == null) {
+                ProtectionDomain cd = JarClassLoader.class.getProtectionDomain();
+                URL url = cd.getCodeSource().getLocation();
+                try {
+                    url = new URL(&quot;jar:&quot; + url + &quot;!/&quot; + bytecode.codebase);
+                } catch (MalformedURLException mux) {
+                    mux.printStackTrace(System.out);    			
+                }
+                
+                CodeSource source = new CodeSource(url, (Certificate[])null);
+                pd = new ProtectionDomain(source, null, this, null);
+                pdCache.put(bytecode.codebase, pd);
+            }
+            
+            // Do it the simple way.
+            byte bytes[] = bytecode.bytes;
+			
+			int i = name.lastIndexOf('.');
+			if (i != -1) {
+				String pkgname = name.substring(0, i);
+				// Check if package already loaded.
+				Package pkg = getPackage(pkgname);
+				Manifest man = bytecode.manifest;
+				if (pkg != null) {
+					// Package found, so check package sealing.
+					if (pkg.isSealed()) {
+						// Verify that code source URL is the same.
+						if (!pkg.isSealed()) {
+							throw new SecurityException(&quot;sealing violation: package &quot; + pkgname + &quot; is sealed&quot;);
+						}
+
+					} else {
+						// Make sure we are not attempting to seal the package
+						// at this code source URL.
+						if ((man != null) &amp;&amp; isSealed(pkgname, man)) {
+							throw new SecurityException(&quot;sealing violation: can't seal package &quot; + pkgname + &quot;: already loaded&quot;);
+						}
+					}
+				} else {
+					if (man != null) {
+						definePackage(pkgname, man);
+					} else {
+						definePackage(pkgname, null, null, null, null, null, null, null);
+					}
+				}
+			}
+			
+            return defineClass(name, bytes, pd);
+        }
+        VERBOSE(name + &quot; not found&quot;);
+        throw new ClassNotFoundException(name);
+        
+    }
+    
+    private boolean isSealed(String name, Manifest man) {
+		String path = name.replace('.', '/').concat(&quot;/&quot;);
+		Attributes attr = man.getAttributes(path);
+		String sealed = null;
+		if (attr != null) {
+			sealed = attr.getValue(Name.SEALED);
+		}
+		if (sealed == null) {
+			if ((attr = man.getMainAttributes()) != null) {
+				sealed = attr.getValue(Name.SEALED);
+			}
+		}
+		return &quot;true&quot;.equalsIgnoreCase(sealed);
+	}
+
+    /**
+	 * Defines a new package by name in this ClassLoader. The attributes
+	 * contained in the specified Manifest will be used to obtain package
+	 * version and sealing information. For sealed packages, the additional URL
+	 * specifies the code source URL from which the package was loaded.
+	 * 
+	 * @param name
+	 *            the package name
+	 * @param man
+	 *            the Manifest containing package version and sealing
+	 *            information
+	 * @param url
+	 *            the code source url for the package, or null if none
+	 * @exception IllegalArgumentException
+	 *                if the package name duplicates an existing package either
+	 *                in this class loader or one of its ancestors
+	 * @return the newly defined Package object
+	 */
+	protected Package definePackage(String name, Manifest man) throws IllegalArgumentException {
+		String path = name.replace('.', '/').concat(&quot;/&quot;);
+		String specTitle = null, specVersion = null, specVendor = null;
+		String implTitle = null, implVersion = null, implVendor = null;
+		String sealed = null;
+		URL sealBase = null;
+
+		Attributes attr = man.getAttributes(path);
+		if (attr != null) {
+			specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
+			specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
+			specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
+			implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
+			implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
+			implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
+			sealed = attr.getValue(Name.SEALED);
+		}
+		attr = man.getMainAttributes();
+		if (attr != null) {
+			if (specTitle == null) {
+				specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
+			}
+			if (specVersion == null) {
+				specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
+			}
+			if (specVendor == null) {
+				specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
+			}
+			if (implTitle == null) {
+				implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
+			}
+			if (implVersion == null) {
+				implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
+			}
+			if (implVendor == null) {
+				implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
+			}
+			if (sealed == null) {
+				sealed = attr.getValue(Name.SEALED);
+			}
+		}
+        if (sealed != null) {
+            try {
+                sealBase = new URL(sealed);
+            } catch (MalformedURLException mux) {
+                // Would use IllegalArgumentException, but it don't have the chained constructor.
+                throw new RuntimeException(&quot;Error in &quot; + Name.SEALED + &quot; manifest attribute: &quot; + sealed, mux);
+            }
+        }
+		return definePackage(name, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor, sealBase);
+	}
+	
+    protected Class defineClass(String name, byte[] bytes, ProtectionDomain pd) throws ClassFormatError {
+        // Simple, non wrapped class definition.
+        return defineClass(name, bytes, 0, bytes.length, pd);
+    }
+    
+    protected void record(ByteCode bytecode) {
+        String fileName = bytecode.original;
+        // Write out into the record directory.
+        File dir = new File(recording, flatten? &quot;&quot;: bytecode.codebase);
+        File file = new File(dir, fileName);
+        if (!file.exists()) {
+            file.getParentFile().mkdirs();
+            VERBOSE(&quot;&quot; + file);
+            try {
+                FileOutputStream fos = new FileOutputStream(file);
+                fos.write(bytecode.bytes);
+                fos.close();
+                
+            } catch (IOException iox) {
+                System.err.println(PREFIX() + &quot;unable to record &quot; + file + &quot;: &quot; + iox);
+            }
+            
+        }
+    }
+    
+    /**
+     * Overriden to return resources from the appropriate codebase.
+     * There are basically two ways this method will be called: most commonly
+     * it will be called through the class of an object which wishes to 
+     * load a resource, i.e. this.getClass().getResourceAsStream().  Before
+     * passing the call to us, java.lang.Class mangles the name.  It 
+     * converts a file path such as foo/bar/Class.class into a name like foo.bar.Class, 
+     * and it strips leading '/' characters e.g. converting '/foo' to 'foo'.
+     * All of which is a nuisance, since we wish to do a lookup on the original
+     * name of the resource as present in the One-Jar jar files.  
+     * The other way is more direct, i.e. this.getClass().getClassLoader().getResourceAsStream().
+     * Then we get the name unmangled, and can deal with it directly. 
+     *
+     * The problem is this: if one resource is called /foo/bar/data, and another 
+     * resource is called /foo.bar.data, both will have the same mangled name, 
+     * namely 'foo.bar.data' and only one of them will be visible.  Perhaps the
+     * best way to deal with this is to store the lookup names in mangled form, and
+     * simply issue warnings if collisions occur.  This is not very satisfactory,
+     * but is consistent with the somewhat limiting design of the resource name mapping
+     * strategy in Java today.
+     */
+    public InputStream getByteStream(String resource) {
+        
+        InputStream result = null;
+        // Look up without resolving first.  This allows jar-local 
+        // resolution to take place.
+        ByteCode bytecode = (ByteCode)byteCode.get(resource);
+        if (bytecode == null) {
+            // Try again with a resolved name.
+            bytecode = (ByteCode)byteCode.get(resolve(resource));
+        }
+        if (bytecode != null) result = new ByteArrayInputStream(bytecode.bytes);
+        // Special case: if we are a wrapping classloader, look up to our
+        // parent codebase.  Logic is that the boot JarLoader will have 
+        // delegateToParent = false, the wrapping classloader will have 
+        // delegateToParent = true;
+        if (result == null &amp;&amp; delegateToParent) {
+            result = ((JarClassLoader)getParent()).getByteStream(resource);
+        }
+        VERBOSE(&quot;getByteStream(&quot; + resource + &quot;) -&gt; &quot; + result);
+        return result;
+    }
+    
+    /**
+     * Resolve a resource name.  Look first in jar-relative, then in global scope.
+     * @param resource
+     * @return
+     */
+    protected String resolve(String $resource) {
+        
+        if ($resource.startsWith(&quot;/&quot;)) $resource = $resource.substring(1);
+        $resource = $resource.replace('/', '.');
+        String resource = null;
+        String caller = getCaller();
+        ByteCode callerCode = (ByteCode)byteCode.get(caller + &quot;.class&quot;);
+        
+        if (callerCode != null) {
+            // Jar-local first, then global.
+            String tmp = callerCode.codebase + &quot;/&quot; + $resource;
+            if (byteCode.get(tmp) != null) {
+                resource = tmp; 
+            } 
+        }
+        if (resource == null) {
+            // One last try.
+            if (byteCode.get($resource) == null) {
+                resource = null; 
+            } else {
+                resource = $resource;
+            }
+        }
+        VERBOSE(&quot;resource &quot; + $resource + &quot; resolved to &quot; + resource);
+        return resource;
+    }
+    
+    protected boolean alreadyCached(String name, String jar, ByteArrayOutputStream baos) {
+        // TODO: check resource map to see how we will map requests for this
+        // resource from this jar file.  Only a conflict if we are using a
+        // global map and the resource is defined by more than
+        // one jar file (default is to map to local jar).
+        byte[] bytes = baos.toByteArray();
+        ByteCode existing = (ByteCode)byteCode.get(name);
+        if (existing != null) {
+            // If bytecodes are identical, no real problem.  Likewise if it's in
+            // META-INF.
+            if (!Arrays.equals(existing.bytes, bytes) &amp;&amp; !name.startsWith(&quot;/META-INF&quot;)) {
+                INFO(existing.name + &quot; in &quot; + jar + &quot; is hidden by &quot; + existing.codebase + &quot; (with different bytecode)&quot;);
+            } else {
+                VERBOSE(existing.name + &quot; in &quot; + jar + &quot; is hidden by &quot; + existing.codebase + &quot; (with same bytecode)&quot;);
+            }
+            return true;
+        }
+        return false;
+    }
+    
+    
+    protected String getCaller() {
+        StackTraceElement[] stack = new Throwable().getStackTrace();
+        // Search upward until we get to a known class, i.e. one with a non-null
+        // codebase.
+        String caller = null;
+        for (int i=0; i&lt;stack.length; i++) {
+            if (byteCode.get(stack[i].getClassName() + &quot;.class&quot;) != null) {
+                caller = stack[i].getClassName();
+                break;
+            }
+        }
+        return caller;
+    }
+    
+    /**
+     * Sets the name of the used  classes recording directory.
+     * 
+     * @param $recording A value of &quot;&quot; will use the current working directory 
+     * (not recommended).  A value of 'null' will use the default directory, which
+     * is called 'recording' under the launch directory (recommended).
+     */
+    public void setRecording(String $recording) {
+        recording = $recording;
+        if (recording == null) recording = RECORDING;
+    }
+    
+    public String getRecording() {
+        return recording;
+    }
+    
+    public void setRecord(boolean $record) {
+        record = $record;
+    }
+    public boolean getRecord() {
+        return record;
+    }
+    
+    public void setFlatten(boolean $flatten) {
+        flatten = $flatten;
+    }
+    public boolean isFlatten() {
+        return flatten;
+    }
+    
+    public void setVerbose(boolean $verbose) {
+        verbose = $verbose;
+        if (verbose) info = true;
+    }
+    
+    public boolean getVerbose() {
+        return verbose;
+    }
+    
+    public void setInfo(boolean $info) {
+        info = $info;
+    }
+    public boolean getInfo() {
+        return info;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.ClassLoader#findResource(java.lang.String)
+     */
+    protected URL findResource(String $resource) {
+        try {
+            INFO(&quot;findResource(&quot; + $resource + &quot;)&quot;);
+            // Do we have the named resource in our cache?  If so, construct a 
+            // 'onejar:' URL so that a later attempt to access the resource
+            // will be redirected to our Handler class, and thence to this class.
+            String resource = resolve($resource);
+            if (resource != null) {
+                // We know how to handle it.
+                INFO(&quot;findResource() found: &quot; + $resource);
+                return new URL(Handler.PROTOCOL + &quot;:&quot; + resource); 
+            }
+            INFO(&quot;findResource(): unable to locate &quot; + $resource);
+            // If all else fails, return null.
+            return null;
+        } catch (MalformedURLException mux) {
+            WARNING(&quot;unable to locate &quot; + $resource + &quot; due to &quot; + mux);
+        }
+        return null;
+        
+    }
+    
+    public Enumeration findResources(String name) throws IOException {
+        INFO(&quot;findResources(&quot; + name + &quot;)&quot;);
+        INFO(&quot;findResources: looking in &quot; + jarNames);
+        Iterator iter = jarNames.iterator();
+        final List resources = new ArrayList();
+        // Mangle name to match our dot separated format.  This still 
+        // seems a bit flakey to me.  TODO: revisit.
+        name = name.replace('/', '.');
+        while (iter.hasNext()) {
+            String resource = iter.next().toString() + &quot;/&quot; + name;
+            if (byteCode.containsKey(resource)) {
+                resources.add(new URL(Handler.PROTOCOL + &quot;:&quot; + resource));
+            }
+        }
+        final Iterator ri = resources.iterator();
+        return new Enumeration() {
+            public boolean hasMoreElements() {
+                return ri.hasNext();
+            }
+            public Object nextElement() {
+                return ri.next();
+            }
+        };
+    }
+    
+    /**
+     * Utility to assist with copying InputStream to OutputStream.  All
+     * bytes are copied, but both streams are left open.
+     * @param in Source of bytes to copy.
+     * @param out Destination of bytes to copy.
+     * @throws IOException
+     */
+    protected void copy(InputStream in, OutputStream out) throws IOException {
+        byte[] buf = new byte[1024];
+        while (true) {
+            int len = in.read(buf);
+            if (len &lt; 0) break;
+            out.write(buf, 0, len);
+        }
+    }
+    
+    public String toString() {
+        return super.toString() + (name != null? &quot;(&quot; + name + &quot;)&quot;: &quot;&quot;);
+    }
+    
+    /**
+     * Returns name of the classloader.
+     * @return
+     */
+    public String getName() {
+        return name;
+    }
+    
+    /**
+     * Sets name of the classloader.  Default is null.
+     * @param string
+     */
+    public void setName(String string) {
+        name = string;
+    }
+    
+    public void setExpand(boolean expand) {
+        noExpand = !expand;
+    }
+    
+    public boolean isExpanded() {
+        return expanded;
+    }
+    
+    /**
+     * If the system specific library exists in the JAR, expand it and return the path
+     * to the expanded library to the caller. Otherwise return null so the caller
+     * searches the java.library.path for the requested library.
+     *
+     *
+     * @author Christopher Ottley
+     * @param name the (system specific) name of the requested library
+     * @return the full pathname to the requested library, or null
+     * @see Runtime#loadLibrary()
+     * @since 1.2
+     */
+    protected String findLibrary(String name) {
+        String result = null; // By default, search the java.library.path for it
+        
+        String resourcePath = BINLIB_PREFIX + System.mapLibraryName(name);
+        
+        // If it isn't in the map, try to expand to temp and return the full path
+        // otherwise, remain null so the java.library.path is searched.
+        
+        // If it has been expanded already and in the map, return the expanded value
+        if (binLibPath.get(resourcePath) != null) {
+            result = (String)binLibPath.get(resourcePath);
+        } else {
+            
+            // See if it's a resource in the JAR that can be extracted
+            try {
+                int lastdot = resourcePath.lastIndexOf('.');
+                String suffix = null;
+                if (lastdot &gt;= 0) {
+                    suffix = resourcePath.substring(lastdot);
+                }
+                InputStream is = this.getClass().getResourceAsStream(&quot;/&quot; + resourcePath);
+                File tempNativeLib = File.createTempFile(name + &quot;-&quot;, suffix);
+                FileOutputStream os = new FileOutputStream(tempNativeLib);
+                copy(is, os);
+                os.close();
+                
+                VERBOSE(&quot;Stored native library &quot; + name + &quot; at &quot; + tempNativeLib);
+                
+                tempNativeLib.deleteOnExit();
+                
+                binLibPath.put(resourcePath, tempNativeLib.getPath());
+                
+                result = tempNativeLib.getPath();
+                if (result != null) {
+                    VERBOSE(&quot;Found &quot; + result + &quot; in native binary library &quot; + resourcePath);
+                }
+            } catch(Throwable e)  {
+                // Couldn't load the library
+                // Return null by default to search the java.library.path
+                WARNING(&quot;Unable to load native library: &quot; + e);
+            }
+            
+        }
+        
+        return result;
+    }
+
+    protected String getConfirmation(File location) throws IOException {
+        File dotconfirm = new File(location, DOT_CONFIRM);
+        String answer = &quot;&quot;;
+        if (dotconfirm.exists()) {
+            BufferedReader br = new BufferedReader(new FileReader(dotconfirm));
+            answer = br.readLine();
+            br.close();
+            PRINTLN(&quot;Previous confirmation for file expansion (&quot; + answer + &quot;) was read from &quot; + dotconfirm);
+            return answer;
+        }
+        while (answer == null || (!answer.startsWith(&quot;n&quot;) &amp;&amp; !answer.startsWith(&quot;y&quot;) &amp;&amp; !answer.startsWith(&quot;q&quot;))) {
+            promptForConfirm(location);
+            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+            answer = br.readLine();
+            br.close();
+        }
+        try {
+            BufferedWriter bw = new BufferedWriter(new FileWriter(dotconfirm));
+            bw.write(answer + NL);
+            bw.close();
+            PRINTLN(&quot;Your response has been stored in &quot; + dotconfirm.getAbsolutePath() + &quot;.  Please remove this file if you wish to change your mind.&quot;);
+        } catch (IOException iox) {
+            WARNING(&quot;Unable to store confirmation response in &quot; + dotconfirm.getAbsolutePath() + &quot;: &quot; + iox);
+        }
+        return answer;
+    }
+    
+    protected void promptForConfirm(File location) {
+        PRINTLN(&quot;Do you want to allow '&quot; + Boot.getMyJarName() + &quot;' to expand files into the file-system at the following location?&quot;);
+        PRINTLN(&quot;  &quot; + location);
+        PRINT(&quot;Answer y(es) to expand files, n(o) to continue without expanding, or q(uit) to exit: &quot;);
+    }
+    
+}</diff>
      <filename>onejar/com/simontuffs/onejar/JarClassLoader.java</filename>
    </modified>
    <modified>
      <diff>@@ -1,31 +1,33 @@
-/*
- * One-JAR (http://one-jar.sourceforge.net).  Copyright (c) 2004, 
- * P. Simon Tuffs (simon@simontuffs.com).  	All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of P. Simon Tuffs, nor the names of any contributors, 
- * nor the name One-JAR may be used to endorse or promote products derived 
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot;
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
+/*
+ * One-JAR (http://www.simontuffs.com/one-jar).  Copyright (c) 2004-2007, 
+ * P. Simon Tuffs (simon@simontuffs.com).  	All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.  
+ *
+ * Neither the name of P. Simon Tuffs, nor the names of any contributors, 
+ * nor the name One-JAR may be used to endorse or promote products derived 
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot;
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Including this file inside the built One-JAR file conforms with these terms.
+ */
+</diff>
      <filename>onejar/doc/one-jar-license.txt</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,7 @@
 # Each property should occupy a single line. For example:
 apple.laf.useScreenMenuBar=true
 apple.awt.showGrowBox=true
-apple.awt.brushMetalLook=true
+apple.awt.brushMetalLook=false
 apple.awt.window.position.forceSafeCreation=true
 apple.awt.window.position.forceSafeProgrammaticPositioning=true
 apple.awt.window.position.forceSafeUserPositioning=true
@@ -14,7 +14,7 @@ com.apple.macos.useScreenMenuBar=true
 com.apple.mrj.application.apple.menu.about.name=JBidwatcher
 com.apple.mrj.application.build.version=1.0
 com.apple.mrj.application.classloading.verbose=false
-com.apple.mrj.application.classpath=Contents/Resources/Java/:Contents/Resources/Java/`binary`:
+com.apple.mrj.application.classpath=Contents/Resources/Java/:Contents/Resources/Java/`binary`:Contents/Resources/Java/quaqua.jar
 com.apple.mrj.application.gc.async=true
 com.apple.mrj.application.gc.max=64M
 com.apple.mrj.application.gc.min=16M
@@ -22,7 +22,7 @@ com.apple.mrj.application.growbox.intrudes=true
 com.apple.mrj.application.jitc.disable=false
 com.apple.mrj.application.JVMVersion=1.3+
 com.apple.mrj.application.live-resize=true
-com.apple.mrj.application.main=JBidWatch
+com.apple.mrj.application.main=com.simontuffs.onejar.Boot
 com.apple.mrj.application.parameters=
 com.apple.mrj.application.profiling=false
 com.apple.mrj.application.stderr.append=false</diff>
      <filename>platform/MRJApp.properties</filename>
    </modified>
    <modified>
      <diff>@@ -593,15 +593,34 @@ public final class JBidWatch implements JConfig.ConfigListener, MessageQueue.Lis
       }
     }
 
+    String oldLaF = null;
+
     Platform.checkLaF(whatLaF);
 
+    if(Platform.isMac()) {
+      oldLaF = whatLaF;
+      // set the Quaqua Look and Feel in the UIManager
+      whatLaF = &quot;ch.randelshofer.quaqua.QuaquaLookAndFeel&quot;;
+    }
+
     try {
       UIManager.setLookAndFeel(whatLaF);
       if(inFrame != null) {
         SwingUtilities.updateComponentTreeUI(inFrame);
       }
     } catch(Exception exMe) {
-      ErrorManagement.handleException(&quot;Exception in setUI, failure to set &quot; + whatLaF + &quot;: &quot; + exMe, exMe);
+	boolean failed = true;
+	if(oldLaF != null) {
+	    try {
+		UIManager.setLookAndFeel(oldLaF);
+		failed = false;
+	    } catch(Exception ex2) {
+		ErrorManagement.handleException(&quot;Exception in setUI, failure to set &quot; + whatLaF + &quot;: &quot; + exMe, exMe);
+		ErrorManagement.handleException(&quot;Exception in setUI, failure to set &quot; + oldLaF + &quot;: &quot; + ex2, ex2);
+	    }
+	} else {
+	    ErrorManagement.handleException(&quot;Exception in setUI, failure to set &quot; + whatLaF + &quot;: &quot; + exMe, exMe);
+	}
     }
   }
 </diff>
      <filename>src/com/jbidwatcher/JBidWatch.java</filename>
    </modified>
    <modified>
      <diff>@@ -73,10 +73,12 @@ public class Platform {
       System.setProperty(&quot;apple.laf.useScreenMenuBar&quot;, &quot;true&quot;);
       System.setProperty(&quot;com.apple.macos.useScreenMenuBar&quot;, &quot;true&quot;);
 
+      System.setProperty(&quot;Quaqua.tabLayoutPolicy&quot;,&quot;wrap&quot;);
+
       //  Allow users to override the brushed metal look.
-      if(JConfig.queryConfiguration(&quot;mac.useMetal&quot;, &quot;true&quot;).equals(&quot;false&quot;)) {
-        System.setProperty(&quot;apple.awt.brushMetalLook&quot;, &quot;false&quot;);
-      }
+      //      if(JConfig.queryConfiguration(&quot;mac.useMetal&quot;, &quot;true&quot;).equals(&quot;false&quot;)) {
+      //        System.setProperty(&quot;apple.awt.brushMetalLook&quot;, &quot;false&quot;);
+      //      }
     }
   }
 </diff>
      <filename>src/com/jbidwatcher/platform/Platform.java</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>onejar/com/simontuffs/onejar/services/IHello.class</filename>
    </removed>
    <removed>
      <filename>onejar/com/simontuffs/onejar/services/IHelloService.class</filename>
    </removed>
    <removed>
      <filename>onejar/com/simontuffs/onejar/services/english/HelloService$1.class</filename>
    </removed>
    <removed>
      <filename>onejar/com/simontuffs/onejar/services/english/HelloService.class</filename>
    </removed>
    <removed>
      <filename>onejar/com/simontuffs/onejar/services/french/HelloService$1.class</filename>
    </removed>
    <removed>
      <filename>onejar/com/simontuffs/onejar/services/french/HelloService.class</filename>
    </removed>
    <removed>
      <filename>onejar/com/simontuffs/onejar/services/german/HelloService$1.class</filename>
    </removed>
    <removed>
      <filename>onejar/com/simontuffs/onejar/services/german/HelloService.class</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>bfac4aa27c4ac1626c66a9a1f30fc54c4d841425</id>
    </parent>
  </parents>
  <author>
    <name>Morgan Schweers</name>
    <email>cyberfox@jbidwatcher.com</email>
  </author>
  <url>http://github.com/cyberfox/jbidwatcher/commit/6c72aecbc0241b8e50a4d1f84ca5f0c85cf78fab</url>
  <id>6c72aecbc0241b8e50a4d1f84ca5f0c85cf78fab</id>
  <committed-date>2008-01-19T06:20:54-08:00</committed-date>
  <authored-date>2008-01-19T06:20:54-08:00</authored-date>
  <message>Add QuaQua to the Mac OS X build, and fix up the deployment for it, as well as using a newer OneJar loader.

git-svn-id: svn://svn.jbidwatcher.com/jbidwatcher/trunk@291 b1acfa68-eb39-11db-b167-a3a8cd6b847e</message>
  <tree>0fa1618cbf2c67d43e26070257af65e7078476de</tree>
  <committer>
    <name>Morgan Schweers</name>
    <email>cyberfox@jbidwatcher.com</email>
  </committer>
</commit>
