JAL-4409 Updated getdown classes
authorBen Soares <b.soares@dundee.ac.uk>
Wed, 15 May 2024 14:48:41 +0000 (15:48 +0100)
committerBen Soares <b.soares@dundee.ac.uk>
Wed, 15 May 2024 14:48:41 +0000 (15:48 +0100)
15 files changed:
getdown/lib/getdown-core.jar
getdown/lib/getdown-launcher-local.jar
getdown/lib/getdown-launcher.jar
getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Application.java
getdown/src/getdown/core/src/main/java/jalview/bin/Console.java [new file with mode: 0644]
getdown/src/getdown/core/src/main/java/jalview/bin/GetMemory.java
getdown/src/getdown/core/src/main/java/jalview/bin/HiDPISetting.java
getdown/src/getdown/core/src/main/java/jalview/bin/MemorySetting.java
getdown/src/getdown/core/src/main/java/jalview/util/ChannelProperties.java
getdown/src/getdown/core/src/main/java/jalview/util/ErrorLog.java [new file with mode: 0644]
getdown/src/getdown/core/src/main/java/jalview/util/HttpUtils.java [new file with mode: 0644]
getdown/src/getdown/core/src/main/java/jalview/util/LaunchUtils.java
getdown/src/getdown/core/src/main/java/jalview/util/StringUtils.java
j11lib/getdown-core.jar
j8lib/getdown-core.jar

index bd6924d..2a4159a 100644 (file)
Binary files a/getdown/lib/getdown-core.jar and b/getdown/lib/getdown-core.jar differ
index 02c4711..ad2e6dc 100644 (file)
Binary files a/getdown/lib/getdown-launcher-local.jar and b/getdown/lib/getdown-launcher-local.jar differ
index b8801ac..09c29ae 100644 (file)
Binary files a/getdown/lib/getdown-launcher.jar and b/getdown/lib/getdown-launcher.jar differ
index cfc8d97..e0170d2 100644 (file)
@@ -31,6 +31,7 @@ import java.util.zip.GZIPInputStream;
 
 import jalview.bin.HiDPISetting;
 import jalview.bin.MemorySetting;
+import jalview.util.HttpUtils;
 import jalview.util.LaunchUtils;
 
 import com.threerings.getdown.util.*;
@@ -1122,37 +1123,12 @@ public class Application
           _appargs.add(0, _jalviewUri);
         }
         if (_appargs.size() > 0) {
-          String uri = _appargs.get(0);
-          try {
-            log.info("Trying to parse uri '"+uri+"'");
-            URI jalviewUri = new URI(uri);
-            if (jalviewUri != null) {
-              String scheme = jalviewUri.getScheme();
-              String host = jalviewUri.getHost();
-              if (scheme != null && scheme.startsWith("jalview")
-                    && (scheme.length() == 8 || scheme.equals("jalviewhttp") || scheme.equals("jalviewhttps"))) {
-                _appargs.clear();
-                if (host != null && host.length() > 0) {
-                  URI newUri = new URI(
-                    scheme.equals("jalviewhttp") ? "http" : "https",
-                    jalviewUri.getUserInfo(),
-                    host,
-                    jalviewUri.getPort(),
-                    jalviewUri.getPath(),
-                    jalviewUri.getQuery(),
-                    jalviewUri.getFragment()
-                  );
-                  // open a URL
-                  _appargs.add(newUri.toURL().toString());
-                } else {
-                  // open a file
-                  _appargs.add(jalviewUri.getPath());
-                }
-              }
-
-            }
-          } catch (URISyntaxException | MalformedURLException e) {
-            log.error("Malformed jalview URI", uri);
+          String jalviewUri = _appargs.get(0);
+          log.info("Trying to parse uri '"+jalviewUri+"'");
+          String jalviewUrl = HttpUtils.equivalentJalviewUrl(jalviewUri);
+          if (jalviewUrl != null) {
+            _appargs.clear();
+            _appargs.add(jalviewUrl);
           }
         }
         
diff --git a/getdown/src/getdown/core/src/main/java/jalview/bin/Console.java b/getdown/src/getdown/core/src/main/java/jalview/bin/Console.java
new file mode 100644 (file)
index 0000000..66fc865
--- /dev/null
@@ -0,0 +1,11 @@
+package jalview.bin;
+
+public class Console {
+  public static boolean initLogger() {
+    return false;
+  }
+  public static void outPrintln(String s) {
+  }
+  public static void errPrintln(String s) {
+  }
+}
index b01dfb8..1bcc841 100644 (file)
@@ -23,6 +23,8 @@ package jalview.bin;
 import java.lang.management.ManagementFactory;
 import java.lang.management.OperatingSystemMXBean;
 
+import jalview.util.ErrorLog;
+
 /**
  * Isolated class to ascertain physical memory of the system using
  * com.sun.management.OperatingSystemMXBean class's getTotalPhysicalMemorySize
@@ -61,7 +63,7 @@ class GetMemory
     } catch (NoClassDefFoundError e)
     {
       // com.sun.management.OperatingSystemMXBean doesn't exist in this JVM
-      System.err.println(
+      ErrorLog.errPrintln(
               "No com.sun.management.OperatingSystemMXBean: cannot get total physical memory size");
     }
 
index 2bce673..871a6f7 100644 (file)
  */
 package jalview.bin;
 
+import java.awt.HeadlessException;
 import java.util.Locale;
 
-import java.awt.HeadlessException;
+import jalview.util.ErrorLog;
 
 public class HiDPISetting
 {
@@ -117,7 +118,7 @@ public class HiDPISetting
         }
       } catch (NumberFormatException e)
       {
-        System.err.println(setHiDPIScalePropertyName + " property give ("
+        ErrorLog.errPrintln(setHiDPIScalePropertyName + " property give ("
                 + setHiDPIScaleProperty + ") but not parseable as integer");
       }
     }
