Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

1049
LINES

< > BotCompany Repo | #2000470 // class _x16 (embeddable, fixed)

New Tinybrain snippet

1  
/**
2  
 JavaX runner version 16
3  
4  
 Changes to v15:
5  
 -fixed caching bug
6  
 -remove "hash match" messages on System.err
7  
 -cache transpiled translators
8  
9  
 */
10  
11  
class _x16 {
12  
  static final String version = "JavaX 16";
13  
14  
  static boolean verbose = false, translate = false, list = false, virtualizeTranslators = true;
15  
  static String translateTo = null;
16  
  static boolean preferCached = false, safeOnly = false, noID = false;
17  
  static List<String[]> mainTranslators = new ArrayList<String[]>();
18  
  private static Map<Long, String> memSnippetCache = new HashMap<Long, String>();
19  
  private static int processesStarted, compilations;
20  
21  
  // snippet ID -> md5
22  
  private static HashMap<Long, String> prefetched = new HashMap<Long, String>();
23  
  private static File virtCache;
24  
25  
  // doesn't work yet
26  
  private static Map<String, Class<?>> programCache = new HashMap<String, Class<?>>();
27  
  static boolean cacheTranslators = false;
28  
29  
  // this should work (caches transpiled translators)
30  
  private static HashMap<Long, Object[]> translationCache = new HashMap<Long, Object[]>();
31  
  static boolean cacheTranspiledTranslators = true;
32  
33  
  public static void main(String[] args) throws Exception {
34  
    File ioBaseDir = new File("."), inputDir = null, outputDir = null;
35  
    String src = null;
36  
    List<String> programArgs = new ArrayList<String>();
37  
38  
    for (int i = 0; i < args.length; i++) {
39  
      String arg = args[i];
40  
      if (arg.equals("-v") || arg.equals("-verbose"))
41  
        verbose = true;
42  
      else if (arg.equals("-finderror"))
43  
        verbose = true;
44  
      else if (arg.equals("-offline") || arg.equalsIgnoreCase("-prefercached"))
45  
        preferCached = true;
46  
      else if (arg.equals("-novirt"))
47  
        virtualizeTranslators = false;
48  
      else if (arg.equals("-safeonly"))
49  
        safeOnly = true;
50  
      else if (arg.equals("-noid"))
51  
        noID = true;
52  
      else if (arg.equals("-nocachetranspiled"))
53  
        cacheTranspiledTranslators = false;
54  
      else if (arg.equals("translate"))
55  
        translate = true;
56  
      else if (arg.equals("list")) {
57  
        list = true;
58  
        virtualizeTranslators = false; // so they are silenced
59  
      } else if (arg.equals("run")) {
60  
        // it's the default command anyway
61  
      } else if (arg.startsWith("input="))
62  
        inputDir = new File(arg.substring(6));
63  
      else if (arg.startsWith("output="))
64  
        outputDir = new File(arg.substring(7));
65  
      else if (arg.equals("with"))
66  
        mainTranslators.add(new String[] {args[++i], null});
67  
      else if (translate && arg.equals("to"))
68  
        translateTo = args[++i];
69  
      else if (src == null) {
70  
        //System.out.println("src=" + arg);
71  
        src = arg;
72  
      } else
73  
        programArgs.add(arg);
74  
    }
75  
76  
    if (src == null) src = ".";
77  
78  
    // Might actually want to write to 2 disk caches (global/per program).
79  
    if (virtualizeTranslators && !preferCached)
80  
      virtCache = TempDirMaker_make();
81  
82  
    if (inputDir != null) {
83  
      ioBaseDir = TempDirMaker_make();
84  
      System.out.println("Taking input from: " + inputDir.getAbsolutePath());
85  
      System.out.println("Output is in: " + new File(ioBaseDir, "output").getAbsolutePath());
86  
      copyInput(inputDir, new File(ioBaseDir, "input"));
87  
    }
88  
89  
    javaxmain(src, ioBaseDir, translate, list, programArgs.toArray(new String[programArgs.size()]));
90  
91  
    if (outputDir != null) {
92  
      copyInput(new File(ioBaseDir, "output"), outputDir);
93  
      System.out.println("Output copied to: " + outputDir.getAbsolutePath());
94  
    }
95  
96  
    if (verbose) {
97  
      // print stats
98  
      System.out.println("Processes started: " + processesStarted + ", compilations: " + compilations);
99  
    }
100  
  }
101  
102  
  public static void javaxmain(String src, File ioDir, boolean translate, boolean list,
103  
                               String[] args) throws Exception {
104  
    File srcDir;
105  
    if (isSnippetID(src)) {
106  
      prefetch(src);
107  
      srcDir = loadSnippetAsMainJava(src);
108  
    } else {
109  
      srcDir = new File(src);
110  
111  
      // if the argument is a file, it is assumed to be main.java
112  
      if (srcDir.isFile()) {
113  
        srcDir = TempDirMaker_make();
114  
        copy(new File(src), new File(srcDir, "main.java"));
115  
      }
116  
117  
      if (!new File(srcDir, "main.java").exists()) {
118  
        System.out.println("This is " + version  + ".\n" +
119  
          "No main.java found, exiting");
120  
        return;
121  
      }
122  
    }
123  
124  
    // translate
125  
126  
    List<File> libraries = new ArrayList<File>();
127  
    File X = topLevelTranslate(srcDir, libraries);
128  
129  
    // save prefetch data
130  
    if (isSnippetID(src))
131  
      savePrefetchData(src);
132  
133  
    // list or run
134  
135  
    if (translate) {
136  
      File to = X;
137  
      if (translateTo != null)
138  
        if (new File(translateTo).isDirectory())
139  
          to = new File(translateTo, "main.java");
140  
        else
141  
          to = new File(translateTo);
142  
      if (to != X)
143  
        copy(new File(X, "main.java"), to);
144  
      System.out.println("Program translated to: " + to.getAbsolutePath());
145  
    } else if (list)
146  
      System.out.println(loadTextFile(new File(X, "main.java").getPath(), null));
147  
    else
148  
      javax2(X, ioDir, false, false, libraries, args, null);
149  
  }
150  
151  
  private static void prefetch(String mainSnippetID) throws IOException {
152  
    long mainID = parseSnippetID(mainSnippetID);
153  
    String s = mainID + " " + loadTextFile(new File(".tinybrain/prefetch/" + mainID + ".txt").getPath(), "");
154  
    String[] ids = s.trim().split(" ");
155  
    if (ids.length > 1) {
156  
      String url = "http://tinybrain.de:8080/tb-int/prefetch.php?ids=" + URLEncoder.encode(s, "UTF-8");
157  
      String data = loadPage(new URL(url));
158  
      String[] split = data.split(" ");
159  
      if (split.length == ids.length)
160  
        for (int i = 0; i < ids.length; i++)
161  
          prefetched.put(parseSnippetID(ids[i]), split[i]);
162  
    }
163  
  }
164  
165  
  private static void savePrefetchData(String mainSnippetID) throws IOException {
166  
    List<String> ids = new ArrayList<String>();
167  
    long mainID = parseSnippetID(mainSnippetID);
168  
169  
    for (long id : memSnippetCache.keySet())
170  
      if (id != mainID)
171  
        ids.add(String.valueOf(id));
172  
173  
    saveTextFile(new File(".tinybrain/prefetch/" + mainID + ".txt").getPath(), join(" ", ids));
174  
  }
175  
176  
  static File topLevelTranslate(File srcDir, List<File> libraries_out) throws Exception {
177  
    File X = srcDir;
178  
    X = applyTranslators(X, mainTranslators, libraries_out);
179  
    X = defaultTranslate(X, libraries_out);
180  
    return X;
181  
  }
182  
183  
  private static File defaultTranslate(File x, List<File> libraries_out) throws Exception {
184  
    x = luaPrintToJavaPrint(x);
185  
    x = repeatAutoTranslate(x, libraries_out);
186  
    return x;
187  
  }
188  
189  
  private static File repeatAutoTranslate(File x, List<File> libraries_out) throws Exception {
190  
    while (true) {
191  
      File y = autoTranslate(x, libraries_out);
192  
      if (y == x)
193  
        return x;
194  
      x = y;
195  
    }
196  
  }
197  
198  
  private static File autoTranslate(File x, List<File> libraries_out) throws Exception {
199  
    String main = loadTextFile(new File(x, "main.java").getPath(), null);
200  
    List<String> lines = toLines(main);
201  
    List<String[]> translators = findTranslators(lines);
202  
    if (translators.isEmpty())
203  
      return x;
204  
205  
    main = fromLines(lines);
206  
    File newDir = TempDirMaker_make();
207  
    saveTextFile(new File(newDir, "main.java").getPath(), main);
208  
    return applyTranslators(newDir, translators, libraries_out);
209  
  }
210  
211  
  private static List<String[]> findTranslators(List<String> lines) {
212  
    List<String[]> translators = new ArrayList<String[]>();
213  
    Pattern pattern = Pattern.compile("^!([0-9# \t]+)");
214  
    Pattern pArgs = Pattern.compile("^\\s*\\((.*)\\)");
215  
    for (ListIterator<String> iterator = lines.listIterator(); iterator.hasNext(); ) {
216  
      String line = iterator.next();
217  
      line = line.trim();
218  
      Matcher matcher = pattern.matcher(line);
219  
      if (matcher.find()) {
220  
        String[] t = matcher.group(1).split("[ \t]+");
221  
        String rest = line.substring(matcher.end());
222  
        String arg = null;
223  
        if (t.length == 1) {
224  
          Matcher mArgs = pArgs.matcher(rest);
225  
          if (mArgs.find())
226  
            arg = mArgs.group(1);
227  
        }
228  
        for (String transi : t)
229  
          translators.add(new String[]{transi, arg});
230  
        iterator.remove();
231  
      }
232  
    }
233  
    return translators;
234  
  }
235  
236  
  public static List<String> toLines(String s) {
237  
    List<String> lines = new ArrayList<String>();
238  
    int start = 0;
239  
    while (true) {
240  
      int i = toLines_nextLineBreak(s, start);
241  
      if (i < 0) {
242  
        if (s.length() > start) lines.add(s.substring(start));
243  
        break;
244  
      }
245  
246  
      lines.add(s.substring(start, i));
247  
      if (s.charAt(i) == '\r' && i+1 < s.length() && s.charAt(i+1) == '\n')
248  
        i += 2;
249  
      else
250  
        ++i;
251  
252  
      start = i;
253  
    }
254  
    return lines;
255  
  }
256  
257  
  private static int toLines_nextLineBreak(String s, int start) {
258  
    for (int i = start; i < s.length(); i++) {
259  
      char c = s.charAt(i);
260  
      if (c == '\r' || c == '\n')
261  
        return i;
262  
    }
263  
    return -1;
264  
  }
265  
266  
  public static String fromLines(List<String> lines) {
267  
    StringBuilder buf = new StringBuilder();
268  
    for (String line : lines) {
269  
      buf.append(line).append('\n');
270  
    }
271  
    return buf.toString();
272  
  }
273  
274  
  private static File applyTranslators(File x, List<String[]> translators, List<File> libraries_out) throws Exception {
275  
    for (String[] translator : translators)
276  
      x = applyTranslator(x, translator[0], translator[1], libraries_out);
277  
    return x;
278  
  }
279  
280  
  // also takes a library
281  
  private static File applyTranslator(File x, String translator, String arg, List<File> libraries_out) throws Exception {
282  
    if (verbose)
283  
      System.out.println("Using translator " + translator + " on sources in " + x.getPath());
284  
285  
    File newDir = runTranslatorOnInput(translator, null, arg, x, !verbose, libraries_out);
286  
287  
    if (!new File(newDir, "main.java").exists()) {
288  
      throw new Exception("Translator " + translator + " did not generate main.java");
289  
      // TODO: show translator output
290  
    }
291  
    if (verbose)
292  
      System.out.println("Translated with " + translator + " from " + x.getPath() + " to " + newDir.getPath());
293  
    x = newDir;
294  
    return x;
295  
  }
296  
297  
  private static File luaPrintToJavaPrint(File x) throws IOException {
298  
    File newDir = TempDirMaker_make();
299  
    String code = loadTextFile(new File(x, "main.java").getPath(), null);
300  
    code = luaPrintToJavaPrint(code);
301  
    if (verbose)
302  
      System.out.println(code);
303  
    saveTextFile(new File(newDir, "main.java").getPath(), code);
304  
    return newDir;
305  
  }
306  
307  
  public static String luaPrintToJavaPrint(String code) {
308  
    return ("\n" + code).replaceAll(
309  
      "(\n\\s*)print (\".*\")",
310  
      "$1System.out.println($2);").substring(1);
311  
  }
312  
313  
  public static File loadSnippetAsMainJava(String snippetID) throws IOException {
314  
    checkProgramSafety(snippetID);
315  
    File srcDir = TempDirMaker_make();
316  
    saveTextFile(new File(srcDir, "main.java").getPath(), loadSnippet(snippetID));
317  
    return srcDir;
318  
  }
319  
320  
  public static File loadSnippetAsMainJavaVerified(String snippetID, String hash) throws IOException {
321  
    checkProgramSafety(snippetID);
322  
    File srcDir = TempDirMaker_make();
323  
    saveTextFile(new File(srcDir, "main.java").getPath(), loadSnippetVerified(snippetID, hash));
324  
    return srcDir;
325  
  }
326  
327  
  /** returns output dir */
328  
  private static File runTranslatorOnInput(String snippetID, String hash, String arg, File input,
329  
                                           boolean silent,
330  
                                           List<File> libraries_out) throws Exception {
331  
    File libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(snippetID));
332  
    if (libraryFile != null) {
333  
      loadLibrary(snippetID, libraries_out, libraryFile);
334  
      return input;
335  
    }
336  
337  
    String[] args = arg != null ? new String[]{arg} : new String[0];
338  
339  
    File srcDir = hash == null ? loadSnippetAsMainJava(snippetID)
340  
      : loadSnippetAsMainJavaVerified(snippetID, hash);
341  
    long mainJavaSize = new File(srcDir, "main.java").length();
342  
343  
    if (mainJavaSize == 0) { // no text in snippet? assume it's a library
344  
      loadLibrary(snippetID, libraries_out, libraryFile);
345  
      return input;
346  
    }
347  
348  
    File ioBaseDir = TempDirMaker_make();
349  
350  
    /*Class<?> mainClass = programCache.get("" + parseSnippetID(snippetID));
351  
    if (mainClass != null)
352  
      return runCached(ioBaseDir, input, args);*/
353  
    // Doesn't work yet because virtualized directories are hardcoded in translator...
354  
355  
    List<File> libraries = new ArrayList<File>();
356  
    Object[] cached = translationCache.get(parseSnippetID(snippetID));
357  
    if (cached != null) {
358  
      //System.err.println("Taking translator " + snippetID + " from cache!");
359  
      srcDir = (File) cached[0];
360  
      libraries = (List<File>) cached[1];
361  
    } else {
362  
      srcDir = defaultTranslate(srcDir, libraries);
363  
      if (cacheTranspiledTranslators)
364  
        translationCache.put(parseSnippetID(snippetID), new Object[] {srcDir, libraries});
365  
    }
366  
    boolean runInProcess = false;
367  
368  
    if (virtualizeTranslators) {
369  
      if (verbose) System.out.println("Virtualizing translator");
370  
371  
      //srcDir = applyTranslator(srcDir, "#2000351"); // I/O-virtualize the translator
372  
      // that doesn't work because it recurses infinitely...
373  
374  
      // So we do it right here:
375  
      String s = loadTextFile(new File(srcDir, "main.java").getPath(), null);
376  
      s = s.replaceAll("new\\s+File\\(", "virtual.newFile(");
377  
      s = s.replaceAll("new\\s+FileInputStream\\(", "virtual.newFileInputStream(");
378  
      s = s.replaceAll("new\\s+FileOutputStream\\(", "virtual.newFileOutputStream(");
379  
      s += "\n\n" + loadSnippet("#2000355"); // load class virtual
380  
381  
      // change baseDir
382  
      s = s.replace("virtual_baseDir = \"\";",
383  
        "virtual_baseDir = " + javaQuote(ioBaseDir.getAbsolutePath()) + ";");
384  
385  
      // forward snippet cache (virtualized one)
386  
      File dir = virtCache != null ? virtCache : DiskSnippetCache_dir;
387  
      s = s.replace("static File DiskSnippetCache_dir;",
388  
        "static File DiskSnippetCache_dir = new File(" + javaQuote(dir.getAbsolutePath()) + ");");
389  
      s = s.replace("static boolean preferCached = false;", "static boolean preferCached = true;");
390  
391  
      if (verbose) {
392  
        System.out.println("==BEGIN VIRTUALIZED TRANSLATOR==");
393  
        System.out.println(s);
394  
        System.out.println("==END VIRTUALIZED TRANSLATOR==");
395  
      }
396  
      srcDir = TempDirMaker_make();
397  
      saveTextFile(new File(srcDir, "main.java").getPath(), s);
398  
399  
      // TODO: silence translator also
400  
      runInProcess = true;
401  
    }
402  
403  
    return runJavaX(ioBaseDir, srcDir, input, silent, runInProcess, libraries,
404  
      args, cacheTranslators ? "" + parseSnippetID(snippetID) : null);
405  
  }
