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

2654
LINES

< > BotCompany Repo | #1004305 // x31.java (JavaX)

JavaX source code [tags: use-pretranspiled] - run with: x30.jar

Libraryless. Compilation Failed (6279L/45K).

1  
!759
2  
3  
/**
4  
 JavaX runner version 31
5  
6  
 Changes to v31:
7  
 -trying to cache unchanged programs
8  
9  
 TODO when making x32: change program ID in source
10  
 */
11  
12  
m { p { throw new RuntimeException("placebo"); } }
13  
14  
interface StringFunc {
15  
  String get(String s);
16  
}
17  
18  
class x30 implements Runnable {
19  
  static final String version = "JavaX 31";
20  
  static final int subversion = 1;
21  
  static final S javaxProgramID = "#1004305";
22  
  
23  
  // If programs run longer than this, they might have their class files
24  
  // deleted. We make it way longer for now.
25  
  static int tempFileRetentionTime = 30*24; // hours
26  
  
27  
  static int maxConsoleChars = 1024*1024;
28  
  
29  
  static boolean verbose = false, translate = false, list = false, virtualizeTranslators = true;
30  
  static String translateTo = null;
31  
  static boolean preferCached = false, noID = false, noPrefetch = false, noAWT = false;
32  
  static boolean safeOnly = false, safeTranslate = false, javacOnly = false, logOn = true;
33  
  static boolean runMainInProcess = true, consoleOn = true, hasHelloMessage = false;
34  
  static List<String[]> mainTranslators = new ArrayList<String[]>();
35  
  private static Map<Long, String> memSnippetCache = new HashMap<Long, String>();
36  
  private static int processesStarted, compilations;
37  
38  
  // snippet ID -> md5
39  
  private static HashMap<Long, String> prefetched = new HashMap<Long, String>();
40  
  private static File virtCache;
41  
  
42  
  // doesn't work yet
43  
  private static Map<String, Class<?>> programCache = new HashMap<String, Class<?>>();
44  
  static boolean cacheTranslators = false;
45  
46  
  // this should work (caches transpiled translators)
47  
  private static HashMap<Long, Object[]> translationCache = new HashMap<Long, Object[]>();
48  
  static boolean cacheTranspiledTranslators = true;
49  
50  
  // which snippets are available pre-transpiled server-side?
51  
  private static Set<Long> hasTranspiledSet = new HashSet<Long>();
52  
  static boolean useServerTranspiled = true;
53  
54  
  static Object androidContext;
55  
  static boolean android = isAndroid();
56  
  
57  
  // We stick to 1.7 for now to support android.
58  
  // Scripts like #1001155 might change to 1.6
59  
  static S javaTarget = System.getProperty("java.version").startsWith("1.6.") ? "1.6" : "1.7";
60  
61  
  // Translators currently being translated (to detect recursions)
62  
  private static Set<Long> translating = new HashSet<Long>();
63  
64  
  static String lastOutput;
65  
  static String[] fullArgs;
66  
  private static Console console;
67  
  
68  
  static String javaCompilerOutput;
69  
  
70  
  static int systemOutPipeSize = 128*1024; // 128 K
71  
  static int systemErrPipeSize = 4*1024; // 4 K
72  
  static int systemInPipeSize = 4*1024; // 4 K
73  
74  
  public static void main(String[] args) {
75  
    try {
76  
      goMain(args);
77  
    } catch (Throwable e) {
78  
      e.printStackTrace();
79  
    }
80  
  }
81  
  
82  
  static void goMain(String[] args) throws Exception {
83  
    __javax = x30.class; // for hotwire
84  
    
85  
    if (args.length != 0 && args[0].equals("-v")) verbose = true;
86  
    redirectSystemOutAndErr();
87  
88  
    for (S arg : args)
89  
      if (arg.equals("-noawt"))
90  
        noAWT = true;
91  
        
92  
    if (consoleOn && console == null && !noAWT)
93  
      tryToOpenConsole(args);
94  
    
95  
    String autoReport = loadTextFile(new File(userHome(), ".javax/auto-report-to-chat").getPath(), "").trim();
96  
    //print("autoReport=" + autoReport);
97  
    if (!isChatServer(args) && autoReport.equals("1"))
98  
      autoReportToChat();
99  
100  
    if (!hasHelloMessage) {
101  
      hasHelloMessage = true;
102  
      //installHelloMessage(args.length == 0 ? "JavaX Start-Up VM" : "JavaX VM (" + smartJoin(args) + ")");
103  
      makeVMAndroid();
104  
    }
105  
    
106  
    File ioBaseDir = new File("."), inputDir = null, outputDir = null;
107  
    String src = null;
108  
    List<String> programArgs = new ArrayList<String>();
109  
    fullArgs = args;
110  
111  
    for (int i = 0; i < args.length; i++) {
112  
      String arg = args[i];
113  
114  
      if (arg.equals("-version")) {
115  
        showVersion();
116  
        System.exit(0);
117  
      }
118  
119  
      if (arg.equals("-sysprop")) {
120  
        showSystemProperties();
121  
        return;
122  
      }
123  
124  
      if (arg.equals("-v") || arg.equals("-verbose"))
125  
        verbose = true;
126  
      else if (arg.equals("-finderror"))
127  
        verbose = true;
128  
      else if (arg.equals("-offline") || arg.equalsIgnoreCase("-prefercached"))
129  
        preferCached = true;
130  
      else if (arg.equals("-novirt"))
131  
        virtualizeTranslators = false;
132  
      else if (arg.equals("-safeonly"))
133  
        safeOnly = true;
134  
      else if (arg.equals("-safetranslate"))
135  
        safeTranslate = true;
136  
      else if (arg.equals("-noawt"))
137  
        noAWT = true;
138  
      else if (arg.equals("-noid"))
139  
        noID = true;
140  
      else if (arg.equals("-nocachetranspiled"))
141  
        cacheTranspiledTranslators = false;
142  
      else if (arg.equals("-javac"))
143  
        javacOnly = true;
144  
      else if (arg.equals("-localtranspile"))
145  
        useServerTranspiled = false;
146  
      else if (arg.equals("translate") && src == null)
147  
        translate = true;
148  
      else if (arg.equals("list") && src == null) {
149  
        list = true;
150  
        virtualizeTranslators = false; // so they are silenced
151  
      } else if (arg.equals("run") && src == null) {
152  
        // it's the default command anyway
153  
      } else if (arg.startsWith("input="))
154  
        inputDir = new File(arg.substring(6));
155  
      else if (arg.startsWith("output="))
156  
        outputDir = new File(arg.substring(7));
157  
      else if (arg.equals("with"))
158  
        mainTranslators.add(new String[] {args[++i], null});
159  
      else if (translate && arg.equals("to"))
160  
        translateTo = args[++i];
161  
      else if (src == null) {
162  
        //System.out.println("src=" + arg);
163  
        src = arg;
164  
      } else
165  
        programArgs.add(arg);
166  
    }
167  
168  
    cleanCache();
169  
170  
    if (useServerTranspiled)
171  
      noPrefetch = true;
172  
173  
    if (src == null) src = ".";
174  
175  
    // Might actually want to write to 2 disk caches (global/per program).
176  
    if (virtualizeTranslators && !preferCached)
177  
      virtCache = TempDirMaker_make();
178  
179  
    if (inputDir != null) {
180  
      ioBaseDir = TempDirMaker_make();
181  
      System.out.println("Taking input from: " + inputDir.getAbsolutePath());
182  
      System.out.println("Output is in: " + new File(ioBaseDir, "output").getAbsolutePath());
183  
      copyInput(inputDir, new File(ioBaseDir, "input"));
184  
    }
185  
    
186  
    if (logOn)
187  
      logStart(args);
188  
189  
    javaxmain(src, ioBaseDir, translate, list, programArgs.toArray(new String[programArgs.size()]));
190  
191  
    if (outputDir != null) {
192  
      copyInput(new File(ioBaseDir, "output"), outputDir);
193  
      System.out.println("Output copied to: " + outputDir.getAbsolutePath());
194  
    }
195  
196  
    if (verbose) {
197  
      // print stats
198  
      System.out.println("Processes started: " + processesStarted + ", compilations: " + compilations);
199  
    }
200  
  }
201  
202  
  public static void javaxmain(String src, File ioDir, boolean translate, boolean list,
203  
                               String[] args) throws Exception {
204  
    String programID = isSnippetID(src) ? "" + parseSnippetID(src) : null;
205  
    
206  
    if (programID != null)
207  
      System.err.println("JavaX TRANSLATE " + programID + " " + smartJoin(args));
208  
    
209  
    List<File> libraries = new ArrayList<File>();
210  
    File X = transpileMain(src, libraries);
211  
    if (verbose)
212  
      print("After transpileMain: " + X);
213  
      
214  
    if (X == null) {
215  
      showVersion();
216  
      
217  
      if (fullArgs != null) {
218  
        String[] nargs;
219  
        if (fullArgs.length == 0)
220  
          nargs = new String[] {"1000825"}; // swing-start
221  
        else {
222  
          // forward to search
223  
          nargs = new String[fullArgs.length+1];
224  
          nargs[0] = "636";
225  
          // nargs[1] = "search-runnables";
226  
          System.arraycopy(fullArgs, 0, nargs, 1, fullArgs.length);
227  
        }
228  
        main(nargs); // Hopefully we get no infinite recursion :)
229  
        return;
230  
      }
231  
      
232  
      System.out.println("No main.java found, exiting");
233  
      return;
234  
    }
235  
    
236  
    info.transpiledSrc = X;
237  
238  
    // list or run
239  
240  
    if (translate) {
241  
      File to = X;
242  
      if (translateTo != null) {
243  
        StringBuilder buf = new StringBuilder();
244  
        for (File f : libraries) buf.append(f.getName()+"\n");
245  
        if (new File(translateTo).isDirectory()) {
246  
          to = new File(translateTo, "main.java");
247  
          saveTextFile(new File(translateTo, "libraries.txt").getPath(), buf.toString());
248  
        } else {
249  
          to = new File(translateTo);
250  
          saveTextFile(new File(translateTo + "_libraries").getPath(), buf.toString());
251  
        }
252  
      }
253  
      if (to != X)
254  
        copy(new File(X, "main.java"), to);
255  
      System.out.println("Program translated to: " + to.getAbsolutePath());
256  
    } else if (list)
257  
      System.out.println(loadTextFile(new File(X, "main.java").getPath(), null));
258  
    else {
259  
      if (programID != null)
260  
        System.err.println("JavaX RUN " + programID + " " + smartJoin(args));
261  
      System.err.println(); // Make empty line before actual program starts
262  
      
263  
      javax2(X, ioDir, false, runMainInProcess, libraries, args, null, programID, info);
264  
      
265  
      System.out.println("[main done]");
266  
      
267  
      // cleanup reportToChat thread
268  
      if (reportToChat_q != null) {
269  
        if (customSystemOut != null)
270  
          Thread.sleep(1000); // delay to finish autoReportToChat. Yes it's hacky.
271  
        if (verbose) System.out.println("Closing reportToChat queue");
272  
        reportToChat_q.done();
273  
      }
274  
    }
275  
  }
276  
277  
  static File transpileMain(String src, List<File> libraries) throws Exception {
278  
    File srcDir = null;
279  
    boolean isTranspiled = false;
280  
    if (isSnippetID(src)) {
281  
      S transpiledSrc = getTranspilationFromBossBot(parseSnippetID(src));
282  
      if (transpiledSrc != null) {
283  
        int i = transpiledSrc.indexOf('\n');
284  
        String libs = transpiledSrc.substring(0, Math.max(0, i));
285  
        transpiledSrc = transpiledSrc.substring(i+1);
286  
        if (!transpiledSrc.isEmpty()) {
287  
          srcDir = TempDirMaker_make();
288  
          saveTextFile(new File(srcDir, "main.java").getPath(), transpiledSrc);
289  
          isTranspiled = true;
290  
291  
          Matcher m = Pattern.compile("\\d+").matcher(libs);
292  
          while (m.find()) {
293  
            String libid = m.group();
294  
            File libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(libid));
295  
            loadLibrary(libid, libraries, libraryFile);
296  
          }
297  
        }
298  
      }
299  
     
300  
      if (srcDir == null) {
301  
        prefetch(src);
302  
        long id = parseSnippetID(src);
303  
        prefetched.remove(id); // hackfix to ensure transpiled main program is found.
304  
        srcDir = loadSnippetAsMainJava(src);
305  
        if (verbose)
306  
          System.err.println("hasTranspiledSet: " + hasTranspiledSet);
307  
        if (hasTranspiledSet.contains(id) && useServerTranspiled) {
308  
          //System.err.println("Trying pretranspiled main program: #" + id);
309  
          transpiledSrc = getServerTranspiled("#" + id);
310  
          int i = transpiledSrc.indexOf('\n');
311  
          String libs = transpiledSrc.substring(0, Math.max(0, i));
312  
          transpiledSrc = transpiledSrc.substring(i+1);
313  
          if (!transpiledSrc.isEmpty()) {
314  
            srcDir = TempDirMaker_make();
315  
            saveTextFile(new File(srcDir, "main.java").getPath(), transpiledSrc);
316  
            isTranspiled = true;
317  
            //translationCache.put(id, new Object[] {srcDir, libraries});
318  
  
319  
            Matcher m = Pattern.compile("\\d+").matcher(libs);
320  
            while (m.find()) {
321  
              String libid = m.group();
322  
              File libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(libid));
323  
              loadLibrary(libid, libraries, libraryFile);
324  
            }
325  
          }
326  
        }
327  
      }
328  
    } else {
329  
      srcDir = new File(src);
330  
331  
      // if the argument is a file, it is assumed to be main.java
332  
      if (srcDir.isFile()) {
333  
        srcDir = TempDirMaker_make();
334  
        copy(new File(src), new File(srcDir, "main.java"));
335  
      }
336  
337  
      if (!new File(srcDir, "main.java").exists())
338  
        return null;
339  
    }
