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

5160
LINES

< > BotCompany Repo | #1007390 // x30 for Android (backup before multiport)

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

Author comment

Began life as a copy of #1004182

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: #1007390
Snippet name: x30 for Android (backup before multiport)
Eternal ID of this version: #1007390/1
Text MD5: 910bdce1b6093dded261f02f06aac8d3
Author: stefan
Category: javax / android
Type: JavaX source code (Android)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2017-03-21 11:49:34
Source code size: 165766 bytes / 5160 lines
Pitched / IR pitched: No / No
Views / Downloads: 507 / 457
Referenced in: [show references]