406  
407  
  static void checkProgramSafety(String snippetID) throws IOException {
408  
    if (!safeOnly) return;
409  
    URL url = new URL("http://tinybrain.de:8080/tb-int/is-javax-safe.php?id=" + parseSnippetID(snippetID));
410  
    String text = loadPage(url);
411  
    if (!text.startsWith("{\"safe\":\"1\"}"))
412  
      throw new RuntimeException("Translator not safe: #" + parseSnippetID(snippetID));
413  
  }
414  
415  
  private static void loadLibrary(String snippetID, List<File> libraries_out, File libraryFile) throws IOException {
416  
    if (verbose)
417  
      System.out.println("Assuming " + snippetID + " is a library.");
418  
419  
    if (libraryFile == null) {
420  
      byte[] data = loadDataSnippetImpl(snippetID);
421  
      DiskSnippetCache_putLibrary(parseSnippetID(snippetID), data);
422  
      libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(snippetID));
423  
    }
424  
425  
    if (!libraries_out.contains(libraryFile))
426  
      libraries_out.add(libraryFile);
427  
  }
428  
429  
  private static byte[] loadDataSnippetImpl(String snippetID) throws IOException {
430  
    byte[] data;
431  
    try {
432  
      URL url = new URL("http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_"
433  
        + parseSnippetID(snippetID) + "&contentType=application/binary");
434  
      System.err.println("Loading library: " + url);
435  
      data = loadBinaryPage(url.openConnection());
436  
      if (verbose)
437  
        System.err.println("Bytes loaded: " + data.length);
438  
    } catch (FileNotFoundException e) {
439  
      throw new IOException("Binary snippet #" + snippetID + " not found or not public");
440  
    }
441  
    return data;
442  
  }
443  
444  
  /** returns output dir */
445  
  private static File runJavaX(File ioBaseDir, File originalSrcDir, File originalInput,
446  
                               boolean silent, boolean runInProcess,
447  
                               List<File> libraries, String[] args, String cacheAs) throws Exception {
448  
    File srcDir = new File(ioBaseDir, "src");
449  
    File inputDir = new File(ioBaseDir, "input");
450  
    File outputDir = new File(ioBaseDir, "output");
451  
    copyInput(originalSrcDir, srcDir);
452  
    copyInput(originalInput, inputDir);
453  
    javax2(srcDir, ioBaseDir, silent, runInProcess, libraries, args, cacheAs);
454  
    return outputDir;
455  
  }