340  
341  
    // translate
342  
343  
    File X = srcDir;
344  
345  
    if (!isTranspiled) {
346  
      X = topLevelTranslate(X, libraries);
347  
      System.err.println("Translated " + src);
348  
349  
      // save prefetch data
350  
      if (isSnippetID(src))
351  
        savePrefetchData(src);
352  
    }
353  
    return X;
354  
  }
355  
356  
  private static void prefetch(String mainSnippetID) throws IOException {
357  
    if (noPrefetch) return;
358  
359  
    long mainID = parseSnippetID(mainSnippetID);
360  
    String s = mainID + " " + loadTextFile(new File(userHome(), ".tinybrain/prefetch/" + mainID + ".txt").getPath(), "");
361  
    String[] ids = s.trim().split(" ");
362  
    if (ids.length > 1) {
363  
      String url = "http://tinybrain.de:8080/tb-int/prefetch.php?ids=" + URLEncoder.encode(s, "UTF-8");
364  
      String data = loadPage(new URL(url));
365  
      String[] split = data.split(" ");
366  
      if (split.length == ids.length)
367  
        for (int i = 0; i < ids.length; i++)
368  
          prefetched.put(parseSnippetID(ids[i]), split[i]);
369  
    }
370  
  }
371  
372  
  static String userHome() {
373  
    if (android)
374  
      return ((File) call(androidContext, "getFilesDir")).getAbsolutePath();
375  
    else
376  
      return System.getProperty("user.home");
377  
  }
378  
379  
  private static void savePrefetchData(String mainSnippetID) throws IOException {
380  
    List<String> ids = new ArrayList<String>();
381  
    long mainID = parseSnippetID(mainSnippetID);
382  
383  
    for (long id : memSnippetCache.keySet())
384  
      if (id != mainID)
385  
        ids.add(String.valueOf(id));
386  
387  
    saveTextFile(new File(userHome(),".tinybrain/prefetch/" + mainID + ".txt").getPath(), join(" ", ids));
388  
  }
389  
390  
  static File topLevelTranslate(File srcDir, List<File> libraries_out) throws Exception {
391  
    File X = srcDir;
392  
    X = applyTranslators(X, mainTranslators, libraries_out); // translators supplied on command line (unusual)
393  
394  
    // actual inner translation of the JavaX source
395  
    X = defaultTranslate(X, libraries_out);
396  
    return X;
397  
  }
398  
399  
  private static File defaultTranslate(File x, List<File> libraries_out) throws Exception {
400  
    x = luaPrintToJavaPrint(x);
401  
    x = repeatAutoTranslate(x, libraries_out);
402  
    return x;
403  
  }
404  
405  
  private static File repeatAutoTranslate(File x, List<File> libraries_out) throws Exception {
406  
    new List<String[]> postTranslators;
407  
    
408  
    while (true) {
409  
      String main = loadTextFile(new File(x, "main.java").getPath(), null);
410  
      List<String> lines = toLines(main);
411  
      List<String[]> t = findPostTranslators(lines);
412  
      postTranslators.addAll(t);
413  
      
414  
      if (!t.isEmpty()) {
415  
        main = fromLines(lines);
416  
        x = TempDirMaker_make();
417  
        saveTextFile(new File(x, "main.java").getPath(), main);
418  
      }
419  
420  
      File y = autoTranslate(x, libraries_out);
421  
      if (y == x)
422  
        break;
423  
      x = y;
424  
    }
425  
    
426  
    x = applyTranslators(x, postTranslators, libraries_out);
427  
    
428  
    return x;
429  
  }
430  
431  
  private static File autoTranslate(File x, List<File> libraries_out) throws Exception {
432  
    String main = loadTextFile(new File(x, "main.java").getPath(), null);
433  
    List<String> lines = toLines(main);
434  
    List<String[]> translators = findTranslators(lines);
435  
    if (translators.isEmpty())
436  
      return x;
437  
438  
    main = fromLines(lines);
439  
    File newDir = TempDirMaker_make();
440  
    saveTextFile(new File(newDir, "main.java").getPath(), main);
441  
    return applyTranslators(newDir, translators, libraries_out);
442  
  }
443  
444  
  static List<String[]> findTranslators(List<String> lines) {
445  
    List<String[]> translators = new ArrayList<String[]>();
446  
    Pattern pattern = Pattern.compile("^!([0-9# \t]+)");
447  
    Pattern pArgs = Pattern.compile("^\\s*\\((.*)\\)");
448  
    for (ListIterator<String> iterator = lines.listIterator(); iterator.hasNext(); ) {
449  
      String line = iterator.next();
450  
      line = line.trim();
451  
      Matcher matcher = pattern.matcher(line);
452  
      if (matcher.find()) {
453  
        String[] t = matcher.group(1).split("[ \t]+");
454  
        String rest = line.substring(matcher.end());
455  
        String arg = null;
456  
        if (t.length == 1) {
457  
          Matcher mArgs = pArgs.matcher(rest);
458  
          if (mArgs.find())
459  
            arg = mArgs.group(1);
460  
        }
461  
        for (String transi : t)
462  
          translators.add(new String[]{transi, arg});
463  
        iterator.remove();
464  
      }
465  
    }
466  
    return translators;
467  
  }
468  
469  
  static List<String[]> findPostTranslators(List<String> lines) {
470  
    List<String[]> translators = new ArrayList<String[]>();
471  
    Pattern pattern = Pattern.compile("^!post\\s*([0-9# \t]+)");
472  
    Pattern pArgs = Pattern.compile("^\\s*\\((.*)\\)");
473  
    for (ListIterator<String> iterator = lines.listIterator(); iterator.hasNext(); ) {
474  
      String line = iterator.next();
475  
      line = line.trim();
476  
      Matcher matcher = pattern.matcher(line);
477  
      if (matcher.find()) {
478  
        String[] t = matcher.group(1).split("[ \t]+");
479  
        String rest = line.substring(matcher.end());
480  
        String arg = null;
481  
        if (t.length == 1) {
482  
          Matcher mArgs = pArgs.matcher(rest);
483  
          if (mArgs.find())
484  
            arg = mArgs.group(1);
485  
        }
486  
        for (String transi : t)
487  
          translators.add(new String[]{transi, arg});
488  
        iterator.remove();
489  
      }
490  
    }
491  
    return translators;
492  
  }
493  
494  
  public static List<String> toLines(String s) {
495  
    List<String> lines = new ArrayList<String>();
496  
    int start = 0;
497  
    while (true) {
498  
      int i = toLines_nextLineBreak(s, start);
499  
      if (i < 0) {
500  
        if (s.length() > start) lines.add(s.substring(start));
501  
        break;
502  
      }
503  
504  
      lines.add(s.substring(start, i));
505  
      if (s.charAt(i) == '\r' && i+1 < s.length() && s.charAt(i+1) == '\n')
506  
        i += 2;
507  
      else
508  
        ++i;
509  
510  
      start = i;
511  
    }
512  
    return lines;
513  
  }
514  
515  
  private static int toLines_nextLineBreak(String s, int start) {
516  
    for (int i = start; i < s.length(); i++) {
517  
      char c = s.charAt(i);
518  
      if (c == '\r' || c == '\n')
519  
        return i;
520  
    }
521  
    return -1;
522  
  }
523  
524  
  public static String fromLines(List<String> lines) {
525  
    StringBuilder buf = new StringBuilder();
526  
    for (String line : lines) {
527  
      buf.append(line).append('\n');
528  
    }
529  
    return buf.toString();
530  
  }
531  
532  
  private static File applyTranslators(File x, List<String[]> translators, List<File> libraries_out) throws Exception {
533  
    for (String[] translator : translators)
534  
      x = applyTranslator(x, translator[0], translator[1], libraries_out);
535  
    return x;
536  
  }
537  
538  
  // also takes a library
539  
  private static File applyTranslator(File x, String translator, String arg, List<File> libraries_out) throws Exception {
540  
    if (verbose)
541  
      System.out.println("Using translator " + translator + " on sources in " + x.getPath());
542  
543  
    File newDir = runTranslatorOnInput(translator, null, arg, x, !verbose, libraries_out);
544  
545  
    if (!new File(newDir, "main.java").exists()) {
546  
      throw new Exception("Translator " + translator + " did not generate main.java");
547  
      // TODO: show translator output
548  
    }
549  
    if (verbose)
550  
      System.out.println("Translated with " + translator + " from " + x.getPath() + " to " + newDir.getPath());
551  
    x = newDir;
552  
    return x;
553  
  }
554  
555  
  private static File luaPrintToJavaPrint(File x) throws IOException {
556  
    File newDir = TempDirMaker_make();
557  
    String code = loadTextFile(new File(x, "main.java").getPath(), null);
558  
    code = luaPrintToJavaPrint(code);
559  
    saveTextFile(new File(newDir, "main.java").getPath(), code);
560  
    return newDir;
561  
  }
562  
563  
  public static String luaPrintToJavaPrint(String code) {
564  
    return ("\n" + code).replaceAll(
565  
      "(\n\\s*)print (\".*\")",
566  
      "$1System.out.println($2);").substring(1);
567  
  }
568  
569  
  public static File loadSnippetAsMainJava(String snippetID) throws IOException {
570  
    checkProgramSafety(snippetID);
571  
    File srcDir = TempDirMaker_make();
572  
    saveTextFile(new File(srcDir, "main.java").getPath(), loadSnippet(snippetID));
573  
    return srcDir;
574  
  }
575  
576  
  public static File loadSnippetAsMainJavaVerified(String snippetID, String hash) throws IOException {
577  
    checkProgramSafety(snippetID);
578  
    File srcDir = TempDirMaker_make();
579  
    saveTextFile(new File(srcDir, "main.java").getPath(), loadSnippetVerified(snippetID, hash));
580  
    return srcDir;
581  
  }
582  
583  
  @SuppressWarnings( "unchecked" )
584  
  /** returns output dir */
585  
  private static File runTranslatorOnInput(String snippetID, String hash, String arg, File input,
586  
                                           boolean silent,
587  
                                           List<File> libraries_out) throws Exception {
588  
    if (safeTranslate)
589  
      checkProgramSafetyImpl(snippetID);
590  
    long id = parseSnippetID(snippetID);
591  
592  
    // It's a library, not a translator.
593  
    File libraryFile = DiskSnippetCache_getLibrary(id);
594  
    if (verbose)
595  
      System.out.println("Library file for " + id + ": " + libraryFile);
596  
    if (libraryFile != null) {
597  
      loadLibrary(snippetID, libraries_out, libraryFile);
598  
      return input;
599  
    }
600  
601  
    String[] args = arg != null ? new String[]{arg} : new String[0];
602  
603  
    File srcDir = hash == null ? loadSnippetAsMainJava(snippetID)
604  
      : loadSnippetAsMainJavaVerified(snippetID, hash);
605  
    long mainJavaSize = new File(srcDir, "main.java").length();
606  
607  
    if (verbose)
608  
      System.out.println(snippetID + ": length = " + mainJavaSize);
609  
    if (mainJavaSize == 0) { // no text in snippet? assume it's a library
610  
      loadLibrary(snippetID, libraries_out, libraryFile);
611  
      return input;
612  
    }
613  
614  
    List<File> libraries = new ArrayList<File>();
615  
    Object[] cached = translationCache.get(id);
616  
    if (cached != null) {
617  
      //System.err.println("Taking translator " + snippetID + " from cache!");
618  
      srcDir = (File) cached[0];
619  
      libraries = (List<File>) cached[1];
620  
    } else if (hasTranspiledSet.contains(id) && useServerTranspiled) {
621  
      System.err.println("Trying pretranspiled translator: #" + snippetID);
622  
      String transpiledSrc = getServerTranspiled(snippetID);
623  
      transpiledSrc = transpiledSrc.substring(transpiledSrc.indexOf('\n')+1);
624  
      // TODO: check for libraries
625  
      if (!transpiledSrc.isEmpty()) {
626  
        srcDir = TempDirMaker_make();
627  
        saveTextFile(new File(srcDir, "main.java").getPath(), transpiledSrc);
628  
        translationCache.put(id, cached = new Object[] {srcDir, libraries});
629  
      }
630  
    }
631  
632  
    File ioBaseDir = TempDirMaker_make();
633  
634  
    /*Class<?> mainClass = programCache.get("" + parseSnippetID(snippetID));
635  
    if (mainClass != null)
636  
      return runCached(ioBaseDir, input, args);*/
637  
    // Doesn't work yet because virtualized directories are hardcoded in translator...
638  
639  
    if (cached == null) {
640  
      System.err.println("Translating translator #" + id);
641  
      if (translating.contains(id))
642  
        throw new RuntimeException("Recursive translator reference chain: " + structure(translating));
643  
      translating.add(id);
644  
      try {
645  
        srcDir = defaultTranslate(srcDir, libraries);
646  
      } finally {
647  
        translating.remove(id);
648  
      }
649  
      System.err.println("Translated translator #" + id);
650  
      translationCache.put(id, new Object[]{srcDir, libraries});
651  
    }
652  
653  
    boolean runInProcess = false;
654  
655  
    if (virtualizeTranslators) {
656  
      if (verbose) System.out.println("Virtualizing translator");
657  
658  
      // TODO: don't virtualize class _javax (as included in, say, #636)
659  
660  
      //srcDir = applyTranslator(srcDir, "#2000351"); // I/O-virtualize the translator
661  
      // that doesn't work because it recurses infinitely...
662  
663  
      // So we do it right here:
664  
      String s = loadTextFile(new File(srcDir, "main.java").getPath(), null);
665  
      s = s.replaceAll("new\\s+File\\(", "virtual.newFile(");
666  
      s = s.replaceAll("new\\s+FileInputStream\\(", "virtual.newFileInputStream(");
667  
      s = s.replaceAll("new\\s+FileOutputStream\\(", "virtual.newFileOutputStream(");
668  
      s += "\n\n" + loadSnippet("#2000355"); // load class virtual
669  
670  
      // forward snippet cache (virtualized one)
671  
      File dir = virtCache != null ? virtCache : DiskSnippetCache_dir;
672  
      s = s.replace("static File DiskSnippetCache_dir" + ";",
673  
        "static File DiskSnippetCache_dir " + "= new File(" + javaQuote(dir.getAbsolutePath()) + ");"); // extra + is necessary for Dumb TinyBrain :)
674  
      s = s.replace("static boolean preferCached = false;", "static boolean preferCached = true;");
675  
676  
      if (verbose) {
677  
        System.out.println("==BEGIN VIRTUALIZED TRANSLATOR==");
678  
        System.out.println(s);
679  
        System.out.println("==END VIRTUALIZED TRANSLATOR==");
680  
      }
681  
      srcDir = TempDirMaker_make();
682  
      saveTextFile(new File(srcDir, "main.java").getPath(), s);
683  
684  
      // TODO: silence translator also
685  
      runInProcess = true;
686  
    }
687  
688  
    return runJavaX(ioBaseDir, srcDir, input, silent, runInProcess, libraries,
689  
      args, cacheTranslators ? "" + id : null, "" + id);
690  
  }
