private String generateExceptionReport() {
   StringBuilder builder = new StringBuilder("Spoutcraft Launcher Error Report:\n");
   builder.append("( Please submit this report to http://spout.in/issues )\n");
   builder.append("    Launcher Build: ").append(Settings.getLauncherBuild()).append("\n");
   builder
       .append("----------------------------------------------------------------------")
       .append("\n");
   builder.append("Stack Trace:").append("\n");
   builder.append("    Exception: ").append(cause.getClass().getSimpleName()).append("\n");
   builder.append("    Message: ").append(cause.getMessage()).append("\n");
   logTrace(builder, cause);
   builder
       .append("----------------------------------------------------------------------")
       .append("\n");
   builder.append("System Information:\n");
   builder.append("    Operating System: ").append(System.getProperty("os.name")).append("\n");
   builder
       .append("    Operating System Version: ")
       .append(System.getProperty("os.version"))
       .append("\n");
   builder
       .append("    Operating System Architecture: ")
       .append(System.getProperty("os.arch"))
       .append("\n");
   builder
       .append("    Java version: ")
       .append(System.getProperty("java.version"))
       .append(" ")
       .append(System.getProperty("sun.arch.data.model", "32"))
       .append(" bit")
       .append("\n");
   builder
       .append("    Total Memory: ")
       .append(Runtime.getRuntime().totalMemory() / 1024L / 1024L)
       .append(" MB\n");
   builder
       .append("    Max Memory: ")
       .append(Runtime.getRuntime().maxMemory() / 1024L / 1024L)
       .append(" MB\n");
   builder
       .append("    Memory Free: ")
       .append(Runtime.getRuntime().freeMemory() / 1024L / 1024L)
       .append(" MB\n");
   builder
       .append("    CPU Cores: ")
       .append(Runtime.getRuntime().availableProcessors())
       .append("\n");
   return builder.toString();
 }
 public static Download downloadFile(
     String url, String output, String cacheName, String md5, DownloadListener listener)
     throws IOException {
   int tries = Settings.getLoginTries();
   File outputFile = null;
   Download download = null;
   while (tries > 0) {
     System.out.println("Starting download of " + url + ", with " + tries + " tries remaining");
     tries--;
     download = new Download(url, output);
     download.setListener(listener);
     download.run();
     if (!download.isSuccess()) {
       if (download.getOutFile() != null) {
         download.getOutFile().delete();
       }
       System.err.println("Download of " + url + " Failed!");
       if (listener != null)
         listener.stateChanged("Download Failed, retries remaining: " + tries, 0F);
     } else {
       if (md5 != null) {
         String resultMD5 = MD5Utils.getMD5(download.getOutFile());
         System.out.println("Expected MD5: " + md5 + " Calculated MD5: " + resultMD5);
         if (resultMD5.equals(md5)) {
           outputFile = download.getOutFile();
           break;
         }
       } else {
         outputFile = download.getOutFile();
         break;
       }
     }
   }
   if (outputFile == null) {
     throw new IOException("Failed to download " + url);
   }
   if (cacheName != null) {
     Utils.copy(outputFile, new File(Launcher.getGameUpdater().getBinCacheDir(), cacheName));
   }
   return download;
 }