456  
457  
  private static void copyInput(File src, File dst) throws IOException {
458  
    copyDirectory(src, dst);
459  
  }
460  
461  
  public static boolean hasFile(File inputDir, String name) {
462  
    return new File(inputDir, name).exists();
463  
  }
464  
465  
  public static void copyDirectory(File src, File dst) throws IOException {
466  
    if (verbose) System.out.println("Copying " + src.getAbsolutePath() + " to " + dst.getAbsolutePath());
467  
    dst.mkdirs();
468  
    File[] files = src.listFiles();
469  
    if (files == null) return;
470  
    for (File file : files) {
471  
      File dst1 = new File(dst, file.getName());
472  
      if (file.isDirectory())
473  
        copyDirectory(file, dst1);
474  
      else {
475  
        if (verbose) System.out.println("Copying " + file.getAbsolutePath() + " to " + dst1.getAbsolutePath());
476  
        copy(file, dst1);
477  
      }
478  
    }
479  
  }
480  
481  
  /** Quickly copy a file without a progress bar or any other fancy GUI... :) */
482  
  public static void copy(File src, File dest) throws IOException {
483  
    FileInputStream inputStream = new FileInputStream(src);
484  
    FileOutputStream outputStream = new FileOutputStream(dest);
485  
    try {
486  
      copy(inputStream, outputStream);
487  
      inputStream.close();
488  
    } finally {
489  
      outputStream.close();
490  
    }
491  
  }
492  
493  
  public static void copy(InputStream in, OutputStream out) throws IOException {
494  
    byte[] buf = new byte[65536];
495  
    while (true) {
496  
      int n = in.read(buf);
497  
      if (n <= 0) return;
498  
      out.write(buf, 0, n);
499  
    }
500  
  }
501  
502  
  /** writes safely (to temp file, then rename) */
503  
  public static void saveTextFile(String fileName, String contents) throws IOException {
504  
    File file = new File(fileName);
505  
    File parentFile = file.getParentFile();
506  
    if (parentFile != null)
507  
      parentFile.mkdirs();
508  
    String tempFileName = fileName + "_temp";
509  
    FileOutputStream fileOutputStream = new FileOutputStream(tempFileName);
510  
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, charsetForTextFiles);
511  
    PrintWriter printWriter = new PrintWriter(outputStreamWriter);
512  
    printWriter.print(contents);
513  
    printWriter.close();
514  
    if (file.exists() && !file.delete())
515  
      throw new IOException("Can't delete " + fileName);
516  
517  
    if (!new File(tempFileName).renameTo(file))
518  
      throw new IOException("Can't rename " + tempFileName + " to " + fileName);
519  
  }
520  
521  
  /** writes safely (to temp file, then rename) */
522  
  public static void saveBinaryFile(String fileName, byte[] contents) throws IOException {
523  
    File file = new File(fileName);
524  
    File parentFile = file.getParentFile();
525  
    if (parentFile != null)
526  
      parentFile.mkdirs();
527  
    String tempFileName = fileName + "_temp";
528  
    FileOutputStream fileOutputStream = new FileOutputStream(tempFileName);
529  
    fileOutputStream.write(contents);
530  
    fileOutputStream.close();
531  
    if (file.exists() && !file.delete())
532  
      throw new IOException("Can't delete " + fileName);
533  
534  
    if (!new File(tempFileName).renameTo(file))
535  
      throw new IOException("Can't rename " + tempFileName + " to " + fileName);
536  
  }
537  
538  
  public static String loadTextFile(String fileName, String defaultContents) throws IOException {
539  
    if (!new File(fileName).exists())
540  
      return defaultContents;
541  
542  
    FileInputStream fileInputStream = new FileInputStream(fileName);
543  
    InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, charsetForTextFiles);
544  
    return loadTextFile(inputStreamReader, (int) new File(fileName).length());
545  
  }
546  
547  
  public static String loadTextFile(Reader reader, int length) throws IOException {
548  
    try {
549  
      char[] chars = new char[length];
550  
      int n = reader.read(chars);
551  
      return new String(chars, 0, n);
552  
    } finally {
553  
      reader.close();
554  
    }
555  
  }
556  
557  
  static File DiskSnippetCache_dir;
558  
559  
  public static void initDiskSnippetCache(File dir) {
560  
    DiskSnippetCache_dir = dir;
561  
    dir.mkdirs();
562  
  }
563  
564  
  // Data files are immutable, use centralized cache
565  
  public static synchronized File DiskSnippetCache_getLibrary(long snippetID) throws IOException {
566  
    File file = new File(getGlobalCache(), "data_" + snippetID + ".jar");
567  
    if (verbose)
568  
      System.out.println("Checking data cache: " + file.getPath());
569  
    return file.exists() ? file : null;
570  
  }
571  
572  
  public static synchronized String DiskSnippetCache_get(long snippetID) throws IOException {
573  
    return loadTextFile(DiskSnippetCache_getFile(snippetID).getPath(), null);
574  
  }
575  
576  
  private static File DiskSnippetCache_getFile(long snippetID) {
577  
    return new File(DiskSnippetCache_dir, "" + snippetID);
578  
  }
579  
580  
  public static synchronized void DiskSnippetCache_put(long snippetID, String snippet) throws IOException {
581  
    saveTextFile(DiskSnippetCache_getFile(snippetID).getPath(), snippet);
582  
  }
583  
584  
  public static synchronized void DiskSnippetCache_putLibrary(long snippetID, byte[] data) throws IOException {
585  
    saveBinaryFile(new File(getGlobalCache(), "data_" + snippetID).getPath() + ".jar", data);
586  
  }
587  
588  
  public static File DiskSnippetCache_getDir() {
589  
    return DiskSnippetCache_dir;
590  
  }
591  
592  
  public static void initSnippetCache() {
593  
    if (DiskSnippetCache_dir == null)
594  
      initDiskSnippetCache(getGlobalCache());
595  
  }
596  
597  
  private static File getGlobalCache() {
598  
    File file = new File(System.getProperty("user.home"), ".tinybrain/snippet-cache");
599  
    file.mkdirs();
600  
    return file;
601  
  }
602  
603  
  public static String loadSnippetVerified(String snippetID, String hash) throws IOException {
604  
    String text = loadSnippet(snippetID);
605  
    String realHash = getHash(text.getBytes("UTF-8"));
606  
    if (!realHash.equals(hash)) {
607  
      String msg;
608  
      if (hash.isEmpty())
609  
        msg = "Here's your hash for " + snippetID + ", please put in your program: " + realHash;
610  
      else
611  
        msg = "Hash mismatch for " + snippetID + ": " + realHash + " (new) vs " + hash + " - has tinybrain.de been hacked??";
612  
      throw new RuntimeException(msg);
613  
    }
614  
    return text;
615  
  }
616  
617  
  public static String getHash(byte[] data) {
618  
    return bytesToHex(getFullFingerprint(data));
619  
  }
620  
621  
  public static byte[] getFullFingerprint(byte[] data) {
622  
    try {
623  
      return MessageDigest.getInstance("MD5").digest(data);
624  
    } catch (NoSuchAlgorithmException e) {
625  
      throw new RuntimeException(e);
626  
    }
627  
  }
628  
629  
  public static String bytesToHex(byte[] bytes) {
630  
    return bytesToHex(bytes, 0, bytes.length);
631  
  }
632  
633  
  public static String bytesToHex(byte[] bytes, int ofs, int len) {
634  
    StringBuilder stringBuilder = new StringBuilder(len*2);
635  
    for (int i = 0; i < len; i++) {
636  
      String s = "0" + Integer.toHexString(bytes[ofs+i]);
637  
      stringBuilder.append(s.substring(s.length()-2, s.length()));
638  
    }
639  
    return stringBuilder.toString();
640  
  }
641  
642  
  public static String loadSnippet(String snippetID) throws IOException {
643  
    return loadSnippet(parseSnippetID(snippetID));
644  
  }
645  
646  
  public static long parseSnippetID(String snippetID) {
647  
    return Long.parseLong(shortenSnippetID(snippetID));
648  
  }
649  
650  
  private static String shortenSnippetID(String snippetID) {
651  
    if (snippetID.startsWith("#"))
652  
      snippetID = snippetID.substring(1);
653  
    String httpBlaBla = "http://tinybrain.de/";
654  
    if (snippetID.startsWith(httpBlaBla))
655  
      snippetID = snippetID.substring(httpBlaBla.length());
656  
    return snippetID;
657  
  }
658  
659  
  public static boolean isSnippetID(String snippetID) {
660  
    snippetID = shortenSnippetID(snippetID);
661  
    return isInteger(snippetID) && Long.parseLong(snippetID) != 0;
662  
  }
663  
664  
  public static boolean isInteger(String s) {
665  
    return Pattern.matches("\\-?\\d+", s);
666  
  }