@@ -135,7 +136,7 @@ public class HiDPISetting
       try
       {
         int existingPropertyVal = Integer.parseInt(existingProperty);
-        System.out.println("Existing " + scalePropertyName + " is "
+        ErrorLog.outPrintln("Existing " + scalePropertyName + " is "
                 + existingPropertyVal);
         if (existingPropertyVal > 1)
         {
@@ -144,8 +145,9 @@ public class HiDPISetting
         }
       } catch (NumberFormatException e)
       {
-        System.out.println("Could not convert property " + scalePropertyName
-                + " vale '" + existingProperty + "' to number");
+        ErrorLog.outPrintln(
+                "Could not convert property " + scalePropertyName
+                        + " vale '" + existingProperty + "' to number");
       }
     }
 
@@ -159,7 +161,11 @@ public class HiDPISetting
       dpi = screenInfo.getScreenResolution();
     } catch (HeadlessException e)
     {
-      System.err.println("Cannot get screen resolution: " + e.getMessage());
+      if (isLinux)
+      {
+        ErrorLog.errPrintln(
+                "Cannot get screen resolution: " + e.getMessage());
+      }
     }
 
     // try and get screen size height and width
@@ -171,8 +177,11 @@ public class HiDPISetting
       mindimension = Math.min(height, width);
     } catch (HeadlessException e)
     {
-      System.err.println(
-              "Cannot get screen size height and width:" + e.getMessage());
+      if (isLinux)
+      {
+        ErrorLog.errPrintln("Cannot get screen size height and width:"
+                + e.getMessage());
+      }
     }
 
     // attempt at a formula for scaling based on screen dpi and mindimension.
index bb545cb..dbef0d9 100644 (file)
@@ -24,6 +24,8 @@ package jalview.bin;
 
 import java.util.Locale;
 
