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

2859
LINES

< > BotCompany Repo | #1024219 // x30.java (JavaX) backup with JTextArea

JavaX module (desktop)

Download Jar.

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

Author comment

Began life as a copy of #1001638

download  show line numbers  debug dex  old transpilations   

Travelled to 7 computer(s): bhatertpkbcr, mqqgnosmbjvj, podlckwnjdmb, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1024219
Snippet name: x30.java (JavaX) backup with JTextArea
Eternal ID of this version: #1024219/1
Text MD5: 0474664c74fa12cb07b1b2471b3a51d3
Author: stefan
Category: javax
Type: JavaX module (desktop)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2019-07-26 23:06:45
Source code size: 96430 bytes / 2859 lines
Pitched / IR pitched: No / No
Views / Downloads: 372 / 529
Referenced in: [show references]