667  
668  
  public static String loadSnippet(long snippetID) throws IOException {
669  
    String text = memSnippetCache.get(snippetID);
670  
    if (text != null)
671  
      return text;
672  
673  
    initSnippetCache();
674  
    text = DiskSnippetCache_get(snippetID);
675  
    if (preferCached && text != null)
676  
      return text;
677  
678  
    String md5 = text != null ? md5(text) : "-";
679  
    if (text != null) {
680  
      String hash = prefetched.get(snippetID);
681  
      if (hash != null) {
682  
        if (md5.equals(hash)) {
683  
          memSnippetCache.put(snippetID, text);
684  
          return text;
685  
        } else
686  
          prefetched.remove(snippetID); // (maybe this is not necessary)
687  
      }
688  
    }
689  
690  
    try {
691  
      /*URL url = new URL("http://tinybrain.de:8080/getraw.php?id=" + snippetID);
692  
      text = loadPage(url);*/
693  
      String theURL = "http://tinybrain.de:8080/getraw.php?id=" + snippetID + "&getmd5=1&utf8=1";
694  
      if (text != null) {
695  
        //System.err.println("MD5: " + md5);
696  
        theURL += "&md5=" + md5;
697  
      }
698  
      URL url = new URL(theURL);
699  
      String page = loadPage(url);
700  
      if (page.startsWith("==*#*==")) {
701  
        // same, keep text
702  
        //System.err.println("Snippet unchanged, keeping.");
703  
      } else {
704  
        // drop md5 line
705  
        int i = page.indexOf('\n');
706  
        String hash = page.substring(0, i).trim();
707  
        text = page.substring(i+1);
708  
709  
        String myHash = md5(text);
710  
        if (myHash.equals(hash)) {
711  
          //System.err.println("Hash match: " + hash);
712  
        } else
713  
          System.err.println("Hash mismatch");
714  
      }
715  
    } catch (FileNotFoundException e) {
716  
      throw new IOException("Snippet #" + snippetID + " not found or not public");
717  
    }
718  
719  
    memSnippetCache.put(snippetID, text);
720  
721  
    try {
722  
      initSnippetCache();
723  
      DiskSnippetCache_put(snippetID, text);
724  
    } catch (IOException e) {
725  
      System.err.println("Minor warning: Couldn't save snippet to cache ("  + DiskSnippetCache_getDir() + ")");
726  
    }
727  
728  
    return text;
729  
  }
730  
731  
  private static String md5(String text) {
732  
    try {
733  
      return bytesToHex(md5impl(text.getBytes("UTF-8"))); // maybe different than the way PHP does it...
734  
    } catch (UnsupportedEncodingException e) {
735  
      throw new RuntimeException(e);
736  
    }
737  
  }
738  
739  
  public static byte[] md5impl(byte[] data) {
740  
    try {
741  
      return MessageDigest.getInstance("MD5").digest(data);
742  
    } catch (NoSuchAlgorithmException e) {
743  
      throw new RuntimeException(e);
744  
    }
745  
  }
746  
747  
  private static String loadPage(URL url) throws IOException {
748  
    System.err.println("Loading: " + url.toExternalForm());
749  
    URLConnection con = url.openConnection();
750  
    return loadPage(con, url);
751  
  }
752  
753  
  public static String loadPage(URLConnection con, URL url) throws IOException {
754  
    setHeaders(con);
755  
    String contentType = con.getContentType();
756  
    if (contentType == null)
757  
      throw new IOException("Page could not be read: " + url);
758  
    //Log.info("Content-Type: " + contentType);
759  
    String charset = guessCharset(contentType);
760  
    //System.err.println("Charset: " + charset);
761  
    Reader r = new InputStreamReader(con.getInputStream(), charset);
762  
    StringBuilder buf = new StringBuilder();
763  
    while (true) {
764  
      int ch = r.read();
765  
      if (ch < 0)
766  
        break;
767  
      //Log.info("Chars read: " + buf.length());
768  
      buf.append((char) ch);
769  
    }
770  
    return buf.toString();
771  
  }
772  
773  
  public static byte[] loadBinaryPage(URLConnection con) throws IOException {
774  
    setHeaders(con);
775  
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
776  
    InputStream inputStream = con.getInputStream();
777  
    while (true) {
778  
      int ch = inputStream.read();
779  
      if (ch < 0)
780  
        break;
781  
      buf.write(ch);
782  
    }
783  
    inputStream.close();
784  
    return buf.toByteArray();
785  
  }
786  
787  
  private static void setHeaders(URLConnection con) throws IOException {
788  
    String computerID = getComputerID();
789  
    if (computerID != null)
790  
      con.setRequestProperty("X-ComputerID", computerID);
791  
  }
792  
793  
  public static String guessCharset(String contentType) {
794  
    Pattern p = Pattern.compile("text/html;\\s+charset=([^\\s]+)\\s*");
795  
    Matcher m = p.matcher(contentType);
796  
    /* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */
797  
    return m.matches() ? m.group(1) : "ISO-8859-1";
798  
  }
799  
800  
  /** runs a transpiled set of sources */
801  
  public static void javax2(File srcDir, File ioBaseDir, boolean silent, boolean runInProcess,
802  
                            List<File> libraries, String[] args, String cacheAs) throws Exception {
803  
    File classesDir = TempDirMaker_make();
804  
    String javacOutput = compileJava(srcDir, libraries, classesDir);
805  
806  
    // run
807  
808  
    if (verbose) System.out.println("Running program (" + srcDir.getAbsolutePath()
809  
      + ") on io dir " + ioBaseDir.getAbsolutePath() + (runInProcess ? "[in-process]" : "") + "\n");
810  
    runProgram(javacOutput, classesDir, ioBaseDir, silent, runInProcess, libraries, args, cacheAs);
811  
  }
812  
813  
  static String compileJava(File srcDir, List<File> libraries, File classesDir) throws IOException {
814  
    ++compilations;
815  
816  
    // collect sources
817  
818  
    List<File> sources = new ArrayList<File>();
819  
    if (verbose) System.out.println("Scanning for sources in " + srcDir.getPath());
820  
    scanForSources(srcDir, sources, true);
821  
    if (sources.isEmpty())
822  
      throw new IOException("No sources found");
823  
824  
    // compile
825  
826  
    File optionsFile = File.createTempFile("javax", "");
827  
    if (verbose) System.out.println("Compiling " + sources.size() + " source(s) to " + classesDir.getPath());
828  
    String options = "-d " + bashQuote(classesDir.getPath());
829  
    writeOptions(sources, libraries, optionsFile, options);
830  
    classesDir.mkdirs();
831  
    return invokeJavac(optionsFile);
832  
  }
833  
834  
  private static void runProgram(String javacOutput, File classesDir, File ioBaseDir,
835  
                                 boolean silent, boolean runInProcess,
836  
                                 List<File> libraries, String[] args, String cacheAs) throws Exception {
837  
    // print javac output if compile failed and it hasn't been printed yet
838  
    boolean didNotCompile = !didCompile(classesDir);
839  
    if (verbose || didNotCompile)
840  
      System.out.println(javacOutput);
841  
    if (didNotCompile)
842  
      return;
843  
844  
    if (runInProcess
845  
      || (ioBaseDir.getAbsolutePath().equals(new File(".").getAbsolutePath()) && !silent)) {
846  
      runProgramQuick(classesDir, libraries, args, cacheAs);
847  
      return;
848  
    }
849  
850  
    boolean echoOK = false;
851  
    // TODO: add libraries to class path
852  
    String bashCmd = "(cd " + bashQuote(ioBaseDir.getAbsolutePath()) + " && (java -cp "
853  
      + bashQuote(classesDir.getAbsolutePath()) + " main" + (echoOK ? "; echo ok" : "") + "))";
854  
    if (verbose) System.out.println(bashCmd);
855  
    String output = backtick(bashCmd);
856  
    if (verbose || !silent)
857  
      System.out.println(output);
858  
  }
859  
860  
  static boolean didCompile(File classesDir) {
861  
    return hasFile(classesDir, "main.class");
862  
  }
863  
864  
  private static void runProgramQuick(File classesDir, List<File> libraries,
865  
                                      String[] args, String cacheAs) throws Exception {
866  
    // collect urls
867  
    URL[] urls = new URL[libraries.size()+1];
868  
    urls[0] = classesDir.toURI().toURL();
869  
    for (int i = 0; i < libraries.size(); i++)
870  
      urls[i+1] = libraries.get(i).toURI().toURL();
871  
872  
    // make class loader
873  
    URLClassLoader classLoader = new URLClassLoader(urls);
874  
875  
    // load JavaX main class
876  
    Class<?> mainClass = classLoader.loadClass("main");
877  
878  
    if (cacheAs != null)
879  
      programCache.put(cacheAs, mainClass);
880  
881  
    // run main method
882  
    Method main = mainClass.getMethod("main", String[].class);
883  
    main.invoke(null, (Object) args);
884  
  }
885  
886  
  private static String invokeJavac(File optionsFile) throws IOException {
887  
    String output;
888  
    try {
889  
      output = invokeEcj(optionsFile);
890  
    } catch (NoClassDefFoundError e) {
891  
      if (verbose) {
892  
        System.err.println("ecj not found - using javac");
893  
        e.printStackTrace();
894  
      }
895  
      output = backtick("javac " + bashQuote("@" + optionsFile.getPath()));
896  
    }
897  
    if (verbose) System.out.println(output);
898  
    return output;
899  
  }
900  
901  
  // throws ClassNotFoundError if ecj is not in classpath
902  
  static String invokeEcj(File optionsFile) {
903  
    StringWriter writer = new StringWriter();
904  
    PrintWriter printWriter = new PrintWriter(writer);
905  
    org.eclipse.jdt.core.compiler.CompilationProgress progress = null;
906  
907  
    // add more eclipse options in the line below
908  
909  
    org.eclipse.jdt.core.compiler.batch.BatchCompiler.compile(
910  
      new String[] { "@" + optionsFile.getPath(),
911  
        "-source", "1.7",
912  
        "-nowarn"
913  
      },
914  
      printWriter,
915  
      printWriter,
916  
      progress);
917  
    return writer.toString();
918  
  }