+import jalview.util.ErrorLog;
+
 /**
  * Methods to decide on appropriate memory setting for Jalview based on two
  * optionally provided values: jvmmempc - the maximum percentage of total
@@ -37,8 +39,10 @@ import java.util.Locale;
  */
 public class MemorySetting
 {
+  // This must match the value of Arg.JVMMEMPC.getName()
   public static final String MAX_HEAPSIZE_PERCENT_PROPERTY_NAME = "jvmmempc";
 
+  // This must match the value of Arg.JVMMEMMAX.getName()
   public static final String MAX_HEAPSIZE_PROPERTY_NAME = "jvmmemmax";
 
   private static final int MAX_HEAPSIZE_PERCENT_DEFAULT = 90; // 90%
@@ -354,7 +358,7 @@ public class MemorySetting
     else
     {
       // number too big for a Long. Limit to Long.MAX_VALUE
-      System.out.println("Memory parsing of '" + memString
+      ErrorLog.outPrintln("Memory parsing of '" + memString
               + "' produces number too big.  Limiting to Long.MAX_VALUE="
               + Long.MAX_VALUE);
       return Long.MAX_VALUE;
@@ -395,7 +399,7 @@ public class MemorySetting
     ADJUSTMENT_MESSAGE = reason;
     if (!quiet)
     {
-      System.out.println(reason);
+      ErrorLog.outPrintln(reason);
     }
   }
 
index 4832588..ffcb6a1 100644 (file)
@@ -86,7 +86,7 @@ public class ChannelProperties
     if (channelPropsURL == null)
     {
       // complete failure of channel_properties, set all properties to defaults
-      System.err.println("Failed to find '/" + CHANNEL_PROPERTIES_FILENAME
+      ErrorLog.errPrintln("Failed to find '/" + CHANNEL_PROPERTIES_FILENAME
               + "' file at '"
               + (channelPropsURL == null ? "null"
                       : channelPropsURL.toString())
@@ -97,12 +97,12 @@ public class ChannelProperties
     {
       try
       {
-        InputStream channelPropsIS = channelPropsURL.openStream();
+        InputStream channelPropsIS = HttpUtils.openStream(channelPropsURL);
         tryChannelProps.load(channelPropsIS);
         channelPropsIS.close();
       } catch (IOException e)
       {
-        System.err.println(e.getMessage());
+        ErrorLog.errPrintln(e.getMessage());
         // return false;
       }
     }
@@ -157,10 +157,10 @@ public class ChannelProperties
         channelProps.load(is);
       } catch (FileNotFoundException e)
       {
-        System.err.println(e.getMessage());
+        ErrorLog.errPrintln(e.getMessage());
       } catch (IOException e)
       {
-        System.err.println(e.getMessage());
+        ErrorLog.errPrintln(e.getMessage());
       }
     }
   }
@@ -214,7 +214,7 @@ public class ChannelProperties
       }
       else
       {
-        System.err.println("Failed to get channel property '" + key + "'");
+        ErrorLog.errPrintln("Failed to get channel property '" + key + "'");
       }
     }
     return null;
