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

5242
LINES

< > BotCompany Repo | #1004183 // Boot-up code for JavaX/Android (backup)

JavaX source code (Android) - run with: the app

1  
import java.util.*;
2  
import java.util.zip.*;
3  
import java.util.List;
4  
import java.util.regex.*;
5  
import java.util.concurrent.*;
6  
import java.util.concurrent.atomic.*;
7  
import java.io.*;
8  
import java.net.*;
9  
import java.lang.reflect.*;
10  
import java.lang.ref.*;
11  
import java.lang.management.*;
12  
import java.security.*;
13  
import java.security.spec.*;
14  
import java.math.*;
15  
16  
import android.widget.*;
17  
import android.view.*;
18  
import android.view.View;
19  
import android.content.Context;
20  
import android.app.Activity;
21  
import android.view.inputmethod.*;
22  
import android.content.*;
23  
import android.text.*;
24  
25  
public class main {
26  
  static String awarenessID = "#1004078";
27  
  
28  
  static List<Prog> programsStarted = new ArrayList<Prog>();
29  
  static File defSnip, defargs;
30  
31  
  static class Prog {
32  
    String snippetID;
33  
    Thread thread;
34  
  }
35  
36  
  static class Lg {
37  
    static int maxBufferLength = 2048;
38  
    
39  
    Activity context;
40  
    ScrollView sv;
41  
    TextView tv;
42  
    StringBuilder buf = new StringBuilder();
43  
    
44  
    Lg(Activity context) {
45  
      this.context = context;
46  
      sv = new ScrollView(context);
47  
      tv = new TextView(context);
48  
      tv.setText(buf.toString());
49  
      sv.addView(tv);
50  
    }
51  
    
52  
    View getView() {
53  
      return sv;
54  
    }
55  
    
56  
    void shortenBuffer() {
57  
      while (buf.length() > maxBufferLength) {
58  
        String s = buf.toString();
59  
        int i = s.indexOf('\n');
60  
        if (i < 0) return;
61  
        buf = new StringBuilder(s.substring(i+1));
62  
      }
63  
    }
64  
    
65  
    void print(final String s) {
66  
      context.runOnUiThread(new Runnable() {
67  
        public void run() {
68  
          buf.append(s);
69  
          shortenBuffer();
70  
          tv.setText(buf.toString());
71  
          
72  
          sv.post(new Runnable() {
73  
            public void run() {
74  
              // This method works but animates the scrolling 
75  
              // which looks weird on first load
76  
              sv.fullScroll(View.FOCUS_DOWN);
77  
78  
              // This method works even better because there are no animations.
79  
              //sv.scrollTo(0, sv.getBottom());
80  
            }
81  
          });
82  
        }
83  
      });
84  
    }
85  
    
86  
    void println(String s) {
87  
      print(s + "\n");
88  
    }
89  
  }
90  
  
91  
  public static String snippetToRun;
92  
  
93  
  public static View main(final Context _context) throws Exception {
94  
    final Activity context = _context instanceof Activity ? (Activity) _context : null;
95  
    
96  
    System.out.println("676 context: " + _context);
97  
    
98  
    x30.androidContext = _context;
99  
    
100  
    if (context == null) {
101  
      if (snippetToRun != null) {
102  
        new Thread() {
103  
          public void run() {
104  
            String[] a = { snippetToRun };
105  
            x30.main(a);
106  
          }
107  
        }.start();
108  
      }
109  
      return null;
110  
    }
111  
    
112  
    defSnip = new File(x30.userHome(), ".javax/defsnip");
113  
    String id = x30.loadTextFile(defSnip.getPath(), "636");
114  
    defargs = new File(x30.userHome(), ".javax/defargs");
115  
    String arg = x30.loadTextFile(defargs.getPath(), "");
116  
117  
    ScrollView sv = new ScrollView(context);
118  
    LinearLayout ll = new LinearLayout(context);
119  
    ll.setOrientation(LinearLayout.VERTICAL);
120  
    
121  
    LinearLayout line1 = new LinearLayout(context);
122  
    
123  
    TextView label = new TextView(context);
124  
    label.setText("Run which snippet ID?");
125  
    line1.addView(label);
126  
    
127  
    final EditText tv = new EditText(context);
128  
    // BAD - tv.setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL);
129  
    tv.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_CLASS_NUMBER);
130  
    tv.setText(id);
131  
    line1.addView(tv);
132  
    
133  
    Button btnGo = new Button(context);
134  
    btnGo.setText("Go");
135  
    line1.addView(btnGo);
136  
    
137  
    ll.addView(line1);
138  
    
139  
    LinearLayout line2 = new LinearLayout(context);
140  
    
141  
    label = new TextView(context);
142  
    label.setText("Program arguments:");
143  
    line2.addView(label);
144  
    
145  
    final EditText tvArgs = new EditText(context);
146  
    tvArgs.setText(arg);
147  
    line2.addView(tvArgs);
148  
    
149  
    ll.addView(line2);
150  
    
151  
    LinearLayout line3 = new LinearLayout(context);
152  
    
153  
    /*Button btnLeo = new Button(context);
154  
    btnLeo.setText("Sprechen mit Leo");
155  
    line3.addView(btnLeo);*/
156  
    
157  
    Button btn = new Button(context);
158  
    btn.setText("Start Awareness [" + awarenessID + "]");
159  
    btn.setOnClickListener(new View.OnClickListener() {
160  
      public void onClick(View v) {
161  
        saveDef(awarenessID, "");
162  
        run(context, awarenessID, new String[0]);
163  
      }
164  
    });
165  
    line3.addView(btn);
166  
167  
    ll.addView(line3);
168  
    
169  
    btnGo.setOnClickListener(new View.OnClickListener() {
170  
      public void onClick(View v) {
171  
        hideKeyboard(context);
172  
        String snippetID = tv.getText().toString();
173  
        String text = "Running: " + snippetID;
174  
        Toast.makeText(context, text, 2000).show();
175  
        
176  
        saveDef(snippetID, tvArgs.getText().toString());
177  
        
178  
        // TODO: quoted args
179  
        run(context, snippetID, tvArgs.getText().toString().split(" +"));
180  
      }
181  
    });
182  
183  
    sv.addView(ll);
184  
    return sv;
185  
  }
186  
  
187  
  static void saveDef(String snippetID, String args) {
188  
    try {
189  
      x30.saveTextFile(defSnip.getPath(), snippetID);
190  
      x30.saveTextFile(defargs.getPath(), args);
191  
    } catch (IOException e) {
192  
    }
193  
  }
194  
  
195  
  static Lg lg;
196  
  
197  
  public static void run(final Activity context, final String mainSnippet, final String[] args) {
198  
    lg = new Lg(context);
199  
    
200  
    OutputStream outputStream = new OutputStream() {
201  
      public void write(int b) {
202  
        try {
203  
          lg.print(new String(new byte[] {(byte) b}, "UTF-8")); // This is crap
204  
        } catch (UnsupportedEncodingException e) {}
205  
      }
206  
      
207  
      @Override
208  
      public void write(byte[] b, int off, int len) {
209  
        try {
210  
          lg.print(new String(b, off, len, "UTF-8")); // This is crap
211  
        } catch (UnsupportedEncodingException e) {}
212  
      }
213  
    };
214  
    
215  
    PrintStream ps = new PrintStream(outputStream, true);
216  
    System.setOut(ps);
217  
    System.setErr(ps);
218  
    
219  
    Prog prog = new Prog();
220  
    prog.snippetID = mainSnippet;
221  
222  
    prog.thread = new Thread() {
223  
      public void run() {
224  
        try {
225  
          String[] a = new String[args.length+1];
226  
          System.arraycopy(args, 0, a, 1, args.length);
227  
          a[0] = mainSnippet;
228  
          x30.main(a);
229  
        } catch (Throwable e) {
230  
          System.out.println("Whoa!");
231  
          e.printStackTrace();
232  
        }
233  
      }
234  
    };
235  
    
236  
    programsStarted.add(prog);
237  
    prog.thread.start();
238  
    
239  
    context.setContentView(lg.getView());
240  
  }
241  
  
242  
  static void setContentViewInUIThread(final View view) {
243  
    ((Activity) x30.androidContext).runOnUiThread(new Runnable() {
244  
      public void run() {
245  
        ((Activity) x30.androidContext).setContentView(view);
246  
      }
247  
    });
248  
  }
249  
  
250  
  public static void hideKeyboard(Activity context) {   
251  
    View view = context.getCurrentFocus();
252  
    if (view != null) {
253  
        InputMethodManager inputManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
254  
        inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
255  
    }
256  
  }
257  
  
258  
  static void onActivityResult(int requestCode, int resultCode, Intent data) {
259  
    /* TODO?
260  
    if (x30.mainClass != null)
261  
      x30.call(x30.mainClass, "onActivityResult", requestCode, resultCode, data);*/
262  
  }
263  
}
264  
265  
/**
266  
 JavaX runner version 30
267  
268  
 Changes to v29:
269  
 -weakref
270  
 -made first program an injection
271  
 -manage multi-ports
272  
 -multitry for loadPage (partially implemented)
273  
 -list injections
274  
 -additional "get output" questions
275  
 -send line * to system.in
276  
 -multi-port 1 accessible directly through VM android
277  
 -getInjectionID (from main.class)
278  
 -allow programs without main method
279  
 -increase buffer size for PipedInputStream (console output/input)
280  
 -registerSourceCode + getSourceCodeForClass
281  
 -autoScroll
282  
 -retaining class files for 30 days (restart JavaX programs after 30 days!!)
283  
 -close confirmation for console (no running apps without console!)
284  
 -utf8 fixed in transpilations!
285  
 -maxConsoleChars
286  
 -pause button
287  
 
288  
 TODO when making x31: change program ID in source
289  
 */
290  
291  
interface StringFunc {
292  
  String get(String s);
293  
}
294  
295  
class x30 implements Runnable {
296  
  static final String version = "JavaX 30";
297  
  static final int subversion = 1;
298  
  static final String javaxProgramID = "#1001638";
299  
  
300  
  // If programs run longer than this, they might have their class files
301  
  // deleted. We make it way longer for now.
302  
  static int tempFileRetentionTime = 30*24; // hours
303  
  
304  
  static int maxConsoleChars = 1024*1024;
305  
  
306  
  static boolean verbose = false, translate = false, list = false, virtualizeTranslators = true;
307  
  static String translateTo = null;
308  
  static boolean preferCached = false, noID = false, noPrefetch = false, noAWT = false;
309  
  static boolean safeOnly = false, safeTranslate = false, javacOnly = false, logOn = true;
310  
  static boolean runMainInProcess = true, consoleOn = true, hasHelloMessage = false;
311  
  static List<String[]> mainTranslators = new ArrayList<String[]>();
312  
  private static Map<Long, String> memSnippetCache = new HashMap<Long, String>();
313  
  private static int processesStarted, compilations;
314  
315  
  // snippet ID -> md5
316  
  private static HashMap<Long, String> prefetched = new HashMap<Long, String>();
317  
  private static File virtCache;
318  
  
319  
  // doesn't work yet
320  
  private static Map<String, Class<?>> programCache = new HashMap<String, Class<?>>();
321  
  static boolean cacheTranslators = false;
322  
323  
  // this should work (caches transpiled translators)
324  
  private static HashMap<Long, Object[]> translationCache = new HashMap<Long, Object[]>();
325  
  static boolean cacheTranspiledTranslators = true;
326  
327  
  // which snippets are available pre-transpiled server-side?
328  
  private static Set<Long> hasTranspiledSet = new HashSet<Long>();
329  
  static boolean useServerTranspiled = true;
330  
331  
  static Object androidContext;
332  
  static boolean android = isAndroid();
333  
  
334  
  // We stick to 1.7 for now to support android.
335  
  // Scripts like #1001155 might change to 1.6
336  
  static String javaTarget = System.getProperty("java.version").startsWith("1.6.") ? "1.6" : "1.7";
337  
338  
  // Translators currently being translated (to detect recursions)
339  
  private static Set<Long> translating = new HashSet<Long>();
340  
341  
  static String lastOutput;
342  
  static String[] fullArgs;
343  
  private static Console console;
344  
  
345  
  static String javaCompilerOutput;
346  
  
347  
  static int systemOutPipeSize = 128*1024; // 128 K
348  
  static int systemErrPipeSize = 4*1024; // 4 K
349  
  static int systemInPipeSize = 4*1024; // 4 K
350  
351  
  public static void main(String[] args) {
352  
    try {
353  
      goMain(args);
354  
    } catch (Throwable e) {
355  
      e.printStackTrace();
356  
    }
357  
  }
358  
  
359  
  static void goMain(String[] args) throws Exception {
360  
    __javax = x30.class; // for hotwire
361  
    
362  
    if (args.length != 0 && args[0].equals("-v")) verbose = true;
363  
364  
    for (String arg : args)
365  
      if (arg.equals("-noawt"))
366  
        noAWT = true;
367  
        
368  
    if (!hasHelloMessage) {
369  
      hasHelloMessage = true;
370  
      //installHelloMessage(args.length == 0 ? "JavaX Start-Up VM" : "JavaX VM (" + smartJoin(args) + ")");
371  
      makeVMAndroid();
372  
    }
373  
    
374  
    File ioBaseDir = new File("."), inputDir = null, outputDir = null;
375  
    String src = null;
376  
    List<String> programArgs = new ArrayList<String>();
377  
    fullArgs = args;
378  
379  
    for (int i = 0; i < args.length; i++) {
380  
      String arg = args[i];
381  
382  
      if (arg.equals("-version")) {
383  
        showVersion();
384  
        System.exit(0);
385  
      }
386  
387  
      if (arg.equals("-sysprop")) {
388  
        showSystemProperties();
389  
        return;
390  
      }
391  
392  
      if (arg.equals("-v") || arg.equals("-verbose"))
393  
        verbose = true;
394  
      else if (arg.equals("-finderror"))
395  
        verbose = true;
396  
      else if (arg.equals("-offline") || arg.equalsIgnoreCase("-prefercached"))
397  
        preferCached = true;
398  
      else if (arg.equals("-novirt"))
399  
        virtualizeTranslators = false;
400  
      else if (arg.equals("-safeonly"))
401  
        safeOnly = true;
402  
      else if (arg.equals("-safetranslate"))
403  
        safeTranslate = true;
404  
      else if (arg.equals("-noawt"))
405  
        noAWT = true;
406  
      else if (arg.equals("-noid"))
407  
        noID = true;
408  
      else if (arg.equals("-nocachetranspiled"))
409  
        cacheTranspiledTranslators = false;
410  
      else if (arg.equals("-javac"))
411  
        javacOnly = true;
412  
      else if (arg.equals("-localtranspile"))
413  
        useServerTranspiled = false;
414  
      else if (arg.equals("translate") && src == null)
415  
        translate = true;
416  
      else if (arg.equals("list") && src == null) {
417  
        list = true;
418  
        virtualizeTranslators = false; // so they are silenced
419  
      } else if (arg.equals("run") && src == null) {
420  
        // it's the default command anyway
421  
      } else if (arg.startsWith("input="))
422  
        inputDir = new File(arg.substring(6));
423  
      else if (arg.startsWith("output="))
424  
        outputDir = new File(arg.substring(7));
425  
      else if (arg.equals("with"))
426  
        mainTranslators.add(new String[] {args[++i], null});
427  
      else if (translate && arg.equals("to"))
428  
        translateTo = args[++i];
429  
      else if (src == null) {
430  
        //System.out.println("src=" + arg);
431  
        src = arg;
432  
      } else
433  
        programArgs.add(arg);
434  
    }
435  
436  
    cleanCache();
437  
438  
    if (useServerTranspiled)
439  
      noPrefetch = true;
440  
441  
    if (src == null) src = ".";
442  
443  
    // Might actually want to write to 2 disk caches (global/per program).
444  
    if (virtualizeTranslators && !preferCached)
445  
      virtCache = TempDirMaker_make();
446  
447  
    if (inputDir != null) {
448  
      ioBaseDir = TempDirMaker_make();
449  
      System.out.println("Taking input from: " + inputDir.getAbsolutePath());
450  
      System.out.println("Output is in: " + new File(ioBaseDir, "output").getAbsolutePath());
451  
      copyInput(inputDir, new File(ioBaseDir, "input"));
452  
    }
453  
    
454  
    if (logOn)
455  
      logStart(args);
456  
457  
    javaxmain(src, ioBaseDir, translate, list, programArgs.toArray(new String[programArgs.size()]));
458  
459  
    if (outputDir != null) {
460  
      copyInput(new File(ioBaseDir, "output"), outputDir);
461  
      System.out.println("Output copied to: " + outputDir.getAbsolutePath());
462  
    }
463  
464  
    if (verbose) {
465  
      // print stats
466  
      System.out.println("Processes started: " + processesStarted + ", compilations: " + compilations);
467  
    }
468  
  }
469  
470  
  public static void javaxmain(String src, File ioDir, boolean translate, boolean list,
471  
                               String[] args) throws Exception {
472  
    String programID = isSnippetID(src) ? "" + parseSnippetID(src) : null;
473  
    
474  
    if (programID != null)
475  
      System.err.println("JavaX TRANSLATE " + programID + " " + smartJoin(args));
476  
    
477  
    List<File> libraries = new ArrayList<File>();
478  
    File X = transpileMain(src, libraries);
479  
    if (verbose)
480  
      print("After transpileMain: " + X);
481  
      
482  
    if (X == null) {
483  
      showVersion();
484  
      
485  
      if (fullArgs != null) {
486  
        String[] nargs;
487  
        if (fullArgs.length == 0)
488  
          nargs = new String[] {"1000825"}; // swing-start
489  
        else {
490  
          // forward to search
491  
          nargs = new String[fullArgs.length+1];
492  
          nargs[0] = "636";
493  
          // nargs[1] = "search-runnables";
494  
          System.arraycopy(fullArgs, 0, nargs, 1, fullArgs.length);
495  
        }
496  
        main(nargs); // Hopefully we get no infinite recursion :)
497  
        return;
498  
      }
499  
      
500  
      System.out.println("No main.java found, exiting");
501  
      return;
502  
    }
503  
    
504  
    info.transpiledSrc = X;
505  
506  
    // list or run
507  
508  
    if (translate) {
509  
      File to = X;
510  
      if (translateTo != null) {
511  
        StringBuilder buf = new StringBuilder();
512  
        for (File f : libraries) buf.append(f.getName()+"\n");
513  
        if (new File(translateTo).isDirectory()) {
514  
          to = new File(translateTo, "main.java");
515  
          saveTextFile(new File(translateTo, "libraries.txt").getPath(), buf.toString());
516  
        } else {
517  
          to = new File(translateTo);
518  
          saveTextFile(new File(translateTo + "_libraries").getPath(), buf.toString());
519  
        }
520  
      }
521  
      if (to != X)
522  
        copy(new File(X, "main.java"), to);
523  
      System.out.println("Program translated to: " + to.getAbsolutePath());
524  
    } else if (list)
525  
      System.out.println(loadTextFile(new File(X, "main.java").getPath(), null));
526  
    else {
527  
      if (programID != null)
528  
        System.err.println("JavaX RUN " + programID + " " + smartJoin(args));
529  
      System.err.println(); // Make empty line before actual program starts
530  
      
531  
      javax2(X, ioDir, false, runMainInProcess, libraries, args, null, programID, info);
532  
      
533  
      System.out.println("[main done]");
534  
    }
535  
  }
536  
537  
  static File transpileMain(String src, List<File> libraries) throws Exception {
538  
    File srcDir = null;
539  
    boolean isTranspiled = false;
540  
    if (isSnippetID(src)) {
541  
      String transpiledSrc = getTranspilationFromBossBot(parseSnippetID(src));
542  
      if (transpiledSrc != null) {
543  
        int i = transpiledSrc.indexOf('\n');
544  
        String libs = transpiledSrc.substring(0, Math.max(0, i));
545  
        transpiledSrc = transpiledSrc.substring(i+1);
546  
        if (!transpiledSrc.isEmpty()) {
547  
          srcDir = TempDirMaker_make();
548  
          saveTextFile(new File(srcDir, "main.java").getPath(), transpiledSrc);
549  
          isTranspiled = true;
550  
551  
          Matcher m = Pattern.compile("\\d+").matcher(libs);
552  
          while (m.find()) {
553  
            String libid = m.group();
554  
            File libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(libid));
555  
            loadLibrary(libid, libraries, libraryFile);
556  
          }
557  
        }
558  
      }
559  
     
560  
      if (srcDir == null) {
561  
        prefetch(src);
562  
        long id = parseSnippetID(src);
563  
        prefetched.remove(id); // hackfix to ensure transpiled main program is found.
564  
        srcDir = loadSnippetAsMainJava(src);
565  
        if (verbose)
566  
          System.err.println("hasTranspiledSet: " + hasTranspiledSet);
567  
        if (hasTranspiledSet.contains(id) && useServerTranspiled) {
568  
          //System.err.println("Trying pretranspiled main program: #" + id);
569  
          transpiledSrc = getServerTranspiled("#" + id);
570  
          int i = transpiledSrc.indexOf('\n');
571  
          String libs = transpiledSrc.substring(0, Math.max(0, i));
572  
          transpiledSrc = transpiledSrc.substring(i+1);
573  
          if (!transpiledSrc.isEmpty()) {
574  
            srcDir = TempDirMaker_make();
575  
            saveTextFile(new File(srcDir, "main.java").getPath(), transpiledSrc);
576  
            isTranspiled = true;
577  
            //translationCache.put(id, new Object[] {srcDir, libraries});
578  
  
579  
            Matcher m = Pattern.compile("\\d+").matcher(libs);
580  
            while (m.find()) {
581  
              String libid = m.group();
582  
              File libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(libid));
583  
              loadLibrary(libid, libraries, libraryFile);
584  
            }
585  
          }
586  
        }
587  
      }
588  
    } else {
589  
      srcDir = new File(src);
590  
591  
      // if the argument is a file, it is assumed to be main.java
592  
      if (srcDir.isFile()) {
593  
        srcDir = TempDirMaker_make();
594  
        copy(new File(src), new File(srcDir, "main.java"));
595  
      }
596  
597  
      if (!new File(srcDir, "main.java").exists())
598  
        return null;
599  
    }
600  
601  
    // translate
602  
603  
    File X = srcDir;
604  
605  
    if (!isTranspiled) {
606  
      X = topLevelTranslate(X, libraries);
607  
      System.err.println("Translated " + src);
608  
609  
      // save prefetch data
610  
      if (isSnippetID(src))
611  
        savePrefetchData(src);
612  
    }
613  
    return X;
614  
  }
615  
616  
  private static void prefetch(String mainSnippetID) throws IOException {
617  
    if (noPrefetch) return;
618  
619  
    long mainID = parseSnippetID(mainSnippetID);
620  
    String s = mainID + " " + loadTextFile(new File(userHome(), ".tinybrain/prefetch/" + mainID + ".txt").getPath(), "");
621  
    String[] ids = s.trim().split(" ");
622  
    if (ids.length > 1) {
623  
      String url = "http://tinybrain.de:8080/tb-int/prefetch.php?ids=" + URLEncoder.encode(s, "UTF-8");
624  
      String data = loadPage(new URL(url));
625  
      String[] split = data.split(" ");
626  
      if (split.length == ids.length)
627  
        for (int i = 0; i < ids.length; i++)
628  
          prefetched.put(parseSnippetID(ids[i]), split[i]);
629  
    }
630  
  }
631  
632  
  static String userHome() {
633  
    if (android)
634  
      return ((File) call(androidContext, "getFilesDir")).getAbsolutePath();
635  
    else
636  
      return System.getProperty("user.home");
637  
  }
638  
639  
  private static void savePrefetchData(String mainSnippetID) throws IOException {
640  
    List<String> ids = new ArrayList<String>();
641  
    long mainID = parseSnippetID(mainSnippetID);
642  
643  
    for (long id : memSnippetCache.keySet())
644  
      if (id != mainID)
645  
        ids.add(String.valueOf(id));
646  
647  
    saveTextFile(new File(userHome(),".tinybrain/prefetch/" + mainID + ".txt").getPath(), join(" ", ids));
648  
  }
649  
650  
  static File topLevelTranslate(File srcDir, List<File> libraries_out) throws Exception {
651  
    File X = srcDir;
652  
    X = applyTranslators(X, mainTranslators, libraries_out); // translators supplied on command line (unusual)
653  
654  
    // actual inner translation of the JavaX source
655  
    X = defaultTranslate(X, libraries_out);
656  
    return X;
657  
  }
658  
659  
  private static File defaultTranslate(File x, List<File> libraries_out) throws Exception {
660  
    x = luaPrintToJavaPrint(x);
661  
    x = repeatAutoTranslate(x, libraries_out);
662  
    return x;
663  
  }
664  
665  
  private static File repeatAutoTranslate(File x, List<File> libraries_out) throws Exception {
666  
    List<String[]> postTranslators = new ArrayList<String[]>();
667  
    
668  
    while (true) {
669  
      String main = loadTextFile(new File(x, "main.java").getPath(), null);
670  
      List<String> lines = toLines(main);
671  
      List<String[]> t = findPostTranslators(lines);
672  
      postTranslators.addAll(t);
673  
      
674  
      if (!t.isEmpty()) {
675  
        main = fromLines(lines);
676  
        x = TempDirMaker_make();
677  
        saveTextFile(new File(x, "main.java").getPath(), main);
678  
      }
679  
680  
      File y = autoTranslate(x, libraries_out);
681  
      if (y == x)
682  
        break;
683  
      x = y;
684  
    }
685  
    
686  
    x = applyTranslators(x, postTranslators, libraries_out);
687  
    
688  
    return x;
689  
  }