919  
920  
  private static void writeOptions(List<File> sources, List<File> libraries,
921  
                                   File optionsFile, String moreOptions) throws IOException {
922  
    FileWriter writer = new FileWriter(optionsFile);
923  
    for (File source : sources)
924  
      writer.write(bashQuote(source.getPath()) + " ");
925  
    if (!libraries.isEmpty()) {
926  
      List<String> cp = new ArrayList<String>();
927  
      for (File lib : libraries)
928  
        cp.add(lib.getAbsolutePath());
929  
      writer.write("-cp " + bashQuote(join(File.pathSeparator, cp)) + " ");
930  
    }
931  
    writer.write(moreOptions);
932  
    writer.close();
933  
  }
934  
935  
  static void scanForSources(File source, List<File> sources, boolean topLevel) {
936  
    if (source.isFile() && source.getName().endsWith(".java"))
937  
      sources.add(source);
938  
    else if (source.isDirectory() && !isSkippedDirectoryName(source.getName(), topLevel)) {
939  
      File[] files = source.listFiles();
940  
      for (File file : files)
941  
        scanForSources(file, sources, false);
942  
    }
943  
  }
944  
945  
  private static boolean isSkippedDirectoryName(String name, boolean topLevel) {
946  
    if (topLevel) return false; // input or output ok as highest directory (intentionally specified by user, not just found by a directory scan in which case we probably don't want it. it's more like heuristics actually.)
947  
    return name.equalsIgnoreCase("input") || name.equalsIgnoreCase("output");
948  
  }
949  
950  
  public static String backtick(String cmd) throws IOException {
951  
    ++processesStarted;
952  
    File outFile = File.createTempFile("_backtick", "");
953  
    File scriptFile = File.createTempFile("_backtick", isWindows() ? ".bat" : "");
954  
955  
    String command = cmd + ">" + bashQuote(outFile.getPath()) + " 2>&1";
956  
    //Log.info("[Backtick] " + command);
957  
    try {
958  
      saveTextFile(scriptFile.getPath(), command);
959  
      String[] command2;
960  
      if (isWindows())
961  
        command2 = new String[] { scriptFile.getPath() };
962  
      else
963  
        command2 = new String[] { "/bin/bash", scriptFile.getPath() };
964  
      Process process = Runtime.getRuntime().exec(command2);
965  
      try {
966  
        process.waitFor();
967  
      } catch (InterruptedException e) {
968  
        throw new RuntimeException(e);
969  
      }
970  
      process.exitValue();
971  
      return loadTextFile(outFile.getPath(), "");
972  
    } finally {
973  
      scriptFile.delete();
974  
    }
975  
  }
976  
977  
  /** possibly improvable */
978  
  public static String javaQuote(String text) {
979  
    return bashQuote(text);
980  
  }
981  
982  
  /** possibly improvable */
983  
  public static String bashQuote(String text) {
984  
    if (text == null) return null;
985  
    return "\"" + text
986  
      .replace("\\", "\\\\")
987  
      .replace("\"", "\\\"")
988  
      .replace("\n", "\\n")
989  
      .replace("\r", "\\r") + "\"";
990  
  }
991  
992  
  public final static String charsetForTextFiles = "UTF8";
993  
994  
  static long TempDirMaker_lastValue;
995  
996  
  public static File TempDirMaker_make() {
997  
    File dir = new File(System.getProperty("user.home"), ".javax/" + TempDirMaker_newValue());
998  
    dir.mkdirs();
999  
    return dir;
1000  
  }
1001  
1002  
  private static long TempDirMaker_newValue() {
1003  
    long value;
1004  
    do
1005  
      value = System.currentTimeMillis();
1006  
    while (value == TempDirMaker_lastValue);
1007  
    TempDirMaker_lastValue = value;
1008  
    return value;
1009  
  }
1010  
1011  
  public static String join(String glue, Iterable<String> strings) {
1012  
    StringBuilder buf = new StringBuilder();
1013  
    Iterator<String> i = strings.iterator();
1014  
    if (i.hasNext()) {
1015  
      buf.append(i.next());
1016  
      while (i.hasNext())
1017  
        buf.append(glue).append(i.next());
1018  
    }
1019  
    return buf.toString();
1020  
  }
1021  
1022  
  public static boolean isWindows() {
1023  
    return System.getProperty("os.name").contains("Windows");
1024  
  }
1025  
1026  
  public static String makeRandomID(int length) {
1027  
    Random random = new Random();
1028  
    char[] id = new char[length];
1029  
    for (int i = 0; i< id.length; i++)
1030  
      id[i] = (char) ((int) 'a' + random.nextInt(26));
1031  
    return new String(id);
1032  
  }
1033  
1034  
  static String computerID;
1035  
  public static String getComputerID() throws IOException {
1036  
    if (noID) return null;
1037  
    if (computerID == null) {
1038  
      File file = new File(System.getProperty("user.home"), ".tinybrain/computer-id");
1039  
      computerID = loadTextFile(file.getPath(), null);
1040  
      if (computerID == null) {
1041  
        computerID = makeRandomID(12);
1042  
        saveTextFile(file.getPath(), computerID);
1043  
      }
1044  
      if (verbose)
1045  
        System.out.println("Local computer ID: " + computerID);
1046  
    }
1047  
    return computerID;
1048  
  }
1049  
}

Author comment

Began life as a copy of #2000469

download  show line numbers   

Snippet is not live.

Travelled to 12 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

Comments [hide]

ID Author/Program Comment Date
679 #1000610 Edit suggestion:
!636
!629