691  
692  
  static void checkProgramSafety(String snippetID) throws IOException {
693  
    if (!safeOnly) return;
694  
    checkProgramSafetyImpl(snippetID);
695  
  }
696  
697  
  static void checkProgramSafetyImpl(String snippetID) throws IOException {
698  
    URL url = new URL("http://tinybrain.de:8080/tb-int/is-javax-safe.php?id=" + parseSnippetID(snippetID));
699  
    String text = loadPage(url);
700  
    if (!text.startsWith("{\"safe\":\"1\"}"))
701  
      throw new RuntimeException("Program not safe: #" + parseSnippetID(snippetID));
702  
  }
703  
704  
  static void loadLibrary(String snippetID, List<File> libraries_out, File libraryFile) throws IOException {
705  
    if (verbose)
706  
      System.out.println("Assuming " + snippetID + " is a library.");
707  
708  
    if (libraryFile == null) {
709  
      byte[] data = loadDataSnippetImpl(snippetID);
710  
      DiskSnippetCache_putLibrary(parseSnippetID(snippetID), data);
711  
      libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(snippetID));
712  
    }
713  
714  
    if (!libraries_out.contains(libraryFile))
715  
      libraries_out.add(libraryFile);
716  
  }
717  
718  
  /** returns output dir */
719  
  private static File runJavaX(File ioBaseDir, File originalSrcDir, File originalInput,
720  
                               boolean silent, boolean runInProcess,
721  
                               List<File> libraries, String[] args, String cacheAs,
722  
                               String programID) throws Exception {
723  
    File srcDir = new File(ioBaseDir, "src");
724  
    File inputDir = new File(ioBaseDir, "input");
725  
    File outputDir = new File(ioBaseDir, "output");
726  
    copyInput(originalSrcDir, srcDir);
727  
    copyInput(originalInput, inputDir);
728  
    javax2(srcDir, ioBaseDir, silent, runInProcess, libraries, args, cacheAs, programID, null);
729  
    return outputDir;
730  
  }
731  
732  
  private static void copyInput(File src, File dst) throws IOException {
733  
    copyDirectory(src, dst);
734  
  }
735  
736  
  public static boolean hasFile(File inputDir, String name) {
737  
    return new File(inputDir, name).exists();
738  
  }
739  
740  
  public static void copyDirectory(File src, File dst) throws IOException {
741  
    if (verbose) System.out.println("Copying " + src.getAbsolutePath() + " to " + dst.getAbsolutePath());
742  
    dst.mkdirs();
743  
    File[] files = src.listFiles();
744  
    if (files == null) return;
745  
    for (File file : files) {
746  
      File dst1 = new File(dst, file.getName());
747  
      if (file.isDirectory())
748  
        copyDirectory(file, dst1);
749  
      else {
750  
        if (verbose) System.out.println("Copying " + file.getAbsolutePath() + " to " + dst1.getAbsolutePath());
751  
        copy(file, dst1);
752  
      }
753  
    }
754  
  }
755  
756  
  /** Quickly copy a file without a progress bar or any other fancy GUI... :) */
757  
  public static void copy(File src, File dest) throws IOException {
758  
    FileInputStream inputStream = newFileInputStream(src);
759  
    FileOutputStream outputStream = newFileOutputStream(dest);
760  
    try {
761  
      copy(inputStream, outputStream);
762  
      inputStream.close();
763  
    } finally {
764  
      outputStream.close();
765  
    }
766  
  }
767  
768  
  private static FileInputStream newFileInputStream(File f) throws FileNotFoundException {
769  
    /*if (androidContext != null)
770  
      return (FileInputStream) call(androidContext,
771  
        "openFileInput", f.getPath());
772  
    else*/
773  
    return new // line break for Dumb TinyBrain :)
774  
    FileInputStream(f);
775  
  }
776  
777  
  private static FileOutputStream newFileOutputStream(File f) throws FileNotFoundException {
778  
    /*if (androidContext != null)
779  
      return (FileOutputStream) call(androidContext,
780  
        "openFileOutput", f.getPath(), 0);
781  
    else*/
782  
    return new // line break for Dumb TinyBrain :)
783  
    FileOutputStream(f);
784  
  }
785  
786  
  public static void copy(InputStream in, OutputStream out) throws IOException {
787  
    byte[] buf = new byte[65536];
788  
    while (true) {
789  
      int n = in.read(buf);
790  
      if (n <= 0) return;
791  
      out.write(buf, 0, n);
792  
    }
793  
  }
794  
795  
  /** writes safely (to temp file, then rename) */
796  
  public static void saveTextFile(String fileName, String contents) throws IOException {
797  
    File file = new File(fileName);
798  
    File parentFile = file.getParentFile();
799  
    if (parentFile != null)
800  
      parentFile.mkdirs();
801  
    String tempFileName = fileName + "_temp";
802  
    FileOutputStream fileOutputStream = newFileOutputStream(new File(tempFileName));
803  
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, charsetForTextFiles);
804  
    PrintWriter printWriter = new PrintWriter(outputStreamWriter);
805  
    printWriter.print(contents);
806  
    printWriter.close();
807  
    if (file.exists() && !file.delete())
808  
      throw new IOException("Can't delete " + fileName);
809  
810  
    if (!new File(tempFileName).renameTo(file))
811  
      throw new IOException("Can't rename " + tempFileName + " to " + fileName);
812  
  }
813  
814  
  /** writes safely (to temp file, then rename) */
815  
  public static void saveBinaryFile(String fileName, byte[] contents) throws IOException {
816  
    File file = new File(fileName);
817  
    File parentFile = file.getParentFile();
818  
    if (parentFile != null)
819  
      parentFile.mkdirs();
820  
    String tempFileName = fileName + "_temp";
821  
    FileOutputStream fileOutputStream = newFileOutputStream(new File(tempFileName));
822  
    fileOutputStream.write(contents);
823  
    fileOutputStream.close();
824  
    if (file.exists() && !file.delete())
825  
      throw new IOException("Can't delete " + fileName);
826  
827  
    if (!new File(tempFileName).renameTo(file))
828  
      throw new IOException("Can't rename " + tempFileName + " to " + fileName);
829  
  }
830  
831  
  !include #1001049 // loadTextFile
832  
  
833  
  static File DiskSnippetCache_dir;
834  
835  
  public static void initDiskSnippetCache(File dir) {
836  
    DiskSnippetCache_dir = dir;
837  
    dir.mkdirs();
838  
  }
839  
840  
  // Data files are immutable, use centralized cache
841  
  public static synchronized File DiskSnippetCache_getLibrary(long snippetID) throws IOException {
842  
    File file = new File(getGlobalCache(), "data_" + snippetID + ".jar");
843  
    if (verbose)
844  
      System.out.println("Checking data cache: " + file.getPath());
845  
    return file.exists() ? file : null;
846  
  }
847  
848  
  public static synchronized String DiskSnippetCache_get(long snippetID) throws IOException {
849  
    return loadTextFile(DiskSnippetCache_getFile(snippetID).getPath(), null);
850  
  }
851  
852  
  private static File DiskSnippetCache_getFile(long snippetID) {
853  
    return new File(DiskSnippetCache_dir, "" + snippetID);
854  
  }
855  
856  
  public static synchronized void DiskSnippetCache_put(long snippetID, String snippet) throws IOException {
857  
    saveTextFile(DiskSnippetCache_getFile(snippetID).getPath(), snippet);
858  
  }
859  
860  
  public static synchronized void DiskSnippetCache_putLibrary(long snippetID, byte[] data) throws IOException {
861  
    saveBinaryFile(new File(getGlobalCache(), "data_" + snippetID).getPath() + ".jar", data);
862  
  }
863  
864  
  public static File DiskSnippetCache_getDir() {
865  
    return DiskSnippetCache_dir;
866  
  }
867  
868  
  public static void initSnippetCache() {
869  
    if (DiskSnippetCache_dir == null)
870  
      initDiskSnippetCache(getGlobalCache());
871  
  }
872  
873  
  private static File getGlobalCache() {
874  
    File file = new File(userHome(), ".tinybrain/snippet-cache");
875  
    file.mkdirs();
876  
    return file;
877  
  }
878  
879  
  public static String loadSnippetVerified(String snippetID, String hash) throws IOException {
880  
    String text = loadSnippet(snippetID);
881  
    String realHash = getHash(text.getBytes("UTF-8"));
882  
    if (!realHash.equals(hash)) {
883  
      String msg;
884  
      if (hash.isEmpty())
885  
        msg = "Here's your hash for " + snippetID + ", please put in your program: " + realHash;
886  
      else
887  
        msg = "Hash mismatch for " + snippetID + ": " + realHash + " (new) vs " + hash + " - has tinybrain.de been hacked??";
888  
      throw new RuntimeException(msg);
889  
    }
890  
    return text;
891  
  }
892  
893  
  public static String getHash(byte[] data) {
894  
    return bytesToHex(getFullFingerprint(data));
895  
  }
896  
897  
  public static byte[] getFullFingerprint(byte[] data) {
898  
    try {
899  
      return MessageDigest.getInstance("MD5").digest(data);
900  
    } catch (NoSuchAlgorithmException e) {
901  
      throw new RuntimeException(e);
902  
    }
903  
  }
904  
905  
  public static String bytesToHex(byte[] bytes) {
906  
    return bytesToHex(bytes, 0, bytes.length);
907  
  }
908  
909  
  public static String bytesToHex(byte[] bytes, int ofs, int len) {
910  
    StringBuilder stringBuilder = new StringBuilder(len*2);
911  
    for (int i = 0; i < len; i++) {
912  
      String s = "0" + Integer.toHexString(bytes[ofs+i]);
913  
      stringBuilder.append(s.substring(s.length()-2, s.length()));
914  
    }
915  
    return stringBuilder.toString();
916  
  }
917  
918  
  public static String loadSnippet(String snippetID) throws IOException {
919  
    return loadSnippet(parseSnippetID(snippetID));
920  
  }
921  
922  
  public static long parseSnippetID(String snippetID) {
923  
    return Long.parseLong(shortenSnippetID(snippetID));
924  
  }
925  
926  
  private static String shortenSnippetID(String snippetID) {
927  
    if (snippetID.startsWith("#"))
928  
      snippetID = snippetID.substring(1);
929  
    String httpBlaBla = "http://tinybrain.de/";
930  
    if (snippetID.startsWith(httpBlaBla))
931  
      snippetID = snippetID.substring(httpBlaBla.length());
932  
    return snippetID;
933  
  }
934  
935  
  public static boolean isSnippetID(String snippetID) {
936  
    snippetID = shortenSnippetID(snippetID);
937  
    return isInteger(snippetID) && Long.parseLong(snippetID) != 0;
938  
  }
939  
940  
  public static boolean isInteger(String s) {
941  
    return Pattern.matches("\\-?\\d+", s);
942  
  }
943  
  
944  
  static String getTranspilationFromBossBot(long snippetID) {
945  
    return boss(format3("get transpilation for *", snippetID));
946  
  }
947  
  
948  
  // This is DIFFERENT from the std library loadSnippet
949  
  // (this is only for code!)