@@ -266,7 +266,7 @@ public class ChannelProperties
       img = imgIcon == null ? null : imgIcon.getImage();
       if (img == null)
       {
-        System.err.println(
+        ErrorLog.errPrintln(
                 "Failed to load channel image " + key + "=" + path);
         if (!useClassDefaultImage)
         {
@@ -293,7 +293,7 @@ public class ChannelProperties
       {
         return urlMap().getOrDefault(key, null);
       }
-      System.err.println(
+      ErrorLog.errPrintln(
               "Do not use getImageURL(key) before using getImage(key...)");
     }
     return null;
diff --git a/getdown/src/getdown/core/src/main/java/jalview/util/ErrorLog.java b/getdown/src/getdown/core/src/main/java/jalview/util/ErrorLog.java
new file mode 100644 (file)
index 0000000..e94b59e
--- /dev/null
@@ -0,0 +1,58 @@
+package jalview.util;
+
+public class ErrorLog
+{
+  private static boolean hasConsole = true;
+
+  public static void outPrintln(String message)
+  {
+    println(message, false);
+  }
+
+  public static void errPrintln(String message)
+  {
+    println(message, true);
+  }
+
+  public static void println(String message, boolean err)
+  {
+    if (hasConsole)
+    {
+      try
+      {
+        hasConsole = jalview.bin.Console.initLogger();
+        if (hasConsole)
+        {
+          if (err)
+          {
+            jalview.bin.Console.errPrintln(message);
+          }
+          else
+          {
+            jalview.bin.Console.outPrintln(message);
+          }
+        }
+      } catch (Exception e)
+      {
+        e.printStackTrace();
+      } catch (NoClassDefFoundError t)
+      {
+        hasConsole = false;
+        System.err.println(
+                "jalview.util.ErrorLog has no jalview.bin.Console. Using System.err and System.out.");
+      }
+    }
+    if (!hasConsole)
+    {
+      if (err)
+      {
+        System.err.println("jalview.util.ErrorLog: " + message);
+      }
+      else
+      {
+        System.out.println("jalview.util.ErrorLog: " + message);
+
+      }
+    }
+  }
+}
diff --git a/getdown/src/getdown/core/src/main/java/jalview/util/HttpUtils.java b/getdown/src/getdown/core/src/main/java/jalview/util/HttpUtils.java
new file mode 100644 (file)
index 0000000..e600c6c
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.ProtocolException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+public class HttpUtils
+{
+
+  /**
+   * Returns true if it is possible to open an input stream at the given URL,
+   * else false. The input stream is closed.
+   * 
+   * @param url
+   * @return
+   */
+  public static boolean isValidUrl(String url)
+  {
+    InputStream is = null;
+    try
+    {
+      is = HttpUtils.openStream(new URL(url));
+      if (is != null)
+      {
+        return true;
+      }
+    } catch (IOException x)
+    {
+      // MalformedURLException, FileNotFoundException
+      return false;
+    } finally
+    {
+      if (is != null)
+      {
+        try
+        {
+          is.close();
+        } catch (IOException e)
+        {
+          // ignore
+        }
+      }
+    }
+    return false;
+  }
+
+  public static boolean startsWithHttpOrHttps(String file)
+  {
+    return file.startsWith("http://") || file.startsWith("https://");
+  }
+
+  /**
+   * wrapper to get/post to a URL or check headers
+   * 
+   * @param url
+   * @param ids
+   * @param readTimeout
+   * @return
+   * @throws IOException
+   * @throws ProtocolException
+   */
+  public static boolean checkUrlAvailable(URL url, int readTimeout)
+          throws IOException, ProtocolException
+  {
+    // jalview.bin.Console.outPrintln(System.currentTimeMillis() + " " + url);
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod("HEAD");
+    connection.setDoInput(true);
+    connection.setUseCaches(false);
+    connection.setConnectTimeout(300);
+    connection.setReadTimeout(readTimeout);
+
+    // HttpURLConnection doesn't follow redirects from http to https. It should!
+    HttpURLConnection conn = followConnection(connection);
+    return conn.getResponseCode() == 200;
+  }
+
+  /**
+   * wrapper to follow a URL connection ALLOWING redirects from http to https
+   * 
+   * @param HttpURLConnection
+   *          conn0
+   * @return HttpUrlConnection conn
+   */
+  public static HttpURLConnection followConnection(HttpURLConnection conn0)
+          throws IOException
+  {
+    URL url = conn0.getURL();
+    if (url == null)
+    {
+      return null;
+    }
+    HttpURLConnection conn = null;
+    int response = conn0.getResponseCode();
+    boolean followed = false;
+    if (response >= 300 && response < 400 && conn0.getFollowRedirects())
+    {
+      // we are only checking for a redirect from http to https
+      if ("http".equals(url.getProtocol()))
+      {
+        URL loc = new URL(conn0.getHeaderField("Location"));
+        if (loc != null && "https".equals(loc.getProtocol()))
+        {
+          conn = (HttpURLConnection) loc.openConnection();
+          conn.setRequestMethod(conn0.getRequestMethod());
+          conn.setDoInput(conn0.getDoInput());
+          conn.setUseCaches(conn0.getUseCaches());
+          conn.setConnectTimeout(conn0.getConnectTimeout());
+          conn.setReadTimeout(conn0.getReadTimeout());
+          conn.setInstanceFollowRedirects(
+                  conn0.getInstanceFollowRedirects());
+          followed = true;
+        }
+      }
+    }
+    return followed && conn != null ? conn : conn0;
+  }
+
+  /**
+   * wrapper to follow a URL connection ALLOWING redirects from http to https
+   * 
+   * @param URL
+   *          url
+   * @return HttpUrlConnection conn
+   */
+  public static HttpURLConnection openConnection(URL url) throws IOException
+  {
+    if (url == null)
+    {
+      return null;
+    }
+    HttpURLConnection conn = null;
+    String protocol = url.getProtocol();
+    if ("http".equals(protocol) || "https".equals(protocol))
+    {
+      HttpURLConnection conn0 = (HttpURLConnection) url.openConnection();
+      if (conn0 != null)
+      {
+        conn = HttpUtils.followConnection(conn0);
+      }
+      else
+      {
+        conn = conn0;
+      }
+    }
+    return conn;
+  }
+
+  /**
+   * wrapper to follow a URL connection ALLOWING redirects from http to https
+   * and return the followed InputStream
+   * 
+   * @param URL
+   *          url
+   * @return HttpUrlConnection conn
+   */
+  public static InputStream openStream(URL url) throws IOException
+  {
+    if (url == null)
+    {
+      return null;
+    }
+    InputStream is = null;
+    String protocol = url.getProtocol();
+    if ("http".equals(protocol) || "https".equals(protocol))
+    {
+      HttpURLConnection conn = HttpUtils
+              .followConnection((HttpURLConnection) url.openConnection());
+      if (conn != null)
+      {
+        is = conn.getInputStream();
+      }
+    }
+    else
+    {
+      is = url.openStream();
+    }
+    return is;
+  }
+
+  /**
+   * check if a jalview:// scheme URL is given
+   * 
+   * @param String
+   *          uri
+   * @return boolean
+   */
+  public static boolean isJalviewSchemeUri(String jalviewUriString)
+  {
+    URI jalviewUri;
+    try
+    {
+      jalviewUri = new URI(jalviewUriString);
+    } catch (URISyntaxException e)
+    {
+      return false;
+    }
+    String scheme = jalviewUri.getScheme();
+    if (scheme == null || !scheme.startsWith("jalview"))
+    {
+      return false;
+    }
+    return scheme.length() == 7 // jalview
+            || scheme.length() == 8 // jalviewX
+            || scheme.substring(7).equals("http") // jalviewhttp
+            || scheme.substring(7).equals("https"); // jalviewhttps
+  }
+
+  /**
+   * convert a jalview scheme URI to its equivalent URL or path
+   * 
+   * @param String
+   *          uri
+   * @return String
+   */
+  public static String equivalentJalviewUrl(String jalviewUriString)
+  {
+    if (!isJalviewSchemeUri(jalviewUriString))
+    {
+      return null;
+    }
+    URI jalviewUri;
+    try
+    {
+      jalviewUri = new URI(jalviewUriString);
+    } catch (URISyntaxException e)
+    {
+      return null;
+    }
+    String scheme = jalviewUri.getScheme();
+    String host = jalviewUri.getHost();
+    if (host != null && host.length() > 0)
+    {
+      URI newUri;
+      try
+      {
+        newUri = new URI(scheme.equals("jalviewhttp") ? "http" : "https",
+                jalviewUri.getUserInfo(), host, jalviewUri.getPort(),
+                jalviewUri.getPath(), jalviewUri.getQuery(),
+                jalviewUri.getFragment());
+        // return a URL
+        return newUri.toURL().toString();
+      } catch (URISyntaxException | MalformedURLException e)
+      {
+        ErrorLog.errPrintln("Trying to convert '" + jalviewUriString
+                + "' to URL failed");
+      }
+    }
+    else
+    {
+      // return a file path (not a file URI)
+      return jalviewUri.getPath();
+    }
+    return null;
+  }
+}
index 784eb5a..5894fec 100644 (file)
@@ -31,7 +31,6 @@ import java.util.Properties;
 
 public class LaunchUtils
 {
-
   // setting these is LaunchUtils so don't need to import Platform
   public final static boolean isMac = System.getProperty("os.name")
           .indexOf("Mac") > -1;
@@ -75,7 +74,7 @@ public class LaunchUtils
         return null;
       } catch (IOException e)
       {
-        System.err.println(e.getMessage());
+        ErrorLog.errPrintln(e.getMessage());
         return null;
       }
     }
@@ -105,7 +104,7 @@ public class LaunchUtils
     try
     {
       URL localFileURL = new URL(buildDetails);
-      InputStream in = localFileURL.openStream();
+      InputStream in = HttpUtils.openStream(localFileURL);
       Properties buildProperties = new Properties();
       buildProperties.load(in);
       in.close();
@@ -113,22 +112,21 @@ public class LaunchUtils
               null);
       if (JCV == null)
       {
-        System.out.println(
-                "Could not obtain JAVA_COMPILE_VERSION for comparison");
+        ErrorLog.errPrintln("Could not obtain JAVA_COMPILE_VERSION for comparison");
         return -2;
       }
       JAVA_COMPILE_VERSION = Integer.parseInt(JCV);
     } catch (MalformedURLException e)
     {
-      System.err.println("Could not find " + buildDetails);
+      ErrorLog.errPrintln("Could not find " + buildDetails);
       return -3;
     } catch (IOException e)
     {
-      System.err.println("Could not load " + buildDetails);
+      ErrorLog.errPrintln("Could not load " + buildDetails);
       return -4;
     } catch (NumberFormatException e)
     {
-      System.err.println("Could not parse JAVA_COMPILE_VERSION");
+      ErrorLog.errPrintln("Could not parse JAVA_COMPILE_VERSION");
       return -5;
     }
 
@@ -152,7 +150,7 @@ public class LaunchUtils
       String JV = System.getProperty("java.version");
       if (JV == null)
       {
-        System.out.println("Could not obtain java.version for comparison");
+        ErrorLog.errPrintln("Could not obtain java.version for comparison");
         return -2;
       }
       if (JV.startsWith("1."))
@@ -163,7 +161,7 @@ public class LaunchUtils
               : Integer.parseInt(JV.substring(0, JV.indexOf(".")));
     } catch (NumberFormatException e)
     {
-      System.err.println("Could not parse java.version");
+      ErrorLog.errPrintln("Could not parse java.version");
       return -3;
     }
     return JAVA_VERSION;