main {
static Object androidContext;
static String programID;

public static void main(String[] args) throws Exception {
/**
JavaX runner version 16

Changes to v15:
-fixed caching bug
-remove "hash match" messages on System.err
-cache transpiled translators

*/

class _x16 {
static final String version = "JavaX 16";

static boolean verbose = false, translate = false, list = false, virtualizeTranslators = true;
static String translateTo = null;
static boolean preferCached = false, safeOnly = false, noID = false;
static List<String[]> mainTranslators = new ArrayList<String[]>();
private static Map<Long, String> memSnippetCache = new HashMap<Long, String>();
private static int processesStarted, compilations;

// snippet ID -> md5
private static HashMap<Long, String> prefetched = new HashMap<Long, String>();
private static File virtCache;

// doesn't work yet
private static Map<String, Class<?>> programCache = new HashMap<String, Class<?>>();
static boolean cacheTranslators = false;

// this should work (caches transpiled translators)
private static HashMap<Long, Object[]> translationCache = new HashMap<Long, Object[]>();
static boolean cacheTranspiledTranslators = true;

public static void main(String[] args) throws Exception {
File ioBaseDir = new File("."), inputDir = null, outputDir = null;
String src = null;
List<String> programArgs = new ArrayList<String>();

for (int i = 0; i < args.length; i++) {
String arg = args[i];
if (arg.equals("-v") || arg.equals("-verbose"))
verbose = true;
else if (arg.equals("-finderror"))
verbose = true;
else if (arg.equals("-offline") || arg.equalsIgnoreCase("-prefercached"))
preferCached = true;
else if (arg.equals("-novirt"))
virtualizeTranslators = false;
else if (arg.equals("-safeonly"))
safeOnly = true;
else if (arg.equals("-noid"))
noID = true;
else if (arg.equals("-nocachetranspiled"))
cacheTranspiledTranslators = false;
else if (arg.equals("translate"))
translate = true;
else if (arg.equals("list")) {
list = true;
virtualizeTranslators = false; // so they are silenced
} else if (arg.equals("run")) {
// it's the default command anyway
} else if (arg.startsWith("input="))
inputDir = new File(arg.substring(6));
else if (arg.startsWith("output="))
outputDir = new File(arg.substring(7));
else if (arg.equals("with"))
mainTranslators.add(new String[] {args[++i], null});
else if (translate && arg.equals("to"))
translateTo = args[++i];
else if (src == null) {
//System.out.println("src=" + arg);
src = arg;
} else
programArgs.add(arg);
}

if (src == null) src = ".";

// Might actually want to write to 2 disk caches (global/per program).
if (virtualizeTranslators && !preferCached)
virtCache = TempDirMaker_make();

if (inputDir != null) {
ioBaseDir = TempDirMaker_make();
System.out.println("Taking input from: " + inputDir.getAbsolutePath());
System.out.println("Output is in: " + new File(ioBaseDir, "output").getAbsolutePath());
copyInput(inputDir, new File(ioBaseDir, "input"));
}

javaxmain(src, ioBaseDir, translate, list, programArgs.toArray(new String[programArgs.size()]));

if (outputDir != null) {
copyInput(new File(ioBaseDir, "output"), outputDir);
System.out.println("Output copied to: " + outputDir.getAbsolutePath());
}

if (verbose) {
// print stats
System.out.println("Processes started: " + processesStarted + ", compilations: " + compilations);
}
}

public static void javaxmain(String src, File ioDir, boolean translate, boolean list,
String[] args) throws Exception {
File srcDir;
if (isSnippetID(src)) {
prefetch(src);
srcDir = loadSnippetAsMainJava(src);
} else {
srcDir = new File(src);

// if the argument is a file, it is assumed to be main.java
if (srcDir.isFile()) {
srcDir = TempDirMaker_make();
copy(new File(src), new File(srcDir, "main.java"));
}

if (!new File(srcDir, "main.java").exists()) {
System.out.println("This is " + version + ".\n" +
"No main.java found, exiting");
return;
}
}

// translate

List<File> libraries = new ArrayList<File>();
File X = topLevelTranslate(srcDir, libraries);

// save prefetch data
if (isSnippetID(src))
savePrefetchData(src);

// list or run

if (translate) {
File to = X;
if (translateTo != null)
if (new File(translateTo).isDirectory())
to = new File(translateTo, "main.java");
else
to = new File(translateTo);
if (to != X)
copy(new File(X, "main.java"), to);
System.out.println("Program translated to: " + to.getAbsolutePath());
} else if (list)
System.out.println(loadTextFile(new File(X, "main.java").getPath(), null));
else
javax2(X, ioDir, false, false, libraries, args, null);
}

private static void prefetch(String mainSnippetID) throws IOException {
long mainID = parseSnippetID(mainSnippetID);
String s = mainID + " " + loadTextFile(new File(".tinybrain/prefetch/" + mainID + ".txt").getPath(), "");
String[] ids = s.trim().split(" ");
if (ids.length > 1) {
String url = "http://tinybrain.de:8080/tb-int/prefetch.php?ids=" + URLEncoder.encode(s, "UTF-8");
String data = loadPage(new URL(url));
String[] split = data.split(" ");
if (split.length == ids.length)
for (int i = 0; i < ids.length; i++)
prefetched.put(parseSnippetID(ids[i]), split[i]);
}
}

private static void savePrefetchData(String mainSnippetID) throws IOException {
List<String> ids = new ArrayList<String>();
long mainID = parseSnippetID(mainSnippetID);

for (long id : memSnippetCache.keySet())
if (id != mainID)
ids.add(String.valueOf(id));

saveTextFile(new File(".tinybrain/prefetch/" + mainID + ".txt").getPath(), join(" ", ids));
}

static File topLevelTranslate(File srcDir, List<File> libraries_out) throws Exception {
File X = srcDir;
X = applyTranslators(X, mainTranslators, libraries_out);
X = defaultTranslate(X, libraries_out);
return X;
}

private static File defaultTranslate(File x, List<File> libraries_out) throws Exception {
x = luaPrintToJavaPrint(x);
x = repeatAutoTranslate(x, libraries_out);
return x;
}

private static File repeatAutoTranslate(File x, List<File> libraries_out) throws Exception {
while (true) {
File y = autoTranslate(x, libraries_out);
if (y == x)
return x;
x = y;
}
}

private static File autoTranslate(File x, List<File> libraries_out) throws Exception {
String main = loadTextFile(new File(x, "main.java").getPath(), null);
List<String> lines = toLines(main);
List<String[]> translators = findTranslators(lines);
if (translators.isEmpty())
return x;

main = fromLines(lines);
File newDir = TempDirMaker_make();
saveTextFile(new File(newDir, "main.java").getPath(), main);
return applyTranslators(newDir, translators, libraries_out);
}

private static List<String[]> findTranslators(List<String> lines) {
List<String[]> translators = new ArrayList<String[]>();
Pattern pattern = Pattern.compile("^!([0-9# \t]+)");
Pattern pArgs = Pattern.compile("^\\s*\\((.*)\\)");
for (ListIterator<String> iterator = lines.listIterator(); iterator.hasNext(); ) {
String line = iterator.next();
line = line.trim();
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
String[] t = matcher.group(1).split("[ \t]+");
String rest = line.substring(matcher.end());
String arg = null;
if (t.length == 1) {
Matcher mArgs = pArgs.matcher(rest);
if (mArgs.find())
arg = mArgs.group(1);
}
for (String transi : t)
translators.add(new String[]{transi, arg});
iterator.remove();
}
}
return translators;
}

public static List<String> toLines(String s) {
List<String> lines = new ArrayList<String>();
int start = 0;
while (true) {
int i = toLines_nextLineBreak(s, start);
if (i < 0) {
if (s.length() > start) lines.add(s.substring(start));
break;
}

lines.add(s.substring(start, i));
if (s.charAt(i) == '\r' && i+1 < s.length() && s.charAt(i+1) == '\n')
i += 2;
else
++i;

start = i;
}
return lines;
}

private static int toLines_nextLineBreak(String s, int start) {
for (int i = start; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '\r' || c == '\n')
return i;
}
return -1;
}

public static String fromLines(List<String> lines) {
StringBuilder buf = new StringBuilder();
for (String line : lines) {
buf.append(line).append('\n');
}
return buf.toString();
}

private static File applyTranslators(File x, List<String[]> translators, List<File> libraries_out) throws Exception {
for (String[] translator : translators)
x = applyTranslator(x, translator[0], translator[1], libraries_out);
return x;
}

// also takes a library
private static File applyTranslator(File x, String translator, String arg, List<File> libraries_out) throws Exception {
if (verbose)
System.out.println("Using translator " + translator + " on sources in " + x.getPath());

File newDir = runTranslatorOnInput(translator, null, arg, x, !verbose, libraries_out);

if (!new File(newDir, "main.java").exists()) {
throw new Exception("Translator " + translator + " did not generate main.java");
// TODO: show translator output
}
if (verbose)
System.out.println("Translated with " + translator + " from " + x.getPath() + " to " + newDir.getPath());
x = newDir;
return x;
}

private static File luaPrintToJavaPrint(File x) throws IOException {
File newDir = TempDirMaker_make();
String code = loadTextFile(new File(x, "main.java").getPath(), null);
code = luaPrintToJavaPrint(code);
if (verbose)
System.out.println(code);
saveTextFile(new File(newDir, "main.java").getPath(), code);
return newDir;
}

public static String luaPrintToJavaPrint(String code) {
return ("\n" + code).replaceAll(
"(\n\\s*)print (\".*\")",
"$1System.out.println($2);").substring(1);
}

public static File loadSnippetAsMainJava(String snippetID) throws IOException {
checkProgramSafety(snippetID);
File srcDir = TempDirMaker_make();
saveTextFile(new File(srcDir, "main.java").getPath(), loadSnippet(snippetID));
return srcDir;
}

public static File loadSnippetAsMainJavaVerified(String snippetID, String hash) throws IOException {
checkProgramSafety(snippetID);
File srcDir = TempDirMaker_make();
saveTextFile(new File(srcDir, "main.java").getPath(), loadSnippetVerified(snippetID, hash));
return srcDir;
}

/** returns output dir */
private static File runTranslatorOnInput(String snippetID, String hash, String arg, File input,
boolean silent,
List<File> libraries_out) throws Exception {
File libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(snippetID));
if (libraryFile != null) {
loadLibrary(snippetID, libraries_out, libraryFile);
return input;
}

String[] args = arg != null ? new String[]{arg} : new String[0];

File srcDir = hash == null ? loadSnippetAsMainJava(snippetID)
: loadSnippetAsMainJavaVerified(snippetID, hash);
long mainJavaSize = new File(srcDir, "main.java").length();

if (mainJavaSize == 0) { // no text in snippet? assume it's a library
loadLibrary(snippetID, libraries_out, libraryFile);
return input;
}

File ioBaseDir = TempDirMaker_make();

/*Class<?> mainClass = programCache.get("" + parseSnippetID(snippetID));
if (mainClass != null)
return runCached(ioBaseDir, input, args);*/
// Doesn't work yet because virtualized directories are hardcoded in translator...

List<File> libraries = new ArrayList<File>();
Object[] cached = translationCache.get(parseSnippetID(snippetID));
if (cached != null) {
//System.err.println("Taking translator " + snippetID + " from cache!");
srcDir = (File) cached[0];
libraries = (List<File>) cached[1];
} else {
srcDir = defaultTranslate(srcDir, libraries);
if (cacheTranspiledTranslators)
translationCache.put(parseSnippetID(snippetID), new Object[] {srcDir, libraries});
}
boolean runInProcess = false;

if (virtualizeTranslators) {
if (verbose) System.out.println("Virtualizing translator");

//srcDir = applyTranslator(srcDir, "#2000351"); // I/O-virtualize the translator
// that doesn't work because it recurses infinitely...

// So we do it right here:
String s = loadTextFile(new File(srcDir, "main.java").getPath(), null);
s = s.replaceAll("new\\s+File\\(", "virtual.newFile(");
s = s.replaceAll("new\\s+FileInputStream\\(", "virtual.newFileInputStream(");
s = s.replaceAll("new\\s+FileOutputStream\\(", "virtual.newFileOutputStream(");
s += "\n\n" + loadSnippet("#2000355"); // load class virtual

// change baseDir
s = s.replace("virtual_baseDir = \"\";",
"virtual_baseDir = " + javaQuote(ioBaseDir.getAbsolutePath()) + ";");

// forward snippet cache (virtualized one)
File dir = virtCache != null ? virtCache : DiskSnippetCache_dir;
s = s.replace("static File DiskSnippetCache_dir;",
"static File DiskSnippetCache_dir = new File(" + javaQuote(dir.getAbsolutePath()) + ");");
s = s.replace("static boolean preferCached = false;", "static boolean preferCached = true;");

if (verbose) {
System.out.println("==BEGIN VIRTUALIZED TRANSLATOR==");
System.out.println(s);
System.out.println("==END VIRTUALIZED TRANSLATOR==");
}
srcDir = TempDirMaker_make();
saveTextFile(new File(srcDir, "main.java").getPath(), s);

// TODO: silence translator also
runInProcess = true;
}

return runJavaX(ioBaseDir, srcDir, input, silent, runInProcess, libraries,
args, cacheTranslators ? "" + parseSnippetID(snippetID) : null);
}

static void checkProgramSafety(String snippetID) throws IOException {
if (!safeOnly) return;
URL url = new URL("http://tinybrain.de:8080/tb-int/is-javax-safe.php?id=" + parseSnippetID(snippetID));
String text = loadPage(url);
if (!text.startsWith("{\"safe\":\"1\"}"))
throw new RuntimeException("Translator not safe: #" + parseSnippetID(snippetID));
}

private static void loadLibrary(String snippetID, List<File> libraries_out, File libraryFile) throws IOException {
if (verbose)
System.out.println("Assuming " + snippetID + " is a library.");

if (libraryFile == null) {
byte[] data = loadDataSnippetImpl(snippetID);
DiskSnippetCache_putLibrary(parseSnippetID(snippetID), data);
libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(snippetID));
}

if (!libraries_out.contains(libraryFile))
libraries_out.add(libraryFile);
}