950  
  public static String loadSnippet(long snippetID) throws IOException {
951  
    String text = getSnippetFromBossBot(snippetID);
952  
    if (text != null) return text;
953  
    
954  
    text = memSnippetCache.get(snippetID);
955  
    if (text != null) {
956  
      if (verbose)
957  
        System.out.println("Getting " + snippetID + " from mem cache");
958  
      return text;
959  
    }
960  
    
961  
    initSnippetCache();
962  
    text = DiskSnippetCache_get(snippetID);
963  
    if (preferCached && text != null) {
964  
      if (verbose)
965  
        System.out.println("Getting " + snippetID + " from disk cache (preferCached)");
966  
      return text;
967  
    }
968  
969  
    String md5 = text != null ? md5(text) : "-";
970  
    if (text != null) {
971  
      String hash = prefetched.get(snippetID);
972  
      if (hash != null) {
973  
        if (md5.equals(hash)) {
974  
          memSnippetCache.put(snippetID, text);
975  
          if (verbose)
976  
            System.out.println("Getting " + snippetID + " from prefetched");
977  
          return text;
978  
        } else
979  
          prefetched.remove(snippetID); // (maybe this is not necessary)
980  
      }
981  
    }
982  
983  
    try {
984  
      /*URL url = new URL("http://tinybrain.de:8080/getraw.php?id=" + snippetID);
985  
      text = loadPage(url);*/
986  
      String theURL = "http://tinybrain.de:8080/getraw.php?id=" + snippetID + "&getmd5=1&utf8=1&usetranspiled=1";
987  
      if (text != null) {
988  
        //System.err.println("MD5: " + md5);
989  
        theURL += "&md5=" + md5;
990  
      }
991  
      URL url = new URL(theURL);
992  
      String page = loadPage(url);
993  
994  
      // parse & drop transpilation flag available line
995  
      int i = page.indexOf('\n');
996  
      boolean hasTranspiled = page.substring(0, i).trim().equals("1");
997  
      if (hasTranspiled)
998  
        hasTranspiledSet.add(snippetID);
999  
      else
1000  
        hasTranspiledSet.remove(snippetID);
1001  
      page = page.substring(i+1);
1002  
1003  
      if (page.startsWith("==*#*==")) {
1004  
        // same, keep text
1005  
        //System.err.println("Snippet unchanged, keeping.");
1006  
      } else {
1007  
        // drop md5 line
1008  
        i = page.indexOf('\n');
1009  
        String hash = page.substring(0, i).trim();
1010  
        text = page.substring(i+1);
1011  
1012  
        String myHash = md5(text);
1013  
        if (myHash.equals(hash)) {
1014  
          //System.err.println("Hash match: " + hash);
1015  
        } else
1016  
          System.err.println("Hash mismatch");
1017  
      }
1018  
    } catch (Exception e) {
1019  
      e.printStackTrace();
1020  
      throw new IOException("Snippet #" + snippetID + " not found or not public");
1021  
    }
1022  
1023  
    memSnippetCache.put(snippetID, text);
1024  
1025  
    try {
1026  
      initSnippetCache();
1027  
      DiskSnippetCache_put(snippetID, text);
1028  
    } catch (IOException e) {
1029  
      System.err.println("Minor warning: Couldn't save snippet to cache ("  + DiskSnippetCache_getDir() + ")");
1030  
    }
1031  
1032  
    return text;
1033  
  }
1034  
1035  
  private static String md5(String text) {
1036  
    try {
1037  
      return bytesToHex(md5impl(text.getBytes("UTF-8"))); // maybe different than the way PHP does it...
1038  
    } catch (UnsupportedEncodingException e) {
1039  
      throw new RuntimeException(e);
1040  
    }
1041  
  }
1042  
1043  
  public static byte[] md5impl(byte[] data) {
1044  
    try {
1045  
      return MessageDigest.getInstance("MD5").digest(data);
1046  
    } catch (NoSuchAlgorithmException e) {
1047  
      throw new RuntimeException(e);
1048  
    }
1049  
  }
1050  
1051  
  public static byte[] loadBinaryPage(URLConnection con) throws IOException {
1052  
    setHeaders(con);
1053  
    return loadBinaryPage_noHeaders(con);
1054  
  }
1055  
1056  
  private static byte[] loadBinaryPage_noHeaders(URLConnection con) throws IOException {
1057  
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
1058  
    InputStream inputStream = con.getInputStream();
1059  
    int n = 0;
1060  
    while (true) {
1061  
      int ch = inputStream.read();
1062  
      if (ch < 0)
1063  
        break;
1064  
      buf.write(ch);
1065  
      if (++n % 100000 == 0)
1066  
        System.err.println("  " + n + " bytes loaded.");
1067  
    }
1068  
    inputStream.close();
1069  
    return buf.toByteArray();
1070  
  }
1071  
1072  
  private static void setHeaders(URLConnection con) throws IOException {
1073  
    String computerID = getComputerID();
1074  
    if (computerID != null)
1075  
      con.setRequestProperty("X-ComputerID", computerID);
1076  
  }
1077  
1078  
  public static String guessCharset(String contentType) {
1079  
    Pattern p = Pattern.compile("text/html;\\s+charset=([^\\s]+)\\s*");
1080  
    Matcher m = p.matcher(contentType);
1081  
    /* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */
1082  
    return m.matches() ? m.group(1) : "ISO-8859-1";
1083  
  }
1084  
1085  
  /** runs a transpiled set of sources */
1086  
  public static void javax2(File srcDir, File ioBaseDir, boolean silent, boolean runInProcess,
1087  
                            List<File> libraries, String[] args, String cacheAs,
1088  
                            String programID, Info info) throws Exception {
1089  
    if (android) {
1090  
      // TODO: no translator virtualization? huh?
1091  
      javax2android(srcDir, args, programID);
1092  
    } else {
1093  
      File classesDir = TempDirMaker_make();
1094  
      String javacOutput = compileJava(srcDir, libraries, classesDir);
1095  
1096  
      // run
1097  
1098  
      if (verbose) System.out.println("Running program (" + srcDir.getAbsolutePath()
1099  
        + ") on io dir " + ioBaseDir.getAbsolutePath() + (runInProcess ? "[in-process]" : "") + "\n");
1100  
      runProgram(javacOutput, classesDir, ioBaseDir, silent, runInProcess, libraries, args, cacheAs, programID, info);
1101  
    }
1102  
  }
1103  
1104  
  static Class<?> loadx2android(File srcDir, String programID) throws Exception {
1105  
    // TODO: optimize if it's a loaded snippet anyway
1106  
    URL url = new URL("http://tinybrain.de:8080/dexcompile.php");
1107  
    URLConnection conn = url.openConnection();
1108  
    String postData = "src=" + URLEncoder.encode(loadTextFile(new File(srcDir, "main.java").getPath(), null), "UTF-8");
1109  
    byte[] dexData = doPostBinary(postData, conn);
1110  
    if (!isDex(dexData))
1111  
      throw new RuntimeException("Dex generation error: " + dexData.length + " bytes - " + new String(dexData, "UTF-8"));
1112  
    System.out.println("Dex loaded: " + dexData.length + "b");
1113  
1114  
    File dexDir = TempDirMaker_make();
1115  
    File dexFile = new File(dexDir, System.currentTimeMillis() + ".dex");
1116  
    File dexOutputDir = TempDirMaker_make();
1117  
1118  
    System.out.println("Saving dex to: " + dexDir.getAbsolutePath());
1119  
    try {
1120  
      saveBinaryFile(dexFile.getPath(), dexData);
1121  
    } catch (Throwable e) {
1122  
      System.out.println("Whoa!");
1123  
      throw new RuntimeException(e);
1124  
    }
1125  
1126  
    System.out.println("Getting parent class loader.");
1127  
    ClassLoader parentClassLoader =
1128  
      //ClassLoader.getSystemClassLoader(); // does not find support jar
1129  
      //getClass().getClassLoader(); // Let's try this...
1130  
      x30.class.getClassLoader().getParent(); // XXX !
1131  
1132  
    //System.out.println("Making DexClassLoader.");
1133  
    //DexClassLoader classLoader = new DexClassLoader(dexFile.getAbsolutePath(), dexOutputDir.getAbsolutePath(), null,
1134  
    //  parentClassLoader);
1135  
    Class dcl = Class.forName("dalvik.system.DexClassLoader");
1136  
    Object classLoader = dcl.getConstructors()[0].newInstance(dexFile.getAbsolutePath(), dexOutputDir.getAbsolutePath(), null,
1137  
      parentClassLoader);
1138  
1139  
    //System.out.println("Loading main class.");
1140  
    //Class<?> theClass = classLoader.loadClass(mainClassName);
1141  
    Class<?> theClass = (Class<?>) call(classLoader, "loadClass", "main");
1142  
1143  
    //System.out.println("Main class loaded.");
1144  
    try {
1145  
      set(theClass, "androidContext", androidContext);
1146  
    } catch (Throwable e) {}
1147  
1148  
    setVars(theClass, programID);
1149  
    
1150  
    addInstance(programID, theClass);
1151  
    
1152  
    return theClass;
1153  
  }
1154  
  
1155  
  static void addInstance(S programID, Class mainClass) {
1156  
    programID = "" + parseSnippetID(programID);
1157  
    instances.put(programID, new WeakReference<Class>(mainClass));
1158  
  }
1159  
  
1160  
  static Class getInstance(S programID) {
1161  
    programID = "" + parseSnippetID(programID);
1162  
    L<WeakReference<Class>> l = instances.get(programID);
1163  
    for (WeakReference<Class> c : l) {
1164  
      Class theClass = c.get();
1165  
      // TODO: shorten the list
1166  
      if (theClass != null)
1167  
        return theClass;
1168  
    }
1169  
    return null;
1170  
  }
1171  
  
1172  
  static MultiMap<String, WeakReference<Class>> instances = new MultiMap<String, WeakReference<Class>>();
1173  
  
1174  
  !include #1001296 // MultiMap
1175  
1176  
  static void javax2android(File srcDir, String[] args, String programID) throws Exception {
1177  
    Class<?> theClass = loadx2android(srcDir, programID);
1178  
1179  
    Method main = null;
1180  
    try {
1181  
      main = call_findStaticMethod(theClass, "main", new Object[]{androidContext}, false);
1182  
    } catch (RuntimeException e) {
1183  
    }
1184  
1185  
    //System.out.println("main method for " + androidContext + " of " + theClass + ": " + main);
1186  
1187  
    if (main != null) {
1188  
      // old style main program that returns a View
1189  
      // TODO: maybe allow programs without main method, although it doesn't seem to make sense here really (Android main program)
1190  
      System.out.println("Calling main (old-style)");
1191  
      Object view = main.invoke(null, androidContext);
1192  
      System.out.println("Calling setContentView with " + view);
1193  
      call(Class.forName("main"), "setContentViewInUIThread", view);
1194  
      //call(androidContext, "setContentView", view);
1195  
      System.out.println("Done.");
1196  
    } else {
1197  
      System.out.println("New-style main method running.\n\n====\n");
1198  
      runMainMethod(args, theClass);
1199  
    }
1200  
  }
1201  
1202  
  static byte[] DEX_FILE_MAGIC = { 0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00 };
1203  
1204  
  static boolean isDex(byte[] dexData) {
1205  
    if (dexData.length < DEX_FILE_MAGIC.length) return false;
1206  
    for (int i = 0; i < DEX_FILE_MAGIC.length; i++)
1207  
      if (dexData[i] != DEX_FILE_MAGIC[i])
1208  
        return false;
1209  
    return true;
1210  
  }
1211  
1212  
  static byte[] doPostBinary(String urlParameters, URLConnection conn) throws IOException {
1213  
    // connect and do POST
1214  
    setHeaders(conn);
1215  
    conn.setDoOutput(true);
1216  
1217  
    OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
1218  
    writer.write(urlParameters);
1219  
    writer.flush();
1220  
1221  
    byte[] contents = loadBinaryPage_noHeaders(conn);
1222  
    writer.close();
1223  
    return contents;
1224  
  }
1225  
1226  
  static String compileJava(File srcDir, List<File> libraries, File classesDir) throws IOException {
1227  
    javaCompilerOutput = null;
1228  
    ++compilations;
1229  
1230  
    // collect sources
1231  
1232  
    List<File> sources = new ArrayList<File>();
1233  
    if (verbose) System.out.println("Scanning for sources in " + srcDir.getPath());
1234  
    scanForSources(srcDir, sources, true);
1235  
    if (sources.isEmpty())
1236  
      throw new IOException("No sources found");
1237  
1238  
    // compile
1239  
1240  
    File optionsFile = File.createTempFile("javax", "");
1241  
    if (verbose) System.out.println("Compiling " + sources.size() + " source(s) to " + classesDir.getPath());
1242  
    if (verbose) System.out.println("Libraries: " + libraries);
1243  
    String options = "-d " + bashQuote(classesDir.getPath());
1244  
    writeOptions(sources, libraries, optionsFile, options);
1245  
    classesDir.mkdirs();
1246  
    return invokeJavaCompiler(optionsFile);
1247  
  }
1248  
1249  
  private static void runProgram(String javacOutput, File classesDir, File ioBaseDir,
1250  
                                 boolean silent, boolean runInProcess,
1251  
                                 List<File> libraries, String[] args, String cacheAs,
1252  
                                 String programID, Info info) throws Exception {
1253  
    // print javac output if compile failed and it hasn't been printed yet
1254  
    if (info != null) {
1255  
      info.programID = programID;
1256  
      info.programArgs = args;
1257  
    }
1258  
    boolean didNotCompile = !didCompile(classesDir);
1259  
    if (verbose || didNotCompile)
1260  
      System.out.println(javacOutput);
1261  
    if (didNotCompile)
1262  
      return;
1263  
1264  
    if (runInProcess
1265  
      || (ioBaseDir.getAbsolutePath().equals(new File(".").getAbsolutePath()) && !silent)) {
1266  
      runProgramQuick(classesDir, libraries, args, cacheAs, programID, info, ioBaseDir);
1267  
      return;
1268  
    }
1269  
1270  
    boolean echoOK = false;
1271  
    // TODO: add libraries to class path
1272  
    String bashCmd = "(cd " + bashQuote(ioBaseDir.getAbsolutePath()) + " && (java -cp "
1273  
      + bashQuote(classesDir.getAbsolutePath()) + " main" + (echoOK ? "; echo ok" : "") + "))";
1274  
    if (verbose) System.out.println(bashCmd);
1275  
    String output = backtick(bashCmd);
1276  
    lastOutput = output;
1277  
    if (verbose || !silent)
1278  
      System.out.println(output);
1279  
  }