@@ -184,7 +182,7 @@ public class LaunchUtils
 
     if (java_compile_version <= 0 || java_version <= 0)
     {
-      System.out.println("Could not make Java version check");
+      ErrorLog.errPrintln("Could not make Java version check");
       return true;
     }
     // Warn if these java.version and JAVA_COMPILE_VERSION conditions exist
index 1c67c92..42c52a7 100644 (file)
@@ -202,18 +202,18 @@ public class StringUtils
       jv.clear();
       if (DEBUG)
       {
-        System.err.println("Array from '" + delimiter
+        ErrorLog.errPrintln("Array from '" + delimiter
                 + "' separated List:\n" + v.length);
         for (int i = 0; i < v.length; i++)
         {
-          System.err.println("item " + i + " '" + v[i] + "'");
+          ErrorLog.errPrintln("item " + i + " '" + v[i] + "'");
         }
       }
       return v;
     }
     if (DEBUG)
     {
-      System.err.println(
+      ErrorLog.errPrintln(
               "Empty Array from '" + delimiter + "' separated List");
     }
     return null;
@@ -249,13 +249,13 @@ public class StringUtils
       {
         System.err
                 .println("Returning '" + separator + "' separated List:\n");
-        System.err.println(v);
+        ErrorLog.errPrintln(v.toString());
       }
       return v.toString();
     }
     if (DEBUG)
     {
-      System.err.println(
+      ErrorLog.errPrintln(
               "Returning empty '" + separator + "' separated List\n");
     }
     return "" + separator;
@@ -586,6 +586,15 @@ public class StringUtils
     return min < text.length() + 1 ? min : -1;
   }
 
+  public static boolean equalsIgnoreCase(String s1, String s2)
+  {
+    if (s1 == null || s2 == null)
+    {
+      return s1 == s2;
+    }
+    return s1.toLowerCase(Locale.ROOT).equals(s2.toLowerCase(Locale.ROOT));
+  }
+
   public static int indexOfFirstWhitespace(String text)
   {
     int index = -1;
index bd6924d..2a4159a 100644 (file)
Binary files a/j11lib/getdown-core.jar and b/j11lib/getdown-core.jar differ
index bd6924d..2a4159a 100644 (file)
Binary files a/j8lib/getdown-core.jar and b/j8lib/getdown-core.jar differ