private static byte[] loadDataSnippetImpl(String snippetID) throws IOException {
byte[] data;
try {
URL url = new URL("http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_"
+ parseSnippetID(snippetID) + "&contentType=application/binary");
System.err.println("Loading library: " + url);
data = loadBinaryPage(url.openConnection());
if (verbose)
System.err.println("Bytes loaded: " + data.length);
} catch (FileNotFoundException e) {
throw new IOException("Binary snippet #" + snippetID + " not found or not public");
}
return data;
}

/** returns output dir */
private static File runJavaX(File ioBaseDir, File originalSrcDir, File originalInput,
boolean silent, boolean runInProcess,
List<File> libraries, String[] args, String cacheAs) throws Exception {
File srcDir = new File(ioBaseDir, "src");
File inputDir = new File(ioBaseDir, "input");
File outputDir = new File(ioBaseDir, "output");
copyInput(originalSrcDir, srcDir);
copyInput(originalInput, inputDir);
javax2(srcDir, ioBaseDir, silent, runInProcess, libraries, args, cacheAs);
return outputDir;
}

private static void copyInput(File src, File dst) throws IOException {
copyDirectory(src, dst);
}

public static boolean hasFile(File inputDir, String name) {
return new File(inputDir, name).exists();
}

public static void copyDirectory(File src, File dst) throws IOException {
if (verbose) System.out.println("Copying " + src.getAbsolutePath() + " to " + dst.getAbsolutePath());
dst.mkdirs();
File[] files = src.listFiles();
if (files == null) return;
for (File file : files) {
File dst1 = new File(dst, file.getName());
if (file.isDirectory())
copyDirectory(file, dst1);
else {
if (verbose) System.out.println("Copying " + file.getAbsolutePath() + " to " + dst1.getAbsolutePath());
copy(file, dst1);
}
}
}

/** Quickly copy a file without a progress bar or any other fancy GUI... :) */
public static void copy(File src, File dest) throws IOException {
FileInputStream inputStream = new FileInputStream(src);
FileOutputStream outputStream = new FileOutputStream(dest);
try {
copy(inputStream, outputStream);
inputStream.close();
} finally {
outputStream.close();
}
}

public static void copy(InputStream in, OutputStream out) throws IOException {
byte[] buf = new byte[65536];
while (true) {
int n = in.read(buf);
if (n <= 0) return;
out.write(buf, 0, n);
}
}

/** writes safely (to temp file, then rename) */
public static void saveTextFile(String fileName, String contents) throws IOException {
File file = new File(fileName);
File parentFile = file.getParentFile();
if (parentFile != null)
parentFile.mkdirs();
String tempFileName = fileName + "_temp";
FileOutputStream fileOutputStream = new FileOutputStream(tempFileName);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, charsetForTextFiles);
PrintWriter printWriter = new PrintWriter(outputStreamWriter);
printWriter.print(contents);
printWriter.close();
if (file.exists() && !file.delete())
throw new IOException("Can't delete " + fileName);

if (!new File(tempFileName).renameTo(file))
throw new IOException("Can't rename " + tempFileName + " to " + fileName);
}

/** writes safely (to temp file, then rename) */
public static void saveBinaryFile(String fileName, byte[] contents) throws IOException {
File file = new File(fileName);
File parentFile = file.getParentFile();
if (parentFile != null)
parentFile.mkdirs();
String tempFileName = fileName + "_temp";
FileOutputStream fileOutputStream = new FileOutputStream(tempFileName);
fileOutputStream.write(contents);
fileOutputStream.close();
if (file.exists() && !file.delete())
throw new IOException("Can't delete " + fileName);

if (!new File(tempFileName).renameTo(file))
throw new IOException("Can't rename " + tempFileName + " to " + fileName);
}

public static String loadTextFile(String fileName, String defaultContents) throws IOException {
if (!new File(fileName).exists())
return defaultContents;

FileInputStream fileInputStream = new FileInputStream(fileName);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, charsetForTextFiles);
return loadTextFile(inputStreamReader, (int) new File(fileName).length());
}

public static String loadTextFile(Reader reader, int length) throws IOException {
try {
char[] chars = new char[length];
int n = reader.read(chars);
return new String(chars, 0, n);
} finally {
reader.close();
}
}

static File DiskSnippetCache_dir;

public static void initDiskSnippetCache(File dir) {
DiskSnippetCache_dir = dir;
dir.mkdirs();
}

// Data files are immutable, use centralized cache
public static synchronized File DiskSnippetCache_getLibrary(long snippetID) throws IOException {
File file = new File(getGlobalCache(), "data_" + snippetID + ".jar");
if (verbose)
System.out.println("Checking data cache: " + file.getPath());
return file.exists() ? file : null;
}

public static synchronized String DiskSnippetCache_get(long snippetID) throws IOException {
return loadTextFile(DiskSnippetCache_getFile(snippetID).getPath(), null);
}

private static File DiskSnippetCache_getFile(long snippetID) {
return new File(DiskSnippetCache_dir, "" + snippetID);
}

public static synchronized void DiskSnippetCache_put(long snippetID, String snippet) throws IOException {
saveTextFile(DiskSnippetCache_getFile(snippetID).getPath(), snippet);
}

public static synchronized void DiskSnippetCache_putLibrary(long snippetID, byte[] data) throws IOException {
saveBinaryFile(new File(getGlobalCache(), "data_" + snippetID).getPath() + ".jar", data);
}

public static File DiskSnippetCache_getDir() {
return DiskSnippetCache_dir;
}

public static void initSnippetCache() {
if (DiskSnippetCache_dir == null)
initDiskSnippetCache(getGlobalCache());
}

private static File getGlobalCache() {
File file = new File(System.getProperty("user.home"), ".tinybrain/snippet-cache");
file.mkdirs();
return file;
}

public static String loadSnippetVerified(String snippetID, String hash) throws IOException {
String text = loadSnippet(snippetID);
String realHash = getHash(text.getBytes("UTF-8"));
if (!realHash.equals(hash)) {
String msg;
if (hash.isEmpty())
msg = "Here's your hash for " + snippetID + ", please put in your program: " + realHash;
else
msg = "Hash mismatch for " + snippetID + ": " + realHash + " (new) vs " + hash + " - has tinybrain.de been hacked??";
throw new RuntimeException(msg);
}
return text;
}

public static String getHash(byte[] data) {
return bytesToHex(getFullFingerprint(data));
}