690  
691  
  private static File autoTranslate(File x, List<File> libraries_out) throws Exception {
692  
    String main = loadTextFile(new File(x, "main.java").getPath(), null);
693  
    List<String> lines = toLines(main);
694  
    List<String[]> translators = findTranslators(lines);
695  
    if (translators.isEmpty())
696  
      return x;
697  
698  
    main = fromLines(lines);
699  
    File newDir = TempDirMaker_make();
700  
    saveTextFile(new File(newDir, "main.java").getPath(), main);
701  
    return applyTranslators(newDir, translators, libraries_out);
702  
  }
703  
704  
  static List<String[]> findTranslators(List<String> lines) {
705  
    List<String[]> translators = new ArrayList<String[]>();
706  
    Pattern pattern = Pattern.compile("^!([0-9# \t]+)");
707  
    Pattern pArgs = Pattern.compile("^\\s*\\((.*)\\)");
708  
    for (ListIterator<String> iterator = lines.listIterator(); iterator.hasNext(); ) {
709  
      String line = iterator.next();
710  
      line = line.trim();
711  
      Matcher matcher = pattern.matcher(line);
712  
      if (matcher.find()) {
713  
        String[] t = matcher.group(1).split("[ \t]+");
714  
        String rest = line.substring(matcher.end());
715  
        String arg = null;
716  
        if (t.length == 1) {
717  
          Matcher mArgs = pArgs.matcher(rest);
718  
          if (mArgs.find())
719  
            arg = mArgs.group(1);
720  
        }
721  
        for (String transi : t)
722  
          translators.add(new String[]{transi, arg});
723  
        iterator.remove();
724  
      }
725  
    }
726  
    return translators;
727  
  }
728  
729  
  static List<String[]> findPostTranslators(List<String> lines) {
730  
    List<String[]> translators = new ArrayList<String[]>();
731  
    Pattern pattern = Pattern.compile("^!post\\s*([0-9# \t]+)");
732  
    Pattern pArgs = Pattern.compile("^\\s*\\((.*)\\)");
733  
    for (ListIterator<String> iterator = lines.listIterator(); iterator.hasNext(); ) {
734  
      String line = iterator.next();
735  
      line = line.trim();
736  
      Matcher matcher = pattern.matcher(line);
737  
      if (matcher.find()) {
738  
        String[] t = matcher.group(1).split("[ \t]+");
739  
        String rest = line.substring(matcher.end());
740  
        String arg = null;
741  
        if (t.length == 1) {
742  
          Matcher mArgs = pArgs.matcher(rest);
743  
          if (mArgs.find())
744  
            arg = mArgs.group(1);
745  
        }
746  
        for (String transi : t)
747  
          translators.add(new String[]{transi, arg});
748  
        iterator.remove();
749  
      }
750  
    }
751  
    return translators;
752  
  }
753  
754  
  public static List<String> toLines(String s) {
755  
    List<String> lines = new ArrayList<String>();
756  
    int start = 0;
757  
    while (true) {
758  
      int i = toLines_nextLineBreak(s, start);
759  
      if (i < 0) {
760  
        if (s.length() > start) lines.add(s.substring(start));
761  
        break;
762  
      }
763  
764  
      lines.add(s.substring(start, i));
765  
      if (s.charAt(i) == '\r' && i+1 < s.length() && s.charAt(i+1) == '\n')
766  
        i += 2;
767  
      else
768  
        ++i;
769  
770  
      start = i;
771  
    }
772  
    return lines;
773  
  }
774  
775  
  private static int toLines_nextLineBreak(String s, int start) {
776  
    for (int i = start; i < s.length(); i++) {
777  
      char c = s.charAt(i);
778  
      if (c == '\r' || c == '\n')
779  
        return i;
780  
    }
781  
    return -1;
782  
  }
783  
784  
  public static String fromLines(List<String> lines) {
785  
    StringBuilder buf = new StringBuilder();
786  
    for (String line : lines) {
787  
      buf.append(line).append('\n');
788  
    }
789  
    return buf.toString();
790  
  }
791  
792  
  private static File applyTranslators(File x, List<String[]> translators, List<File> libraries_out) throws Exception {
793  
    for (String[] translator : translators)
794  
      x = applyTranslator(x, translator[0], translator[1], libraries_out);
795  
    return x;
796  
  }
797  
798  
  // also takes a library
799  
  private static File applyTranslator(File x, String translator, String arg, List<File> libraries_out) throws Exception {
800  
    if (verbose)
801  
      System.out.println("Using translator " + translator + " on sources in " + x.getPath());
802  
803  
    File newDir = runTranslatorOnInput(translator, null, arg, x, !verbose, libraries_out);
804  
805  
    if (!new File(newDir, "main.java").exists()) {
806  
      throw new Exception("Translator " + translator + " did not generate main.java");
807  
      // TODO: show translator output
808  
    }
809  
    if (verbose)
810  
      System.out.println("Translated with " + translator + " from " + x.getPath() + " to " + newDir.getPath());
811  
    x = newDir;
812  
    return x;
813  
  }
814  
815  
  private static File luaPrintToJavaPrint(File x) throws IOException {
816  
    File newDir = TempDirMaker_make();
817  
    String code = loadTextFile(new File(x, "main.java").getPath(), null);
818  
    code = luaPrintToJavaPrint(code);
819  
    saveTextFile(new File(newDir, "main.java").getPath(), code);
820  
    return newDir;
821  
  }
822  
823  
  public static String luaPrintToJavaPrint(String code) {
824  
    return ("\n" + code).replaceAll(
825  
      "(\n\\s*)print (\".*\")",
826  
      "$1System.out.println($2);").substring(1);
827  
  }
828  
829  
  public static File loadSnippetAsMainJava(String snippetID) throws IOException {
830  
    checkProgramSafety(snippetID);
831  
    File srcDir = TempDirMaker_make();
832  
    saveTextFile(new File(srcDir, "main.java").getPath(), loadSnippet(snippetID));
833  
    return srcDir;
834  
  }
835  
836  
  public static File loadSnippetAsMainJavaVerified(String snippetID, String hash) throws IOException {
837  
    checkProgramSafety(snippetID);
838  
    File srcDir = TempDirMaker_make();
839  
    saveTextFile(new File(srcDir, "main.java").getPath(), loadSnippetVerified(snippetID, hash));
840  
    return srcDir;
841  
  }
842  
843  
  @SuppressWarnings( "unchecked" )
844  
  /** returns output dir */
845  
  private static File runTranslatorOnInput(String snippetID, String hash, String arg, File input,
846  
                                           boolean silent,
847  
                                           List<File> libraries_out) throws Exception {
848  
    if (safeTranslate)
849  
      checkProgramSafetyImpl(snippetID);
850  
    long id = parseSnippetID(snippetID);
851  
852  
    // It's a library, not a translator.
853  
    File libraryFile = DiskSnippetCache_getLibrary(id);
854  
    if (verbose)
855  
      System.out.println("Library file for " + id + ": " + libraryFile);
856  
    if (libraryFile != null) {
857  
      loadLibrary(snippetID, libraries_out, libraryFile);
858  
      return input;
859  
    }
860  
861  
    String[] args = arg != null ? new String[]{arg} : new String[0];
862  
863  
    File srcDir = hash == null ? loadSnippetAsMainJava(snippetID)
864  
      : loadSnippetAsMainJavaVerified(snippetID, hash);
865  
    long mainJavaSize = new File(srcDir, "main.java").length();
866  
867  
    if (verbose)
868  
      System.out.println(snippetID + ": length = " + mainJavaSize);
869  
    if (mainJavaSize == 0) { // no text in snippet? assume it's a library
870  
      loadLibrary(snippetID, libraries_out, libraryFile);
871  
      return input;
872  
    }
873  
874  
    List<File> libraries = new ArrayList<File>();
875  
    Object[] cached = translationCache.get(id);
876  
    if (cached != null) {
877  
      //System.err.println("Taking translator " + snippetID + " from cache!");
878  
      srcDir = (File) cached[0];
879  
      libraries = (List<File>) cached[1];
880  
    } else if (hasTranspiledSet.contains(id) && useServerTranspiled) {
881  
      System.err.println("Trying pretranspiled translator: #" + snippetID);
882  
      String transpiledSrc = getServerTranspiled(snippetID);
883  
      transpiledSrc = transpiledSrc.substring(transpiledSrc.indexOf('\n')+1);
884  
      // TODO: check for libraries
885  
      if (!transpiledSrc.isEmpty()) {
886  
        srcDir = TempDirMaker_make();
887  
        saveTextFile(new File(srcDir, "main.java").getPath(), transpiledSrc);
888  
        translationCache.put(id, cached = new Object[] {srcDir, libraries});
889  
      }
890  
    }
891  
892  
    File ioBaseDir = TempDirMaker_make();
893  
894  
    /*Class<?> mainClass = programCache.get("" + parseSnippetID(snippetID));
895  
    if (mainClass != null)
896  
      return runCached(ioBaseDir, input, args);*/
897  
    // Doesn't work yet because virtualized directories are hardcoded in translator...
898  
899  
    if (cached == null) {
900  
      System.err.println("Translating translator #" + id);
901  
      if (translating.contains(id))
902  
        throw new RuntimeException("Recursive translator reference chain: " + structure(translating));
903  
      translating.add(id);
904  
      try {
905  
        srcDir = defaultTranslate(srcDir, libraries);
906  
      } finally {
907  
        translating.remove(id);
908  
      }
909  
      System.err.println("Translated translator #" + id);
910  
      translationCache.put(id, new Object[]{srcDir, libraries});
911  
    }
912  
913  
    boolean runInProcess = false;
914  
915  
    if (virtualizeTranslators) {
916  
      if (verbose) System.out.println("Virtualizing translator");
917  
918  
      // TODO: don't virtualize class _javax (as included in, say, #636)
919  
920  
      //srcDir = applyTranslator(srcDir, "#2000351"); // I/O-virtualize the translator
921  
      // that doesn't work because it recurses infinitely...
922  
923  
      // So we do it right here:
924  
      String s = loadTextFile(new File(srcDir, "main.java").getPath(), null);
925  
      s = s.replaceAll("new\\s+File\\(", "virtual.newFile(");
926  
      s = s.replaceAll("new\\s+FileInputStream\\(", "virtual.newFileInputStream(");
927  
      s = s.replaceAll("new\\s+FileOutputStream\\(", "virtual.newFileOutputStream(");
928  
      s += "\n\n" + loadSnippet("#2000355"); // load class virtual
929  
930  
      // forward snippet cache (virtualized one)
931  
      File dir = virtCache != null ? virtCache : DiskSnippetCache_dir;
932  
      s = s.replace("static File DiskSnippetCache_dir" + ";",
933  
        "static File DiskSnippetCache_dir " + "= new File(" + javaQuote(dir.getAbsolutePath()) + ");"); // extra + is necessary for Dumb TinyBrain :)
934  
      s = s.replace("static boolean preferCached = false;", "static boolean preferCached = true;");
935  
936  
      if (verbose) {
937  
        System.out.println("==BEGIN VIRTUALIZED TRANSLATOR==");
938  
        System.out.println(s);
939  
        System.out.println("==END VIRTUALIZED TRANSLATOR==");
940  
      }
941  
      srcDir = TempDirMaker_make();
942  
      saveTextFile(new File(srcDir, "main.java").getPath(), s);
943  
944  
      // TODO: silence translator also
945  
      runInProcess = true;
946  
    }
947  
948  
    return runJavaX(ioBaseDir, srcDir, input, silent, runInProcess, libraries,
949  
      args, cacheTranslators ? "" + id : null, "" + id);
950  
  }
951  
952  
  static void checkProgramSafety(String snippetID) throws IOException {
953  
    if (!safeOnly) return;
954  
    checkProgramSafetyImpl(snippetID);
955  
  }
956  
957  
  static void checkProgramSafetyImpl(String snippetID) throws IOException {
958  
    URL url = new URL("http://tinybrain.de:8080/tb-int/is-javax-safe.php?id=" + parseSnippetID(snippetID));
959  
    String text = loadPage(url);
960  
    if (!text.startsWith("{\"safe\":\"1\"}"))
961  
      throw new RuntimeException("Program not safe: #" + parseSnippetID(snippetID));
962  
  }
963  
964  
  static void loadLibrary(String snippetID, List<File> libraries_out, File libraryFile) throws IOException {
965  
    if (verbose)
966  
      System.out.println("Assuming " + snippetID + " is a library.");
967  
968  
    if (libraryFile == null) {
969  
      byte[] data = loadDataSnippetImpl(snippetID);
970  
      DiskSnippetCache_putLibrary(parseSnippetID(snippetID), data);
971  
      libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(snippetID));
972  
    }
973  
974  
    if (!libraries_out.contains(libraryFile))
975  
      libraries_out.add(libraryFile);
976  
  }
977  
978  
  /** returns output dir */
979  
  private static File runJavaX(File ioBaseDir, File originalSrcDir, File originalInput,
980  
                               boolean silent, boolean runInProcess,
981  
                               List<File> libraries, String[] args, String cacheAs,
982  
                               String programID) throws Exception {
983  
    File srcDir = new File(ioBaseDir, "src");
984  
    File inputDir = new File(ioBaseDir, "input");
985  
    File outputDir = new File(ioBaseDir, "output");
986  
    copyInput(originalSrcDir, srcDir);
987  
    copyInput(originalInput, inputDir);
988  
    javax2(srcDir, ioBaseDir, silent, runInProcess, libraries, args, cacheAs, programID, null);
989  
    return outputDir;
990  
  }
991  
992  
  private static void copyInput(File src, File dst) throws IOException {
993  
    copyDirectory(src, dst);
994  
  }
995  
996  
  public static boolean hasFile(File inputDir, String name) {
997  
    return new File(inputDir, name).exists();
998  
  }
999  
1000  
  public static void copyDirectory(File src, File dst) throws IOException {
1001  
    if (verbose) System.out.println("Copying " + src.getAbsolutePath() + " to " + dst.getAbsolutePath());
1002  
    dst.mkdirs();
1003  
    File[] files = src.listFiles();
1004  
    if (files == null) return;
1005  
    for (File file : files) {
1006  
      File dst1 = new File(dst, file.getName());
1007  
      if (file.isDirectory())
1008  
        copyDirectory(file, dst1);
1009  
      else {
1010  
        if (verbose) System.out.println("Copying " + file.getAbsolutePath() + " to " + dst1.getAbsolutePath());
1011  
        copy(file, dst1);
1012  
      }
1013  
    }
1014  
  }
1015  
1016  
  /** Quickly copy a file without a progress bar or any other fancy GUI... :) */
1017  
  public static void copy(File src, File dest) throws IOException {
1018  
    FileInputStream inputStream = newFileInputStream(src);
1019  
    FileOutputStream outputStream = newFileOutputStream(dest);
1020  
    try {
1021  
      copy(inputStream, outputStream);
1022  
      inputStream.close();
1023  
    } finally {
1024  
      outputStream.close();
1025  
    }
1026  
  }
1027  
1028  
  private static FileInputStream newFileInputStream(File f) throws FileNotFoundException {
1029  
    /*if (androidContext != null)
1030  
      return (FileInputStream) call(androidContext,
1031  
        "openFileInput", f.getPath());
1032  
    else*/
1033  
    return new // line break for Dumb TinyBrain :)
1034  
    FileInputStream(f);
1035  
  }
1036  
1037  
  private static FileOutputStream newFileOutputStream(File f) throws FileNotFoundException {
1038  
    /*if (androidContext != null)
1039  
      return (FileOutputStream) call(androidContext,
1040  
        "openFileOutput", f.getPath(), 0);
1041  
    else*/
1042  
    return new // line break for Dumb TinyBrain :)
1043  
    FileOutputStream(f);
1044  
  }
1045  
1046  
  public static void copy(InputStream in, OutputStream out) throws IOException {
1047  
    byte[] buf = new byte[65536];
1048  
    while (true) {
1049  
      int n = in.read(buf);
1050  
      if (n <= 0) return;
1051  
      out.write(buf, 0, n);
1052  
    }
1053  
  }
1054  
1055  
  /** writes safely (to temp file, then rename) */
1056  
  public static void saveTextFile(String fileName, String contents) throws IOException {
1057  
    File file = new File(fileName);
1058  
    File parentFile = file.getParentFile();
1059  
    if (parentFile != null)
1060  
      parentFile.mkdirs();
1061  
    String tempFileName = fileName + "_temp";
1062  
    FileOutputStream fileOutputStream = newFileOutputStream(new File(tempFileName));
1063  
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, charsetForTextFiles);
1064  
    PrintWriter printWriter = new PrintWriter(outputStreamWriter);
1065  
    printWriter.print(contents);
1066  
    printWriter.close();
1067  
    if (file.exists() && !file.delete())
1068  
      throw new IOException("Can't delete " + fileName);
1069  
1070  
    if (!new File(tempFileName).renameTo(file))
1071  
      throw new IOException("Can't rename " + tempFileName + " to " + fileName);
1072  
  }
1073  
1074  
  /** writes safely (to temp file, then rename) */
1075  
  public static void saveBinaryFile(String fileName, byte[] contents) throws IOException {
1076  
    File file = new File(fileName);
1077  
    File parentFile = file.getParentFile();
1078  
    if (parentFile != null)
1079  
      parentFile.mkdirs();
1080  
    String tempFileName = fileName + "_temp";
1081  
    FileOutputStream fileOutputStream = newFileOutputStream(new File(tempFileName));
1082  
    fileOutputStream.write(contents);
1083  
    fileOutputStream.close();
1084  
    if (file.exists() && !file.delete())
1085  
      throw new IOException("Can't delete " + fileName);
1086  
1087  
    if (!new File(tempFileName).renameTo(file))
1088  
      throw new IOException("Can't rename " + tempFileName + " to " + fileName);
1089  
  }
1090  
  public static String loadTextFile(String fileName) {
1091  
    try {
1092  
      return loadTextFile(fileName, null);
1093  
    } catch (IOException e) {
1094  
      throw new RuntimeException(e);
1095  
    }
1096  
  }
1097  
  
1098  
  public static String loadTextFile(String fileName, String defaultContents) throws IOException {
1099  
    if (!new File(fileName).exists())
1100  
      return defaultContents;
1101  
1102  
    FileInputStream fileInputStream = new FileInputStream(fileName);
1103  
    InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
1104  
    return loadTextFile(inputStreamReader);
1105  
  }
1106  
  
1107  
  public static String loadTextFile(File fileName) {
1108  
    try {
1109  
      return loadTextFile(fileName, null);
1110  
    } catch (IOException e) {
1111  
      throw new RuntimeException(e);
1112  
    }
1113  
  }
1114  
1115  
  public static String loadTextFile(File fileName, String defaultContents) throws IOException {
1116  
    try {
1117  
      return loadTextFile(fileName.getPath(), defaultContents);
1118  
    } catch (IOException e) {
1119  
      throw new RuntimeException(e);
1120  
    }
1121  
  }
1122  
  
1123  
  public static String loadTextFile(Reader reader) throws IOException {
1124  
    StringBuilder builder = new StringBuilder();
1125  
    try {
1126  
      char[] buffer = new char[1024];
1127  
      int n;
1128  
      while (-1 != (n = reader.read(buffer)))
1129  
        builder.append(buffer, 0, n);
1130  
        
1131  
    } finally {
1132  
      reader.close();
1133  
    }
1134  
    return builder.toString();
1135  
  } // loadTextFile
1136  
  
1137  
  static File DiskSnippetCache_dir;
1138  
1139  
  public static void initDiskSnippetCache(File dir) {
1140  
    DiskSnippetCache_dir = dir;
1141  
    dir.mkdirs();
1142  
  }
1143  
1144  
  // Data files are immutable, use centralized cache
1145  
  public static synchronized File DiskSnippetCache_getLibrary(long snippetID) throws IOException {
1146  
    File file = new File(getGlobalCache(), "data_" + snippetID + ".jar");
1147  
    if (verbose)
1148  
      System.out.println("Checking data cache: " + file.getPath());
1149  
    return file.exists() ? file : null;
1150  
  }
1151  
1152  
  public static synchronized String DiskSnippetCache_get(long snippetID) throws IOException {
1153  
    return loadTextFile(DiskSnippetCache_getFile(snippetID).getPath(), null);
1154  
  }
1155  
1156  
  private static File DiskSnippetCache_getFile(long snippetID) {
1157  
    return new File(DiskSnippetCache_dir, "" + snippetID);
1158  
  }
1159  
1160  
  public static synchronized void DiskSnippetCache_put(long snippetID, String snippet) throws IOException {
1161  
    saveTextFile(DiskSnippetCache_getFile(snippetID).getPath(), snippet);
1162  
  }
1163  
1164  
  public static synchronized void DiskSnippetCache_putLibrary(long snippetID, byte[] data) throws IOException {
1165  
    saveBinaryFile(new File(getGlobalCache(), "data_" + snippetID).getPath() + ".jar", data);
1166  
  }
1167  
1168  
  public static File DiskSnippetCache_getDir() {
1169  
    return DiskSnippetCache_dir;
1170  
  }
1171  
1172  
  public static void initSnippetCache() {
1173  
    if (DiskSnippetCache_dir == null)
1174  
      initDiskSnippetCache(getGlobalCache());
1175  
  }
1176  
1177  
  private static File getGlobalCache() {
1178  
    File file = new File(userHome(), ".tinybrain/snippet-cache");
1179  
    file.mkdirs();
1180  
    return file;
1181  
  }
1182  
1183  
  public static String loadSnippetVerified(String snippetID, String hash) throws IOException {
1184  
    String text = loadSnippet(snippetID);
1185  
    String realHash = getHash(text.getBytes("UTF-8"));
1186  
    if (!realHash.equals(hash)) {
1187  
      String msg;
1188  
      if (hash.isEmpty())
1189  
        msg = "Here's your hash for " + snippetID + ", please put in your program: " + realHash;
1190  
      else
1191  
        msg = "Hash mismatch for " + snippetID + ": " + realHash + " (new) vs " + hash + " - has tinybrain.de been hacked??";
1192  
      throw new RuntimeException(msg);
1193  
    }
1194  
    return text;
1195  
  }
1196  
1197  
  public static String getHash(byte[] data) {
1198  
    return bytesToHex(getFullFingerprint(data));
1199  
  }
1200  
1201  
  public static byte[] getFullFingerprint(byte[] data) {
1202  
    try {
1203  
      return MessageDigest.getInstance("MD5").digest(data);
1204  
    } catch (NoSuchAlgorithmException e) {
1205  
      throw new RuntimeException(e);
1206  
    }
1207  
  }
1208  
1209  
  public static String bytesToHex(byte[] bytes) {
1210  
    return bytesToHex(bytes, 0, bytes.length);
1211  
  }
1212  
1213  
  public static String bytesToHex(byte[] bytes, int ofs, int len) {
1214  
    StringBuilder stringBuilder = new StringBuilder(len*2);
1215  
    for (int i = 0; i < len; i++) {
1216  
      String s = "0" + Integer.toHexString(bytes[ofs+i]);
1217  
      stringBuilder.append(s.substring(s.length()-2, s.length()));
1218  
    }
1219  
    return stringBuilder.toString();
1220  
  }
1221  
1222  
  public static String loadSnippet(String snippetID) throws IOException {
1223  
    return loadSnippet(parseSnippetID(snippetID));
1224  
  }
1225  
1226  
  public static long parseSnippetID(String snippetID) {
1227  
    return Long.parseLong(shortenSnippetID(snippetID));
1228  
  }
1229  
1230  
  private static String shortenSnippetID(String snippetID) {
1231  
    if (snippetID.startsWith("#"))
1232  
      snippetID = snippetID.substring(1);
1233  
    String httpBlaBla = "http://tinybrain.de/";
1234  
    if (snippetID.startsWith(httpBlaBla))
1235  
      snippetID = snippetID.substring(httpBlaBla.length());
1236  
    return snippetID;
1237  
  }
1238  
1239  
  public static boolean isSnippetID(String snippetID) {
1240  
    snippetID = shortenSnippetID(snippetID);
1241  
    return isInteger(snippetID) && Long.parseLong(snippetID) != 0;
1242  
  }
1243  
1244  
  public static boolean isInteger(String s) {
1245  
    return Pattern.matches("\\-?\\d+", s);
1246  
  }
1247  
  
1248  
  static String getTranspilationFromBossBot(long snippetID) {
1249  
    return boss(format3("get transpilation for *", snippetID));
1250  
  }
1251  
  