1280  
1281  
  static boolean didCompile(File classesDir) {
1282  
    return hasFile(classesDir, "main.class");
1283  
  }
1284  
1285  
  private static void runProgramQuick(File classesDir, List<File> libraries,
1286  
                                      String[] args, String cacheAs,
1287  
                                      String programID, Info info,
1288  
                                      File ioBaseDir) throws Exception {
1289  
    // make class loader
1290  
    JavaXClassLoader classLoader = new JavaXClassLoader(concatLists(ll(classesDir), libraries));
1291  
1292  
    // load JavaX main class
1293  
    Class<?> mainClass = classLoader.loadClass("main");
1294  
    
1295  
    if (info != null) {
1296  
      info.mainClass = mainClass;
1297  
      if (info.transpiledSrc != null)
1298  
        registerSourceCode(mainClass, loadTextFile(new File(info.transpiledSrc, "main.java")));
1299  
    }
1300  
      
1301  
    if (cacheAs != null)
1302  
      programCache.put(cacheAs, mainClass);
1303  
      
1304  
    // record injection
1305  
    final PaA paa = new PaA(programID, args);
1306  
    paa.injectionID = randomID(8);
1307  
    paa.mainClass = mainClass;
1308  
    addInjection(paa);
1309  
1310  
    // change baseDir
1311  
    try {
1312  
      //print("Changing base dir to " + ioBaseDir.getAbsolutePath());
1313  
      Class virtual = mainClass.getClassLoader().loadClass("virtual");
1314  
      set(virtual, "virtual_baseDir", ioBaseDir.getAbsolutePath());
1315  
    } catch (Throwable e) { /* whatever */ }
1316  
1317  
    setVars(mainClass, programID);
1318  
    addInstance(programID, mainClass);
1319  
    try {
1320  
      runMainMethod(args, mainClass);
1321  
    } catch (Exception e) {
1322  
      paa.exception = e;
1323  
      throw e;
1324  
    } finally {
1325  
      paa.mainDone = true;
1326  
    }
1327  
  }
1328  
1329  
  static void setVars(Class<?> theClass, String programID) {
1330  
    try {
1331  
      set(theClass, "programID", programID);
1332  
    } catch (Throwable e) {}
1333  
1334  
    try {
1335  
      set(theClass, "__javax", x30.class);
1336  
    } catch (Throwable e) {}
1337  
  }
1338  
1339  
1340  
  static void runMainMethod(String[] args, Class<?> mainClass) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
1341  
    callMain(mainClass, args);
1342  
  }
1343  
1344  
  static String invokeJavaCompiler(File optionsFile) throws IOException {
1345  
    String output;
1346  
    if (hasEcj() && !javacOnly)
1347  
      output = invokeEcj(optionsFile);
1348  
    else
1349  
      output = invokeJavac(optionsFile);
1350  
    if (verbose) System.out.println(output);
1351  
    return output;
1352  
  }
1353  
1354  
  private static boolean hasEcj() {
1355  
    try {
1356  
      Class.forName("org.eclipse.jdt.internal.compiler.batch.Main");
1357  
      return true;
1358  
    } catch (ClassNotFoundException e) {
1359  
      return false;
1360  
    }
1361  
  }
1362  
1363  
  // TODO: fix UTF-8 here too
1364  
  private static String invokeJavac(File optionsFile) throws IOException {
1365  
    String output;
1366  
    output = backtick("javac " + bashQuote("@" + optionsFile.getPath()));
1367  
    javaCompilerOutput = output;
1368  
    if (exitValue != 0) {
1369  
      System.out.println(output);
1370  
      throw new RuntimeException("javac returned errors.");
1371  
    }
1372  
    return output;
1373  
  }
1374  
1375  
  // throws ClassNotFoundException if ecj is not in classpath
1376  
  static String invokeEcj(File optionsFile) {
1377  
    try {
1378  
      StringWriter writer = new StringWriter();
1379  
      PrintWriter printWriter = new PrintWriter(writer);
1380  
1381  
      // add more eclipse options in the line below
1382  
1383  
      String[] args = {
1384  
        "-source", javaTarget,
1385  
        "-target", javaTarget,
1386  
        "-nowarn",
1387  
        "-encoding", "UTF-8",
1388  
        "@" + optionsFile.getPath()
1389  
      };
1390  
      
1391  
      if (verbose)
1392  
        print("ECJ options: " + structure(args));
1393  
1394  
      Class ecjClass = Class.forName("org.eclipse.jdt.internal.compiler.batch.Main");
1395  
      Object main = newInstance(ecjClass, printWriter, printWriter, false);
1396  
      call(main, "compile", new Object[]{args});
1397  
      int errors = (Integer) get(main, "globalErrorsCount");
1398  
1399  
      String output = writer.toString();
1400  
      javaCompilerOutput = output;
1401  
      if (errors != 0) {
1402  
        System.out.println(output);
1403  
        throw new RuntimeException("Java compiler returned errors.");
1404  
      }
1405  
      return output;
1406  
    } catch (Exception e) {
1407  
      throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
1408  
    }
1409  
  }
1410  
1411  
  static Object newInstance(Class c, Object... args) { try {
1412  
    Constructor m = findConstructor(c, args);
1413  
    m.setAccessible(true);
1414  
    return m.newInstance(args);
1415  
  } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
1416  
1417  
  static Constructor findConstructor(Class c, Object... args) {
1418  
    for (Constructor m : c.getDeclaredConstructors()) {
1419  
      if (!checkArgs(m.getParameterTypes(), args, verbose))
1420  
        continue;
1421  
      return m;
1422  
    }
1423  
    throw new RuntimeException("Constructor with " + args.length + " matching parameter(s) not found in " + c.getName());
1424  
  }
1425  
1426  
  static boolean checkArgs(Class[] types, Object[] args, boolean debug) {
1427  
    if (types.length != args.length) {
1428  
      if (debug)
1429  
        System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
1430  
      return false;
1431  
    }
1432  
    for (int i = 0; i < types.length; i++)
1433  
      if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
1434  
        if (debug)
1435  
          System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
1436  
        return false;
1437  
      }
1438  
    return true;
1439  
  }
1440  
1441  
  private static void writeOptions(List<File> sources, List<File> libraries,
1442  
                                   File optionsFile, String moreOptions) throws IOException {
1443  
    FileWriter writer = new FileWriter(optionsFile);
1444  
    for (File source : sources)
1445  
      writer.write(bashQuote(source.getPath()) + " ");
1446  
    if (!libraries.isEmpty()) {
1447  
      List<String> cp = new ArrayList<String>();
1448  
      for (File lib : libraries)
1449  
        cp.add(lib.getAbsolutePath());
1450  
      writer.write("-cp " + bashQuote(join(File.pathSeparator, cp)) + " ");
1451  
    }
1452  
    writer.write(moreOptions);
1453  
    writer.close();
1454  
  }
1455  
1456  
  static void scanForSources(File source, List<File> sources, boolean topLevel) {
1457  
    if (source.isFile() && source.getName().endsWith(".java"))
1458  
      sources.add(source);
1459  
    else if (source.isDirectory() && !isSkippedDirectoryName(source.getName(), topLevel)) {
1460  
      File[] files = source.listFiles();
1461  
      for (File file : files)
1462  
        scanForSources(file, sources, false);
1463  
    }
1464  
  }
1465  
1466  
  private static boolean isSkippedDirectoryName(String name, boolean topLevel) {
1467  
    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.)
1468  
    return name.equalsIgnoreCase("input") || name.equalsIgnoreCase("output");
1469  
  }
1470  
1471  
  public final static String charsetForTextFiles = "UTF8";
1472  
1473  
  static long TempDirMaker_lastValue;
1474  
1475  
  public static File TempDirMaker_make() {
1476  
    File dir = new File(userHome(), ".javax/" + TempDirMaker_newValue());
1477  
    dir.mkdirs();
1478  
    return dir;
1479  
  }
1480  
1481  
  private static long TempDirMaker_newValue() {
1482  
    long value;
1483  
    do
1484  
      value = System.currentTimeMillis();
1485  
    while (value == TempDirMaker_lastValue);
1486  
    TempDirMaker_lastValue = value;
1487  
    return value;
1488  
  }
1489  
1490  
  !include #1000810 // join
1491  
  
1492  
  public static boolean isWindows() {
1493  
    return System.getProperty("os.name").contains("Windows");
1494  
  }
1495  
1496  
  public static String makeRandomID(int length) {
1497  
    Random random = new Random();
1498  
    char[] id = new char[length];
1499  
    for (int i = 0; i< id.length; i++)
1500  
      id[i] = (char) ((int) 'a' + random.nextInt(26));
1501  
    return new String(id);
1502  
  }
1503  
1504  
  static String computerID;
1505  
  public static String getComputerID() throws IOException {
1506  
    if (noID) return null;
1507  
    if (computerID == null) {
1508  
      File file = new File(userHome(), ".tinybrain/computer-id");
1509  
      computerID = loadTextFile(file.getPath(), null);
1510  
      if (computerID == null) {
1511  
        computerID = makeRandomID(12);
1512  
        saveTextFile(file.getPath(), computerID);
1513  
      }
1514  
      if (verbose)
1515  
        System.out.println("Local computer ID: " + computerID);
1516  
    }
1517  
    return computerID;
1518  
  }
1519  
1520  
  static void cleanCache() {
1521  
    cleanJavaXCache(tempFileRetentionTime, verbose);
1522  
  }
1523  
1524  
  static void showSystemProperties() {
1525  
    System.out.println("System properties:\n");
1526  
    for (Map.Entry<Object, Object> entry : System.getProperties().entrySet()) {
1527  
      System.out.println("  " + entry.getKey() + " = " + entry.getValue());
1528  
    }
1529  
    System.out.println();
1530  
  }
1531  
1532  
  static void showVersion() {
1533  
    //showSystemProperties();
1534  
    boolean eclipseFound = hasEcj();
1535  
    //String platform = System.getProperty("java.vendor") + " " + System.getProperty("java.runtime.name") + " " + System.getProperty("java.version");
1536  
    String platform = System.getProperty("java.vm.name") + " " + System.getProperty("java.version");
1537  
    String os = System.getProperty("os.name"), arch = System.getProperty("os.arch");
1538  
    System.out.println("This is " + version + ".");
1539  
    System.out.println("[Details: " +
1540  
      (eclipseFound ? "Eclipse compiler (good)" : "javac (not so good)")
1541  
      + ", " + platform + ", " + arch + ", " + os + "]");
1542  
  }
1543  
1544  
  static boolean isAndroid() {
1545  
    return System.getProperty("java.vendor").toLowerCase().indexOf("android") >= 0;
1546  
  }
1547  
  
1548  
  !include #1000415 // set function
1549  
1550  
  static String smartJoin(String[] args) {
1551  
    String[] a2 = new String[args.length];
1552  
    for (int i = 0; i < args.length; i++) {
1553  
      a2[i] = Pattern.compile("\\w+").matcher(args[i]).matches() ? args[i] : quote(args[i]);
1554  
    }
1555  
    return join(" ", a2);
1556  
  }
1557  
  
1558  
  static void logStart(String[] args) throws IOException {
1559  
    String line = smartJoin(args);
1560  
    appendToLog(new File(userHome(), ".javax/log.txt").getPath(), line);
1561  
  }
1562  
  
1563  
  static String quote(String s) {
1564  
    if (s == null) return "null";
1565  
    return "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\r", "\\r").replace("\n", "\\n") + "\"";
1566  
  }
1567  
  
1568  
  static void appendToLog(String path, String line) throws IOException {
1569  
    appendToFile(path, "\n" + line + "\n");
1570  
  }
1571  
  
1572  
  static void appendToFile(String path, String s) throws IOException {
1573  
    new File(path).getParentFile().mkdirs();
1574  
    Writer writer = new BufferedWriter(new OutputStreamWriter(
1575  
      new FileOutputStream(path, true), "UTF-8"));
1576  
    writer.write(s);
1577  
    writer.close();
1578  
  }
1579  
1580  
  !include #1000943
1581  
1582  
  static PrintStream oldOut, oldErr;
1583  
  static Thread reader, reader2;
1584  
  static boolean quit; // always false now
1585  
  static PipedInputStream pin=new PipedInputStream(systemOutPipeSize);
1586  
  static PipedInputStream pin2=new PipedInputStream(systemErrPipeSize);
1587  
  static PipedInputStream pin3=new PipedInputStream(systemInPipeSize);
1588  
  static PipedOutputStream pout3;