public static byte[] getFullFingerprint(byte[] data) {
try {
return MessageDigest.getInstance("MD5").digest(data);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}

public static String bytesToHex(byte[] bytes) {
return bytesToHex(bytes, 0, bytes.length);
}

public static String bytesToHex(byte[] bytes, int ofs, int len) {
StringBuilder stringBuilder = new StringBuilder(len*2);
for (int i = 0; i < len; i++) {
String s = "0" + Integer.toHexString(bytes[ofs+i]);
stringBuilder.append(s.substring(s.length()-2, s.length()));
}
return stringBuilder.toString();
}

public static String loadSnippet(String snippetID) throws IOException {
return loadSnippet(parseSnippetID(snippetID));
}

public static long parseSnippetID(String snippetID) {
return Long.parseLong(shortenSnippetID(snippetID));
}

private static String shortenSnippetID(String snippetID) {
if (snippetID.startsWith("#"))
snippetID = snippetID.substring(1);
String httpBlaBla = "http://tinybrain.de/";
if (snippetID.startsWith(httpBlaBla))
snippetID = snippetID.substring(httpBlaBla.length());
return snippetID;
}

public static boolean isSnippetID(String snippetID) {
snippetID = shortenSnippetID(snippetID);
return isInteger(snippetID) && Long.parseLong(snippetID) != 0;
}

public static boolean isInteger(String s) {
return Pattern.matches("\\-?\\d+", s);
}

public static String loadSnippet(long snippetID) throws IOException {
String text = memSnippetCache.get(snippetID);
if (text != null)
return text;

initSnippetCache();
text = DiskSnippetCache_get(snippetID);
if (preferCached && text != null)
return text;

String md5 = text != null ? md5(text) : "-";
if (text != null) {
String hash = prefetched.get(snippetID);
if (hash != null) {
if (md5.equals(hash)) {
memSnippetCache.put(snippetID, text);
return text;
} else
prefetched.remove(snippetID); // (maybe this is not necessary)
}
}

try {
/*URL url = new URL("http://tinybrain.de:8080/getraw.php?id=" + snippetID);
text = loadPage(url);*/
String theURL = "http://tinybrain.de:8080/getraw.php?id=" + snippetID + "&getmd5=1&utf8=1";
if (text != null) {
//System.err.println("MD5: " + md5);
theURL += "&md5=" + md5;
}
URL url = new URL(theURL);
String page = loadPage(url);
if (page.startsWith("==*#*==")) {
// same, keep text
//System.err.println("Snippet unchanged, keeping.");
} else {
// drop md5 line
int i = page.indexOf('\n');
String hash = page.substring(0, i).trim();
text = page.substring(i+1);

String myHash = md5(text);
if (myHash.equals(hash)) {
//System.err.println("Hash match: " + hash);
} else
System.err.println("Hash mismatch");
}
} catch (FileNotFoundException e) {
throw new IOException("Snippet #" + snippetID + " not found or not public");
}

memSnippetCache.put(snippetID, text);

try {
initSnippetCache();
DiskSnippetCache_put(snippetID, text);
} catch (IOException e) {
System.err.println("Minor warning: Couldn't save snippet to cache (" + DiskSnippetCache_getDir() + ")");
}

return text;
}

private static String md5(String text) {
try {
return bytesToHex(md5impl(text.getBytes("UTF-8"))); // maybe different than the way PHP does it...
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}

public static byte[] md5impl(byte[] data) {
try {
return MessageDigest.getInstance("MD5").digest(data);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}

private static String loadPage(URL url) throws IOException {
System.err.println("Loading: " + url.toExternalForm());
URLConnection con = url.openConnection();
return loadPage(con, url);
}

public static String loadPage(URLConnection con, URL url) throws IOException {
setHeaders(con);
String contentType = con.getContentType();
if (contentType == null)
throw new IOException("Page could not be read: " + url);
//Log.info("Content-Type: " + contentType);
String charset = guessCharset(contentType);
//System.err.println("Charset: " + charset);
Reader r = new InputStreamReader(con.getInputStream(), charset);
StringBuilder buf = new StringBuilder();
while (true) {
int ch = r.read();
if (ch < 0)
break;
//Log.info("Chars read: " + buf.length());
buf.append((char) ch);
}
return buf.toString();
}

public static byte[] loadBinaryPage(URLConnection con) throws IOException {
setHeaders(con);
ByteArrayOutputStream buf = new ByteArrayOutputStream();
InputStream inputStream = con.getInputStream();
while (true) {
int ch = inputStream.read();
if (ch < 0)
break;
buf.write(ch);
}
inputStream.close();
return buf.toByteArray();
}

private static void setHeaders(URLConnection con) throws IOException {
String computerID = getComputerID();
if (computerID != null)
con.setRequestProperty("X-ComputerID", computerID);
}

public static String guessCharset(String contentType) {
Pattern p = Pattern.compile("text/html;\\s+charset=([^\\s]+)\\s*");
Matcher m = p.matcher(contentType);
/* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */
return m.matches() ? m.group(1) : "ISO-8859-1";
}

/** runs a transpiled set of sources */
public static void javax2(File srcDir, File ioBaseDir, boolean silent, boolean runInProcess,
List<File> libraries, String[] args, String cacheAs) throws Exception {
File classesDir = TempDirMaker_make();
String javacOutput = compileJava(srcDir, libraries, classesDir);

// run

if (verbose) System.out.println("Running program (" + srcDir.getAbsolutePath()
+ ") on io dir " + ioBaseDir.getAbsolutePath() + (runInProcess ? "[in-process]" : "") + "\n");
runProgram(javacOutput, classesDir, ioBaseDir, silent, runInProcess, libraries, args, cacheAs);
}

static String compileJava(File srcDir, List<File> libraries, File classesDir) throws IOException {
++compilations;

// collect sources

List<File> sources = new ArrayList<File>();
if (verbose) System.out.println("Scanning for sources in " + srcDir.getPath());
scanForSources(srcDir, sources, true);
if (sources.isEmpty())
throw new IOException("No sources found");

// compile

File optionsFile = File.createTempFile("javax", "");
if (verbose) System.out.println("Compiling " + sources.size() + " source(s) to " + classesDir.getPath());
String options = "-d " + bashQuote(classesDir.getPath());
writeOptions(sources, libraries, optionsFile, options);
classesDir.mkdirs();
return invokeJavac(optionsFile);
}

private static void runProgram(String javacOutput, File classesDir, File ioBaseDir,
boolean silent, boolean runInProcess,
List<File> libraries, String[] args, String cacheAs) throws Exception {
// print javac output if compile failed and it hasn't been printed yet
boolean didNotCompile = !didCompile(classesDir);
if (verbose || didNotCompile)
System.out.println(javacOutput);
if (didNotCompile)
return;

if (runInProcess
|| (ioBaseDir.getAbsolutePath().equals(new File(".").getAbsolutePath()) && !silent)) {
runProgramQuick(classesDir, libraries, args, cacheAs);
return;
}

boolean echoOK = false;
// TODO: add libraries to class path
String bashCmd = "(cd " + bashQuote(ioBaseDir.getAbsolutePath()) + " && (java -cp "
+ bashQuote(classesDir.getAbsolutePath()) + " main" + (echoOK ? "; echo ok" : "") + "))";
if (verbose) System.out.println(bashCmd);
String output = backtick(bashCmd);
if (verbose || !silent)
System.out.println(output);
}

static boolean didCompile(File classesDir) {
return hasFile(classesDir, "main.class");
}

private static void runProgramQuick(File classesDir, List<File> libraries,
String[] args, String cacheAs) throws Exception {
// collect urls
URL[] urls = new URL[libraries.size()+1];
urls[0] = classesDir.toURI().toURL();
for (int i = 0; i < libraries.size(); i++)
urls[i+1] = libraries.get(i).toURI().toURL();

// make class loader
URLClassLoader classLoader = new URLClassLoader(urls);

// load JavaX main class
Class<?> mainClass = classLoader.loadClass("main");

if (cacheAs != null)
programCache.put(cacheAs, mainClass);

// run main method
Method main = mainClass.getMethod("main", String[].class);
main.invoke(null, (Object) args);
}

private static String invokeJavac(File optionsFile) throws IOException {
String output;
try {
output = invokeEcj(optionsFile);
} catch (NoClassDefFoundError e) {
if (verbose) {
System.err.println("ecj not found - using javac");
e.printStackTrace();
}
output = backtick("javac " + bashQuote("@" + optionsFile.getPath()));
}
if (verbose) System.out.println(output);
return output;
}

// throws ClassNotFoundError if ecj is not in classpath
static String invokeEcj(File optionsFile) {
StringWriter writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
org.eclipse.jdt.core.compiler.CompilationProgress progress = null;

// add more eclipse options in the line below

org.eclipse.jdt.core.compiler.batch.BatchCompiler.compile(
new String[] { "@" + optionsFile.getPath(),
"-source", "1.7",
"-nowarn"
},
printWriter,
printWriter,
progress);
return writer.toString();
}

private static void writeOptions(List<File> sources, List<File> libraries,
File optionsFile, String moreOptions) throws IOException {
FileWriter writer = new FileWriter(optionsFile);
for (File source : sources)
writer.write(bashQuote(source.getPath()) + " ");
if (!libraries.isEmpty()) {
List<String> cp = new ArrayList<String>();
for (File lib : libraries)
cp.add(lib.getAbsolutePath());
writer.write("-cp " + bashQuote(join(File.pathSeparator, cp)) + " ");
}
writer.write(moreOptions);
writer.close();
}

static void scanForSources(File source, List<File> sources, boolean topLevel) {
if (source.isFile() && source.getName().endsWith(".java"))
sources.add(source);
else if (source.isDirectory() && !isSkippedDirectoryName(source.getName(), topLevel)) {
File[] files = source.listFiles();
for (File file : files)
scanForSources(file, sources, false);
}
}

private static boolean isSkippedDirectoryName(String name, boolean topLevel) {
if (topLevel) return false; // input or output ok as highest directory (intentionally specified by user, not just found by a directory scan in which case we probably don't want it. it's more like heuristics actually.)
return name.equalsIgnoreCase("input") || name.equalsIgnoreCase("output");
}

public static String backtick(String cmd) throws IOException {
++processesStarted;
File outFile = File.createTempFile("_backtick", "");
File scriptFile = File.createTempFile("_backtick", isWindows() ? ".bat" : "");

String command = cmd + ">" + bashQuote(outFile.getPath()) + " 2>&1";
//Log.info("[Backtick] " + command);
try {
saveTextFile(scriptFile.getPath(), command);
String[] command2;
if (isWindows())
command2 = new String[] { scriptFile.getPath() };
else
command2 = new String[] { "/bin/bash", scriptFile.getPath() };
Process process = Runtime.getRuntime().exec(command2);
try {
process.waitFor();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
process.exitValue();
return loadTextFile(outFile.getPath(), "");
} finally {
scriptFile.delete();
}
}

/** possibly improvable */
public static String javaQuote(String text) {
return bashQuote(text);
}

/** possibly improvable */
public static String bashQuote(String text) {
if (text == null) return null;
return "\"" + text
.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\n", "\\n")
.replace("\r", "\\r") + "\"";
}

public final static String charsetForTextFiles = "UTF8";

static long TempDirMaker_lastValue;

public static File TempDirMaker_make() {
File dir = new File(System.getProperty("user.home"), ".javax/" + TempDirMaker_newValue());
dir.mkdirs();
return dir;
}

private static long TempDirMaker_newValue() {
long value;
do
value = System.currentTimeMillis();
while (value == TempDirMaker_lastValue);
TempDirMaker_lastValue = value;
return value;
}

public static String join(String glue, Iterable<String> strings) {
StringBuilder buf = new StringBuilder();
Iterator<String> i = strings.iterator();
if (i.hasNext()) {
buf.append(i.next());
while (i.hasNext())
buf.append(glue).append(i.next());
}
return buf.toString();
}

public static boolean isWindows() {
return System.getProperty("os.name").contains("Windows");
}

public static String makeRandomID(int length) {
Random random = new Random();
char[] id = new char[length];
for (int i = 0; i< id.length; i++)
id[i] = (char) ((int) 'a' + random.nextInt(26));
return new String(id);
}

static String computerID;
public static String getComputerID() throws IOException {
if (noID) return null;
if (computerID == null) {
File file = new File(System.getProperty("user.home"), ".tinybrain/computer-id");
computerID = loadTextFile(file.getPath(), null);
if (computerID == null) {
computerID = makeRandomID(12);
saveTextFile(file.getPath(), computerID);
}
if (verbose)
System.out.println("Local computer ID: " + computerID);
}
return computerID;
}
}
}}
2015-08-19 07:50:05  delete 
677 #1000604 (pitcher) 2015-08-18 00:07:22

add comment

Snippet ID: #2000470
Snippet name: class _x16 (embeddable, fixed)
Eternal ID of this version: #2000470/1
Text MD5: 8aff7b8572db7a78e05349b76db4d847
Author: stefan
Category: javax
Type: New Tinybrain snippet
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2015-07-29 18:16:08
Source code size: 38165 bytes / 1049 lines
Pitched / IR pitched: No / Yes
Views / Downloads: 935 / 1779
Referenced in: [show references]