1252  
  public static String loadSnippet(long snippetID) throws IOException {
1253  
    String text = getSnippetFromBossBot(snippetID);
1254  
    if (text != null) return text;
1255  
    
1256  
    text = memSnippetCache.get(snippetID);
1257  
    if (text != null) {
1258  
      if (verbose)
1259  
        System.out.println("Getting " + snippetID + " from mem cache");
1260  
      return text;
1261  
    }
1262  
    
1263  
    initSnippetCache();
1264  
    text = DiskSnippetCache_get(snippetID);
1265  
    if (preferCached && text != null) {
1266  
      if (verbose)
1267  
        System.out.println("Getting " + snippetID + " from disk cache (preferCached)");
1268  
      return text;
1269  
    }
1270  
1271  
    String md5 = text != null ? md5(text) : "-";
1272  
    if (text != null) {
1273  
      String hash = prefetched.get(snippetID);
1274  
      if (hash != null) {
1275  
        if (md5.equals(hash)) {
1276  
          memSnippetCache.put(snippetID, text);
1277  
          if (verbose)
1278  
            System.out.println("Getting " + snippetID + " from prefetched");
1279  
          return text;
1280  
        } else
1281  
          prefetched.remove(snippetID); // (maybe this is not necessary)
1282  
      }
1283  
    }
1284  
1285  
    try {
1286  
      /*URL url = new URL("http://tinybrain.de:8080/getraw.php?id=" + snippetID);
1287  
      text = loadPage(url);*/
1288  
      String theURL = "http://tinybrain.de:8080/getraw.php?id=" + snippetID + "&getmd5=1&utf8=1&usetranspiled=1";
1289  
      if (text != null) {
1290  
        //System.err.println("MD5: " + md5);
1291  
        theURL += "&md5=" + md5;
1292  
      }
1293  
      URL url = new URL(theURL);
1294  
      String page = loadPage(url);
1295  
1296  
      // parse & drop transpilation flag available line
1297  
      int i = page.indexOf('\n');
1298  
      boolean hasTranspiled = page.substring(0, i).trim().equals("1");
1299  
      if (hasTranspiled)
1300  
        hasTranspiledSet.add(snippetID);
1301  
      else
1302  
        hasTranspiledSet.remove(snippetID);
1303  
      page = page.substring(i+1);
1304  
1305  
      if (page.startsWith("==*#*==")) {
1306  
        // same, keep text
1307  
        //System.err.println("Snippet unchanged, keeping.");
1308  
      } else {
1309  
        // drop md5 line
1310  
        i = page.indexOf('\n');
1311  
        String hash = page.substring(0, i).trim();
1312  
        text = page.substring(i+1);
1313  
1314  
        String myHash = md5(text);
1315  
        if (myHash.equals(hash)) {
1316  
          //System.err.println("Hash match: " + hash);
1317  
        } else
1318  
          System.err.println("Hash mismatch");
1319  
      }
1320  
    } catch (Exception e) {
1321  
      e.printStackTrace();
1322  
      throw new IOException("Snippet #" + snippetID + " not found or not public / " + e);
1323  
    }
1324  
1325  
    memSnippetCache.put(snippetID, text);
1326  
1327  
    try {
1328  
      initSnippetCache();
1329  
      DiskSnippetCache_put(snippetID, text);
1330  
    } catch (IOException e) {
1331  
      System.err.println("Minor warning: Couldn't save snippet to cache ("  + DiskSnippetCache_getDir() + ")");
1332  
    }
1333  
1334  
    return text;
1335  
  }
1336  
1337  
  private static String md5(String text) {
1338  
    try {
1339  
      return bytesToHex(md5impl(text.getBytes("UTF-8"))); // maybe different than the way PHP does it...
1340  
    } catch (UnsupportedEncodingException e) {
1341  
      throw new RuntimeException(e);
1342  
    }
1343  
  }
1344  
1345  
  public static byte[] md5impl(byte[] data) {
1346  
    try {
1347  
      return MessageDigest.getInstance("MD5").digest(data);
1348  
    } catch (NoSuchAlgorithmException e) {
1349  
      throw new RuntimeException(e);
1350  
    }
1351  
  }
1352  
1353  
  public static byte[] loadBinaryPage(URLConnection con) throws IOException {
1354  
    setHeaders(con);
1355  
    return loadBinaryPage_noHeaders(con);
1356  
  }
1357  
1358  
  private static byte[] loadBinaryPage_noHeaders(URLConnection con) throws IOException {
1359  
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
1360  
    InputStream inputStream = con.getInputStream();
1361  
    int n = 0;
1362  
    while (true) {
1363  
      int ch = inputStream.read();
1364  
      if (ch < 0)
1365  
        break;
1366  
      buf.write(ch);
1367  
      if (++n % 100000 == 0)
1368  
        System.err.println("  " + n + " bytes loaded.");
1369  
    }
1370  
    inputStream.close();
1371  
    return buf.toByteArray();
1372  
  }
1373  
1374  
  private static void setHeaders(URLConnection con) throws IOException {
1375  
    String computerID = getComputerID();
1376  
    if (computerID != null)
1377  
      con.setRequestProperty("X-ComputerID", computerID);
1378  
  }
1379  
1380  
  public static String guessCharset(String contentType) {
1381  
    Pattern p = Pattern.compile("text/html;\\s+charset=([^\\s]+)\\s*");
1382  
    Matcher m = p.matcher(contentType);
1383  
    /* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */
1384  
    return m.matches() ? m.group(1) : "ISO-8859-1";
1385  
  }
1386  
1387  
  /** runs a transpiled set of sources */
1388  
  public static void javax2(File srcDir, File ioBaseDir, boolean silent, boolean runInProcess,
1389  
                            List<File> libraries, String[] args, String cacheAs,
1390  
                            String programID, Info info) throws Exception {
1391  
    if (android) {
1392  
      // TODO: no translator virtualization? huh?
1393  
      javax2android(srcDir, args, programID);
1394  
    } else {
1395  
      File classesDir = TempDirMaker_make();
1396  
      String javacOutput = compileJava(srcDir, libraries, classesDir);
1397  
1398  
      // run
1399  
1400  
      if (verbose) System.out.println("Running program (" + srcDir.getAbsolutePath()
1401  
        + ") on io dir " + ioBaseDir.getAbsolutePath() + (runInProcess ? "[in-process]" : "") + "\n");
1402  
      runProgram(javacOutput, classesDir, ioBaseDir, silent, runInProcess, libraries, args, cacheAs, programID, info);
1403  
    }
1404  
  }
1405  
1406  
  static Class<?> loadx2android(File srcDir, String programID) throws Exception {
1407  
    // TODO: optimize if it's a loaded snippet anyway
1408  
    URL url = new URL("http://tinybrain.de:8080/dexcompile.php");
1409  
    URLConnection conn = url.openConnection();
1410  
    String postData = "src=" + URLEncoder.encode(loadTextFile(new File(srcDir, "main.java").getPath(), null), "UTF-8");
1411  
    byte[] dexData = doPostBinary(postData, conn);
1412  
    if (!isDex(dexData))
1413  
      throw new RuntimeException("Dex generation error: " + dexData.length + " bytes - " + new String(dexData, "UTF-8"));
1414  
    System.out.println("Dex loaded: " + dexData.length + "b");
1415  
1416  
    File dexDir = TempDirMaker_make();
1417  
    File dexFile = new File(dexDir, System.currentTimeMillis() + ".dex");
1418  
    File dexOutputDir = TempDirMaker_make();
1419  
1420  
    System.out.println("Saving dex to: " + dexDir.getAbsolutePath());
1421  
    try {
1422  
      saveBinaryFile(dexFile.getPath(), dexData);
1423  
    } catch (Throwable e) {
1424  
      System.out.println("Whoa!");
1425  
      throw new RuntimeException(e);
1426  
    }
1427  
1428  
    System.out.println("Getting parent class loader.");
1429  
    ClassLoader parentClassLoader =
1430  
      //ClassLoader.getSystemClassLoader(); // does not find support jar
1431  
      //getClass().getClassLoader(); // Let's try this...
1432  
      x30.class.getClassLoader().getParent(); // XXX !
1433  
1434  
    //System.out.println("Making DexClassLoader.");
1435  
    //DexClassLoader classLoader = new DexClassLoader(dexFile.getAbsolutePath(), dexOutputDir.getAbsolutePath(), null,
1436  
    //  parentClassLoader);
1437  
    Class dcl = Class.forName("dalvik.system.DexClassLoader");
1438  
    Object classLoader = dcl.getConstructors()[0].newInstance(dexFile.getAbsolutePath(), dexOutputDir.getAbsolutePath(), null,
1439  
      parentClassLoader);
1440  
1441  
    //System.out.println("Loading main class.");
1442  
    //Class<?> theClass = classLoader.loadClass(mainClassName);
1443  
    Class<?> theClass = (Class<?>) call(classLoader, "loadClass", "main");
1444  
1445  
    //System.out.println("Main class loaded.");
1446  
    try {
1447  
      set(theClass, "androidContext", androidContext);
1448  
    } catch (Throwable e) {}
1449  
1450  
    setVars(theClass, programID);
1451  
    
1452  
    addInstance(programID, theClass);
1453  
    
1454  
    return theClass;
1455  
  }
1456  
  
1457  
  static void addInstance(String programID, Class mainClass) {
1458  
    programID = "" + parseSnippetID(programID);
1459  
    instances.put(programID, new WeakReference<Class>(mainClass));
1460  
  }
1461  
  
1462  
  static Class getInstance(String programID) {
1463  
    programID = "" + parseSnippetID(programID);
1464  
    List<WeakReference<Class>> l = instances.get(programID);
1465  
    for (WeakReference<Class> c : l) {
1466  
      Class theClass = c.get();
1467  
      // TODO: shorten the list
1468  
      if (theClass != null)
1469  
        return theClass;
1470  
    }
1471  
    return null;
1472  
  }
1473  
  
1474  
  static MultiMap<String, WeakReference<Class>> instances = new MultiMap<String, WeakReference<Class>>();
1475  
static class MultiMap<A,B> {
1476  
  Map<A, List<B>> data = new HashMap<A, List<B>>();
1477  
  
1478  
  MultiMap() {}
1479  
  MultiMap(MultiMap<A, B> map) { putAll(map); }
1480  
1481  
  public void put(A key, B value) {
1482  
    List<B> list = data.get(key);
1483  
    if (list == null)
1484  
      data.put(key, list = new ArrayList<B>());
1485  
    list.add(value);
1486  
  }
1487  
1488  
  public void addAll(A key, Collection<B> values) {
1489  
    putAll(key, values);
1490  
  }
1491  
  
1492  
  public void addAllIfNotThere(A key, Collection<B> values) {
1493  
    for (B value : values)
1494  
      setPut(key, value);
1495  
  }
1496  
  
1497  
  void setPut(A key, B value) {
1498  
    if (!containsPair(key, value))
1499  
      put(key, value);
1500  
  }
1501  
  
1502  
  boolean containsPair(A key, B value) {
1503  
    return get(key).contains(value);
1504  
  }
1505  
  
1506  
  public void putAll(A key, Collection<B> values) {
1507  
    for (B value : values)
1508  
      put(key, value);
1509  
  }
1510  
1511  
  void removeAll(A key, Collection<B> values) {
1512  
    for (B value : values)
1513  
      remove(key, value);
1514  
  }
1515  
  
1516  
  public List<B> get(A key) {
1517  
    List<B> list = data.get(key);
1518  
    return list == null ? Collections.<B> emptyList() : list;
1519  
  }
1520  
1521  
  // returns actual mutable live list
1522  
  // creates the list if not there
1523  
  public List<B> getActual(A key) {
1524  
    List<B> list = data.get(key);
1525  
    if (list == null)
1526  
      data.put(key, list = litlist());
1527  
    return list;
1528  
  }
1529  
 
1530  
  void clean(A key) {
1531  
    List<B> list = data.get(key);
1532  
    if (list != null && list.isEmpty())
1533  
      data.remove(key);
1534  
  }
1535  
1536  
  public Set<A> keySet() {
1537  
    return data.keySet();
1538  
  }
1539  
1540  
  public Set<A> keys() {
1541  
    return data.keySet();
1542  
  }
1543  
1544  
  public void remove(A key) {
1545  
    data.remove(key);
1546  
  }
1547  
1548  
  public void remove(A key, B value) {
1549  
    List<B> list = data.get(key);
1550  
    if (list != null) {
1551  
      list.remove(value);
1552  
      if (list.isEmpty())
1553  
        data.remove(key);
1554  
    }
1555  
  }
1556  
1557  
  public void clear() {
1558  
    data.clear();
1559  
  }
1560  
1561  
  public boolean containsKey(A key) {
1562  
    return data.containsKey(key);
1563  
  }
1564  
1565  
  public B getFirst(A key) {
1566  
    List<B> list = get(key);
1567  
    return list.isEmpty() ? null : list.get(0);
1568  
  }
1569  
  
1570  
  public void putAll(MultiMap<A, B> map) {
1571  
    for (A key : map.keySet())
1572  
      putAll(key, map.get(key));
1573  
  }
1574  
  
1575  
  // note: expensive operation
1576  
  int size() {
1577  
    int n = 0;
1578  
    for (List l : data.values())
1579  
      n += l(l);
1580  
    return n;
1581  
  }
1582  
  
1583  
  // expensive operation
1584  
  List<A> reverseGet(B b) {
1585  
    List<A> l = new ArrayList<A>();
1586  
    for (A key : data.keySet())
1587  
      if (data.get(key).contains(b))
1588  
        l.add(key);
1589  
    return l;
1590  
  }
1591  
} // MultiMap
1592  
1593  
  static void javax2android(File srcDir, String[] args, String programID) throws Exception {
1594  
    Class<?> theClass = loadx2android(srcDir, programID);
1595  
1596  
    Method main = null;
1597  
    try {
1598  
      main = call_findStaticMethod(theClass, "main", new Object[]{androidContext}, false);
1599  
    } catch (RuntimeException e) {
1600  
    }
1601  
1602  
    //System.out.println("main method for " + androidContext + " of " + theClass + ": " + main);
1603  
1604  
    if (main != null) {
1605  
      // old style main program that returns a View
1606  
      // TODO: maybe allow programs without main method, although it doesn't seem to make sense here really (Android main program)
1607  
      System.out.println("Calling main (old-style)");
1608  
      Object view = main.invoke(null, androidContext);
1609  
      System.out.println("Calling setContentView with " + view);
1610  
      call(Class.forName("main"), "setContentViewInUIThread", view);
1611  
      //call(androidContext, "setContentView", view);
1612  
      System.out.println("Done.");
1613  
    } else {
1614  
      System.out.println("New-style main method running.\n\n====\n");
1615  
      runMainMethod(args, theClass);
1616  
    }
1617  
  }
1618  
1619  
  static byte[] DEX_FILE_MAGIC = { 0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00 };
1620  
1621  
  static boolean isDex(byte[] dexData) {
1622  
    if (dexData.length < DEX_FILE_MAGIC.length) return false;
1623  
    for (int i = 0; i < DEX_FILE_MAGIC.length; i++)
1624  
      if (dexData[i] != DEX_FILE_MAGIC[i])
1625  
        return false;
1626  
    return true;
1627  
  }
1628  
1629  
  static byte[] doPostBinary(String urlParameters, URLConnection conn) throws IOException {
1630  
    // connect and do POST
1631  
    setHeaders(conn);
1632  
    conn.setDoOutput(true);
1633  
1634  
    OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
1635  
    writer.write(urlParameters);
1636  
    writer.flush();
1637  
1638  
    byte[] contents = loadBinaryPage_noHeaders(conn);
1639  
    writer.close();
1640  
    return contents;
1641  
  }
1642  
1643  
  static String compileJava(File srcDir, List<File> libraries, File classesDir) throws IOException {
1644  
    javaCompilerOutput = null;
1645  
    ++compilations;
1646  
1647  
    // collect sources
1648  
1649  
    List<File> sources = new ArrayList<File>();
1650  
    if (verbose) System.out.println("Scanning for sources in " + srcDir.getPath());
1651  
    scanForSources(srcDir, sources, true);
1652  
    if (sources.isEmpty())
1653  
      throw new IOException("No sources found");
1654  
1655  
    // compile
1656  
1657  
    File optionsFile = File.createTempFile("javax", "");
1658  
    if (verbose) System.out.println("Compiling " + sources.size() + " source(s) to " + classesDir.getPath());
1659  
    if (verbose) System.out.println("Libraries: " + libraries);
1660  
    String options = "-d " + bashQuote(classesDir.getPath());
1661  
    writeOptions(sources, libraries, optionsFile, options);
1662  
    classesDir.mkdirs();
1663  
    return invokeJavaCompiler(optionsFile);
1664  
  }
1665  
1666  
  private static void runProgram(String javacOutput, File classesDir, File ioBaseDir,
1667  
                                 boolean silent, boolean runInProcess,
1668  
                                 List<File> libraries, String[] args, String cacheAs,
1669  
                                 String programID, Info info) throws Exception {
1670  
    // print javac output if compile failed and it hasn't been printed yet
1671  
    if (info != null) {
1672  
      info.programID = programID;
1673  
      info.programArgs = args;
1674  
    }
1675  
    boolean didNotCompile = !didCompile(classesDir);
1676  
    if (verbose || didNotCompile)
1677  
      System.out.println(javacOutput);
1678  
    if (didNotCompile)
1679  
      return;
1680  
1681  
    if (runInProcess
1682  
      || (ioBaseDir.getAbsolutePath().equals(new File(".").getAbsolutePath()) && !silent)) {
1683  
      runProgramQuick(classesDir, libraries, args, cacheAs, programID, info, ioBaseDir);
1684  
      return;
1685  
    }
1686  
1687  
    boolean echoOK = false;
1688  
    // TODO: add libraries to class path
1689  
    String bashCmd = "(cd " + bashQuote(ioBaseDir.getAbsolutePath()) + " && (java -cp "
1690  
      + bashQuote(classesDir.getAbsolutePath()) + " main" + (echoOK ? "; echo ok" : "") + "))";
1691  
    if (verbose) System.out.println(bashCmd);
1692  
    String output = backtick(bashCmd);
1693  
    lastOutput = output;
1694  
    if (verbose || !silent)
1695  
      System.out.println(output);
1696  
  }
1697  
1698  
  static boolean didCompile(File classesDir) {
1699  
    return hasFile(classesDir, "main.class");
1700  
  }
1701  
1702  
  private static void runProgramQuick(File classesDir, List<File> libraries,
1703  
                                      String[] args, String cacheAs,
1704  
                                      String programID, Info info,
1705  
                                      File ioBaseDir) throws Exception {
1706  
    // collect urls
1707  
    URL[] urls = new URL[libraries.size()+1];
1708  
    urls[0] = classesDir.toURI().toURL();
1709  
    for (int i = 0; i < libraries.size(); i++)
1710  
      urls[i+1] = libraries.get(i).toURI().toURL();
1711  
1712  
    // make class loader
1713  
    URLClassLoader classLoader = new URLClassLoader(urls);
1714  
1715  
    // load JavaX main class
1716  
    Class<?> mainClass = classLoader.loadClass("main");
1717  
    
1718  
    if (info != null) {
1719  
      info.mainClass = mainClass;
1720  
      if (info.transpiledSrc != null)
1721  
        registerSourceCode(mainClass, loadTextFile(new File(info.transpiledSrc, "main.java")));
1722  
    }
1723  
      
1724  
    if (cacheAs != null)
1725  
      programCache.put(cacheAs, mainClass);
1726  
      
1727  
    // record injection
1728  
    final PaA paa = new PaA(programID, args);
1729  
    paa.injectionID = randomID(8);
1730  
    paa.mainClass = mainClass;
1731  
    addInjection(paa);
1732  
1733  
    // change baseDir
1734  
    try {
1735  
      //print("Changing base dir to " + ioBaseDir.getAbsolutePath());
1736  
      Class virtual = mainClass.getClassLoader().loadClass("virtual");
1737  
      set(virtual, "virtual_baseDir", ioBaseDir.getAbsolutePath());
1738  
    } catch (Throwable e) { /* whatever */ }
1739  
1740  
    setVars(mainClass, programID);
1741  
    addInstance(programID, mainClass);
1742  
    try {
1743  
      runMainMethod(args, mainClass);
1744  
    } catch (Exception e) {
1745  
      paa.exception = e;
1746  
      throw e;
1747  
    } finally {
1748  
      paa.mainDone = true;
1749  
    }
1750  
  }
1751  
1752  
  static void setVars(Class<?> theClass, String programID) {
1753  
    try {
1754  
      set(theClass, "programID", programID);
1755  
    } catch (Throwable e) {}
1756  
1757  
    try {
1758  
      set(theClass, "__javax", x30.class);
1759  
    } catch (Throwable e) {}
1760  
  }
1761  
1762  
1763  
  static void runMainMethod(String[] args, Class<?> mainClass) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
1764  
    callMain(mainClass, args);
1765  
  }
1766  
1767  
  static String invokeJavaCompiler(File optionsFile) throws IOException {
1768  
    String output;
1769  
    if (hasEcj() && !javacOnly)
1770  
      output = invokeEcj(optionsFile);
1771  
    else
1772  
      output = invokeJavac(optionsFile);
1773  
    if (verbose) System.out.println(output);
1774  
    return output;
1775  
  }
1776  
1777  
  private static boolean hasEcj() {
1778  
    try {
1779  
      Class.forName("org.eclipse.jdt.internal.compiler.batch.Main");
1780  
      return true;
1781  
    } catch (ClassNotFoundException e) {
1782  
      return false;
1783  
    }
1784  
  }
1785  
1786  
  // TODO: fix UTF-8 here too
1787  
  private static String invokeJavac(File optionsFile) throws IOException {
1788  
    String output;
1789  
    output = backtick("javac " + bashQuote("@" + optionsFile.getPath()));
1790  
    javaCompilerOutput = output;
1791  
    if (exitValue != 0) {
1792  
      System.out.println(output);
1793  
      throw new RuntimeException("javac returned errors.");
1794  
    }
1795  
    return output;
1796  
  }
1797  
1798  
  // throws ClassNotFoundException if ecj is not in classpath
1799  
  static String invokeEcj(File optionsFile) {
1800  
    try {
1801  
      StringWriter writer = new StringWriter();
1802  
      PrintWriter printWriter = new PrintWriter(writer);
1803  
1804  
      // add more eclipse options in the line below
1805  
1806  
      String[] args = {
1807  
        "-source", javaTarget,
1808  
        "-target", javaTarget,
1809  
        "-nowarn",
1810  
        "-encoding", "UTF-8",
1811  
        "@" + optionsFile.getPath()
1812  
      };
1813  
      
1814  
      if (verbose)
1815  
        print("ECJ options: " + structure(args));
1816  
1817  
      Class ecjClass = Class.forName("org.eclipse.jdt.internal.compiler.batch.Main");
1818  
      Object main = newInstance(ecjClass, printWriter, printWriter, false);
1819  
      call(main, "compile", new Object[]{args});
1820  
      int errors = (Integer) get(main, "globalErrorsCount");
1821  
1822  
      String output = writer.toString();
1823  
      javaCompilerOutput = output;
1824  
      if (errors != 0) {
1825  
        System.out.println(output);
1826  
        throw new RuntimeException("Java compiler returned errors.");
1827  
      }
1828  
      return output;
1829  
    } catch (Exception e) {
1830  
      throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
1831  
    }
1832  
  }
1833  
1834  
  static Object newInstance(Class c, Object... args) { try {
1835  
    Constructor m = findConstructor(c, args);
1836  
    m.setAccessible(true);
1837  
    return m.newInstance(args);
1838  
  } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
1839  
1840  
  static Constructor findConstructor(Class c, Object... args) {
1841  
    for (Constructor m : c.getDeclaredConstructors()) {
1842  
      if (!checkArgs(m.getParameterTypes(), args, verbose))
1843  
        continue;
1844  
      return m;
1845  
    }
1846  
    throw new RuntimeException("Constructor with " + args.length + " matching parameter(s) not found in " + c.getName());
1847  
  }
1848  
1849  
  static boolean checkArgs(Class[] types, Object[] args, boolean debug) {
1850  
    if (types.length != args.length) {
1851  
      if (debug)
1852  
        System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
1853  
      return false;
1854  
    }
1855  
    for (int i = 0; i < types.length; i++)
1856  
      if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
1857  
        if (debug)
1858  
          System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
1859  
        return false;
1860  
      }
1861  
    return true;
1862  
  }
1863  
1864  
  private static void writeOptions(List<File> sources, List<File> libraries,
1865  
                                   File optionsFile, String moreOptions) throws IOException {
1866  
    FileWriter writer = new FileWriter(optionsFile);
1867  
    for (File source : sources)
1868  
      writer.write(bashQuote(source.getPath()) + " ");
1869  
    if (!libraries.isEmpty()) {
1870  
      List<String> cp = new ArrayList<String>();
1871  
      for (File lib : libraries)
1872  
        cp.add(lib.getAbsolutePath());
1873  
      writer.write("-cp " + bashQuote(join(File.pathSeparator, cp)) + " ");
1874  
    }
1875  
    writer.write(moreOptions);
1876  
    writer.close();
1877  
  }
1878  
1879  
  static void scanForSources(File source, List<File> sources, boolean topLevel) {
1880  
    if (source.isFile() && source.getName().endsWith(".java"))
1881  
      sources.add(source);
1882  
    else if (source.isDirectory() && !isSkippedDirectoryName(source.getName(), topLevel)) {
1883  
      File[] files = source.listFiles();
1884  
      for (File file : files)
1885  
        scanForSources(file, sources, false);
1886  
    }
1887  
  }