1589  
1590  
  static class Console /*extends WindowAdapter implements WindowListener,*/ implements ActionListener {
1591  
    JFrame frame;
1592  
    JTextArea textArea;
1593  
    JTextField tfInput;
1594  
    StringBuffer buf = new StringBuffer();
1595  
    JButton buttonclear, buttonkill, buttonrestart, buttonduplicate, buttonstacktrace, buttonpause, buttonhide;
1596  
    String[] args;
1597  
    volatile boolean autoScroll = true;
1598  
    JScrollPane scrollPane;
1599  
    S title;
1600  
1601  
    final DelayedUpdate du = new DelayedUpdate(new Runnable() {
1602  
      public void run() { try {
1603  
1604  
        synchronized(buf) {
1605  
          int max = maxConsoleChars;
1606  
          if (buf.length() > max) {
1607  
            try {
1608  
              int newLength = max/2;
1609  
              int ofs = buf.length()-newLength;
1610  
              S newString = buf.substring(ofs);
1611  
              buf.setLength(0);
1612  
              buf.append("[...] ").append(newString);
1613  
            } catch (Exception e) {
1614  
              buf.setLength(0);
1615  
            }
1616  
            textArea.setText("");
1617  
          }
1618  
        }
1619  
        
1620  
        textArea.append(buf.substring(textArea.getText().length()));
1621  
        
1622  
        if (autoScroll)
1623  
          scrollToBottom();
1624  
1625  
      } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
1626  
1627  
    public Console(final String[] args) ctex {
1628  
      this.args = args;
1629  
      // create all components and add them
1630  
      frame=new JFrame(args.length == 0 ? "JavaX Starter Output" : "JavaX Output - " + join(" ", args));
1631  
1632  
		/*Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();
1633  
		Dimension frameSize=new Dimension((int)(screenSize.width/2),(int)(screenSize.height/2));
1634  
		int x=(int)(frameSize.width/2);
1635  
		int y=(int)(frameSize.height/2);
1636  
		frame.setBounds(x,y,frameSize.width,frameSize.height);*/
1637  
1638  
      // put in right-bottom corner
1639  
      Rectangle r = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
1640  
      int w = 550, h = 200;
1641  
      frame.setBounds(r.x+r.width-w, r.y+r.height-h, w, h);
1642  
1643  
      textArea=new JTextArea();
1644  
      textArea.setEditable(false);
1645  
      buttonclear = new JButton("clear");
1646  
      buttonkill = new JButton("kill");
1647  
      buttonrestart = new JButton("restart");
1648  
      buttonduplicate = new JButton("duplicate");
1649  
      buttonstacktrace = new JButton("status");
1650  
      buttonstacktrace.setToolTipText("Show threads & stack traces.");
1651  
1652  
      buttonpause = new JButton("pause");
1653  
      buttonhide = new JButton("hide");
1654  
      JPanel buttons = new JPanel(new GridLayout(1, 7));
1655  
      buttons.add(buttonclear);
1656  
      buttons.add(buttonkill);
1657  
      buttons.add(buttonrestart);
1658  
      buttons.add(buttonduplicate);
1659  
      buttons.add(buttonstacktrace);
1660  
      buttons.add(buttonpause);
1661  
      buttons.add(buttonhide);
1662  
1663  
      pout3=new PipedOutputStream(pin3);
1664  
      tfInput = new JTextField();
1665  
      tfInput.addActionListener(actionListener {
1666  
        S line = tfInput.getText();
1667  
        try {
1668  
          pout3.write((line + "\n").getBytes("UTF-8"));
1669  
          pout3.flush();
1670  
        } catch (Exception e) {}
1671  
        //tfInput.setText("");
1672  
        tfInput.selectAll();
1673  
      });
1674  
      addHistoryToTextField(tfInput);
1675  
      
1676  
      JPanel panel = new JPanel(new BorderLayout());
1677  
      panel.add(scrollPane = new JScrollPane(textArea), BorderLayout.CENTER);
1678  
      panel.add(tfInput, BorderLayout.SOUTH);
1679  
      
1680  
      frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
1681  
      frame.addWindowListener(new WindowAdapter() {
1682  
        public void windowActivated(WindowEvent e) {
1683  
          tfInput.requestFocus();
1684  
        }
1685  
        
1686  
        public synchronized void windowClosing(WindowEvent evt) {
1687  
          if (JOptionPane.showConfirmDialog(frame,
1688  
            "Close " + (empty(title) ? "JavaX Application" : title) + "?", "JavaX", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
1689  
            System.exit(0);
1690  
        }
1691  
      });
1692  
      
1693  
      frame.getContentPane().setLayout(new BorderLayout());
1694  
      frame.getContentPane().add(panel, BorderLayout.CENTER);
1695  
      frame.getContentPane().add(buttons, BorderLayout.SOUTH);
1696  
      frame.setVisible(true);
1697  
      setFrameIconLater(frame, "#1004249");
1698  
      
1699  
      //frame.addWindowListener(this); // disabled for now
1700  
      buttonclear.addActionListener(this);
1701  
      buttonkill.addActionListener(this);
1702  
      buttonrestart.addActionListener(this);
1703  
      buttonduplicate.addActionListener(this);
1704  
      buttonstacktrace.addActionListener(this);
1705  
      buttonpause.addActionListener(this);
1706  
      buttonhide.addActionListener(this);
1707  
1708  
      quit=false; // signals the Threads that they should exit
1709  
      
1710  
      if (args.length != 0) {
1711  
        print("Starting title updater");
1712  
        new Thread("Console Title Updater :)") {
1713  
          public void run() {
1714  
            if (args.length != 0) {
1715  
              int i = 0;
1716  
              while (i < args.length && !isSnippetID(args[i])) ++i;
1717  
              print("Getting title for " + args[i]);
1718  
              title = getSnippetTitle(args[i]);
1719  
              print("Title: " + title);
1720  
              if (title != null && title.length() != 0)
1721  
                frame.setTitle(title + " [Output]");
1722  
            }
1723  
          }
1724  
        }.start();
1725  
      }
1726  
      
1727  
      System.setIn(pin3);
1728  
      
1729  
    }
1730  
    
1731  
    void scrollToBottom() {
1732  
      JScrollBar vertical = scrollPane.getVerticalScrollBar();
1733  
      vertical.setValue(vertical.getMaximum());
1734  
    }
1735  
1736  
    /*public synchronized void windowClosed(WindowEvent evt)
1737  
    {
1738  
      console = null;
1739  
      //quit=true;
1740  
      //this.notifyAll(); // stop all threads
1741  
      //try { reader.join(1000);pin.close();   } catch (Exception e){}
1742  
      //try { reader2.join(1000);pin2.close(); } catch (Exception e){}
1743  
      //System.exit(0);
1744  
    }*/
1745  
1746  
    /*public synchronized void windowClosing(WindowEvent evt)
1747  
    {
1748  
      frame.setVisible(false); // default behaviour of JFrame
1749  
      frame.dispose();
1750  
    }*/
1751  
1752  
    public synchronized void actionPerformed(ActionEvent evt) {
1753  
      if (evt.getSource() == buttonkill) {
1754  
        print("Console: Kill button pressed!");
1755  
        // TODO: give threads time to finish, e.g. reportToChat?
1756  
        System.exit(0);
1757  
      } else if (evt.getSource() == buttonrestart) {
1758  
        print("Console: Restart button pressed.");
1759  
        nohupJavax(smartJoin(args));
1760  
        System.exit(0);
1761  
      } else if (evt.getSource() == buttonduplicate) {
1762  
        print("Console: Duplicate button pressed.");
1763  
        nohupJavax(smartJoin(args));
1764  
      } else if (evt.getSource() == buttonstacktrace) {
1765  
        listUserThreadsWithStackTraces();
1766  
      } else if (evt.getSource() == buttonpause) {
1767  
        O mainClass = getMainMainClass();
1768  
        if (mainClass != null) {
1769  
          if (eq(buttonpause.getText(), "pause")) {
1770  
            buttonpause.setText("resume");
1771  
            setOpt(mainClass, "ping_pauseAll", true);
1772  
          } else {
1773  
            buttonpause.setText("pause");
1774  
            setOpt(mainClass, "ping_pauseAll", false);
1775  
          }
1776  
        }
1777  
      } else if (evt.getSource() == buttonhide) {
1778  
        hideConsole();
1779  
      } else {
1780  
        textArea.setText("");
1781  
        buf = new StringBuffer();
1782  
      }
1783  
    }
1784  
    
1785  
    void showConsole() {
1786  
      frame.setVisible(true);
1787  
    }
1788  
1789  
    void hideConsole() {
1790  
      autoVMExit();
1791  
      frame.setVisible(false);
1792  
    }
1793  
    
1794  
    public void appendText(String s, boolean outNotErr) {
1795  
      //if (verbose) oldOut.println("Console appendText " + outNotErr + " " + quote(s));
1796  
      synchronized(buf) {
1797  
        buf.append(s);
1798  
      }
1799  
      du.trigger();
1800  
    }
1801  
  } // Console
1802  
1803  
	static void tryToOpenConsole(String[] args) {
1804  
	  try {
1805  
	    console = new Console(args);
1806  
	  } catch (HeadlessException e) {
1807  
	    // ok, we're headless.
1808  
	  } catch (Throwable e) {
1809  
	    // some other error in console - continue without it
1810  
	    e.printStackTrace();
1811  
	  }
1812  
	}
1813  
1814  
  //// END CONSOLE STUFF
1815  
1816  
  static long now_virtualTime;
1817  
  static long now() {
1818  
    return now_virtualTime != 0 ? now_virtualTime : System.currentTimeMillis();
1819  
  }
1820  
1821  
  static void print(Object o) {
1822  
    System.out.println(o);
1823  
  }
1824  
1825  
  public synchronized void run()
1826  
  {
1827  
    try
1828  
    {
1829  
      while (Thread.currentThread()==reader)
1830  
      {
1831  
        try { this.wait(100);}catch(InterruptedException ie) {}
1832  
        if (pin.available()!=0)
1833  
        {
1834  
          String input=readLine(pin);
1835  
          //if (verbose) oldOut.println("reader: " + quote(input));
1836  
          appendText(input, true);
1837  
        }
1838  
        if (quit) return;
1839  
      }
1840  
1841  
      while (Thread.currentThread()==reader2)
1842  
      {
1843  
        try { this.wait(100);}catch(InterruptedException ie) {}
1844  
        if (pin2.available()!=0)
1845  
        {
1846  
          String input=readLine(pin2);
1847  
          //if (verbose) oldOut.println("reader2: " + quote(input));
1848  
          appendText(input, false);
1849  
        }
1850  
        if (quit) return;
1851  
      }
1852  
    } catch (Exception e)
1853  
    {
1854  
      appendText("\nConsole reports an Internal error.", false);
1855  
      appendText("The error is: "+e, false);
1856  
    }
1857  
  }
1858  
1859  
  static void redirectSystemOutAndErr() {
1860  
    if (reader != null) return; // did this already
1861  
1862  
    x30 _this = new x30();
1863  
    
1864  
    if (verbose) System.out.println("Redirecting System.out");
1865  
    try
1866  
    {
1867  
      PipedOutputStream pout=new PipedOutputStream(pin);
1868  
      oldOut = System.out;
1869  
      TeeOutputStream tee = new TeeOutputStream(oldOut, pout);
1870  
      System.setOut(new PrintStream(tee,true));
1871  
    }
1872  
    catch (Exception io)
1873  
    {
1874  
      System.err.println("Couldn't redirect STDOUT - " + io.getMessage());
1875  
    }
1876  
1877  
    if (verbose) System.out.println("Redirecting System.err");
1878  
    try
1879  
    {
1880  
      PipedOutputStream pout2=new PipedOutputStream(pin2);
1881  
      oldErr = System.err;
1882  
      TeeOutputStream tee = new TeeOutputStream(oldErr, pout2);
1883  
      System.setErr(new PrintStream(tee,true));
1884  
    }
1885  
    catch (Exception io)
1886  
    {
1887  
      System.err.println("Couldn't redirect STDERR - " + io.getMessage());
1888  
    }
1889  
1890  
    if (verbose) System.out.println("Redirects done. Starting readers");
1891  
    
1892  
    // Starting two seperate threads to read from the PipedInputStreams
1893  
    //
1894  
    reader=new Thread(_this, "StdOut Piper");
1895  
    reader.setDaemon(true);
1896  
    reader.start();
1897  
    //
1898  
    reader2 = new Thread(_this, "StdErr Piper");
1899  
    reader2.setDaemon(true);
1900  
    reader2.start();
1901  
  }
1902  
1903  
  static Appendable customSystemOut;
1904  
  static new StringBuffer outBuf; // We now log it all.
1905  
  
1906  
  static new ArrayDeque<S> systemInBuf;
1907  
1908  
  static void appendText(String s, boolean outNotErr) {
1909  
    // We do this with a TeeOutputStream now (safer).
1910  
    // (outNotErr ? oldOut : oldErr).print(s);
1911  
    
1912  
    if (console != null)
1913  
      console.appendText(s, outNotErr);
1914  
    outBuf.append(s);
1915  
    if (customSystemOut != null)
1916  
      try {
1917  
        customSystemOut.append(s);
1918  
      } catch (IOException e) {
1919  
        e.printStackTrace();
1920  
      }
1921  
  }
1922  
1923  
  static String readLine(PipedInputStream in) throws IOException
1924  
  {
1925  
    String input="";
1926  
    do
1927  
    {
1928  
      int available=in.available();
1929  
      if (available==0) break;
1930  
      byte b[]=new byte[available];
1931  
      in.read(b);
1932  
      input=input+new String(b,0,b.length);
1933  
    }while( !input.endsWith("\n") &&  !input.endsWith("\r\n") && !quit);
1934  
    return input;
1935  
  }
1936  
1937  
  static void nohupJavax(String javaxargs) {
1938  
    try {
1939  
      File xfile = new File(userHome(), ".javax/x30.jar");
1940  
      if (!xfile.isFile()) {
1941  
        String url = "http://tinybrain.de/x30.jar";
1942  
        byte[] data = loadBinaryPage(new URL(url).openConnection());
1943  
        if (data.length < 1000000)
1944  
          throw new RuntimeException("Could not load " + url);
1945  
        saveBinaryFile(xfile.getPath(), data);
1946  
      }
1947  
      String jarPath = xfile.getPath();
1948  
      nohup("java -jar " + (isWindows() ? winQuote(jarPath) : bashQuote(jarPath)) + " " + javaxargs);
1949  
    } catch (Exception e) { throw new RuntimeException(e); }
1950  
  }
1951  
1952  
  /** possibly improvable */
1953  
  public static String winQuote(String text) {
1954  
    if (text == null) return null;
1955  
    return "\"" + text
1956  
      .replace("\\", "\\\\")
1957  
      .replace("\"", "\\\"")
1958  
      .replace("\n", "\\n")
1959  
      .replace("\r", "\\r") + "\"";
1960  
  }
1961  
1962  
  public static File nohup(String cmd) throws IOException {
1963  
    File outFile = File.createTempFile("nohup_" + nohup_sanitize(cmd), ".out");
1964  
    nohup(cmd, outFile, false);
1965  
    return outFile;
1966  
  }
1967  
1968  
  static String nohup_sanitize(String s) {
1969  
    return s.replaceAll("[^a-zA-Z0-9\\-_]", "");
1970  
  }
1971  
1972  
  /** outFile takes stdout and stderr. */
1973  
  public static void nohup(String cmd, File outFile, boolean append) throws IOException {
1974  
    String command = nohup_makeNohupCommand(cmd, outFile, append);
1975  
1976  
    File scriptFile = File.createTempFile("_realnohup", isWindows() ? ".bat" : "");
1977  
    System.out.println("[Nohup] " + command);
1978  
    try {
1979  
      //System.out.println("[RealNohup] Script file: " + scriptFile.getPath());
1980  
      saveTextFile(scriptFile.getPath(), command);
1981  
      String[] command2;
1982  
      if (isWindows())
1983  
        command2 = new String[] {"cmd", "/c", "start", "/b", scriptFile.getPath() };
1984  
      else
1985  
        command2 = new String[] {"/bin/bash", scriptFile.getPath() };
1986  
1987  
      Process process = Runtime.getRuntime().exec(command2);
1988  
      try {
1989  
        process.waitFor();
1990  
      } catch (InterruptedException e) {
1991  
        throw new RuntimeException(e);
1992  
      }
1993  
      int value = process.exitValue();
1994  
      //System.out.println("exit value: " + value);
1995  
    } finally {
1996  
      if (!isWindows())
1997  
        scriptFile.delete();
1998  
    }
1999  
  }
2000  
2001  
  public static String nohup_makeNohupCommand(String cmd, File outFile, boolean append) {
2002  
    mkdirsForFile(outFile);
2003  
2004  
    String command;
2005  
    if (isWindows())
2006  
      command = cmd + (append ? " >>" : " >") + winQuote(outFile.getPath()) + " 2>&1";
2007  
    else
2008  
      command = "nohup " + cmd + (append ? " >>" : " >") + bashQuote(outFile.getPath()) + " 2>&1 &";
2009  
    return command;
2010  
  }
2011  
2012  
  public static void mkdirsForFile(File file) {
2013  
    File dir = file.getParentFile();
2014  
    if (dir != null) // is null if file is in current dir
2015  
      dir.mkdirs();
2016  
  }
2017  
 
2018  
  static void autoReportToChat() {
2019  
    if (customSystemOut == null) {
2020  
      print("Auto-reporting to chat.");
2021  
      customSystemOut = new Appendable() {
2022  
        LineBuf buf = new LineBuf();
2023  
        
2024  
        // only using this one
2025  
        public Appendable append(CharSequence cs) {
2026  
          buf.append(cs.toString());
2027  
          while (true) {
2028  
            String s = buf.nextLine();
2029  
            if (s == null) break;
2030  
            reportToChat(s, true);
2031  
          }
2032  
          return this;
2033  
        }
2034  
    
2035  
        public Appendable append(char c) { return this; }
2036  
        public Appendable append(CharSequence s, int start, int end) { return this; }
2037  
      };
2038  
     }
2039  
  }
2040  
  
2041  
  static class Q {
2042  
    LinkedBlockingQueue<Runnable> q = new LinkedBlockingQueue<Runnable>();
2043  
    
2044  
    static class Done extends RuntimeException {}
2045  
    
2046  
    Q() {}
2047  
    
2048  
    Q(String name, boolean startThread) {
2049  
      if (startThread)
2050  
        new Thread(name) {
2051  
          public void run() {
2052  
            Q.this.run();
2053  
          }
2054  
        }.start();
2055  
    }
2056  
    
2057  
    Iterable<Runnable> master() {
2058  
      return new Iterable<Runnable>() {
2059  
        public Iterator<Runnable> iterator() {
2060  
          return new Iterator<Runnable>() {
2061  
            Runnable x;
2062  
            
2063  
            public boolean hasNext() { try {
2064  
   
2065  
              //debug("hasNext");
2066  
              while (x == null)
2067  
                x = q.poll(1, TimeUnit.DAYS);
2068  
              //debug("hasNext true");
2069  
              return true;
2070  
            
2071  
  } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
2072  
            
2073  
            public Runnable next() {
2074  
              //debug("next");
2075  
              hasNext();
2076  
              Runnable _x = x;
2077  
              x = null;
2078  
              //debug("next " + structure(x));
2079  
              return _x;
2080  
            }
2081  
            
2082  
            public void remove() {
2083  
            }
2084  
          };
2085  
        }
2086  
      };
2087  
    }
2088  
    
2089  
    void add(Runnable r) {
2090  
      q.add(r);
2091  
    }
2092  
    
2093  
    void run() {
2094  
      for (Runnable r : master()) {
2095  
        try {
2096  
          r.run();
2097  
        } catch (Done e) {
2098  
          return; // break signal
2099  
        } catch (Throwable e) {
2100  
          e.printStackTrace();
2101  
        }
2102  
      }
2103  
    }
2104  
    
2105  
    void done() {
2106  
      add(new Runnable() {
2107  
        public void run() {
2108  
          throw new Done();
2109  
        }
2110  
      });
2111  
    }
2112  
  } // class Q
2113  
2114  
static void reportToChat(final String s, boolean silent) {
2115  
    if (s == null || s.length() == 0) return;
2116  
    if (!silent)
2117  
      print("reportToChat: " + quote(s));
2118  
    reportToChat_getChatThread().add(new Runnable() {
2119  
    public void run() { try {
2120  
        startChatServerIfNotUp();
2121  
        waitForChatServer();
2122  
        chatSend(s);
2123  
    } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
2124  
   }
2125  
  
2126  
  static Q reportToChat_q;
2127  
  
2128  
  static Q reportToChat_getChatThread() {
2129  
    if (reportToChat_q == null)
2130  
      reportToChat_q = new Q("reportToChat", true);
2131  
    return reportToChat_q;
2132  
  }
2133  
  
2134  
  static void startChatServerIfNotUp() {
2135  
    if (portIsBound(9751)) {
2136  
      //print("Chat seems to be up.");
2137  
    } else {
2138  
      nohupJavax("1000867");
2139  
      print("Chat server should be coming up any minute now.");
2140  
    }
2141  
  }
2142  
  
2143  
  static void waitForChatServer() {
2144  
    if (!portIsBound(9751)) {
2145  
      //System.out.print("Waiting for chat server... ");
2146  
      do {
2147  
        sleep(1000);
2148  
      } while (!portIsBound(9751));
2149  
      //print("OK.");
2150  
    }
2151  
  }
2152  
2153  
  static boolean portIsBound(int port) {
2154  
    try {
2155  
      ServerSocket s = new ServerSocket(port);
2156  
      s.close();
2157  
      return false;
2158  
    } catch (IOException e) {
2159  
      return true;
2160  
    }
2161  
  }
2162  
  
2163  
  static class LineBuf {
2164  
    StringBuffer buf = new StringBuffer();
2165  
    
2166  
    void append(String s) {
2167  
      buf.append(s);
2168  
    }
2169  
    
2170  
    String nextLine() {
2171  
      int i = buf.indexOf("\n");
2172  
      if (i >= 0) {
2173  
        String s = buf.substring(0, i > 0 && buf.charAt(i-1) == '\r' ? i-1 : i);
2174  
        buf.delete(0, i+1);
2175  
        return s;
2176  
      }
2177  
      return null;
2178  
    }
2179  
  } // LineBuf
2180  
2181  
  !include #1000937 // chatSend
2182  
2183  
  static class TeeOutputStream extends OutputStream {
2184  
    
2185  
    protected OutputStream out, branch;
2186  
2187  
    public TeeOutputStream( OutputStream out, OutputStream branch ) {
2188  
      this.out = out;
2189  
      this.branch = branch;
2190  
    }
2191  
2192  
    @Override
2193  
    public synchronized void write(byte[] b) throws IOException {
2194  
      write(b, 0, b.length);
2195  
    }
2196  
2197  
    @Override
2198  
    public synchronized void write(byte[] b, int off, int len) throws IOException {
2199  
      //if (verbose) oldOut.println("Tee write " + new String(b, "UTF-8"));
2200  
      out.write(b, off, len);
2201  
      this.branch.write(b, off, len);
2202  
    }
2203  
2204  
    @Override
2205  
    public synchronized void write(int b) throws IOException {
2206  
      write(new byte[] {(byte) b});
2207  
    }
2208  
2209  
    /**
2210  
     * Flushes both streams.
2211  
     * @throws IOException if an I/O error occurs
2212  
     */
2213  
    @Override
2214  
    public void flush() throws IOException {
2215  
      out.flush();
2216  
      this.branch.flush();
2217  
    }
2218  
2219  
    /**
2220  
     * Closes both streams.
2221  
     * @throws IOException if an I/O error occurs
2222  
     */
2223  
    @Override
2224  
    public void close() throws IOException {
2225  
      out.close();
2226  
      this.branch.close();
2227  
    }
2228  
  }
2229  
  
2230  
  static boolean isChatServer(String[] args) {
2231  
    for (int i = 0; i < args.length; i++)
2232  
      if (isSnippetID(args[i]))
2233  
        return parseSnippetID(args[i]) == 1000867;
2234  
    return false;
2235  
  }
2236  
  
2237  
  static String getSnippetTitle(String id) {
2238  
    try {
2239  
      return loadPage(new URL("http://tinybrain.de:8080/tb-int/getfield.php?id=" + parseSnippetID(id) + "&field=title"));
2240  
    } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }
2241  
  }
2242  
  
2243  
  static void listUserThreadsWithStackTraces() {
2244  
    print("");
2245  
    Map<Thread, StackTraceElement[]> threadMap = Thread.getAllStackTraces();
2246  
    int n = 0;
2247  
    for (Thread t : threadMap.keySet()) {
2248  
      ThreadGroup g = t.getThreadGroup();
2249  
      if (g != null && g.getName().equals("system")) continue;
2250  
      ++n;
2251  
      print(t);
2252  
      for (StackTraceElement e : threadMap.get(t)) {
2253  
        print("  " + e);
2254  
      }
2255  
      print("");
2256  
    }
2257  
    print(n + " user threads.");
2258  
  }
2259  
  
2260  
  static void killMyself() {
2261  
    print("Killing myself. (insert overall feeling here)");
2262  
    System.exit(0);
2263  
  }
2264  
  
2265  
  static void makeVMAndroid() {
2266  
    Android3 a = new Android3("This is a JavaX VM.");
2267  
    a.responder = new Responder() {
2268  
      S answer(S s, L<S> history) {
2269  
        return x30.answer(s, history);
2270  
      }
2271  
    };
2272  
    a.daemon = true;
2273  
    a.console = false;
2274  
    a.incomingSilent = true; // to avoid too much printing
2275  
    a.useMultiPort = false;
2276  
    makeAndroid3(a);
2277  
  }
2278  
  
2279  
  static class Info {
2280  
    S programID;
2281  
    S[] programArgs;
2282  
    File transpiledSrc;
2283  
    Class mainClass;
2284  
  }
2285  
  
2286  
  static new Info info; // hmm...
2287  
  
2288  
  // injectable info
2289  
  
2290  
  static new L<PaA> injectable_programsInjected;
2291  
  static boolean injectable_on = true;
2292  
  static class PaA {
2293  
    S injectionID;
2294  
    S progID;
2295  
    S[] arguments;
2296  
    Class mainClass; // TODO: release eventually...
2297  
    WeakReference<Thread> mainThread;
2298  
    volatile boolean mainDone;
2299  
    volatile Throwable exception;
2300  
    
2301  
    *(S *progID, S[] *arguments) {}
2302  
    *() {}
2303  
  }
2304  
  
2305  
  static S vmID = makeRandomID(10);
2306  
  
2307  
  static synchronized void addInjection(PaA paa) {
2308  
    injectable_programsInjected.add(paa);
2309  
  }
2310  
  
2311  
  static synchronized void removeInjection(PaA paa) {
2312  
    injectable_programsInjected.remove(paa);
2313  
  }
2314  
  
2315  
  static synchronized L<PaA> getInjections() {
2316  
    ret cloneList(injectable_programsInjected);
2317  
  }
2318  
  
2319  
  static S answer(S s, L<S> history) ctex {
2320  
    new Matches m;
2321  
    
2322  
    if (match3("kill!", s)) {
2323  
      killMyself();
2324  
      return "ok";
2325  
    }
2326  
    if (match3("What is your process ID?", s) || match3("what is your pid?", s))
2327  
      return getPID();
2328  
    if (match3("get vm id", s))
2329  
      return vmID;
2330  
    if (match3("what is the javax program id?", s))
2331  
      return javaxProgramID;
2332  
    if (match3("what is the main program id?", s))
2333  
      return info.programID;
2334  
    if (match3("what are your program arguments?", s))
2335  
      return structure(info.programArgs);
2336  
    if (match3("get output", s))
2337  
      return quote(outBuf.toString());
2338  
    if (match3("get output length", s))
2339  
      return "" + outBuf.length();
2340  
    if (match3("get output substring from *", s, m))
2341  
      return quote(outBuf.substring(parseInt(m.get(0))));
2342  
    if (match3("get output substring from * to *", s, m))
2343  
      return quote(outBuf.substring(parseInt(m.get(0)), parseInt(m.get(1))));
2344  
    if (match3("clear output", s)) {
2345  
      synchronized(x30.class) {
2346  
        int len = outBuf.length();
2347  
        outBuf.setLength(0);
2348  
        return "OK, deleted " + len + " chars.";
2349  
      }
2350  
    }
2351  
    if (match3("send line * to system.in", s, m)) {
2352  
      S line = m.unq(0);
2353  
      synchronized(x30.class) {
2354  
        systemInBuf.add(line);
2355  
      }
2356  
      ret "ok";
2357  
    }
2358  
    if (match3("get fields of main class", s))
2359  
      return structure(listFields(info.mainClass));
2360  
    if (match3("get field * of main class", s, m))
2361  
      return structure(get(info.mainClass, m.m[0]));
2362  
    if (match3("invoke function * of main class", s, m))
2363  
      return structure(call(info.mainClass, m.m[0]));
2364  
    if (match3("set field * of main class to *", s, m)) {
2365  
      set(info.mainClass, m.m[0], unstructure(m.m[1]));
2366  
      return "ok";
2367  
    }
2368  
    if (match3("how much memory are you consuming", s))
2369  
      return "Java heap size: " + (Runtime.getRuntime().totalMemory()+1024*1024-1)/1024/1024 + " MB";
2370  
    if (match3("how much memory is used after GC?", s)) {
2371  
      System.gc();
2372  
      return "Java heap used: " + (Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()+1024*1024-1)/1024/1024 + " MB";
2373  
    }
2374  
    if (match3("how much memory is used?", s))
2375  
      return "Java heap used: " + (Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()+1024*1024-1)/1024/1024 + " MB";
2376  
      
2377  
    if (match3("please inject program *", s, m) || match3("please inject program * with arguments *", s, m)) {
2378  
      synchronized(x30.class) {
2379  
        final S progID = formatSnippetID(unquote(m.m[0]));
2380  
        final S[] arguments = m.m.length > 1 ? toStringArray(unstructure(unquote(m.m[1]))) : new S[0];
2381  
        final PaA paa = new PaA(progID, arguments);
2382  
        paa.injectionID = randomID(8);
2383  
        addInjection(paa);
2384  
    
2385  
        // better call JavaX for translation in a single thread.
2386  
        paa.mainClass = hotwire(progID);
2387  
    
2388  
        // program may run in its own thread.
2389  
        thread progID {
2390  
          paa.mainThread = new WeakReference(currentThread());
2391  
          try {
2392  
            callMain(paa.mainClass, arguments);
2393  
          } catch (Throwable e) {
2394  
            paa.exception = e;
2395  
            e.printStackTrace();
2396  
          } finally {
2397  
            paa.mainDone = true;
2398  
            synchronized(x30.class) {}
2399  
          }
2400  
        }
2401  
  
2402  
        ret format3("OK. Injection ID: *", paa.injectionID);
2403  
      }
2404  
    }
2405  
    
2406  
    if (match3("get injection exception *", s, m)) {
2407  
      S injectionID = unquote(m.m[0]);
2408  
      PaA paa = findInjection(injectionID);
2409  
      if (paa == null)
2410  
        ret "Sorry. Injection not found";
2411  
      ret "OK: " + paa.exception == null ? "no exception" : getStackTrace(paa.exception);
2412  
    }
2413  
     
2414  
    if (match3("get injection * variable *", s, m)) {
2415  
      S injectionID = unquote(m.m[0]);
2416  
      S var = unquote(m.m[1]);
2417  
      PaA paa = findInjection(injectionID);
2418  
      if (paa == null)
2419  
        ret "Sorry. Injection not found";
2420  
      ret "OK: " + structure(getOpt(paa.mainClass, var));
2421  
    }
2422  
     
2423  
    if (match3("get injection result *", s, m)) {
2424  
      S injectionID = unquote(m.m[0]);
2425  
      PaA paa = findInjection(injectionID);
2426  
      if (paa == null)
2427  
        ret "Sorry. Injection not found";
2428  
      ret "OK: " + structure(getOpt(paa.mainClass, "result"));
2429  
    }
2430  
     
2431  
    if (match3("is injection's * main done", s, m)) {
2432  
      S injectionID = unquote(m.m[0]);
2433  
      PaA paa = findInjection(injectionID);
2434  
      if (paa == null)
2435  
        ret "Sorry. Injection not found";
2436  
      ret paa.mainDone ? "Yes." : "No.";
2437  
    }
2438  
    
2439  
    if (match3("get injections", s, m)) {
2440  
      ret structure(getInjections());
2441  
    }
2442  
    
2443  
    if (match3("remove injection *", s, m)) {
2444  
      S injectionID = unquote(m.m[0]);
2445  
      PaA paa = findInjection(injectionID);
2446  
      if (paa == null)
2447  
        ret "Sorry. Injection not found";
2448  
      removeInjection(paa);
2449  
      ret "OK, removed.";
2450  
    }
2451  
    
2452  
    if (match3("which programs are you running (ids only)", s, m)) {
2453  
      synchronized(x30.class) {
2454  
        new L<S> l;
2455  
        for (S progID : instances.keySet())
2456  
          if (getInstance(progID) != null)
2457  
            l.add(progID);
2458  
        return format3("these: *", structure(l));
2459  
      }
2460  
    }
2461  
    
2462  
    if "show console" {
2463  
      if (console != null) {
2464  
        console.showConsole();
2465  
        ret "ok";
2466  
      }
2467  
      ret "no console";
2468  
    }
2469  
    
2470  
    if "hide console" {
2471  
      if (console != null) {
2472  
        console.hideConsole();
2473  
        ret "ok";
2474  
      }
2475  
      ret "no console";
2476  
    }
2477  
     
2478  
    L multiPorts = getMultiPorts();
2479  
    if (!multiPorts.isEmpty()) {
2480  
      O multiPort = multiPorts.get(0);
2481  
      S answer = makeResponder(multiPort).answer(s, history);
2482  
      if (answer != null) ret answer;
2483  
    }
2484  
    
2485  
    if (match3("list bots", s))
2486  
      ret structure(litmap());
2487  
    
2488  
    return null;
2489  
  }
2490  
  
2491  
  static synchronized PaA findInjection(S injectionID) {
2492  
    for (PaA paa : injectable_programsInjected)
2493  
      if (eq(paa.injectionID, injectionID))
2494  
        ret paa;
2495  
    ret null;
2496  
  }
2497  
  
2498  
  !include #1001103 // makeAndroid / makeAndroidNoConsole
2499  
  !include #1000891 // setOpt
2500  
  !include #1000619 // get
2501  
  !include #1001152 // getMainClass
2502  
  !include #1001076 // talkTo
2503  
  !include #1001235 // toStringArray
2504  
  
2505  
static byte[] loadDataSnippetImpl(String snippetID) throws IOException {
2506  
  byte[] data;
2507  
  try {
2508  
    URL url = new URL("http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_"
2509  
      + parseSnippetID(snippetID) + "&contentType=application/binary");
2510  
    System.err.println("Loading library: " + url);
2511  
    try {
2512  
      data = loadBinaryPage(url.openConnection());
2513  
    } catch (IOException e) {
2514  
      data = null;
2515  
    }
2516  
    
2517  
    if (data == null || data.length == 0) {
2518  
      url = new URL("http://data.tinybrain.de/blobs/"
2519  
        + parseSnippetID(snippetID));
2520  
      System.err.println("Loading library: " + url);
2521  
      data = loadBinaryPage(url.openConnection());
2522  
    }
2523  
    System.err.println("Bytes loaded: " + data.length);
2524  
  } catch (FileNotFoundException e) {
2525  
    throw new IOException("Binary snippet #" + snippetID + " not found or not public");
2526  
  }
2527  
  return data;
2528  
}
2529  
  static new AtomicBoolean readLine_used;
2530  
  static BufferedReader readLine_reader;
2531  
  
2532  
  static synchronized S pollSystemInBuf() {
2533  
    ret systemInBuf.poll();
2534  
  }
2535  
2536  
  static S readLine() ctex {
2537  
    if (!readLine_used.compareAndSet(false, true))
2538  
      throw fail("readLine is in use.");
2539  
    try {
2540  
      while (true) {
2541  
        S s = pollSystemInBuf();
2542  
        if (s != null) {
2543  
          print(s);
2544  
          ret s;
2545  
        }
2546  
        
2547  
        if (readLine_reader == null)
2548  
          readLine_reader = new BufferedReader(new InputStreamReader(System.in, "UTF-8")); // XX - is that right?
2549  
          
2550  
        if (!readLine_reader.ready())
2551  
          sleep(100);
2552  
        else {
2553  
          s = readLine_reader.readLine();
2554  
          if (s != null) {
2555  
            print(s);
2556  
            ret s;
2557  
          }
2558  
        }
2559  
      }
2560  
    } finally {
2561  
      readLine_used.set(false);
2562  
    }
2563  
  }
2564  
  
2565  
  static new HashMap<S, WeakReference> weakrefs;
2566  
  // static new WeakIdentityHashMap<O, S> reverseWeakrefs;
2567  
  static long weakRefCounter;
2568  
  
2569  
  // TODO: lookup in reverse map
2570  
  static synchronized S weakref(O o) {
2571  
    if (o == null) ret "null";
2572  
    S id = vmID + "/" + ++weakRefCounter;
2573  
    weakrefs.put(id, new WeakReference(o));
2574  
    ret id;
2575  
  }
2576  
2577  
  static synchronized O getRef(S id) {
2578  
    // TODO: clean up the list some time
2579  
    
2580  
    WeakReference ref = weakrefs.get(id);
2581  
    if (ref == null) ret null;
2582  
    ret ref.get();
2583  
  }
2584  
  
2585  
  static new L<O> multiPorts;
2586  
  
2587  
  static synchronized L<O> getMultiPorts() {
2588  
    ret cloneList(multiPorts);
2589  
  }
2590  
  
2591  
  // true if you're the first one
2592  
  static synchronized boolean addMultiPort(O o) {
2593  
    multiPorts.add(o);
2594  
    if (multiPorts.size() == 1) {
2595  
      thread "keep alive" { x30.sleep(); } // keep VM alive since there is a multiport
2596  
    }
2597  
    ret multiPorts.size() == 1;
2598  
  }
2599  
  
2600  
  static synchronized void removeMultiPort(O o) {
2601  
    multiPorts.remove(o);
2602  
  }
2603  
  
2604  
  static S getInjectionID(Class mainClass) {
2605  
    L<PaA> l = getInjections();
2606  
    for (PaA injection : l)
2607  
      if (injection.mainClass == mainClass)
2608  
        ret injection.injectionID;
2609  
    ret null;
2610  
  }
2611  
  
2612  
  static S getInjectionID() { return null; } // used somewhere...
2613  
  
2614  
  static void sleep(long ms) {
2615  
    try {
2616  
      Thread.sleep(ms);
2617  
    } catch (Exception e) { throw new RuntimeException(e); }
2618  
  }
2619  
2620  
  static void sleep() ctex {
2621  
    print("Sleeping.");
2622  
    synchronized(x30.class) { x30.class.wait(); }
2623  
  }
2624  
  
2625  
  static new WeakHashMap<Class, S> classToSourceCode;
2626  
  
2627  
  synchronized static void registerSourceCode(Class c, S src) {
2628  
    classToSourceCode.put(c, src);
2629  
  }
2630  
  
2631  
  synchronized static S getSourceCodeForClass(Class c) {
2632  
    ret classToSourceCode.get(c);
2633  
  }
2634  
  
2635  
  !include #1001496 // Matches
2636  
  
2637  
  static void autoScroll(boolean on) {
2638  
    if (console == null) ret;
2639  
    console.autoScroll = on;
2640  
    if (on) awt {
2641  
      console.scrollToBottom();
2642  
    }
2643  
  }
2644  
  
2645  
  // get main class of first program (for console)
2646  
  static O getMainMainClass() {
2647  
    PaA paa = first(getInjections());
2648  
    ret paa == null ? null : paa.mainClass;
2649  
  }
2650  
  
2651  
  static bool _inCore() {
2652  
    ret true;
2653  
  }
2654  
}

Author comment

Began life as a copy of #1001638

download  show line numbers  debug dex  old transpilations   

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

No comments. add comment

Snippet ID: #1004305
Snippet name: x31.java (JavaX)
Eternal ID of this version: #1004305/1
Text MD5: 9ee6923a1e19030a9f639c86aa5ef762
Transpilation MD5: e482cb4ffdf12ddc692f31266962e9dc
Author: stefan
Category: javax
Type: JavaX source code
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2016-08-25 16:37:22
Source code size: 90420 bytes / 2654 lines
Pitched / IR pitched: No / No
Views / Downloads: 674 / 967
Referenced in: [show references]