1888  
1889  
  private static boolean isSkippedDirectoryName(String name, boolean topLevel) {
1890  
    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.)
1891  
    return name.equalsIgnoreCase("input") || name.equalsIgnoreCase("output");
1892  
  }
1893  
1894  
  static int exitValue;
1895  
  public static String backtick(String cmd) throws IOException {
1896  
    ++processesStarted;
1897  
    File outFile = File.createTempFile("_backtick", "");
1898  
    File scriptFile = File.createTempFile("_backtick", isWindows() ? ".bat" : "");
1899  
1900  
    String command = cmd + " >" + bashQuote(outFile.getPath()) + " 2>&1";
1901  
    //Log.info("[Backtick] " + command);
1902  
    try {
1903  
      saveTextFile(scriptFile.getPath(), command);
1904  
      String[] command2;
1905  
      if (isWindows())
1906  
        command2 = new String[] { scriptFile.getPath() };
1907  
      else
1908  
        command2 = new String[] { "/bin/bash", scriptFile.getPath() };
1909  
      Process process = Runtime.getRuntime().exec(command2);
1910  
      try {
1911  
        process.waitFor();
1912  
      } catch (InterruptedException e) {
1913  
        throw new RuntimeException(e);
1914  
      }
1915  
      exitValue = process.exitValue();
1916  
      if (verbose)
1917  
        System.out.println("Process return code: " + exitValue);
1918  
      return loadTextFile(outFile.getPath(), "");
1919  
    } finally {
1920  
      scriptFile.delete();
1921  
    }
1922  
  }
1923  
1924  
  /** possibly improvable */
1925  
  public static String javaQuote(String text) {
1926  
    return bashQuote(text);
1927  
  }
1928  
1929  
  /** possibly improvable */
1930  
  public static String bashQuote(String text) {
1931  
    if (text == null) return null;
1932  
    return "\"" + text
1933  
      .replace("\\", "\\\\")
1934  
      .replace("\"", "\\\"")
1935  
      .replace("\n", "\\n")
1936  
      .replace("\r", "\\r") + "\"";
1937  
  }
1938  
1939  
  public final static String charsetForTextFiles = "UTF8";
1940  
1941  
  static long TempDirMaker_lastValue;
1942  
1943  
  public static File TempDirMaker_make() {
1944  
    File dir = new File(userHome(), ".javax/" + TempDirMaker_newValue());
1945  
    dir.mkdirs();
1946  
    return dir;
1947  
  }
1948  
1949  
  private static long TempDirMaker_newValue() {
1950  
    long value;
1951  
    do
1952  
      value = System.currentTimeMillis();
1953  
    while (value == TempDirMaker_lastValue);
1954  
    TempDirMaker_lastValue = value;
1955  
    return value;
1956  
  }
1957  
  public static String join(String glue, Iterable<String> strings) {
1958  
    StringBuilder buf = new StringBuilder();
1959  
    Iterator<String> i = strings.iterator();
1960  
    if (i.hasNext()) {
1961  
      buf.append(i.next());
1962  
      while (i.hasNext())
1963  
        buf.append(glue).append(i.next());
1964  
    }
1965  
    return buf.toString();
1966  
  }
1967  
  
1968  
  public static String join(String glue, String[] strings) {
1969  
    return join(glue, Arrays.asList(strings));
1970  
  }
1971  
  
1972  
  public static String join(Iterable<String> strings) {
1973  
    return join("", strings);
1974  
  }
1975  
  
1976  
  public static String join(String[] strings) {
1977  
    return join("", strings);
1978  
  }
1979  
 // join
1980  
  
1981  
  public static boolean isWindows() {
1982  
    return System.getProperty("os.name").contains("Windows");
1983  
  }
1984  
1985  
  public static String makeRandomID(int length) {
1986  
    Random random = new Random();
1987  
    char[] id = new char[length];
1988  
    for (int i = 0; i< id.length; i++)
1989  
      id[i] = (char) ((int) 'a' + random.nextInt(26));
1990  
    return new String(id);
1991  
  }
1992  
1993  
  static String computerID;
1994  
  public static String getComputerID() throws IOException {
1995  
    if (noID) return null;
1996  
    if (computerID == null) {
1997  
      File file = new File(userHome(), ".tinybrain/computer-id");
1998  
      computerID = loadTextFile(file.getPath(), null);
1999  
      if (computerID == null) {
2000  
        computerID = makeRandomID(12);
2001  
        saveTextFile(file.getPath(), computerID);
2002  
      }
2003  
      if (verbose)
2004  
        System.out.println("Local computer ID: " + computerID);
2005  
    }
2006  
    return computerID;
2007  
  }
2008  
2009  
  static void cleanCache() {
2010  
    cleanJavaXCache(tempFileRetentionTime, verbose);
2011  
  }
2012  
2013  
  static void showSystemProperties() {
2014  
    System.out.println("System properties:\n");
2015  
    for (Map.Entry<Object, Object> entry : System.getProperties().entrySet()) {
2016  
      System.out.println("  " + entry.getKey() + " = " + entry.getValue());
2017  
    }
2018  
    System.out.println();
2019  
  }
2020  
2021  
  static void showVersion() {
2022  
    //showSystemProperties();
2023  
    boolean eclipseFound = hasEcj();
2024  
    //String platform = System.getProperty("java.vendor") + " " + System.getProperty("java.runtime.name") + " " + System.getProperty("java.version");
2025  
    String platform = System.getProperty("java.vm.name") + " " + System.getProperty("java.version");
2026  
    String os = System.getProperty("os.name"), arch = System.getProperty("os.arch");
2027  
    System.out.println("This is " + version + ".");
2028  
    System.out.println("[Details: " +
2029  
      (eclipseFound ? "Eclipse compiler (good)" : "javac (not so good)")
2030  
      + ", " + platform + ", " + arch + ", " + os + "]");
2031  
  }
2032  
2033  
  static boolean isAndroid() {
2034  
    return System.getProperty("java.vendor").toLowerCase().indexOf("android") >= 0;
2035  
  }
2036  
  static void set(Object o, String field, Object value) {
2037  
    if (o instanceof Class) set((Class) o, field, value);
2038  
    else try {
2039  
      Field f = set_findField(o.getClass(), field);
2040  
      smartSet(f, o, value);
2041  
    } catch (Exception e) {
2042  
      throw new RuntimeException(e);
2043  
    }
2044  
  }
2045  
  
2046  
  static void set(Class c, String field, Object value) {
2047  
    try {
2048  
      Field f = set_findStaticField(c, field);
2049  
      smartSet(f, null, value);
2050  
    } catch (Exception e) {
2051  
      throw new RuntimeException(e);
2052  
    }
2053  
  }
2054  
  
2055  
  static Field set_findField(Class<?> c, String field) {
2056  
    for (Field f : c.getDeclaredFields())
2057  
      if (f.getName().equals(field))
2058  
        return f;
2059  
    throw new RuntimeException("Field '" + field + "' not found in " + c.getName());
2060  
  }
2061  
  
2062  
  static Field set_findStaticField(Class<?> c, String field) {
2063  
    for (Field f : c.getDeclaredFields())
2064  
      if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0)
2065  
        return f;
2066  
    throw new RuntimeException("Static field '" + field + "' not found in " + c.getName());
2067  
  } // set function
2068  
2069  
  static String smartJoin(String[] args) {
2070  
    String[] a2 = new String[args.length];
2071  
    for (int i = 0; i < args.length; i++) {
2072  
      a2[i] = Pattern.compile("\\w+").matcher(args[i]).matches() ? args[i] : quote(args[i]);
2073  
    }
2074  
    return join(" ", a2);
2075  
  }
2076  
  
2077  
  static void logStart(String[] args) throws IOException {
2078  
    String line = smartJoin(args);
2079  
    appendToLog(new File(userHome(), ".javax/log.txt").getPath(), line);
2080  
  }
2081  
  
2082  
  static String quote(String s) {
2083  
    if (s == null) return "null";
2084  
    return "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\r", "\\r").replace("\n", "\\n") + "\"";
2085  
  }
2086  
  
2087  
  static void appendToLog(String path, String line) throws IOException {
2088  
    appendToFile(path, "\n" + line + "\n");
2089  
  }
2090  
  
2091  
  static void appendToFile(String path, String s) throws IOException {
2092  
    new File(path).getParentFile().mkdirs();
2093  
    Writer writer = new BufferedWriter(new OutputStreamWriter(
2094  
      new FileOutputStream(path, true), "UTF-8"));
2095  
    writer.write(s);
2096  
    writer.close();
2097  
  }
2098  
  
2099  
  //// END CONSOLE STUFF
2100  
2101  
  static long now_virtualTime;
2102  
  static long now() {
2103  
    return now_virtualTime != 0 ? now_virtualTime : System.currentTimeMillis();
2104  
  }
2105  
2106  
  static void print(Object o) {
2107  
    System.out.println(o);
2108  
  }
2109  
2110  
  public synchronized void run()
2111  
  {
2112  
  }
2113  
2114  
  static void nohupJavax(String javaxargs) {
2115  
    try {
2116  
      File xfile = new File(userHome(), ".javax/x30.jar");
2117  
      if (!xfile.isFile()) {
2118  
        String url = "http://tinybrain.de/x30.jar";
2119  
        byte[] data = loadBinaryPage(new URL(url).openConnection());
2120  
        if (data.length < 1000000)
2121  
          throw new RuntimeException("Could not load " + url);
2122  
        saveBinaryFile(xfile.getPath(), data);
2123  
      }
2124  
      String jarPath = xfile.getPath();
2125  
      nohup("java -jar " + (isWindows() ? winQuote(jarPath) : bashQuote(jarPath)) + " " + javaxargs);
2126  
    } catch (Exception e) { throw new RuntimeException(e); }
2127  
  }
2128  
2129  
  /** possibly improvable */
2130  
  public static String winQuote(String text) {
2131  
    if (text == null) return null;
2132  
    return "\"" + text
2133  
      .replace("\\", "\\\\")
2134  
      .replace("\"", "\\\"")
2135  
      .replace("\n", "\\n")
2136  
      .replace("\r", "\\r") + "\"";
2137  
  }
2138  
2139  
  public static File nohup(String cmd) throws IOException {
2140  
    File outFile = File.createTempFile("nohup_" + nohup_sanitize(cmd), ".out");
2141  
    nohup(cmd, outFile, false);
2142  
    return outFile;
2143  
  }
2144  
2145  
  static String nohup_sanitize(String s) {
2146  
    return s.replaceAll("[^a-zA-Z0-9\\-_]", "");
2147  
  }
2148  
2149  
  /** outFile takes stdout and stderr. */
2150  
  public static void nohup(String cmd, File outFile, boolean append) throws IOException {
2151  
    String command = nohup_makeNohupCommand(cmd, outFile, append);
2152  
2153  
    File scriptFile = File.createTempFile("_realnohup", isWindows() ? ".bat" : "");
2154  
    System.out.println("[Nohup] " + command);
2155  
    try {
2156  
      //System.out.println("[RealNohup] Script file: " + scriptFile.getPath());
2157  
      saveTextFile(scriptFile.getPath(), command);
2158  
      String[] command2;
2159  
      if (isWindows())
2160  
        command2 = new String[] {"cmd", "/c", "start", "/b", scriptFile.getPath() };
2161  
      else
2162  
        command2 = new String[] {"/bin/bash", scriptFile.getPath() };
2163  
2164  
      Process process = Runtime.getRuntime().exec(command2);
2165  
      try {
2166  
        process.waitFor();
2167  
      } catch (InterruptedException e) {
2168  
        throw new RuntimeException(e);
2169  
      }
2170  
      int value = process.exitValue();
2171  
      //System.out.println("exit value: " + value);
2172  
    } finally {
2173  
      if (!isWindows())
2174  
        scriptFile.delete();
2175  
    }
2176  
  }
2177  
2178  
  public static String nohup_makeNohupCommand(String cmd, File outFile, boolean append) {
2179  
    mkdirsForFile(outFile);
2180  
2181  
    String command;
2182  
    if (isWindows())
2183  
      command = cmd + (append ? " >>" : " >") + winQuote(outFile.getPath()) + " 2>&1";
2184  
    else
2185  
      command = "nohup " + cmd + (append ? " >>" : " >") + bashQuote(outFile.getPath()) + " 2>&1 &";
2186  
    return command;
2187  
  }
2188  
2189  
  public static void mkdirsForFile(File file) {
2190  
    File dir = file.getParentFile();
2191  
    if (dir != null) // is null if file is in current dir
2192  
      dir.mkdirs();
2193  
  }
2194  
 
2195  
2196  
  static boolean portIsBound(int port) {
2197  
    try {
2198  
      ServerSocket s = new ServerSocket(port);
2199  
      s.close();
2200  
      return false;
2201  
    } catch (IOException e) {
2202  
      return true;
2203  
    }
2204  
  }
2205  
  
2206  
  static class LineBuf {
2207  
    StringBuffer buf = new StringBuffer();
2208  
    
2209  
    void append(String s) {
2210  
      buf.append(s);
2211  
    }
2212  
    
2213  
    String nextLine() {
2214  
      int i = buf.indexOf("\n");
2215  
      if (i >= 0) {
2216  
        String s = buf.substring(0, i > 0 && buf.charAt(i-1) == '\r' ? i-1 : i);
2217  
        buf.delete(0, i+1);
2218  
        return s;
2219  
      }
2220  
      return null;
2221  
    }
2222  
  } // LineBuf
2223  
2224  
static int chatSend_chatPort = 9751;
2225  
  static abstract class DialogIO {
2226  
    String line;
2227  
    boolean eos;
2228  
    
2229  
    abstract String readLineImpl();
2230  
    abstract boolean isStillConnected();
2231  
    abstract void sendLine(String line);
2232  
    abstract boolean isLocalConnection();
2233  
    abstract Socket getSocket();
2234  
    abstract void close();
2235  
    
2236  
    int getPort() { return getSocket().getPort(); }
2237  
    
2238  
    boolean helloRead;
2239  
    
2240  
    String readLineNoBlock() {
2241  
      String l = line;
2242  
      line = null;
2243  
      return l;
2244  
    }
2245  
    
2246  
    boolean waitForLine() { try {
2247  
 
2248  
      if (line != null) return true;
2249  
      //print("Readline");
2250  
      line = readLineImpl();
2251  
      //print("Readline done: " + line);
2252  
      if (line == null) eos = true;
2253  
      return line != null;
2254  
    
2255  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
2256  
    
2257  
    String readLine() {
2258  
      waitForLine();
2259  
      helloRead = true;
2260  
      return readLineNoBlock();
2261  
    }
2262  
    
2263  
    String ask(String s, Object... args) {
2264  
      if (!helloRead) readLine();
2265  
      if (args.length != 0) s = format3(s, args);
2266  
      sendLine(s);
2267  
      return readLine();
2268  
    }
2269  
    
2270  
    String askLoudly(String s, Object... args) {
2271  
      if (!helloRead) readLine();
2272  
      if (args.length != 0) s = format3(s, args);
2273  
      print("> " + s);
2274  
      sendLine(s);
2275  
      String answer = readLine();
2276  
      print("< " + answer);
2277  
      return answer;
2278  
    }
2279  
    
2280  
    void pushback(String l) {
2281  
      if (line != null)
2282  
        throw fail();
2283  
      line = l;
2284  
      helloRead = false;
2285  
    }
2286  
  }
2287  
  
2288  
  static abstract class DialogHandler {
2289  
    abstract void run(DialogIO io);
2290  
  } // DialogIO
2291  
2292  
static DialogIO chatSend_dialog;
2293  
static String chatSend_id;
2294  
2295  
static void chatSend(String line) { try {
2296  
 
2297  
  if (chatSend_dialog == null) {
2298  
    chatSend_dialog = talkTo("localhost", chatSend_chatPort);    
2299  
    chatSend_dialog.waitForLine();
2300  
    String l = chatSend_dialog.readLineNoBlock();
2301  
    if (l.startsWith("Your ID: "))
2302  
      chatSend_id = l.substring("Your ID: ".length());
2303  
  }
2304  
2305  
  chatSend_dialog.sendLine(line);
2306  
2307  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} // chatSend
2308  
2309  
  static class TeeOutputStream extends OutputStream {
2310  
    
2311  
    protected OutputStream out, branch;
2312  
2313  
    public TeeOutputStream( OutputStream out, OutputStream branch ) {
2314  
      this.out = out;
2315  
      this.branch = branch;
2316  
    }
2317  
2318  
    @Override
2319  
    public synchronized void write(byte[] b) throws IOException {
2320  
      write(b, 0, b.length);
2321  
    }
2322  
2323  
    @Override
2324  
    public synchronized void write(byte[] b, int off, int len) throws IOException {
2325  
      //if (verbose) oldOut.println("Tee write " + new String(b, "UTF-8"));
2326  
      out.write(b, off, len);
2327  
      this.branch.write(b, off, len);
2328  
    }
2329  
2330  
    @Override
2331  
    public synchronized void write(int b) throws IOException {
2332  
      write(new byte[] {(byte) b});
2333  
    }
2334  
2335  
    /**
2336  
     * Flushes both streams.
2337  
     * @throws IOException if an I/O error occurs
2338  
     */
2339  
    @Override
2340  
    public void flush() throws IOException {
2341  
      out.flush();
2342  
      this.branch.flush();
2343  
    }
2344  
2345  
    /**
2346  
     * Closes both streams.
2347  
     * @throws IOException if an I/O error occurs
2348  
     */
2349  
    @Override
2350  
    public void close() throws IOException {
2351  
      out.close();
2352  
      this.branch.close();
2353  
    }
2354  
  }
2355  
  
2356  
  static boolean isChatServer(String[] args) {
2357  
    for (int i = 0; i < args.length; i++)
2358  
      if (isSnippetID(args[i]))
2359  
        return parseSnippetID(args[i]) == 1000867;
2360  
    return false;
2361  
  }
2362  
  
2363  
  static String getSnippetTitle(String id) {
2364  
    try {
2365  
      return loadPage(new URL("http://tinybrain.de:8080/tb-int/getfield.php?id=" + parseSnippetID(id) + "&field=title"));
2366  
    } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }
2367  
  }
2368  
  
2369  
  static void listUserThreadsWithStackTraces() {
2370  
    print("");
2371  
    Map<Thread, StackTraceElement[]> threadMap = Thread.getAllStackTraces();
2372  
    int n = 0;
2373  
    for (Thread t : threadMap.keySet()) {
2374  
      ThreadGroup g = t.getThreadGroup();
2375  
      if (g != null && g.getName().equals("system")) continue;
2376  
      ++n;
2377  
      print(t);
2378  
      for (StackTraceElement e : threadMap.get(t)) {
2379  
        print("  " + e);
2380  
      }
2381  
      print("");
2382  
    }
2383  
    print(n + " user threads.");
2384  
  }
2385  
  
2386  
  static void killMyself() {
2387  
    print("Killing myself. (insert overall feeling here)");
2388  
    System.exit(0);
2389  
  }
2390  
  
2391  
  static void makeVMAndroid() {
2392  
    Android3 a = new Android3("This is a JavaX VM.");
2393  
    a.responder = new Responder() {
2394  
      String answer(String s, List<String> history) {
2395  
        return x30.answer(s, history);
2396  
      }
2397  
    };
2398  
    a.daemon = true;
2399  
    a.console = false;
2400  
    a.incomingSilent = true; // to avoid too much printing
2401  
    a.useMultiPort = false;
2402  
    makeAndroid3(a);
2403  
  }
2404  
  
2405  
  static class Info {
2406  
    String programID;
2407  
    String[] programArgs;
2408  
    File transpiledSrc;
2409  
    Class mainClass;
2410  
  }
2411  
  
2412  
  static Info info = new Info(); // hmm...
2413  
  
2414  
  // injectable info
2415  
  
2416  
  static List<PaA> injectable_programsInjected = new ArrayList<PaA>();
2417  
  static boolean injectable_on = true;
2418  
  static class PaA {
2419  
    String injectionID;
2420  
    String progID;
2421  
    String[] arguments;
2422  
    Class mainClass; // TODO: release eventually...
2423  
    WeakReference<Thread> mainThread;
2424  
    volatile boolean mainDone;
2425  
    volatile Throwable exception;
2426  
    
2427  
    PaA(String progID, String[] arguments) {
2428  
  this.arguments = arguments;
2429  
  this.progID = progID;}
2430  
    PaA() {}
2431  
  }
2432  
  
2433  
  static String vmID = makeRandomID(10);
2434  
  
2435  
  static synchronized void addInjection(PaA paa) {
2436  
    injectable_programsInjected.add(paa);
2437  
  }
2438  
  
2439  
  static synchronized void removeInjection(PaA paa) {
2440  
    injectable_programsInjected.remove(paa);
2441  
  }
2442  
  
2443  
  static synchronized List<PaA> getInjections() {
2444  
    return cloneList(injectable_programsInjected);
2445  
  }
2446  
  
2447  
  static String answer(String s, List<String> history) { try {
2448  
 
2449  
    Matches m = new Matches();
2450  
    
2451  
    if (match3("kill!", s)) {
2452  
      killMyself();
2453  
      return "ok";
2454  
    }
2455  
    if (match3("What is your process ID?", s) || match3("what is your pid?", s))
2456  
      return getPID();
2457  
    if (match3("get vm id", s))
2458  
      return vmID;
2459  
    if (match3("what is the javax program id?", s))
2460  
      return javaxProgramID;
2461  
    if (match3("what is the main program id?", s))
2462  
      return info.programID;
2463  
    if (match3("what are your program arguments?", s))
2464  
      return structure(info.programArgs);
2465  
    if (match3("get fields of main class", s))
2466  
      return structure(listFields(info.mainClass));
2467  
    if (match3("get field * of main class", s, m))
2468  
      return structure(get(info.mainClass, m.m[0]));
2469  
    if (match3("invoke function * of main class", s, m))
2470  
      return structure(call(info.mainClass, m.m[0]));
2471  
    if (match3("set field * of main class to *", s, m)) {
2472  
      set(info.mainClass, m.m[0], unstructure(m.m[1]));
2473  
      return "ok";
2474  
    }
2475  
    if (match3("how much memory are you consuming", s))
2476  
      return "Java heap size: " + (Runtime.getRuntime().totalMemory()+1024*1024-1)/1024/1024 + " MB";
2477  
    if (match3("how much memory is used after GC?", s)) {
2478  
      System.gc();
2479  
      return "Java heap used: " + (Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()+1024*1024-1)/1024/1024 + " MB";
2480  
    }
2481  
    if (match3("how much memory is used?", s))
2482  
      return "Java heap used: " + (Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()+1024*1024-1)/1024/1024 + " MB";
2483  
      
2484  
    if (match3("please inject program *", s, m) || match3("please inject program * with arguments *", s, m)) {
2485  
      synchronized(x30.class) {
2486  
        final String progID = formatSnippetID(unquote(m.m[0]));
2487  
        final String[] arguments = m.m.length > 1 ? toStringArray(unstructure(unquote(m.m[1]))) : new String[0];
2488  
        final PaA paa = new PaA(progID, arguments);
2489  
        paa.injectionID = randomID(8);
2490  
        addInjection(paa);
2491  
    
2492  
        // better call JavaX for translation in a single thread.
2493  
        paa.mainClass = hotwire(progID);
2494  
    
2495  
        // program may run in its own thread.
2496  
        { Thread _t_0 = new Thread(progID) {
2497  
public void run() {
2498  
try  {
2499  
          paa.mainThread = new WeakReference(currentThread());
2500  
          try {
2501  
            callMain(paa.mainClass, arguments);
2502  
          } catch (Throwable e) {
2503  
            paa.exception = e;
2504  
            e.printStackTrace();
2505  
          } finally {
2506  
            paa.mainDone = true;
2507  
            synchronized(x30.class) {}
2508  
          }
2509  
        } catch (Exception _e) {
2510  
  throw _e instanceof RuntimeException ? (RuntimeException) _e : new RuntimeException(_e); } }
2511  
};
2512  
_t_0.start(); }
2513  
  
2514  
        return format3("OK. Injection ID: *", paa.injectionID);
2515  
      }
2516  
    }
2517  
    
2518  
    if (match3("get injection exception *", s, m)) {
2519  
      String injectionID = unquote(m.m[0]);
2520  
      PaA paa = findInjection(injectionID);
2521  
      if (paa == null)
2522  
        return "Sorry. Injection not found";
2523  
      return "OK: " + paa.exception == null ? "no exception" : getStackTrace(paa.exception);
2524  
    }
2525  
     
2526  
    if (match3("get injection * variable *", s, m)) {
2527  
      String injectionID = unquote(m.m[0]);
2528  
      String var = unquote(m.m[1]);
2529  
      PaA paa = findInjection(injectionID);
2530  
      if (paa == null)
2531  
        return "Sorry. Injection not found";
2532  
      return "OK: " + structure(getOpt(paa.mainClass, var));
2533  
    }
2534  
     
2535  
    if (match3("get injection result *", s, m)) {
2536  
      String injectionID = unquote(m.m[0]);
2537  
      PaA paa = findInjection(injectionID);
2538  
      if (paa == null)
2539  
        return "Sorry. Injection not found";
2540  
      return "OK: " + structure(getOpt(paa.mainClass, "result"));
2541  
    }
2542  
     
2543  
    if (match3("is injection's * main done", s, m)) {
2544  
      String injectionID = unquote(m.m[0]);
2545  
      PaA paa = findInjection(injectionID);
2546  
      if (paa == null)
2547  
        return "Sorry. Injection not found";
2548  
      return paa.mainDone ? "Yes." : "No.";
2549  
    }
2550  
    
2551  
    if (match3("get injections", s, m)) {
2552  
      return structure(getInjections());
2553  
    }
2554  
    
2555  
    if (match3("remove injection *", s, m)) {
2556  
      String injectionID = unquote(m.m[0]);
2557  
      PaA paa = findInjection(injectionID);
2558  
      if (paa == null)
2559  
        return "Sorry. Injection not found";
2560  
      removeInjection(paa);
2561  
      return "OK, removed.";
2562  
    }
2563  
    
2564  
    if (match3("which programs are you running (ids only)", s, m)) {
2565  
      synchronized(x30.class) {
2566  
        List<String> l = new ArrayList<String>();
2567  
        for (String progID : instances.keySet())
2568  
          if (getInstance(progID) != null)
2569  
            l.add(progID);
2570  
        return format3("these: *", structure(l));
2571  
      }
2572  
    }
2573  
    
2574  
    List multiPorts = getMultiPorts();
2575  
    if (!multiPorts.isEmpty()) {
2576  
      Object multiPort = multiPorts.get(0);
2577  
      String answer = makeResponder(multiPort).answer(s, history);
2578  
      if (answer != null) return answer;
2579  
    }
2580  
    
2581  
    if (match3("list bots", s))
2582  
      return structure(litmap());
2583  
    
2584  
    return null;
2585  
  
2586  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
2587  
  
2588  
  static synchronized PaA findInjection(String injectionID) {
2589  
    for (PaA paa : injectable_programsInjected)
2590  
      if (eq(paa.injectionID, injectionID))
2591  
        return paa;
2592  
    return null;
2593  
  }
2594  
static int makeAndroid(String greeting) {
2595  
  return makeAndroid3(greeting).port;
2596  
}
2597  
2598  
static void makeAndroid(Android3 a) {
2599  
  makeAndroid3(a);
2600  
} // makeAndroid / makeAndroidNoConsole
2601  
  static void setOpt(Object o, String field, Object value) {
2602  
    if (o instanceof Class) setOpt((Class) o, field, value);
2603  
    else try {
2604  
      Field f = setOpt_findField(o.getClass(), field);
2605  
      if (f != null)
2606  
        smartSet(f, o, value);
2607  
    } catch (Exception e) {
2608  
      throw new RuntimeException(e);
2609  
    }
2610  
  }
2611  
  
2612  
  static void setOpt(Class c, String field, Object value) {
2613  
    try {
2614  
      Field f = setOpt_findStaticField(c, field);
2615  
      if (f != null)
2616  
        smartSet(f, null, value);
2617  
    } catch (Exception e) {
2618  
      throw new RuntimeException(e);
2619  
    }
2620  
  }
2621  
  
2622  
  static Field setOpt_findField(Class<?> c, String field) {
2623  
    for (Field f : c.getDeclaredFields())
2624  
      if (f.getName().equals(field))
2625  
        return f;
2626  
    return null;
2627  
  }
2628  
  
2629  
  static Field setOpt_findStaticField(Class<?> c, String field) {
2630  
    for (Field f : c.getDeclaredFields())
2631  
      if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0)
2632  
        return f;
2633  
    return null;
2634  
  } // setOpt
2635  
// get purpose 1: access a list/array (safer version of x.get(y))
2636  
2637  
static <A> A get(List<A> l, int idx) {
2638  
  return idx >= 0 && idx < l(l) ? l.get(idx) : null;
2639  
}
2640  
2641  
static <A> A get(A[] l, int idx) {
2642  
  return idx >= 0 && idx < l(l) ? l[idx] : null;
2643  
}
2644  
2645  
// get purpose 2: access a field by reflection or a map
2646  
2647  
static Object get(Object o, String field) {
2648  
  if (o instanceof Class) return get((Class) o, field);
2649  
  
2650  
  if (o instanceof Map)
2651  
    return ((Map) o).get(field);
2652  
    
2653  
  if (o.getClass().getName().equals("main$DynamicObject"))
2654  
    return call(get_raw(o, "fieldValues"), "get", field);
2655  
    
2656  
  return get_raw(o, field);
2657  
}
2658  
2659  
static Object get_raw(Object o, String field) {
2660  
  try {
2661  
    Field f = get_findField(o.getClass(), field);
2662  
    f.setAccessible(true);
2663  
    return f.get(o);
2664  
  } catch (Exception e) {
2665  
    throw new RuntimeException(e);
2666  
  }
2667  
}
2668  
2669  
static Object get(Class c, String field) {
2670  
  try {
2671  
    Field f = get_findStaticField(c, field);
2672  
    f.setAccessible(true);
2673  
    return f.get(null);
2674  
  } catch (Exception e) {
2675  
    throw new RuntimeException(e);
2676  
  }
2677  
}
2678  
2679  
static Field get_findStaticField(Class<?> c, String field) {
2680  
  Class _c = c;
2681  
  do {
2682  
    for (Field f : _c.getDeclaredFields())
2683  
      if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0)
2684  
        return f;
2685  
    _c = _c.getSuperclass();
2686  
  } while (_c != null);
2687  
  throw new RuntimeException("Static field '" + field + "' not found in " + c.getName());
2688  
}
2689  
2690  
static Field get_findField(Class<?> c, String field) {
2691  
  Class _c = c;
2692  
  do {
2693  
    for (Field f : _c.getDeclaredFields())
2694  
      if (f.getName().equals(field))
2695  
        return f;
2696  
    _c = _c.getSuperclass();
2697  
  } while (_c != null);
2698  
  throw new RuntimeException("Field '" + field + "' not found in " + c.getName());
2699  
} // get
2700  
static Class getMainClass() { try {
2701  
 
2702  
  return Class.forName("main");
2703  
2704  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
2705  
2706  
static Class getMainClass(Object o) { try {
2707  
 
2708  
  return (o instanceof Class ? (Class) o : o.getClass()).getClassLoader().loadClass("main");
2709  
2710  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} // getMainClass
2711  
static DialogIO talkTo(int port) {
2712  
  return talkTo("localhost", port);
2713  
}
2714  
2715  
static DialogIO talkTo(String ip, int port) { try {
2716  
 
2717  
  final Socket s = new Socket(ip, port);    
2718  
  //print("Talking to " + ip + ":" + port);
2719  
2720  
  final Writer w = new OutputStreamWriter(s.getOutputStream(), "UTF-8");
2721  
  final BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"));
2722  
  return new DialogIO() {
2723  
    boolean isLocalConnection() {
2724  
      return s.getInetAddress().isLoopbackAddress();
2725  
    }
2726  
    
2727  
    boolean isStillConnected() {
2728  
      return !(eos || s.isClosed());
2729  
    }
2730  
    
2731  
    void sendLine(String line) { try {
2732  
 
2733  
      w.write(line + "\n");
2734  
      w.flush();
2735  
    
2736  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
2737  
    
2738  
    String readLineImpl() { try {
2739  
 
2740  
      return in.readLine();
2741  
    
2742  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
2743  
    
2744  
    void close() {
2745  
      try {
2746  
        s.close();
2747  
      } catch (IOException e) {
2748  
        // whatever
2749  
      }
2750  
    }
2751  
    
2752  
    Socket getSocket() {
2753  
      return s;
2754  
    }
2755  
  };
2756  
2757  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} // talkTo
2758  
static String[] toStringArray(List<String> list) {
2759  
  return list.toArray(new String[list.size()]);
2760  
}
2761  
2762  
static String[] toStringArray(Object o) {
2763  
  if (o instanceof String[])
2764  
    return (String[]) o;
2765  
  else if (o instanceof List)
2766  
    return toStringArray((List<String>) o);
2767  
  else
2768  
    throw fail("Not a list or array: " + structure(o));
2769  
}
2770  
 // toStringArray
2771  
  
2772  
static byte[] loadDataSnippetImpl(String snippetID) throws IOException {
2773  
  byte[] data;
2774  
  try {
2775  
    URL url = new URL("http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_"
2776  
      + parseSnippetID(snippetID) + "&contentType=application/binary");
2777  
    System.err.println("Loading library: " + url);
2778  
    try {
2779  
      data = loadBinaryPage(url.openConnection());
2780  
    } catch (IOException e) {
2781  
      data = null;
2782  
    }
2783  
    
2784  
    if (data == null || data.length == 0) {
2785  
      url = new URL("http://data.tinybrain.de/blobs/"
2786  
        + parseSnippetID(snippetID));
2787  
      System.err.println("Loading library: " + url);
2788  
      data = loadBinaryPage(url.openConnection());
2789  
    }
2790  
    System.err.println("Bytes loaded: " + data.length);
2791  
  } catch (FileNotFoundException e) {
2792  
    throw new IOException("Binary snippet #" + snippetID + " not found or not public");
2793  
  }
2794  
  return data;
2795  
}
2796  
  static AtomicBoolean readLine_used = new AtomicBoolean();
2797  
  static BufferedReader readLine_reader;
2798  
2799  
  static String readLine() { try {
2800  
 
2801  
    if (!readLine_used.compareAndSet(false, true))
2802  
      throw fail("readLine is in use.");
2803  
    try {
2804  
      while (true) {
2805  
        if (readLine_reader == null)
2806  
          readLine_reader = new BufferedReader(new InputStreamReader(System.in, "UTF-8")); // XX - is that right?
2807  
          
2808  
        if (!readLine_reader.ready())
2809  
          sleep(100);
2810  
        else {
2811  
          String s = readLine_reader.readLine();
2812  
          if (s != null) {
2813  
            print(s);
2814  
            return s;
2815  
          }
2816  
        }
2817  
      }
2818  
    } finally {
2819  
      readLine_used.set(false);
2820  
    }
2821  
  
2822  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
2823  
  
2824  
  static HashMap<String, WeakReference> weakrefs = new HashMap<String, WeakReference>();
2825  
  // static WeakIdentityHashMap<O, S> reverseWeakrefs = new WeakIdentityHashMap<O, S>();
2826  
  static long weakRefCounter;
2827  
  
2828  
  // TODO: lookup in reverse map
2829  
  static synchronized String weakref(Object o) {
2830  
    if (o == null) return "null";
2831  
    String id = vmID + "/" + ++weakRefCounter;
2832  
    weakrefs.put(id, new WeakReference(o));
2833  
    return id;
2834  
  }
2835  
2836  
  static synchronized Object getRef(String id) {
2837  
    // TODO: clean up the list some time
2838  
    
2839  
    WeakReference ref = weakrefs.get(id);
2840  
    if (ref == null) return null;
2841  
    return ref.get();
2842  
  }
2843  
  
2844  
  static List<Object> multiPorts = new ArrayList<Object>();
2845  
  
2846  
  static synchronized List<Object> getMultiPorts() {
2847  
    return cloneList(multiPorts);
2848  
  }
2849  
  
2850  
  // true if you're the first one
2851  
  static synchronized boolean addMultiPort(Object o) {
2852  
    multiPorts.add(o);
2853  
    if (multiPorts.size() == 1) {
2854  
      { Thread _t_1 = new Thread("keep alive") {
2855  
public void run() {
2856  
try  { x30.sleep(); } catch (Exception _e) {
2857  
  throw _e instanceof RuntimeException ? (RuntimeException) _e : new RuntimeException(_e); } }
2858  
};
2859  
_t_1.start(); } // keep VM alive since there is a multiport
2860  
    }
2861  
    return multiPorts.size() == 1;
2862  
  }
2863  
  
2864  
  static synchronized void removeMultiPort(Object o) {
2865  
    multiPorts.remove(o);
2866  
  }
2867  
  
2868  
  static String getInjectionID(Class mainClass) {
2869  
    List<PaA> l = getInjections();
2870  
    for (PaA injection : l)
2871  
      if (injection.mainClass == mainClass)
2872  
        return injection.injectionID;
2873  
    return null;
2874  
  }
2875  
  
2876  
  static String getInjectionID() { return null; } // used somewhere...
2877  
  
2878  
  static void sleep(long ms) {
2879  
    try {
2880  
      Thread.sleep(ms);
2881  
    } catch (Exception e) { throw new RuntimeException(e); }
2882  
  }
2883  
2884  
  static void sleep() { try {
2885  
 
2886  
    print("Sleeping.");
2887  
    synchronized(x30.class) { x30.class.wait(); }
2888  
  
2889  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
2890  
  
2891  
  static WeakHashMap<Class, String> classToSourceCode = new WeakHashMap<Class, String>();
2892  
  
2893  
  synchronized static void registerSourceCode(Class c, String src) {
2894  
    classToSourceCode.put(c, src);
2895  
  }
2896  
  
2897  
  synchronized static String getSourceCodeForClass(Class c) {
2898  
    return classToSourceCode.get(c);
2899  
  }
2900  
  static class Matches {
2901  
    String[] m;
2902  
    String get(int i) { return m[i]; }
2903  
    String unq(int i) { return unquote(m[i]); }
2904  
    String fsi(int i) { return formatSnippetID(unq(i)); }
2905  
    String fsi() { return fsi(0); }
2906  
    String tlc(int i) { return unq(i).toLowerCase(); }
2907  
    boolean bool(int i) { return "true".equals(unq(i)); }
2908  
    String rest() { return m[m.length-1]; } // for matchStart
2909  
    int psi(int i) { return Integer.parseInt(unq(i)); }
2910  
  }
2911  
 // Matches
2912  
  
2913  
  // get main class of first program (for console)
2914  
  static Object getMainMainClass() {
2915  
    PaA paa = first(getInjections());
2916  
    return paa == null ? null : paa.mainClass;
2917  
  }
2918  
  
2919  
  static boolean _inCore() {
2920  
    return true;
2921  
  }
2922  
2923  
// This is for main classes that are all static.
2924  
// (We don't go to base classes.)
2925  
static Set<String> listFields(Object c) {
2926  
  TreeSet<String> fields = new TreeSet<String>();
2927  
  for (Field f : ((Class) c).getDeclaredFields())
2928  
    fields.add(f.getName());
2929  
  return fields;
2930  
}
2931  
static Thread currentThread() {
2932  
  return Thread.currentThread();
2933  
}
2934  
static <A> List<A> cloneList(Collection<A> l) {
2935  
  //O mutex = getOpt(l, "mutex");
2936  
  /*if (mutex != null)
2937  
    synchronized(mutex) {
2938  
      ret new ArrayList<A>(l);
2939  
    }
2940  
  else
2941  
    ret new ArrayList<A>(l);*/
2942  
  // assume mutex is equal to collection, which will be true unless you explicitly pass a mutex to synchronizedList() which no one ever does.
2943  
  synchronized(l) {
2944  
    return new ArrayList<A>(l);
2945  
  }
2946  
}
2947  
static Map litmap(Object... x) {
2948  
  TreeMap map = new TreeMap();
2949  
  litmap_impl(map, x);
2950  
  return map;
2951  
}
2952  
2953  
static void litmap_impl(Map map, Object... x) {
2954  
  for (int i = 0; i < x.length-1; i += 2)
2955  
    if (x[i+1] != null)
2956  
      map.put(x[i], x[i+1]);
2957  
}
2958  
  static RuntimeException fail() {
2959  
    throw new RuntimeException("fail");
2960  
  }
2961  
  
2962  
  static RuntimeException fail(Object msg) {
2963  
    throw new RuntimeException(String.valueOf(msg));
2964  
  }
2965  
  
2966  
  static RuntimeException fail(String msg) {
2967  
    throw new RuntimeException(unnull(msg));
2968  
  }
2969  
   
2970  
  // disabled for now to shorten some programs 
2971  
  /*static RuntimeException fail(S msg, O... args) {
2972  
    throw new RuntimeException(format(msg, args));
2973  
  }*/
2974  
static void cleanJavaXCache(int retentionHours, boolean verbose) {
2975  
  try {
2976  
    if (verbose)
2977  
      System.out.println("Cleaning JavaX Cache (" + retentionHours + " hours retention time)");
2978  
    int fileDeletions = 0;
2979  
    File javax = new File(userHome(), ".javax");
2980  
    long now = now();
2981  
    File[] files = javax.listFiles();
2982  
    if (files != null) for (File dir : files) {
2983  
      if (dir.isDirectory() && Pattern.compile("\\d+").matcher(dir.getName()).matches()) {
2984  
        long time = Long.parseLong(dir.getName());
2985  
        long seconds = (now - time) / 1000;
2986  
        long minutes = seconds / 60;
2987  
        long hours = minutes / 60;
2988  
        if (hours >= retentionHours) {
2989  
          //System.out.println("Can delete " + dir.getAbsolutePath() + ", age: " + hours + " h");
2990  
          fileDeletions += cleanJavaXCache_removeDir(dir, verbose);
2991  
        }
2992  
      }
2993  
    }
2994  
    if (verbose && fileDeletions != 0)
2995  
      print("Cleaned cache. File deletions: " + fileDeletions);
2996  
  } catch (Throwable __e) { printStackTrace(__e); }
2997  
}
2998  
2999  
static int cleanJavaXCache_removeDir(File dir, boolean verbose) {
3000  
  int fileDeletions = 0;
3001  
  if (dir.getAbsolutePath().indexOf(".javax") < 0)  // security check!
3002  
    throw fail("WHAT ARE YOU DOING!? >> " + dir.getAbsolutePath());
3003  
  for (File f : dir.listFiles()) {
3004  
    if (f.isDirectory())
3005  
      cleanJavaXCache_removeDir(f, verbose);
3006  
    else {
3007  
      if (verbose)
3008  
        print("Deleting " + f.getAbsolutePath());
3009  
      f.delete();
3010  
      ++fileDeletions;
3011  
    }
3012  
  }
3013  
  dir.delete();
3014  
  return fileDeletions;
3015  
}
3016  
3017  
static String fsi(String id) {
3018  
  return formatSnippetID(id);
3019  
}
3020  
 static String boss(String line) {
3021  
    try {
3022  
      //S s = sendToLocalBotOpt("Boss Bot", line);
3023  
      DialogIO io = talkTo(4990); // Boss Bot port
3024  
      io.readLine();
3025  
      io.sendLine(line);
3026  
      String s = io.readLine();
3027  
      Matches m = new Matches();
3028  
      if (match3("text: *", s, m))
3029  
        return unquote(m.m[0]);
3030  
      return null;
3031  
    } catch (Exception e) {
3032  
      //e.printStackTrace();
3033  
      return null;
3034  
    }
3035  
  }
3036  
static class DynamicObject {
3037  
  String className;
3038  
  Map<String, Object> fieldValues = new TreeMap<String, Object>();
3039  
}
3040  
3041  
static Object unstructure(String text) {
3042  
  return unstructure(text, false);
3043  
}
3044  
3045  
// TODO: backrefs for hashmap{} etc
3046  
static Object unstructure(String text, final boolean allDynamic) {
3047  
  if (text == null) return null;
3048  
  final List<String> tok = javaTok(text);
3049  
  final boolean debug = unstructure_debug;
3050  
  
3051  
  class X {
3052  
    int i = 1;
3053  
    HashMap<Integer, Object> refs = new HashMap<Integer, Object>();
3054  
3055  
    Object parse() {
3056  
      String t = tok.get(i);
3057  
      
3058  
      int refID = 0;
3059  
      if (t.startsWith("m") && isInteger(t.substring(1))) {
3060  
        refID = parseInt(t.substring(1));
3061  
        i += 2;
3062  
        t = tok.get(i);
3063  
      }
3064  
      
3065  
      if (debug)
3066  
        print("parse: " + quote(t));
3067  
        
3068  
      if (t.startsWith("\"")) {
3069  
        String s = unquote(tok.get(i));
3070  
        i += 2;
3071  
        return s;
3072  
      }
3073  
      if (t.startsWith("'")) {
3074  
        char c = unquoteCharacter(tok.get(i));
3075  
        i += 2;
3076  
        return c;
3077  
      }
3078  
      if (t.equals("bigint"))
3079  
        return parseBigInt();
3080  
      if (t.equals("d"))
3081  
        return parseDouble();
3082  
      if (t.equals("false") || t.equals("f")) {
3083  
        i += 2; return false;
3084  
      }
3085  
      if (t.equals("true") || t.equals("t")) {
3086  
        i += 2; return true;
3087  
      }
3088  
      if (t.equals("-")) {
3089  
        t = tok.get(i+2);
3090  
        i += 4;
3091  
        return isLongConstant(t) ? (Object) (-parseLong(t)) : (Object) (-parseInt(t));
3092  
      }
3093  
      if (isInteger(t) || isLongConstant(t)) {
3094  
        i += 2;
3095  
        if (debug)
3096  
          print("isLongConstant " + quote(t) + " => " + isLongConstant(t));
3097  
        if (isLongConstant(t)) return parseLong(t);
3098  
        long l = parseLong(t);
3099  
        return l != (int) l ? new Long(l) : new Integer((int) l);
3100  
      }
3101  
      
3102  
      if (t.equals("File")) {
3103  
        File f = new File(unquote(tok.get(i+2)));
3104  
        i += 4;
3105  
        return f;
3106  
      }
3107  
      
3108  
      if (t.startsWith("r") && isInteger(t.substring(1))) {
3109  
        i += 2;
3110  
        int ref = Integer.parseInt(t.substring(1));
3111  
        Object o = refs.get(ref);
3112  
        if (o == null)
3113  
          print("Warning: unsatisfied back reference " + ref);
3114  
        return o;
3115  
      }
3116  
      
3117  
      return parse_inner(refID);
3118  
    }
3119  
    
3120  
    // everything that can be backreferenced
3121  
    Object parse_inner(int refID) {
3122  
      String t = tok.get(i);
3123  
      
3124  
      if (debug)
3125  
        print("parse_inner: " + quote(t));
3126  
        
3127  
      if (t.equals("hashset"))
3128  
        return parseHashSet();
3129  
      if (t.equals("treeset"))
3130  
        return parseTreeSet();
3131  
      if (t.equals("hashmap"))
3132  
        return parseHashMap();
3133  
      if (t.equals("{"))
3134  
        return parseMap();
3135  
      if (t.equals("["))
3136  
        return parseList();
3137  
      if (t.equals("array"))
3138  
        return parseArray();
3139  
      if (t.equals("class"))
3140  
        return parseClass();
3141  
      if (t.equals("l"))
3142  
        return parseLisp();
3143  
      if (t.equals("null")) {
3144  
        i += 2; return null;
3145  
      }
3146  
      if (isJavaIdentifier(t)) {
3147  
        Class c = allDynamic ? null : findClass(t);
3148  
        DynamicObject dO = null;
3149  
        Object o = null;
3150  
        if (c != null)
3151  
          o = nuObject(c);
3152  
        else {
3153  
          dO = new DynamicObject();
3154  
          dO.className = t;
3155  
        }
3156  
        
3157  
        if (refID != 0)
3158  
          refs.put(refID, o);
3159  
          
3160  
        i += 2;
3161  
        if (i < tok.size() && tok.get(i).equals("(")) {
3162  
          consume("(");
3163  
          while (!tok.get(i).equals(")")) {
3164  
            // It's like parsing a map.
3165  
            //Object key = parse();
3166  
            //if (tok.get(i).equals(")"))
3167  
            //  key = onlyField();
3168  
            String key = unquote(tok.get(i));
3169  
            i += 2;
3170  
            consume("=");
3171  
            Object value = parse();
3172  
            if (o != null)
3173  
              setOpt(o, key, value);
3174  
            else
3175  
              dO.fieldValues.put(key, value);
3176  
            if (tok.get(i).equals(",")) i += 2;
3177  
          }
3178  
          consume(")");
3179  
        }
3180  
        return o != null ? o : dO;
3181  
      }
3182  
      throw new RuntimeException("Unknown token " + (i+1) + ": " + t);
3183  
    }
3184  
    
3185  
    Object parseSet(Set set) {
3186  
      set.addAll((List) parseList());
3187  
      return set;
3188  
    }
3189  
    
3190  
    Object parseLisp() {
3191  
      consume("l");
3192  
      consume("(");
3193  
      List list = new ArrayList();
3194  
      while (!tok.get(i).equals(")")) {
3195  
        list.add(parse());
3196  
        if (tok.get(i).equals(",")) i += 2;
3197  
      }
3198  
      consume(")");
3199  
      return newObject("main$Lisp", (String) list.get(0), subList(list, 1));
3200  
    }
3201  
    
3202  
    Object parseList() {
3203  
      consume("[");
3204  
      List list = new ArrayList();
3205  
      while (!tok.get(i).equals("]")) {
3206  
        list.add(parse());
3207  
        if (tok.get(i).equals(",")) i += 2;
3208  
      }
3209  
      consume("]");
3210  
      return list;
3211  
    }
3212  
    
3213  
    Object parseArray() {
3214  
      consume("array");
3215  
      consume("{");
3216  
      List list = new ArrayList();
3217  
      while (!tok.get(i).equals("}")) {
3218  
        list.add(parse());
3219  
        if (tok.get(i).equals(",")) i += 2;
3220  
      }
3221  
      consume("}");
3222  
      return list.toArray();
3223  
    }
3224  
    
3225  
    Object parseClass() {
3226  
      consume("class");
3227  
      consume("(");
3228  
      String name = tok.get(i);
3229  
      i += 2;
3230  
      consume(")");
3231  
      Class c = allDynamic ? null : findClass(name);
3232  
      if (c != null) return c;
3233  
      DynamicObject dO = new DynamicObject();
3234  
      dO.className = "java.lang.Class";
3235  
      dO.fieldValues.put("name", name);
3236  
      return dO;
3237  
    }
3238  
    
3239  
    Object parseBigInt() {
3240  
      consume("bigint");
3241  
      consume("(");
3242  
      String val = tok.get(i);
3243  
      i += 2;
3244  
      if (eq(val, "-")) {
3245  
        val = "-" + tok.get(i);
3246  
        i += 2;
3247  
      }
3248  
      consume(")");
3249  
      return new BigInteger(val);
3250  
    }
3251  
    
3252  
    Object parseDouble() {
3253  
      consume("d");
3254  
      consume("(");
3255  
      String val = unquote(tok.get(i));
3256  
      i += 2;
3257  
      consume(")");
3258  
      return Double.parseDouble(val);
3259  
    }
3260  
    
3261  
    Object parseHashMap() {
3262  
      consume("hashmap");
3263  
      return parseMap(new HashMap());
3264  
    }
3265  
    
3266  
    Object parseHashSet() {
3267  
      consume("hashset");
3268  
      return parseSet(new HashSet());
3269  
    }
3270  
    
3271  
    Object parseTreeSet() {
3272  
      consume("treeset");
3273  
      return parseSet(new TreeSet());
3274  
    }
3275  
    
3276  
    Object parseMap() {
3277  
      return parseMap(new TreeMap());
3278  
    }
3279  
    
3280  
    Object parseMap(Map map) {
3281  
      consume("{");
3282  
      while (!tok.get(i).equals("}")) {
3283  
        Object key = parse();
3284  
        consume("=");
3285  
        Object value = parse();
3286  
        map.put(key, value);
3287  
        if (tok.get(i).equals(",")) i += 2;
3288  
      }
3289  
      consume("}");
3290  
      return map;
3291  
    }
3292  
    
3293  
    void consume(String s) {
3294  
      if (!tok.get(i).equals(s)) {
3295  
        String prevToken = i-2 >= 0 ? tok.get(i-2) : "";
3296  
        String nextTokens = join(tok.subList(i, Math.min(i+4, tok.size())));
3297  
        throw fail(quote(s) + " expected: " + prevToken + " " + nextTokens + " (" + i + "/" + tok.size() + ")");
3298  
      }
3299  
      i += 2;
3300  
    }
3301  
  }
3302  
  
3303  
  return new X().parse();
3304  
}
3305  
3306  
static boolean unstructure_debug;
3307  
static <A> ArrayList<A> litlist(A... a) {
3308  
  return new ArrayList<A>(Arrays.asList(a));
3309  
}
3310  
  static ThreadLocal<String> loadPage_charset = new ThreadLocal<String>();
3311  
  static boolean loadPage_allowGzip = true, loadPage_debug;
3312  
  static boolean loadPage_anonymous; // don't send computer ID
3313  
  static int loadPage_verboseness = 100000;
3314  
3315  
  public static String loadPageSilently(String url) {
3316  
    try {
3317  
      return loadPageSilently(new URL(loadPage_preprocess(url)));
3318  
    } catch (IOException e) { throw new RuntimeException(e); }
3319  
  }
3320  
3321  
  public static String loadPageSilently(URL url) {
3322  
    try {
3323  
      IOException e = null;
3324  
      for (int tries = 0; tries < 60; tries++)
3325  
        try {
3326  
          URLConnection con = url.openConnection();
3327  
          return loadPage(con, url);
3328  
        } catch (IOException _e) {
3329  
          e = _e;
3330  
          print("Retrying because of: " + e);
3331  
          sleepSeconds(1);
3332  
        }
3333  
      throw e;
3334  
    } catch (IOException e) { throw new RuntimeException(e); }
3335  
  }
3336  
3337  
  static String loadPage_preprocess(String url) {  
3338  
    if (url.startsWith("tb/"))
3339  
      url = "tinybrain.de:8080/" + url;
3340  
    if (url.indexOf("://") < 0)
3341  
      url = "http://" + url;
3342  
    return url;
3343  
  }
3344  
  
3345  
  public static String loadPage(String url) {
3346  
    try {
3347  
      return loadPage(new URL(loadPage_preprocess(url)));
3348  
    } catch (IOException e) { throw new RuntimeException(e); }
3349  
  }
3350  
  
3351  
  public static String loadPage(URL url) {
3352  
    print("Loading: " + url.toExternalForm());
3353  
    return loadPageSilently(url);
3354  
  }
3355  
3356  
  public static String loadPage(URLConnection con, URL url) throws IOException {
3357  
    try {
3358  
      if (!loadPage_anonymous) {
3359  
        String computerID = getComputerID();
3360  
        if (computerID != null)
3361  
          con.setRequestProperty("X-ComputerID", computerID);
3362  
      }
3363  
      if (loadPage_allowGzip)
3364  
        con.setRequestProperty("Accept-Encoding", "gzip");
3365  
    } catch (Throwable e) {} // fails if within doPost
3366  
    String contentType = con.getContentType();
3367  
    if (contentType == null)
3368  
      throw new IOException("Page could not be read: " + url);
3369  
    //print("Content-Type: " + contentType);
3370  
    String charset = loadPage_charset == null ? null : loadPage_charset.get();
3371  
    if (charset == null) charset = loadPage_guessCharset(contentType);
3372  
    
3373  
    InputStream in = con.getInputStream();
3374  
    if ("gzip".equals(con.getContentEncoding())) {
3375  
      if (loadPage_debug)
3376  
        print("loadPage: Using gzip.");
3377  
      in = new GZIPInputStream(in);
3378  
    }
3379  
    Reader r = new InputStreamReader(in, charset);
3380  
    
3381  
    StringBuilder buf = new StringBuilder();
3382  
    int n = 0;
3383  
    while (true) {
3384  
      int ch = r.read();
3385  
      if (ch < 0)
3386  
        break;
3387  
      buf.append((char) ch);
3388  
      ++n;
3389  
      if ((n % loadPage_verboseness) == 0) print("  " + n + " chars read");
3390  
    }
3391  
    return buf.toString();
3392  
  }
3393  
  
3394  
  static String loadPage_guessCharset(String contentType) {
3395  
    Pattern p = Pattern.compile("text/[a-z]+;\\s+charset=([^\\s]+)\\s*");
3396  
    Matcher m = p.matcher(contentType);
3397  
    /* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */
3398  
    return m.matches() ? m.group(1) : "ISO-8859-1";
3399  
  }
3400  
3401  
static int l(Object[] array) {
3402  
  return array == null ? 0 : array.length;
3403  
}
3404  
3405  
static int l(byte[] array) {
3406  
  return array == null ? 0 : array.length;
3407  
}
3408  
3409  
static int l(int[] array) {
3410  
  return array == null ? 0 : array.length;
3411  
}
3412  
3413  
static int l(char[] array) {
3414  
  return array == null ? 0 : array.length;
3415  
}
3416  
3417  
static int l(Collection c) {
3418  
  return c == null ? 0 : c.size();
3419  
}
3420  
3421  
static int l(Map m) {
3422  
  return m == null ? 0 : m.size();
3423  
}
3424  
3425  
static int l(String s) {
3426  
  return s == null ? 0 : s.length();
3427  
} 
3428  
3429  
3430  
  static Object call(Object o) {
3431  
    return callFunction(o);
3432  
  }
3433  
  
3434  
  // varargs assignment fixer for a single string array argument
3435  
  static Object call(Object o, String method, String[] arg) {
3436  
    return call(o, method, new Object[] {arg});
3437  
  }
3438  
  
3439  
  static Object call(Object o, String method, Object... args) {
3440  
    try {
3441  
      if (o instanceof Class) {
3442  
        Method m = call_findStaticMethod((Class) o, method, args, false);
3443  
        m.setAccessible(true);
3444  
        return m.invoke(null, args);
3445  
      } else {
3446  
        Method m = call_findMethod(o, method, args, false);
3447  
        m.setAccessible(true);
3448  
        return m.invoke(o, args);
3449  
      }
3450  
    } catch (Exception e) {
3451  
      throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
3452  
    }
3453  
  }
3454  
3455  
  static Method call_findStaticMethod(Class c, String method, Object[] args, boolean debug) {
3456  
    Class _c = c;
3457  
    while (c != null) {
3458  
      for (Method m : c.getDeclaredMethods()) {
3459  
        if (debug)
3460  
          System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
3461  
        if (!m.getName().equals(method)) {
3462  
          if (debug) System.out.println("Method name mismatch: " + method);
3463  
          continue;
3464  
        }
3465  
3466  
        if ((m.getModifiers() & Modifier.STATIC) == 0 || !call_checkArgs(m, args, debug))
3467  
          continue;
3468  
3469  
        return m;
3470  
      }
3471  
      c = c.getSuperclass();
3472  
    }
3473  
    throw new RuntimeException("Method '" + method + "' (static) with " + args.length + " parameter(s) not found in " + _c.getName());
3474  
  }
3475  
3476  
  static Method call_findMethod(Object o, String method, Object[] args, boolean debug) {
3477  
    Class c = o.getClass();
3478  
    while (c != null) {
3479  
      for (Method m : c.getDeclaredMethods()) {
3480  
        if (debug)
3481  
          System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
3482  
        if (m.getName().equals(method) && call_checkArgs(m, args, debug))
3483  
          return m;
3484  
      }
3485  
      c = c.getSuperclass();
3486  
    }
3487  
    throw new RuntimeException("Method '" + method + "' (non-static) with " + args.length + " parameter(s) not found in " + o.getClass().getName());
3488  
  }
3489  
3490  
  private static boolean call_checkArgs(Method m, Object[] args, boolean debug) {
3491  
    Class<?>[] types = m.getParameterTypes();
3492  
    if (types.length != args.length) {
3493  
      if (debug)
3494  
        System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
3495  
      return false;
3496  
    }
3497  
    for (int i = 0; i < types.length; i++)
3498  
      if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
3499  
        if (debug)
3500  
          System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
3501  
        return false;
3502  
      }
3503  
    return true;
3504  
  }
3505  
3506  
3507  
static Object first(Object list) {
3508  
  return ((List) list).isEmpty() ? null : ((List) list).get(0);
3509  
}
3510  
3511  
static <A> A first(List<A> list) {
3512  
  return list.isEmpty() ? null : list.get(0);
3513  
}
3514  
3515  
static <A> A first(A[] bla) {
3516  
  return bla == null || bla.length == 0 ? null : bla[0];
3517  
}
3518  
  static String format3(String pat, Object... args) {
3519  
    if (args.length == 0) return pat;
3520  
    
3521  
    List<String> tok = javaTokPlusPeriod(pat);
3522  
    int argidx = 0;
3523  
    for (int i = 1; i < tok.size(); i += 2)
3524  
      if (tok.get(i).equals("*"))
3525  
        tok.set(i, format3_formatArg(argidx < args.length ? args[argidx++] : "null"));
3526  
    return join(tok);
3527  
  }
3528  
  
3529  
  static String format3_formatArg(Object arg) {
3530  
    if (arg == null) return "null";
3531  
    if (arg instanceof String) {
3532  
      String s = (String) arg;
3533  
      return isIdentifier(s) || isNonNegativeInteger(s) ? s : quote(s);
3534  
    }
3535  
    if (arg instanceof Integer || arg instanceof Long) return String.valueOf(arg);
3536  
    return quote(structure(arg));
3537  
  }
3538  
  
3539  
3540  
  // class Matches is added by #752
3541  
 
3542  
  static boolean match3(String pat, String s) {
3543  
    return match3(pat, s, null);
3544  
  }
3545  
  
3546  
  static boolean match3(String pat, String s, Matches matches) {
3547  
    if (s == null) return false;
3548  
    return match3(pat, parse3(s), matches);
3549  
  }
3550  
    
3551  
  static boolean match3(String pat, List<String> toks, Matches matches) {
3552  
    List<String> tokpat = parse3(pat);
3553  
    return match3(tokpat,toks,matches);
3554  
  }
3555  
3556  
  static boolean match3(List<String> tokpat, List<String> toks, Matches matches) {
3557  
3558  
    String[] m = match2(tokpat, toks);
3559  
    //print(structure(tokpat) + " on " + structure(toks) + " => " + structure(m));
3560  
    if (m == null)
3561  
      return false;
3562  
    else {
3563  
      if (matches != null) matches.m = m;
3564  
      return true;
3565  
    }
3566  
  }
3567  
static class Android3 {
3568  
  String greeting;
3569  
  boolean publicOverride; // optionally set this in client
3570  
  int startPort = 5000; // optionally set this in client
3571  
  Responder responder;
3572  
  boolean console = true;
3573  
  boolean daemon = false;
3574  
  boolean incomingSilent = false;
3575  
  boolean useMultiPort = true;
3576  
  boolean verbose;
3577  
  
3578  
  // set by system
3579  
  int port;
3580  
  long vport;
3581  
  DialogHandler handler;
3582  
  ServerSocket server;
3583  
  
3584  
  Android3(String greeting) {
3585  
  this.greeting = greeting;}
3586  
  Android3() {}
3587  
  
3588  
  synchronized void dispose() {
3589  
    if (server != null) {
3590  
      try {
3591  
        server.close();
3592  
      } catch (IOException e) {
3593  
        print("[internal] " + e);
3594  
      }
3595  
      server = null;
3596  
    }
3597  
    if (vport != 0) try {
3598  
      //print("Dispoing virtual port " + vport);
3599  
      removeFromMultiPort(vport);
3600  
      vport = 0;
3601  
    } catch (Throwable __e) { printStackTrace(__e); }
3602  
  }
3603  
}
3604  
3605  
static abstract class Responder {
3606  
  abstract String answer(String s, List<String> history);
3607  
}
3608  
3609  
static Android3 makeAndroid3(final String greeting) {
3610  
  return makeAndroid3(new Android3(greeting));
3611  
}
3612  
3613  
static Android3 makeAndroid3(final String greeting, Responder responder) {
3614  
  Android3 android = new Android3(greeting);
3615  
  android.responder = responder;
3616  
  return makeAndroid3(android);
3617  
}
3618  
3619  
static Android3 makeAndroid3(final Android3 a) {
3620  
  if (a.responder == null)
3621  
    a.responder = new Responder() {
3622  
      String answer(String s, List<String> history) {
3623  
        return callStaticAnswerMethod(s, history);
3624  
      }
3625  
    };
3626  
    
3627  
  print(a.greeting);
3628  
  
3629  
  if (a.useMultiPort) {
3630  
    a.vport = addToMultiPort(a.greeting,
3631  
      makeAndroid3_verboseResponder(a));
3632  
    if (a.vport == 1)
3633  
      makeAndroid3_handleConsole(a);
3634  
    return a;
3635  
  }
3636  
    
3637  
  a.handler = makeAndroid3_makeDialogHandler(a);
3638  
  a.port = a.daemon
3639  
    ? startDialogServerOnPortAboveDaemon(a.startPort, a.handler)
3640  
    : startDialogServerOnPortAbove(a.startPort, a.handler);
3641  
  a.server = startDialogServer_serverSocket;
3642  
3643  
  if (a.console && makeAndroid3_consoleInUse()) a.console = false;
3644  
  
3645  
  if (a.console)
3646  
    makeAndroid3_handleConsole(a);
3647  
3648  
  record(a);
3649  
  return a;
3650  
}
3651  
3652  
static void makeAndroid3_handleConsole(final Android3 a) {
3653  
  // Console handling stuff
3654  
  print("You may also type on this console.");
3655  
  { Thread _t_0 = new Thread() {
3656  
public void run() {
3657  
try {
3658  
    List<String> history = new ArrayList<String>();
3659  
    String line;
3660  
    while ((line = readLine()) != null) {
3661  
      /*if (eq(line, "bye")) {
3662  
        print("> bye stranger");
3663  
        history = new ArrayList<S>();
3664  
      } else*/ {
3665  
        history.add(line);
3666  
        history.add(makeAndroid3_getAnswer(line, history, a)); // prints answer on console too
3667  
      }
3668  
    }
3669  
  } catch (Exception _e) {
3670  
  throw _e instanceof RuntimeException ? (RuntimeException) _e : new RuntimeException(_e); } }
3671  
};
3672  
_t_0.start(); }
3673  
}
3674  
3675  
static DialogHandler makeAndroid3_makeDialogHandler(final Android3 a) {
3676  
  return new DialogHandler() {
3677  
public void run(final DialogIO io) {
3678  
    if (!a.publicOverride && !(publicCommOn() || io.isLocalConnection())) {
3679  
      io.sendLine("Sorry, not allowed");
3680  
      return;
3681  
    }
3682  
    
3683  
    String dialogID = randomID(8);
3684  
    
3685  
    io.sendLine(a.greeting + " / Your ID: " + dialogID);
3686  
    
3687  
    List<String> history = new ArrayList<String>();
3688  
    
3689  
    while (io.isStillConnected()) {
3690  
      if (io.waitForLine()) {
3691  
        final String line = io.readLineNoBlock();
3692  
        String s = dialogID + " at " + now() + ": " + quote(line);
3693  
        if (!a.incomingSilent)
3694  
          print(s);
3695  
        if (line == "bye") {
3696  
          io.sendLine("bye stranger");
3697  
          return;
3698  
        }
3699  
        Matches m = new Matches();
3700  
        history.add(line);
3701  
        String answer;
3702  
        if (match3("this is a continuation of talk *", s, m)
3703  
          || match3("hello bot! this is a continuation of talk *", s, m)) {
3704  
          dialogID = unquote(m.m[0]);
3705  
          answer = "ok";
3706  
        } else
3707  
          answer = makeAndroid3_getAnswer(line, history, a);
3708  
        history.add(answer);
3709  
        io.sendLine(answer);
3710  
        //appendToLog(logFile, s);
3711  
      }
3712  
    }
3713  
  }};
3714  
}
3715  
3716  
static String makeAndroid3_getAnswer(String line, List<String> history, Android3 a) {
3717  
  String answer;
3718  
  try {
3719  
    answer = makeAndroid3_fallback(line, history, a.responder.answer(line, history));
3720  
  } catch (Throwable e) {
3721  
    e = getInnerException(e);
3722  
    printStackTrace(e);
3723  
    answer = e.toString();
3724  
  }
3725  
  if (!a.incomingSilent)
3726  
    print("> " + shorten(answer, 500));
3727  
  return answer;
3728  
}
3729  
3730  
static String makeAndroid3_fallback(String s, List<String> history, String answer) {
3731  
  // Now we only do the safe thing instead of VM inspection - give out our process ID
3732  
  if (answer == null && match3("what is your pid", s))
3733  
    return getPID();
3734  
    
3735  
  if (answer == null && match3("what is your program id", s)) // should be fairly safe, right?
3736  
    return getProgramID();
3737  
    
3738  
  if (match3("get injection id", s))
3739  
    return getInjectionID();
3740  
    
3741  
  if (answer == null) answer = "?";
3742  
  if (answer.indexOf('\n') >= 0 || answer.indexOf('\r') >= 0)
3743  
    answer = quote(answer);
3744  
  return answer;
3745  
}
3746  
3747  
static boolean makeAndroid3_consoleInUse() {
3748  
  for (Object o : record_list)
3749  
    if (o instanceof Android3 && ((Android3) o).console)
3750  
      return true;
3751  
  return false;
3752  
}
3753  
3754  
static Responder makeAndroid3_verboseResponder(final Android3 a) {
3755  
  return new Responder() {
3756  
    String answer(String s, List<String> history) {
3757  
      if (a.verbose)
3758  
        print("> " + s);
3759  
      String answer = a.responder.answer(s, history);
3760  
      if (a.verbose)
3761  
        print("< " + answer);
3762  
      return answer;
3763  
    }
3764  
  };
3765  
}
3766  
static void callMain(Object c, String... args) {
3767  
  callOpt(c, "main", new Object[] {args});
3768  
}
3769  
static boolean empty(Collection c) {
3770  
  return isEmpty(c);
3771  
}
3772  
3773  
static boolean empty(String s) {
3774  
  return isEmpty(s);
3775  
}
3776  
3777  
static boolean empty(Map map) {
3778  
  return map == null || map.isEmpty();
3779  
}
3780  
3781  
static boolean empty(Object o) {
3782  
  if (o instanceof Collection) return empty((Collection) o);
3783  
  if (o instanceof String) return empty((String) o);
3784  
  if (o instanceof Map) return empty((Map) o);
3785  
  return false;
3786  
}
3787  
static String getServerTranspiled(String snippetID) { try {
3788  
 
3789  
  long id = parseSnippetID(snippetID);
3790  
  /*S t = getTranspilationFromBossBot(id);
3791  
  if (t != null) return t;*/
3792  
  
3793  
  return loadPage_utf8("http://tinybrain.de:8080/tb-int/get-transpiled.php?raw=1&withlibs=1&id=" + id + "&utf8=1");
3794  
3795  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
3796  
static String getStackTrace(Throwable throwable) {
3797  
  StringWriter writer = new StringWriter();
3798  
  throwable.printStackTrace(new PrintWriter(writer));
3799  
  return writer.toString();
3800  
}
3801  
static String formatSnippetID(String id) {
3802  
  return "#" + parseSnippetID(id);
3803  
}
3804  
3805  
static String formatSnippetID(long id) {
3806  
  return "#" + id;
3807  
}
3808  
// extended over Class.isInstance() to handle primitive types
3809  
static boolean isInstanceX(Class type, Object arg) {
3810  
  if (type == boolean.class) return arg instanceof Boolean;
3811  
  if (type == int.class) return arg instanceof Integer;
3812  
  if (type == long.class) return arg instanceof Long;
3813  
  if (type == float.class) return arg instanceof Float;
3814  
  if (type == short.class) return arg instanceof Short;
3815  
  if (type == char.class) return arg instanceof Character;
3816  
  if (type == byte.class) return arg instanceof Byte;
3817  
  if (type == double.class) return arg instanceof Double;
3818  
  return type.isInstance(arg);
3819  
}
3820  
static boolean eq(Object a, Object b) {
3821  
  if (a == null) return b == null;
3822  
  if (a.equals(b)) return true;
3823  
  if (a instanceof BigInteger) {
3824  
    if (b instanceof Integer) return a.equals(BigInteger.valueOf((Integer) b));
3825  
    if (b instanceof Long) return a.equals(BigInteger.valueOf((Long) b));
3826  
  }
3827  
  return false;
3828  
}
3829  
 static String getSnippetFromBossBot(long snippetID) {
3830  
    return boss(format3("get text for *", snippetID));
3831  
  }
3832  
  
3833  
static <A, B> Set<A> keys(Map<A, B> map) {
3834  
  return map.keySet();
3835  
}
3836  
3837  
static Set keys(Object map) {
3838  
  return keys((Map) map);
3839  
}
3840  
static List emptyList() {
3841  
  return new ArrayList();
3842  
  //ret Collections.emptyList();
3843  
}
3844  
// try to get our current process ID
3845  
static String getPID() {
3846  
  String name = ManagementFactory.getRuntimeMXBean().getName();
3847  
  return name.replaceAll("@.*", "");
3848  
}
3849  
  public static String unquote(String s) {
3850  
    if (s.startsWith("[")) {
3851  
      int i = 1;
3852  
      while (i < s.length() && s.charAt(i) == '=') ++i;
3853  
      if (i < s.length() && s.charAt(i) == '[') {
3854  
        String m = s.substring(1, i);
3855  
        if (s.endsWith("]" + m + "]"))
3856  
          return s.substring(i+1, s.length()-i-1);
3857  
      }
3858  
    }
3859  
    
3860  
    if (s.startsWith("\"") /*&& s.endsWith("\"")*/ && s.length() > 1) {
3861  
      String st = s.substring(1, s.endsWith("\"") ? s.length()-1 : s.length());
3862  
      StringBuilder sb = new StringBuilder(st.length());
3863  
  
3864  
      for (int i = 0; i < st.length(); i++) {
3865  
        char ch = st.charAt(i);
3866  
        if (ch == '\\') {
3867  
          char nextChar = (i == st.length() - 1) ? '\\' : st
3868  
                  .charAt(i + 1);
3869  
          // Octal escape?
3870  
          if (nextChar >= '0' && nextChar <= '7') {
3871  
              String code = "" + nextChar;
3872  
              i++;
3873  
              if ((i < st.length() - 1) && st.charAt(i + 1) >= '0'
3874  
                      && st.charAt(i + 1) <= '7') {
3875  
                  code += st.charAt(i + 1);
3876  
                  i++;
3877  
                  if ((i < st.length() - 1) && st.charAt(i + 1) >= '0'
3878  
                          && st.charAt(i + 1) <= '7') {
3879  
                      code += st.charAt(i + 1);
3880  
                      i++;
3881  
                  }
3882  
              }
3883  
              sb.append((char) Integer.parseInt(code, 8));
3884  
              continue;
3885  
          }
3886  
          switch (nextChar) {
3887  
          case '\\':
3888  
              ch = '\\';
3889  
              break;
3890  
          case 'b':
3891  
              ch = '\b';
3892  
              break;
3893  
          case 'f':
3894  
              ch = '\f';
3895  
              break;
3896  
          case 'n':
3897  
              ch = '\n';
3898  
              break;
3899  
          case 'r':
3900  
              ch = '\r';
3901  
              break;
3902  
          case 't':
3903  
              ch = '\t';
3904  
              break;
3905  
          case '\"':
3906  
              ch = '\"';
3907  
              break;
3908  
          case '\'':
3909  
              ch = '\'';
3910  
              break;
3911  
          // Hex Unicode: u????
3912  
          case 'u':
3913  
              if (i >= st.length() - 5) {
3914  
                  ch = 'u';
3915  
                  break;
3916  
              }
3917  
              int code = Integer.parseInt(
3918  
                      "" + st.charAt(i + 2) + st.charAt(i + 3)
3919  
                              + st.charAt(i + 4) + st.charAt(i + 5), 16);
3920  
              sb.append(Character.toChars(code));
3921  
              i += 5;
3922  
              continue;
3923  
          default:
3924  
            ch = nextChar; // added by Stefan
3925  
          }
3926  
          i++;
3927  
        }
3928  
        sb.append(ch);
3929  
      }
3930  
      return sb.toString();      
3931  
    } else
3932  
      return s; // return original
3933  
  }
3934  
  // compile JavaX source, load classes & return main class
3935  
  // src can be a snippet ID or actual source code
3936  
  // TODO: record injection?
3937  
  
3938  
  static Class<?> hotwire(String src) {
3939  
    try {
3940  
      Class j = getJavaX();
3941  
      
3942  
      synchronized(j) { // hopefully this goes well...
3943  
        List<File> libraries = new ArrayList<File>();
3944  
        File srcDir = (File) call(j, "transpileMain", src, libraries);
3945  
        if (srcDir == null)
3946  
          throw fail("transpileMain returned null (src=" + quote(src) + ")");
3947  
        
3948  
        Object androidContext = get(j, "androidContext");
3949  
        if (androidContext != null)
3950  
          return (Class) call(j, "loadx2android", srcDir, src);
3951  
          
3952  
        File classesDir = (File) call(j, "TempDirMaker_make");
3953  
        String javacOutput = (String) call(j, "compileJava", srcDir, libraries, classesDir);
3954  
        System.out.println(javacOutput);
3955  
        
3956  
        URL[] urls = new URL[libraries.size()+1];
3957  
        urls[0] = classesDir.toURI().toURL();
3958  
        for (int i = 0; i < libraries.size(); i++)
3959  
          urls[i+1] = libraries.get(i).toURI().toURL();
3960  
  
3961  
        // make class loader
3962  
        URLClassLoader classLoader = new URLClassLoader(urls);
3963  
    
3964  
        // load & return main class
3965  
        Class<?> theClass = classLoader.loadClass("main");
3966  
        
3967  
        callOpt(j, "registerSourceCode", theClass, loadTextFile(new File(srcDir, "main.java")));
3968  
3969  
        call(j, "setVars", theClass, isSnippetID(src) ? src: null);
3970  
        
3971  
        if (isSnippetID(src))
3972  
          callOpt(j, "addInstance", src, theClass);
3973  
          
3974  
        if (!_inCore())
3975  
          hotwire_copyOver(theClass);
3976  
  
3977  
        return theClass;
3978  
      }
3979  
    } catch (Exception e) {
3980  
      throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
3981  
    }
3982  
  }
3983  
static void smartSet(Field f, Object o, Object value) throws Exception {
3984  
  f.setAccessible(true);
3985  
  
3986  
  // take care of common case (long to int)
3987  
  if (f.getType() == int.class && value instanceof Long)
3988  
    value = ((Long) value).intValue();
3989  
    
3990  
  f.set(o, value);
3991  
}
3992  
static String structure(Object o) {
3993  
  HashSet refd = new HashSet();
3994  
  return structure_2(structure_1(o, 0, new IdentityHashMap(), refd), refd);
3995  
}
3996  
3997  
// leave to false, unless unstructure() breaks
3998  
static boolean structure_allowShortening = false;
3999  
4000  
static String structure_1(Object o, int stringSizeLimit, IdentityHashMap<Object, Integer> seen, HashSet<Integer> refd) {
4001  
  if (o == null) return "null";
4002  
  
4003  
  // these are never back-referenced (for readability)
4004  
  
4005  
  if (o instanceof String)
4006  
    return quote(stringSizeLimit != 0 ? shorten((String) o, stringSizeLimit) : (String) o);
4007  
    
4008  
  if (o instanceof BigInteger)
4009  
    return "bigint(" + o + ")";
4010  
  
4011  
  if (o instanceof Double)
4012  
    return "d(" + quote(str(o)) + ")";
4013  
    
4014  
  if (o instanceof Long)
4015  
    return o + "L";
4016  
  
4017  
  if (o instanceof Integer)
4018  
    return str(o);
4019  
    
4020  
  if (o instanceof Boolean)
4021  
    return ((Boolean) o).booleanValue() ? "t" : "f";
4022  
    
4023  
  if (o instanceof Character)
4024  
    return quoteCharacter((Character) o);
4025  
    
4026  
  if (o instanceof File)
4027  
    return "File " + quote(((File) o).getPath());
4028  
    
4029  
  // referencable objects follow
4030  
  
4031  
  Integer ref = seen.get(o);
4032  
  if (ref != null) {
4033  
    refd.add(ref);
4034  
    return "r" + ref;
4035  
  }
4036  
      
4037  
  ref = seen.size()+1;
4038  
  seen.put(o, ref);
4039  
  String r = "m" + ref + " "; // marker
4040  
4041  
  String name = o.getClass().getName();
4042  
4043  
  StringBuilder buf = new StringBuilder();
4044  
  
4045  
  if (o instanceof HashSet)
4046  
    return r + "hashset " + structure_1(new ArrayList((Set) o), stringSizeLimit, seen, refd);
4047  
4048  
  if (o instanceof TreeSet)
4049  
    return r + "treeset " + structure_1(new ArrayList((Set) o), stringSizeLimit, seen, refd);
4050  
  
4051  
  if (o instanceof Collection) {
4052  
    for (Object x : (Collection) o) {
4053  
      if (buf.length() != 0) buf.append(", ");
4054  
      buf.append(structure_1(x, stringSizeLimit, seen, refd));
4055  
    }
4056  
    return r + "[" + buf + "]";
4057  
  }
4058  
  
4059  
  if (o instanceof Map) {
4060  
    for (Object e : ((Map) o).entrySet()) {
4061  
      if (buf.length() != 0) buf.append(", ");
4062  
      buf.append(structure_1(((Map.Entry) e).getKey(), stringSizeLimit, seen, refd));
4063  
      buf.append("=");
4064  
      buf.append(structure_1(((Map.Entry) e).getValue(), stringSizeLimit, seen, refd));
4065  
    }
4066  
    return r + (o instanceof HashMap ? "hashmap" : "") + "{" + buf + "}";
4067  
  }
4068  
  
4069  
  if (o.getClass().isArray()) {
4070  
    int n = Array.getLength(o);
4071  
    for (int i = 0; i < n; i++) {
4072  
      if (buf.length() != 0) buf.append(", ");
4073  
      buf.append(structure_1(Array.get(o, i), stringSizeLimit, seen, refd));
4074  
    }
4075  
    return r + "array{" + buf + "}";
4076  
  }
4077  
4078  
  if (o instanceof Class)
4079  
    return r + "class(" + quote(((Class) o).getName()) + ")";
4080  
    
4081  
  if (o instanceof Throwable)
4082  
    return r + "exception(" + quote(((Throwable) o).getMessage()) + ")";
4083  
    
4084  
  if (o instanceof BitSet) {
4085  
    BitSet bs = (BitSet) o;
4086  
    for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
4087  
      if (buf.length() != 0) buf.append(", ");
4088  
       buf.append(i);
4089  
    }
4090  
    return "bitset{" + buf + "}";
4091  
  }
4092  
    
4093  
  // Need more cases? This should cover all library classes...
4094  
  if (name.startsWith("java.") || name.startsWith("javax."))
4095  
    return r + String.valueOf(o);
4096  
    
4097  
  String shortName = o.getClass().getName().replaceAll("^main\\$", "");
4098  
  
4099  
  if (shortName.equals("Lisp")) {
4100  
    buf.append("l(" + structure_1(getOpt(o, "head"), stringSizeLimit, seen, refd));
4101  
    List args = (List) ( getOpt(o, "args"));
4102  
    if (nempty(args))
4103  
      for (int i = 0; i < l(args); i++) {
4104  
        buf.append(", ");
4105  
        Object arg = args.get(i);
4106  
        
4107  
        // sweet shortening
4108  
        if (arg != null && eq(arg.getClass().getName(), "main$Lisp") && isTrue(call(arg, "isEmpty")))
4109  
          arg = get(arg, "head");
4110  
          
4111  
        buf.append(structure_1(arg, stringSizeLimit, seen, refd));
4112  
      }
4113  
    buf.append(")");
4114  
    return r + str(buf);
4115  
  }
4116  
    
4117  
  int numFields = 0;
4118  
  String fieldName = "";
4119  
  if (shortName.equals("DynamicObject")) {
4120  
    shortName = (String) get(o, "className");
4121  
    Map<String, Object> fieldValues = (Map) get(o, "fieldValues");
4122  
    
4123  
    for (String _fieldName : fieldValues.keySet()) {
4124  
      fieldName = _fieldName;
4125  
      Object value = fieldValues.get(fieldName);
4126  
      if (value != null) {
4127  
        if (buf.length() != 0) buf.append(", ");
4128  
        buf.append(fieldName + "=" + structure_1(value, stringSizeLimit, seen, refd));
4129  
      }
4130  
      ++numFields;
4131  
   }
4132  
  } else {
4133  
    // regular class
4134  
    
4135  
    Class c = o.getClass();
4136  
    while (c != Object.class) {
4137  
      Field[] fields = c.getDeclaredFields();
4138  
      for (Field field : fields) {
4139  
        if ((field.getModifiers() & Modifier.STATIC) != 0)
4140  
          continue;
4141  
        fieldName = field.getName();
4142  
        
4143  
        // skip outer object reference
4144  
        if (fieldName.indexOf("$") >= 0) continue;
4145  
  
4146  
        Object value;
4147  
        try {
4148  
          field.setAccessible(true);
4149  
          value = field.get(o);
4150  
        } catch (Exception e) {
4151  
          value = "?";
4152  
        }
4153  
        
4154  
        // put special cases here...
4155  
    
4156  
        if (value != null) {
4157  
          if (buf.length() != 0) buf.append(", ");
4158  
          buf.append(fieldName + "=" + structure_1(value, stringSizeLimit, seen, refd));
4159  
        }
4160  
        ++numFields;
4161  
      }
4162  
      c = c.getSuperclass();
4163  
    }
4164  
  }
4165  
  
4166  
  String b = buf.toString();
4167  
  
4168  
  if (numFields == 1 && structure_allowShortening)
4169  
    b = b.replaceAll("^" + fieldName + "=", ""); // drop field name if only one
4170  
  String s = shortName;
4171  
  if (buf.length() != 0)
4172  
    s += "(" + b + ")";
4173  
  return r + s;
4174  
}
4175  
4176  
// drop unused markers
4177  
static String structure_2(String s, HashSet<Integer> refd) {
4178  
  List<String> tok = javaTok(s);
4179  
  StringBuilder out = new StringBuilder();
4180  
  for (int i = 1; i < l(tok); i += 2) {
4181  
    String t = tok.get(i);
4182  
    if (t.startsWith("m") && isInteger(t.substring(1))
4183  
      && !refd.contains(parseInt(t.substring(1))))
4184  
      continue;
4185  
    out.append(t).append(tok.get(i+1));
4186  
  }
4187  
  return str(out);
4188  
}
4189  
4190  
static boolean master() {
4191  
  return webAuthed() || litlist("stefanreich", "bgrgndz", "okhan", "mrshutco").contains(getUserName());
4192  
}
4193  
static int parseInt(String s) {
4194  
  return empty(s) ? 0 : Integer.parseInt(s);
4195  
}
4196  
4197  
static String randomID(int length) {
4198  
  return makeRandomID(length);
4199  
}
4200  
static String makeResponder_callAnswerMethod(Object bot, String s, List<String> history) {
4201  
  String answer = (String) callOpt(bot, "answer", s, history);
4202  
  if (answer == null)
4203  
    answer = (String) callOpt(bot, "answer", s);
4204  
  return answer;
4205  
}
4206  
4207  
static Responder makeResponder(final Object bot) {
4208  
  if (bot instanceof Responder) return (Responder) bot;
4209  
  
4210  
  return new Responder() {
4211  
    String answer(String s, List<String> history) {
4212  
      return makeResponder_callAnswerMethod(bot, s, history);
4213  
    }
4214  
  };
4215  
}
4216  
static Object getOpt(Object o, String field) {
4217  
  if (o instanceof String) o = getBot ((String) o);
4218  
  if (o == null) return null;
4219  
  if (o instanceof Class) return getOpt((Class) o, field);
4220  
  
4221  
  if (o.getClass().getName().equals("main$DynamicObject"))
4222  
    return ((Map) getOpt_raw(o, "fieldValues")).get(field);
4223  
  
4224  
  if (o instanceof Map) return ((Map) o).get(field);
4225  
  
4226  
  return getOpt_raw(o, field);
4227  
}
4228  
4229  
static Object getOpt_raw(Object o, String field) {
4230  
  try {
4231  
    Field f = getOpt_findField(o.getClass(), field);
4232  
    if (f == null) return null;
4233  
    f.setAccessible(true);
4234  
    return f.get(o);
4235  
  } catch (Exception e) {
4236  
    throw new RuntimeException(e);
4237  
  }
4238  
}
4239  
4240  
static Object getOpt(Class c, String field) {
4241  
  try {
4242  
    Field f = getOpt_findStaticField(c, field);
4243  
    if (f == null) return null;
4244  
    f.setAccessible(true);
4245  
    return f.get(null);
4246  
  } catch (Exception e) {
4247  
    throw new RuntimeException(e);
4248  
  }
4249  
}
4250  
4251  
static Field getOpt_findStaticField(Class<?> c, String field) {
4252  
  Class _c = c;
4253  
  do {
4254  
    for (Field f : _c.getDeclaredFields())
4255  
      if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0)
4256  
        return f;
4257  
    _c = _c.getSuperclass();
4258  
  } while (_c != null);
4259  
  return null;
4260  
}
4261  
4262  
static Field getOpt_findField(Class<?> c, String field) {
4263  
  Class _c = c;
4264  
  do {
4265  
    for (Field f : _c.getDeclaredFields())
4266  
      if (f.getName().equals(field))
4267  
        return f;
4268  
    _c = _c.getSuperclass();
4269  
  } while (_c != null);
4270  
  return null;
4271  
}
4272  
4273  
4274  
static Object callFunction(Object f, Object... args) {
4275  
  if (f == null) return null;
4276  
  if (f instanceof Runnable) {
4277  
    ((Runnable) f).run();
4278  
    return null;
4279  
  } else if (f instanceof String)
4280  
    return call(mc(), (String) f, args);
4281  
  else
4282  
    return call(f, "get", args);
4283  
  //else throw fail("Can't call a " + getClassName(f));
4284  
}
4285  
static String shorten(String s, int max) {
4286  
  if (s == null) return "";
4287  
  return s.length() <= max ? s : s.substring(0, Math.min(s.length(), max)) + "...";
4288  
}
4289  
static List<Object> record_list = synchroList();
4290  
4291  
static void record(Object o) {
4292  
  record_list.add(o);
4293  
}
4294  
static Object getBot(String botID) {
4295  
  return callOpt(getMainBot(), "getBot", botID);
4296  
}
4297  
4298  
static String quoteCharacter(char c) {
4299  
  if (c == '\'') return "'\\''";
4300  
  if (c == '\\') return "'\\\\'";
4301  
  return "'" + c + "'";
4302  
}
4303  
4304  
static String loadPage_utf8(String url) {
4305  
  loadPage_charset.set("UTF-8");
4306  
  try {
4307  
    return loadPage(url);
4308  
  } finally {
4309  
    loadPage_charset.set(null);
4310  
  }
4311  
}
4312  
static void printStackTrace(Throwable e) {
4313  
  // we go to system.out now - system.err is nonsense
4314  
  print(getStackTrace(e));
4315  
}
4316  
4317  
static void printStackTrace() {
4318  
  printStackTrace(new Throwable());
4319  
}
4320  
// currently finds only inner classes of class "main"
4321  
// returns null on not found
4322  
// this is the simple version that is not case-tolerant
4323  
static Class findClass(String name) {
4324  
  try {
4325  
    return Class.forName("main$" + name);
4326  
  } catch (ClassNotFoundException e) {
4327  
    return null;
4328  
  }
4329  
}
4330  
static void removeFromMultiPort(long vport) {
4331  
  for (Object port : getMultiPorts())
4332  
    call(port, "removePort", vport);
4333  
}
4334  
static String str(Object o) {
4335  
  return String.valueOf(o);
4336  
}
4337  
static boolean isJavaIdentifier(String s) {
4338  
  if (s.length() == 0 || !Character.isJavaIdentifierStart(s.charAt(0)))
4339  
    return false;
4340  
  for (int i = 1; i < s.length(); i++)
4341  
    if (!Character.isJavaIdentifierPart(s.charAt(i)))
4342  
      return false;
4343  
  return true;
4344  
}
4345  
static Object addToMultiPort_responder;
4346  
4347  
static long addToMultiPort(final String botName) {
4348  
  return addToMultiPort(botName, new Object() {
4349  
    public String answer(String s, List<String> history) {
4350  
      String answer = (String) ( callOpt(getMainClass(), "answer", s, history));
4351  
      if (answer != null) return answer;
4352  
      answer = (String) callOpt(getMainClass(), "answer", s);
4353  
      if (answer != null) return answer;
4354  
      if (match3("get injection id", s))
4355  
        return getInjectionID();
4356  
      return null;
4357  
    }
4358  
  });
4359  
}
4360  
4361  
static long addToMultiPort(final String botName, final Object responder) {
4362  
  print(botName);
4363  
  addToMultiPort_responder = responder;
4364  
  startMultiPort();
4365  
  List ports = getMultiPorts();
4366  
  if (ports == null) return 0;
4367  
  if (ports.isEmpty())
4368  
    throw fail("No multiports!");
4369  
  if (ports.size() > 1)
4370  
    print("Multiple multi-ports. Using last one.");
4371  
  Object port = last(ports);
4372  
  Object responder2 = new Object() {
4373  
    public String answer(String s, List<String> history) {
4374  
      if (match3("get injection id", s))
4375  
        return getInjectionID();
4376  
      if (match3("your name", s))
4377  
        return botName;
4378  
      return (String) call(responder, "answer", s, history);
4379  
    }
4380  
  };
4381  
  record(responder2);
4382  
  return (Long) call(port, "addResponder", botName, responder2);
4383  
}
4384  
4385  
static String programID;
4386  
4387  
static String getProgramID() {
4388  
  return nempty(programID) ? formatSnippetID(programID) : "?";
4389  
}
4390  
4391  
// TODO: ask JavaX instead
4392  
static String getProgramID(Class c) {
4393  
  String id = (String) getOpt(c, "programID");
4394  
  if (nempty(id))
4395  
    return formatSnippetID(id);
4396  
  return "?";
4397  
}
4398  
4399  
static String getProgramID(Object o) {
4400  
  return getProgramID(getMainClass(o));
4401  
}
4402  
4403  
  static String unnull(String s) {
4404  
    return s == null ? "" : s;
4405  
  }
4406  
  
4407  
  static <A> List<A> unnull(List<A> l) {
4408  
    return l == null ? emptyList() : l;
4409  
  }
4410  
  
4411  
  static Object[] unnull(Object[] a) {
4412  
    return a == null ? new Object[0] : a;
4413  
  }
4414  
// replacement for class JavaTok
4415  
// maybe incomplete, might want to add floating point numbers
4416  
// todo also: extended multi-line strings
4417  
4418  
static List<String> javaTok(String s) {
4419  
  List<String> tok = new ArrayList<String>();
4420  
  int l = s.length();
4421  
  
4422  
  int i = 0;
4423  
  while (i < l) {
4424  
    int j = i;
4425  
    char c; String cc;
4426  
    
4427  
    // scan for whitespace
4428  
    while (j < l) {
4429  
      c = s.charAt(j);
4430  
      cc = s.substring(j, Math.min(j+2, l));
4431  
      if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
4432  
        ++j;
4433  
      else if (cc.equals("/*")) {
4434  
        do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/"));
4435  
        j = Math.min(j+2, l);
4436  
      } else if (cc.equals("//")) {
4437  
        do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0);
4438  
      } else
4439  
        break;
4440  
    }
4441  
    
4442  
    tok.add(s.substring(i, j));
4443  
    i = j;
4444  
    if (i >= l) break;
4445  
    c = s.charAt(i); // cc is not needed in rest of loop body
4446  
    cc = s.substring(i, Math.min(i+2, l));
4447  
4448  
    // scan for non-whitespace
4449  
    if (c == '\'' || c == '"') {
4450  
      char opener = c;
4451  
      ++j;
4452  
      while (j < l) {
4453  
        if (s.charAt(j) == opener || s.charAt(j) == '\n') { // end at \n to not propagate unclosed string literal errors
4454  
          ++j;
4455  
          break;
4456  
        } else if (s.charAt(j) == '\\' && j+1 < l)
4457  
          j += 2;
4458  
        else
4459  
          ++j;
4460  
      }
4461  
    } else if (Character.isJavaIdentifierStart(c))
4462  
      do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || "'".indexOf(s.charAt(j)) >= 0)); // for stuff like "don't"
4463  
    else if (Character.isDigit(c)) {
4464  
      do ++j; while (j < l && Character.isDigit(s.charAt(j)));
4465  
      if (j < l && s.charAt(j) == 'L') ++j; // Long constants like 1L
4466  
    } else if (cc.equals("[[")) {
4467  
      do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]"));
4468  
      j = Math.min(j+2, l);
4469  
    } else if (cc.equals("[=") && i+2 < l && s.charAt(i+2) == '[') {
4470  
      do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]"));
4471  
      j = Math.min(j+3, l);
4472  
    } else
4473  
      ++j;
4474  
4475  
    tok.add(s.substring(i, j));
4476  
    i = j;
4477  
  }
4478  
  
4479  
  if ((tok.size() % 2) == 0) tok.add("");
4480  
  return tok;
4481  
}
4482  
4483  
static List<String> javaTok(List<String> tok) {
4484  
  return javaTok(join(tok));
4485  
}
4486  
  static List<String> parse3(String s) {
4487  
    return dropPunctuation(javaTokPlusPeriod(s));
4488  
  }
4489  
static Object newObject(Class c, Object... args) {
4490  
  return nuObject(c, args);
4491  
}
4492  
4493  
static Object newObject(String className, Object... args) {
4494  
  return nuObject(className, args);
4495  
}
4496  
4497  
static boolean isLongConstant(String s) {
4498  
  if (!s.endsWith("L")) return false;
4499  
  s = s.substring(0, l(s)-1);
4500  
  return isInteger(s);
4501  
}
4502  
static Class __javax;
4503  
4504  
static Class getJavaX() {
4505  
  return __javax;
4506  
}
4507  
static <A> List<A> subList(List<A> l, int startIndex) {
4508  
  return subList(l, startIndex, l(l));
4509  
}
4510  
4511  
static <A> List<A> subList(List<A> l, int startIndex, int endIndex) {
4512  
  startIndex = max(0, min(l(l), startIndex));
4513  
  endIndex = max(0, min(l(l), endIndex));
4514  
  if (startIndex > endIndex) return litlist();
4515  
  return l.subList(startIndex, endIndex);
4516  
}
4517  
static Throwable getInnerException(Throwable e) {
4518  
  while (e.getCause() != null)
4519  
    e = e.getCause();
4520  
  return e;
4521  
}
4522  
static boolean isTrue(Object o) {
4523  
  return booleanValue(o);
4524  
}
4525  
static long parseLong(String s) {
4526  
  if (s == null) return 0;
4527  
  return Long.parseLong(dropSuffix("L", s));
4528  
}
4529  
4530  
static long parseLong(Object s) {
4531  
  return Long.parseLong((String) s);
4532  
}
4533  
static boolean isIdentifier(String s) {
4534  
  return isJavaIdentifier(s);
4535  
}
4536  
// match2 matches multiple "*" (matches a single token) wildcards and zero or one "..." wildcards (matches multiple tokens)
4537  
4538  
static String[] match2(List<String> pat, List<String> tok) {
4539  
  // standard case (no ...)
4540  
  int i = pat.indexOf("...");
4541  
  if (i < 0) return match2_match(pat, tok);
4542  
  
4543  
  pat = new ArrayList<String>(pat); // We're modifying it, so copy first
4544  
  pat.set(i, "*");
4545  
  while (pat.size() < tok.size()) {
4546  
    pat.add(i, "*");
4547  
    pat.add(i+1, ""); // doesn't matter
4548  
  }
4549  
  
4550  
  return match2_match(pat, tok);
4551  
}
4552  
4553  
static String[] match2_match(List<String> pat, List<String> tok) {
4554  
  List<String> result = new ArrayList<String>();
4555  
  if (pat.size() != tok.size()) {
4556  
    /*if (debug)
4557  
      print("Size mismatch: " + structure(pat) + " vs " + structure(tok));*/
4558  
    return null;
4559  
  }
4560  
  for (int i = 1; i < pat.size(); i += 2) {
4561  
    String p = pat.get(i), t = tok.get(i);
4562  
    /*if (debug)
4563  
      print("Checking " + p + " against " + t);*/
4564  
    if (eq(p, "*"))
4565  
      result.add(t);
4566  
    else if (!equalsIgnoreCase(unquote(p), unquote(t))) // bold change - match quoted and unquoted now
4567  
      return null;
4568  
  }
4569  
  return result.toArray(new String[result.size()]);
4570  
}
4571  
4572  
static void hotwire_copyOver(Class c) {
4573  
  synchronized(StringBuffer.class) {
4574  
    for (String field : litlist("print_log", "print_silent")) {
4575  
      Object o = get(mc(), field);
4576  
      if (o != null)
4577  
        setOpt(c, field, o);
4578  
    }
4579  
      
4580  
    Object mainBot = getMainBot();
4581  
    if (mainBot != null)
4582  
      setOpt(c, "mainBot", mainBot);
4583  
4584  
    setOpt(c, "creator_class", new WeakReference(mc()));
4585  
  }
4586  
}
4587  
static Class<?> _getClass(String name) {
4588  
  try {
4589  
    return Class.forName(name);
4590  
  } catch (ClassNotFoundException e) {
4591  
    return null;
4592  
  }
4593  
}
4594  
4595  
static Class _getClass(Object o) {
4596  
  return o instanceof Class ? (Class) o : o.getClass();
4597  
}
4598  
4599  
static Class _getClass(Object realm, String name) { try {
4600  
 
4601  
  return getClass(realm).getClassLoader().loadClass(classNameToVM(name));
4602  
4603  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4604  
static boolean publicCommOn() {
4605  
  return "1".equals(loadTextFile(new File(userHome(), ".javax/public-communication")));
4606  
}
4607  
static String getUserName() {
4608  
  return (String) callOpt(getMainBot(), "getUserName");
4609  
}
4610  
static boolean isNonNegativeInteger(String s) {
4611  
  return s != null && Pattern.matches("\\d+", s);
4612  
}
4613  
static boolean hasMethod(Object o, String method, Object... args) {
4614  
  return findMethod(o, method, args) != null;
4615  
}
4616  
static Object nuObject(String className, Object... args) { try {
4617  
 
4618  
  return nuObject(Class.forName(className), args);
4619  
4620  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4621  
4622  
static Object nuObject(Object realm, String className, Object... args) {
4623  
  return nuObject(_getClass(realm, className), args);
4624  
}
4625  
4626  
static <A> A nuObject(Class<A> c, Object... args) { try {
4627  
 
4628  
  Constructor m = nuObject_findConstructor(c, args);
4629  
  m.setAccessible(true);
4630  
  return (A) m.newInstance(args);
4631  
4632  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4633  
4634  
static Constructor nuObject_findConstructor(Class c, Object... args) {
4635  
  for (Constructor m : c.getDeclaredConstructors()) {
4636  
    if (!nuObject_checkArgs(m.getParameterTypes(), args, false))
4637  
      continue;
4638  
    return m;
4639  
  }
4640  
  throw new RuntimeException("Constructor with " + args.length + " matching parameter(s) not found in " + c.getName());
4641  
}
4642  
4643  
 static boolean nuObject_checkArgs(Class[] types, Object[] args, boolean debug) {
4644  
    if (types.length != args.length) {
4645  
      if (debug)
4646  
        System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
4647  
      return false;
4648  
    }
4649  
    for (int i = 0; i < types.length; i++)
4650  
      if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
4651  
        if (debug)
4652  
          System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
4653  
        return false;
4654  
      }
4655  
    return true;
4656  
  }
4657  
// This is made for NL parsing.
4658  
// It's javaTok extended with "..." token, "$n" and "#n" and
4659  
// special quotes (which are converted to normal ones).
4660  
4661  
static List<String> javaTokPlusPeriod(String s) {
4662  
  List<String> tok = new ArrayList<String>();
4663  
  int l = s.length();
4664  
  
4665  
  int i = 0;
4666  
  while (i < l) {
4667  
    int j = i;
4668  
    char c; String cc;
4669  
    
4670  
    // scan for whitespace
4671  
    while (j < l) {
4672  
      c = s.charAt(j);
4673  
      cc = s.substring(j, Math.min(j+2, l));
4674  
      if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
4675  
        ++j;
4676  
      else if (cc.equals("/*")) {
4677  
        do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/"));
4678  
        j = Math.min(j+2, l);
4679  
      } else if (cc.equals("//")) {
4680  
        do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0);
4681  
      } else
4682  
        break;
4683  
    }
4684  
    
4685  
    tok.add(s.substring(i, j));
4686  
    i = j;
4687  
    if (i >= l) break;
4688  
    c = s.charAt(i);
4689  
    cc = s.substring(i, Math.min(i+2, l));
4690  
4691  
    // scan for non-whitespace
4692  
    if (c == '\u201C' || c == '\u201D') c = '"'; // normalize quotes
4693  
    if (c == '\'' || c == '"') {
4694  
      char opener = c;
4695  
      ++j;
4696  
      while (j < l) {
4697  
        char _c = s.charAt(j);
4698  
        if (_c == '\u201C' || _c == '\u201D') _c = '"'; // normalize quotes
4699  
        if (_c == opener) {
4700  
          ++j;
4701  
          break;
4702  
        } else if (s.charAt(j) == '\\' && j+1 < l)
4703  
          j += 2;
4704  
        else
4705  
          ++j;
4706  
      }
4707  
      if (j-1 >= i+1) {
4708  
        tok.add(opener + s.substring(i+1, j-1) + opener);
4709  
        i = j;
4710  
        continue;
4711  
      }
4712  
    } else if (Character.isJavaIdentifierStart(c))
4713  
      do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || s.charAt(j) == '\'')); // for things like "this one's"
4714  
    else if (Character.isDigit(c))
4715  
      do ++j; while (j < l && Character.isDigit(s.charAt(j)));
4716  
    else if (cc.equals("[[")) {
4717  
      do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]"));
4718  
      j = Math.min(j+2, l);
4719  
    } else if (cc.equals("[=") && i+2 < l && s.charAt(i+2) == '[') {
4720  
      do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]"));
4721  
      j = Math.min(j+3, l);
4722  
    } else if (s.substring(j, Math.min(j+3, l)).equals("..."))
4723  
      j += 3;
4724  
    else if (c == '$' || c == '#')
4725  
      do ++j; while (j < l && Character.isDigit(s.charAt(j)));
4726  
    else
4727  
      ++j;
4728  
4729  
    tok.add(s.substring(i, j));
4730  
    i = j;
4731  
  }
4732  
  
4733  
  if ((tok.size() % 2) == 0) tok.add("");
4734  
  return tok;
4735  
}
4736  
4737  
static void sleepSeconds(long s) {
4738  
  if (s > 0) sleep(s*1000);
4739  
}
4740  
  static Object callOpt(Object o, String method, Object... args) {
4741  
    try {
4742  
      if (o == null) return null;
4743  
      if (o instanceof Class) {
4744  
        Method m = callOpt_findStaticMethod((Class) o, method, args, false);
4745  
        if (m == null) return null;
4746  
        m.setAccessible(true);
4747  
        return m.invoke(null, args);
4748  
      } else {
4749  
        Method m = callOpt_findMethod(o, method, args, false);
4750  
        if (m == null) return null;
4751  
        m.setAccessible(true);
4752  
        return m.invoke(o, args);
4753  
      }
4754  
    } catch (Exception e) {
4755  
      throw new RuntimeException(e);
4756  
    }
4757  
  }
4758  
4759  
  static Method callOpt_findStaticMethod(Class c, String method, Object[] args, boolean debug) {
4760  
    Class _c = c;
4761  
    while (c != null) {
4762  
      for (Method m : c.getDeclaredMethods()) {
4763  
        if (debug)
4764  
          System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
4765  
        if (!m.getName().equals(method)) {
4766  
          if (debug) System.out.println("Method name mismatch: " + method);
4767  
          continue;
4768  
        }
4769  
4770  
        if ((m.getModifiers() & Modifier.STATIC) == 0 || !callOpt_checkArgs(m, args, debug))
4771  
          continue;
4772  
4773  
        return m;
4774  
      }
4775  
      c = c.getSuperclass();
4776  
    }
4777  
    return null;
4778  
  }
4779  
4780  
  static Method callOpt_findMethod(Object o, String method, Object[] args, boolean debug) {
4781  
    Class c = o.getClass();
4782  
    while (c != null) {
4783  
      for (Method m : c.getDeclaredMethods()) {
4784  
        if (debug)
4785  
          System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
4786  
        if (m.getName().equals(method) && callOpt_checkArgs(m, args, debug))
4787  
          return m;
4788  
      }
4789  
      c = c.getSuperclass();
4790  
    }
4791  
    return null;
4792  
  }
4793  
4794  
  private static boolean callOpt_checkArgs(Method m, Object[] args, boolean debug) {
4795  
    Class<?>[] types = m.getParameterTypes();
4796  
    if (types.length != args.length) {
4797  
      if (debug)
4798  
        System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
4799  
      return false;
4800  
    }
4801  
    for (int i = 0; i < types.length; i++)
4802  
      if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
4803  
        if (debug)
4804  
          System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
4805  
        return false;
4806  
      }
4807  
    return true;
4808  
  }
4809  
4810  
4811  
static double parseDouble(String s) {
4812  
  return Double.parseDouble(s);
4813  
}
4814  
  static AtomicInteger dialogServer_clients = new AtomicInteger();
4815  
  static boolean dialogServer_printConnects;
4816  
  
4817  
  static Set<String> dialogServer_knownClients = synchroTreeSet();
4818  
  
4819  
  static int startDialogServerOnPortAbove(int port, DialogHandler handler) {
4820  
    while (!startDialogServerIfPortAvailable(port, handler))
4821  
      ++port;
4822  
    return port;
4823  
  }
4824  
  
4825  
  static int startDialogServerOnPortAboveDaemon(int port, DialogHandler handler) {
4826  
    while (!startDialogServerIfPortAvailable(port, handler, true))
4827  
      ++port;
4828  
    return port;
4829  
  }
4830  
  
4831  
  static void startDialogServer(int port, DialogHandler handler) {
4832  
    if (!startDialogServerIfPortAvailable(port, handler))
4833  
      throw fail("Can't start dialog server on port " + port);
4834  
  }
4835  
  
4836  
  static boolean startDialogServerIfPortAvailable(int port, final DialogHandler handler) {
4837  
    return startDialogServerIfPortAvailable(port, handler, false);
4838  
  }
4839  
  
4840  
  static ServerSocket startDialogServer_serverSocket;
4841  
    
4842  
  static boolean startDialogServerIfPortAvailable(int port, final DialogHandler handler, boolean daemon) {
4843  
    ServerSocket serverSocket = null;
4844  
    try {
4845  
      serverSocket = new ServerSocket(port);
4846  
    } catch (IOException e) {
4847  
      // probably the port number is used - let's assume there already is a chat server.
4848  
      return false;
4849  
    }
4850  
    final ServerSocket _serverSocket = serverSocket;
4851  
    startDialogServer_serverSocket = serverSocket;
4852  
4853  
    Thread thread = new Thread("Socket accept port " + port) { public void run() {
4854  
     try {
4855  
      while (true) {
4856  
        try {
4857  
          final Socket s = _serverSocket.accept();
4858  
          
4859  
          String client = s.getInetAddress().toString();
4860  
          if (!dialogServer_knownClients.contains(client) && neq(client, "/127.0.0.1")) {
4861  
            print("connect from " + client + " - clients: " + dialogServer_clients.incrementAndGet());
4862  
            dialogServer_knownClients.add(client);
4863  
          }
4864  
          
4865  
          String threadName = "Handling client " + s.getInetAddress();
4866  
4867  
          Thread t2 = new Thread(threadName) {
4868  
           public void run() {
4869  
            try {
4870  
              final Writer w = new OutputStreamWriter(s.getOutputStream(), "UTF-8");
4871  
              final BufferedReader in = new BufferedReader(
4872  
                new InputStreamReader(s.getInputStream(), "UTF-8"));
4873  
                
4874  
              DialogIO io = new DialogIO() {
4875  
              
4876  
                // This should be the same as #1001076 (talkTo)
4877  
              
4878  
    boolean isLocalConnection() {
4879  
      return s.getInetAddress().isLoopbackAddress();
4880  
    }
4881  
    
4882  
    boolean isStillConnected() {
4883  
      return !(eos || s.isClosed());
4884  
    }
4885  
    
4886  
    void sendLine(String line) { try {
4887  
 
4888  
      w.write(line + "\n");
4889  
      w.flush();
4890  
    
4891  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4892  
    
4893  
    String readLineImpl() { try {
4894  
 
4895  
      return in.readLine();
4896  
    
4897  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4898  
    
4899  
    void close() {
4900  
      try {
4901  
        s.close();
4902  
      } catch (IOException e) {
4903  
        // whatever
4904  
      }
4905  
    }
4906  
    
4907  
    Socket getSocket() {
4908  
      return s;
4909  
    }
4910  
    };
4911  
              
4912  
              try {
4913  
                handler.run(io);
4914  
              } finally {
4915  
                s.close();
4916  
              }
4917  
            } catch (IOException e) {
4918  
              print("[internal] " + e);
4919  
            } finally {
4920  
              //print("client disconnect - " + dialogServer_clients.decrementAndGet() + " remaining");
4921  
            }
4922  
           }
4923  
          }; // Thread t2
4924  
          t2.setDaemon(true); // ?
4925  
          t2.start();
4926  
        } catch (SocketTimeoutException e) {
4927  
        }
4928  
      }   
4929  
     } catch (IOException e) {
4930  
       print("[internal] " + e);
4931  
     }
4932  
    }};
4933  
    if (daemon) thread.setDaemon(true);
4934  
    thread.start();
4935  
   
4936  
    print("Dialog server on port " + port + " started."); 
4937  
    return true;
4938  
  }
4939  
static boolean webAuthed() {
4940  
  return eq(Boolean.TRUE, callOpt(getBot("#1002590"), "currentHttpRequestAuthorized"));
4941  
}
4942  
static boolean isEmpty(Collection c) {
4943  
  return c == null || c.isEmpty();
4944  
}
4945  
4946  
static boolean isEmpty(CharSequence s) {
4947  
  return s == null || s.length() == 0;
4948  
}
4949  
4950  
static boolean isEmpty(Object[] a) {
4951  
  return a == null || a.length == 0;
4952  
}
4953  
4954  
static boolean isEmpty(Map map) {
4955  
  return map == null || map.isEmpty();
4956  
}
4957  
static boolean nempty(Collection c) {
4958  
  return !isEmpty(c);
4959  
}
4960  
4961  
static boolean nempty(CharSequence s) {
4962  
  return !isEmpty(s);
4963  
}
4964  
4965  
static boolean nempty(Object[] o) {
4966  
  return !isEmpty(o);
4967  
}
4968  
4969  
static String callStaticAnswerMethod(List<Class> bots, String s) {
4970  
  for (Class c : bots) try {
4971  
    String answer = callStaticAnswerMethod(c, s);
4972  
    if (!empty(answer)) return answer;
4973  
  } catch (Throwable e) {
4974  
    print("Error calling " + getProgramID(c));
4975  
    e.printStackTrace();
4976  
  }
4977  
  return null;
4978  
}
4979  
4980  
static String callStaticAnswerMethod(Class c, String s) {
4981  
  String answer = (String) callOpt(c, "answer", s, litlist(s));
4982  
  if (answer == null)
4983  
    answer = (String) callOpt(c, "answer", s);
4984  
  return emptyToNull(answer);
4985  
}
4986  
4987  
static String callStaticAnswerMethod(String s, List<String> history) {
4988  
  String answer = (String) callOpt(getMainClass(), "answer", s, history);
4989  
  if (answer == null)
4990  
    answer = (String) callOpt(getMainClass(), "answer", s);
4991  
  return emptyToNull(answer);
4992  
}
4993  
static char unquoteCharacter(String s) {
4994  
  assertTrue(s.startsWith("'") && s.length() > 1);
4995  
  return unquote("\"" + s.substring(1, s.endsWith("'") ? s.length()-1 : s.length()) + "\"").charAt(0);
4996  
}
4997  
4998  
4999  
static boolean equalsIgnoreCase(String a, String b) {
5000  
  return a == null ? b == null : a.equalsIgnoreCase(b);
5001  
}
5002  
static <A> Set<A> synchroTreeSet() {
5003  
  return Collections.synchronizedSet(new TreeSet<A>());
5004  
}
5005  
5006  
static Object mainBot;
5007  
5008  
static Object getMainBot() {
5009  
  return mainBot;
5010  
}
5011  
static int min(int a, int b) {
5012  
  return Math.min(a, b);
5013  
}
5014  
5015  
static double min(double[] c) {
5016  
  double x = Double.MAX_VALUE;
5017  
  for (double d : c) x = Math.min(x, d);
5018  
  return x;
5019  
}
5020  
5021  
static byte min(byte[] c) {
5022  
  byte x = 127;
5023  
  for (byte d : c) if (d < x) x = d;
5024  
  return x;
5025  
}
5026  
static void assertTrue(Object o) {
5027  
  assertEquals(true, o);
5028  
}
5029  
  
5030  
static boolean assertTrue(String msg, boolean b) {
5031  
  if (!b)
5032  
    throw fail(msg);
5033  
  return b;
5034  
}
5035  
5036  
static boolean assertTrue(boolean b) {
5037  
  if (!b)
5038  
    throw fail("oops");
5039  
  return b;
5040  
}
5041  
static int max(int a, int b) {
5042  
  return Math.max(a, b);
5043  
}
5044  
5045  
static long max(int a, long b) {
5046  
  return Math.max((long) a, b);
5047  
}
5048  
5049  
static long max(long a, long b) {
5050  
  return Math.max(a, b);
5051  
}
5052  
5053  
static double max(int a, double b) {
5054  
  return Math.max((double) a, b);
5055  
}
5056  
5057  
static int max(Collection<Integer> c) {
5058  
  int x = Integer.MIN_VALUE;
5059  
  for (int i : c) x = max(x, i);
5060  
  return x;
5061  
}
5062  
5063  
static double max(double[] c) {
5064  
  if (c.length == 0) return Double.MIN_VALUE;
5065  
  double x = c[0];
5066  
  for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]);
5067  
  return x;
5068  
}
5069  
5070  
static byte max(byte[] c) {
5071  
  byte x = -128;
5072  
  for (byte d : c) if (d > x) x = d;
5073  
  return x;
5074  
}
5075  
static Class<?> getClass(String name) {
5076  
  try {
5077  
    return Class.forName(name);
5078  
  } catch (ClassNotFoundException e) {
5079  
    return null;
5080  
  }
5081  
}
5082  
5083  
static Class getClass(Object o) {
5084  
  return o instanceof Class ? (Class) o : o.getClass();
5085  
}
5086  
5087  
static Class getClass(Object realm, String name) { try {
5088  
 
5089  
  return getClass(realm).getClassLoader().loadClass(classNameToVM(name));
5090  
5091  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
5092  
static Class mc() {
5093  
  return getMainClass();
5094  
}
5095  
static boolean neq(Object a, Object b) {
5096  
  return !eq(a, b);
5097  
}
5098  
static <A> A last(List<A> l) {
5099  
  return l.isEmpty() ? null : l.get(l.size()-1);
5100  
}
5101  
static String classNameToVM(String name) {
5102  
  return name.replace(".", "$");
5103  
}
5104  
static String emptyToNull(String s) {
5105  
  return eq(s, "") ? null : s;
5106  
}
5107  
static boolean booleanValue(Object o) {
5108  
  return eq(true, o);
5109  
}
5110  
  static Method findMethod(Object o, String method, Object... args) {
5111  
    try {
5112  
      if (o == null) return null;
5113  
      if (o instanceof Class) {
5114  
        Method m = findMethod_static((Class) o, method, args, false);
5115  
        if (m == null) return null;
5116  
        m.setAccessible(true);
5117  
        return m;
5118  
      } else {
5119  
        Method m = findMethod_instance(o, method, args, false);
5120  
        if (m == null) return null;
5121  
        m.setAccessible(true);
5122  
        return m;
5123  
      }
5124  
    } catch (Exception e) {
5125  
      throw new RuntimeException(e);
5126  
    }
5127  
  }
5128  
5129  
  static Method findMethod_static(Class c, String method, Object[] args, boolean debug) {
5130  
    Class _c = c;
5131  
    while (c != null) {
5132  
      for (Method m : c.getDeclaredMethods()) {
5133  
        if (debug)
5134  
          System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
5135  
        if (!m.getName().equals(method)) {
5136  
          if (debug) System.out.println("Method name mismatch: " + method);
5137  
          continue;
5138  
        }
5139  
5140  
        if ((m.getModifiers() & Modifier.STATIC) == 0 || !findMethod_checkArgs(m, args, debug))
5141  
          continue;
5142  
5143  
        return m;
5144  
      }
5145  
      c = c.getSuperclass();
5146  
    }
5147  
    return null;
5148  
  }
5149  
5150  
  static Method findMethod_instance(Object o, String method, Object[] args, boolean debug) {
5151  
    Class c = o.getClass();
5152  
    while (c != null) {
5153  
      for (Method m : c.getDeclaredMethods()) {
5154  
        if (debug)
5155  
          System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
5156  
        if (m.getName().equals(method) && findMethod_checkArgs(m, args, debug))
5157  
          return m;
5158  
      }
5159  
      c = c.getSuperclass();
5160  
    }
5161  
    return null;
5162  
  }
5163  
5164  
  static boolean findMethod_checkArgs(Method m, Object[] args, boolean debug) {
5165  
    Class<?>[] types = m.getParameterTypes();
5166  
    if (types.length != args.length) {
5167  
      if (debug)
5168  
        System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
5169  
      return false;
5170  
    }
5171  
    for (int i = 0; i < types.length; i++)
5172  
      if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
5173  
        if (debug)
5174  
          System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
5175  
        return false;
5176  
      }
5177  
    return true;
5178  
  }
5179  
5180  
5181  
static <A> List<A> synchroList() {
5182  
  return Collections.synchronizedList(new ArrayList<A>());
5183  
}
5184  
5185  
static <A> List<A> synchroList(List<A> l) {
5186  
  return Collections.synchronizedList(l);
5187  
}
5188  
5189  
static List<String> dropPunctuation_keep = litlist("*", "<", ">");
5190  
5191  
static List<String> dropPunctuation(List<String> tok) {
5192  
  tok = new ArrayList<String>(tok);
5193  
  for (int i = 1; i < tok.size(); i += 2) {
5194  
    String t = tok.get(i);
5195  
    if (t.length() == 1 && !Character.isLetter(t.charAt(0)) && !Character.isDigit(t.charAt(0)) && !dropPunctuation_keep.contains(t)) {
5196  
      tok.set(i-1, tok.get(i-1) + tok.get(i+1));
5197  
      tok.remove(i);
5198  
      tok.remove(i);
5199  
      i -= 2;
5200  
    }
5201  
  }
5202  
  return tok;
5203  
}
5204  
5205  
static String dropPunctuation(String s) {
5206  
  return join(dropPunctuation(nlTok(s)));
5207  
}
5208  
static String dropSuffix(String suffix, String s) {
5209  
  return s.endsWith(suffix) ? s.substring(0, l(s)-l(suffix)) : s;
5210  
}
5211  
// start multi-port if none exists in current VM.
5212  
static void startMultiPort() {
5213  
  List mp = getMultiPorts();
5214  
  if (mp != null && mp.isEmpty())
5215  
    callMain(hotwire("#1001672"));
5216  
}
5217  
5218  
5219  
static <A> A assertEquals(Object x, A y) {
5220  
  return assertEquals(null, x, y);
5221  
}
5222  
5223  
static <A> A assertEquals(String msg, Object x, A y) {
5224  
  if (!(x == null ? y == null : x.equals(y)))
5225  
    throw fail((msg != null ? msg + ": " : "") + structure(x) + " != " + structure(y));
5226  
  return y;
5227  
}
5228  
static List<String> nlTok(String s) {
5229  
  return javaTokPlusPeriod(s);
5230  
}
5231  
5232  
5233  
static boolean match(String pat, String s) {
5234  
  return match3(pat, s);
5235  
}
5236  
5237  
static boolean match(String pat, String s, Matches matches) {
5238  
  return match3(pat, s, matches);
5239  
}
5240  
5241  
5242  
}

Author comment

Began life as a copy of #676

download  show line numbers  debug dex  old transpilations   

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

No comments. add comment

Snippet ID: #1004183
Snippet name: Boot-up code for JavaX/Android (backup)
Eternal ID of this version: #1004183/1
Text MD5: 7e155dc63ddc2af4ddb3a53ab64434ee
Author: stefan
Category: javax
Type: JavaX source code (Android)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2016-08-09 15:27:07
Source code size: 167488 bytes / 5242 lines
Pitched / IR pitched: No / No
Views / Downloads: 511 / 453
Referenced in: [show references]