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

5529
LINES

< > BotCompany Repo | #1004053 // Bug

Document

1  
import javax.swing.event.AncestorListener;
2  
import javax.swing.event.AncestorEvent;
3  
import javax.swing.Timer;
4  
public class main {
5  
static class GenTesting {
6  
  Object makeGenerators; // voidfunc(L<Gen> gens, L<S> log)
7  
  
8  
  // method to compare generator output & user line
9  
  String comparison = "eqic";
10  
  
11  
  GenTesting(Object makeGenerators) {
12  
  this.makeGenerators = makeGenerators;}
13  
14  
  MultiSet<String> scoreGenerators(List<String> log) {
15  
    return scoreGenerators(log, null);
16  
  }
17  
  
18  
  MultiSet<String> scoreGenerators(List<String> log, BitSet interestingLines) {
19  
    new MultiSet<String> scores;
20  
    for (int i = 0; i < l(log); i++)
21  
      if (interestingLines == null || interestingLines.get(i))
22  
        scoreGenerators1(subList(log, 0, i+1), scores);
23  
    print(/*asciiHeading2("SCORES")*/);
24  
    for (String name : scores.getTopTen())
25  
      print("  [" + scores.get(name) + "] " + name);
26  
    print();
27  
    return scores;
28  
  }
29  
    
30  
  void scoreGenerators1(List<String> log, MultiSet<String> scores) {
31  
    if (empty(log)) return;
32  
    String line = last(log);
33  
    log = dropLast(log);
34  
    
35  
    genLog_set(log);
36  
    try {
37  
      List<Gen> gens = makeGenerators(log);
38  
      
39  
      for (Gen gen : gens) {
40  
        try {
41  
          if (compare(callGen(gen), line))
42  
            scores.add(gen.name);
43  
        } catch (Throwable _e) {}
44  
      }
45  
    } finally {
46  
      genLog_clear();
47  
    }
48  
  }
49  
  
50  
  String callSingle(List<String> log, Object genName) {
51  
    genLog_set(log);
52  
    try {
53  
      List<Gen> gens = makeGenerators(log);
54  
      Gen gen = findByField(gens, "name", genName);
55  
      if (gen == null) return null;
56  
      return callGen(gen);
57  
    } finally {
58  
      genLog_clear();
59  
    }
60  
  }
61  
  
62  
  boolean verifySingle(List<String> log, Object genName) {
63  
    if (empty(log)) return false;
64  
    String line = last(log);
65  
    log = dropLast(log);
66  
    
67  
    genLog_set(log);
68  
    try {
69  
      List<Gen> gens = makeGenerators(log);
70  
      Gen gen = findByField(gens, "name", genName);
71  
      if (gen == null) return false;
72  
      
73  
      try {
74  
        if (compare(callGen(gen), line)) return true;
75  
      } catch (Throwable _e) {} return false;
76  
    } finally {
77  
      genLog_clear();
78  
    }
79  
  }
80  
  
81  
  List<Gen> makeGenerators(List<String> log) {
82  
    new List<Gen> gens;
83  
    callF(makeGenerators, gens, log);
84  
    return gens;
85  
  }
86  
  
87  
  // returns score
88  
  int scoreGenerator(List<String> log, String genName) {
89  
    int score = 0;
90  
    for (int i = 1; i < l(log); i++) {
91  
      String expect = log.get(i), s = null;
92  
      boolean ok = false;
93  
      try {
94  
        s = callSingle(subList(log, 0, i), genName);
95  
        ok = compare(s, expect);
96  
      } catch (Throwable e) {
97  
        s = exceptionToStringShort(e);
98  
      }
99  
      if (ok) {
100  
        ++score;
101  
        print(genName + " OK: " + s + (eq(s, expect) ? "" : " / " + expect));
102  
      } else
103  
        print(genName + " NO [" + s + "]: " + expect);
104  
    }
105  
    print();
106  
    return score;
107  
  }
108  
  
109  
  boolean compare(String a, String b) {
110  
    if (eq(comparison, "eq"))
111  
      return eq(a, b);
112  
    else if (eq(comparison, "eqic"))
113  
      return eqic(a, b);
114  
    else if (eq(comparison, "match"))
115  
      return match(a, b);
116  
    else
117  
      throw fail("Unknown comparison: " + comparison);
118  
  }
119  
  
120  
  // run a single generator on all lines and print each line
121  
  void debugSingle(List<String> log, String name) {
122  
    for (int i = 0; i < l(log); i++)
123  
      debugSingle1(subList(log, 0, i+1), name);
124  
  }
125  
  
126  
  void debugSingle1(List<String> log, String genName) {
127  
    String line = last(log);
128  
    log = dropLast(log);
129  
    
130  
    genLog_set(log);
131  
    try {
132  
      List<Gen> gens = makeGenerators(log);
133  
      Gen gen = findByField(gens, "name", genName);
134  
      if (gen == null) return;
135  
      
136  
      boolean ok = false;
137  
      try {
138  
        ok = compare(callGen(gen), line);
139  
      } catch (Throwable _e) {}
140  
      
141  
      print((ok ? "OK" : "NO") + " " + line);
142  
    } finally {
143  
      genLog_clear();
144  
    }
145  
  }
146  
} // GenTesting
147  
148  
static class Thinker {
149  
  List<String> ranking = synchroList();
150  
  int listMakingTimeout = 2000;
151  
  int maxListLength = 100;
152  
  boolean showExceptions, debug;
153  
  volatile int load;
154  
  
155  
  void startUp(List<String> log) {
156  
    readLocally2(this, "ranking");
157  
    print("Ranking: " + structure(ranking));
158  
  }
159  
  
160  
  MultiSet<String> scores(List<String> log) {
161  
    return makeGT().scoreGenerators(log);
162  
  }
163  
  
164  
  MultiSet<String> scores(List<String> log, BitSet interestingLines) {
165  
    return makeGT().scoreGenerators(log, interestingLines);
166  
  }
167  
  
168  
  GenTesting makeGT() {
169  
    return new GenTesting(new Object { void get(List<Gen> gens, List<String> log) {  makeGenerators(gens, log);  }
170  
  public String toString() { return "makeGenerators(gens, log);"; }});
171  
  }
172  
  
173  
  // also called from outside
174  
  void recommendSolver(String solverID) {
175  
    if (!isRecommendedSolver(solverID = fsi(solverID))) {
176  
      print("Adding recommended solver: " + solverID);
177  
      logQuoted("recommendations.txt", solverID);
178  
    } else
179  
      print("Solver already recommended: " + solverID);
180  
  }
181  
  
182  
  boolean isRecommendedSolver(String solverID) {
183  
    return contains(scanLog("recommendations.txt"), fsI(solverID));
184  
  }
185  
  
186  
  // log = what's in the chat
187  
  // input = what user is typing
188  
  void makeListData(List<String> thelog, String input, List l) {
189  
    long started = now();
190  
    try {
191  
      long timeout = started + listMakingTimeout;
192  
      new HashMap<String, Map> seen; // maps to the line
193  
      
194  
      // extended log including what user is typing
195  
      List<String> xlog = listPlus(thelog, input);
196  
      
197  
      // Make generators for both modes
198  
      
199  
      new List<Gen> gens;
200  
      for (boolean completing : ll(false, true)) {
201  
        new List<Gen> gens_;
202  
        try {
203  
          genLog_set(completing ? xlog : log);
204  
          gCompleting_set(completing);
205  
          makeGenerators(gens_, log);
206  
          for (Gen g : gens_)
207  
            gens.add(new Gen(g.name + gMode(), g.func));
208  
        } finally {
209  
          genLog_clear();
210  
          gCompleting_set(null);
211  
        }
212  
      }
213  
      
214  
      // Rank all generators
215  
      
216  
      gens = rankGenerators(gens);
217  
218  
      // Produce list
219  
          
220  
      int i = -1;
221  
      while (now() < timeout && l(l) < maxListLength && nempty(gens)) {
222  
        i = (i+1) % l(gens);
223  
        Gen gen = gens.get(i);
224  
        boolean completing = gen.name.endsWith("/i");
225  
        
226  
        try {
227  
          genLog_set(completing ? xlog : log);
228  
          gCompleting_set(completing);
229  
          boolean remove = false;
230  
          if (debug)
231  
            print("Trying generator " + gen.name);
232  
          try {
233  
            String s = callGen(gen);
234  
            if (empty(s) || eq(input, s))
235  
              remove = true;
236  
            else if (seen.containsKey(s)) {
237  
              Map line = seen.get(s);
238  
              setAdd((List) line.get("Suggesters"), gen.name);
239  
              remove = true;
240  
            } else {
241  
              int k = l(l)+1;
242  
              String key = k <= 12 ? "F" + k : null;
243  
              Map line = litorderedmap("Key", key, "Suggestion", s, "Suggesters", ll(gen.name));
244  
              l.add(line);
245  
              seen.put(s, line);
246  
            }
247  
          } catch (Throwable e) {
248  
            if (showExceptions)
249  
              l.add(litorderedmap("Suggestion", "[error] " + exceptionToStringShort(e), "Suggesters", ll(gen.name)));
250  
            remove = true;
251  
          }
252  
          if (remove)
253  
            gens.remove(i--);
254  
        } finally {
255  
          genLog_clear();
256  
          gCompleting_set(null);
257  
        }
258  
      }
259  
    } catch (Throwable e) {
260  
      printStackTrace(e);
261  
      l.add(e.toString());
262  
    } finally {
263  
      load = (int) ((now()-started)*100/listMakingTimeout);
264  
    }
265  
  }
266  
  
267  
  List<Gen> rankGenerators(List<Gen> gens) {
268  
    Map<String, Gen> index = indexByField(gens, "name");
269  
    new List<Gen> l;
270  
    List<String> rank = cloneList(ranking);
271  
    for (String name : rank) {
272  
      Gen g = index.get(name);
273  
      if (g != null) {
274  
        l.add(g);
275  
        index.remove(name);
276  
      }
277  
    }
278  
    l.addAll(values(index)); // add rest in unspecified order
279  
    //print("Using ranking: " + struct(rank));
280  
    //print("Ranked generators: " + struct(l));
281  
    return l;
282  
  }
283  
  
284  
  void rankToTop(String name) {
285  
    if (empty(name)) return;
286  
    if (eq(first(ranking), name)) return;
287  
    ranking.remove(name);
288  
    ranking.add(0, name);
289  
    saveLocally2(this, "ranking");
290  
    print("New ranking: " + structure(ranking));
291  
  }
292  
} // Thinker
293  
static String generatorsID;
294  
295  
static JFrame frame;
296  
static JTable table, chatTable;
297  
//static JTextArea chat;
298  
static JTextField input;
299  
static List<String> log = synchroList();
300  
static List<String> recommendations;
301  
static List<Thread> thinkThreads = synchroList();
302  
static JLabel status;
303  
static String lastInput;
304  
305  
static int listDelay = 2000;
306  
static int maxLineLength = 1000;
307  
static int maxLongStringLength = 100*1000;
308  
309  
static Boolean thinking;
310  
static new Thinker thinker;
311  
static boolean showCPU = true;
312  
313  
static String systemPrefix = "[system]";
314  
315  
static String dialog = "new";
316  
317  
static void randomMain() {
318  
  //substanceLAF("EmeraldDusk"); // Too dark!
319  
  //substanceLAF("ChallengerDeep"); // So purple!
320  
  //substance("MistAqua");
321  
  substance("Moderate");
322  
323  
  table = tableWithTooltips();
324  
  //chat = autoScroll(wordWrapTextArea());
325  
  chatTable = tableWithTooltips();
326  
  input = new JTextField;
327  
  status = new JLabel(" ");
328  
  
329  
  frame = showFrame(vgrid(centerAndSouth(
330  
    //jtabs(1, "Chat", chat, "Details", chatTable),
331  
    chatTable,
332  
    input), centerAndSouth(table, status)));
333  
  //setFrameIconLater(frame, "#1003593");
334  
  
335  
  addMenu(frame, "Random",
336  
    "Delete last line (!delete)", new Runnable() { public void run() { try { post("!delete"); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}},
337  
    "Reload generators (!gen)", new Runnable() { public void run() { try { post("!gen"); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}},
338  
    "Restart app (!restart)", new Runnable() { public void run() { try { post("!restart"); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}},
339  
    "Restart Java engine (!fresh)", new Runnable() { public void run() { try { post("!fresh"); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}},
340  
    "Execute Java code (!j ...)", new Runnable() { public void run() { try { setInput("!j 1+2"); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}},
341  
    "Switch dialog (!dialog ...)", new Runnable() { public void run() { try { setInput("!dialog bla"); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}},
342  
    "Restore last input", new Runnable() { public void run() { try { if (nempty(lastInput)) setInput(lastInput); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}},
343  
    "Show raw dialog", new Runnable() { public void run() { try { showText("Raw Dialog", rawDialog()); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
344  
  
345  
  onEnter(input, new Runnable() { public void run() { try {
346  
    post();
347  
  } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
348  
  
349  
  onDoubleClick(table, new Object { void get(int row) { 
350  
    chooseSuggestion(row);
351  
   }
352  
  public String toString() { return "chooseSuggestion(row);"; }});
353  
  
354  
  for (int i = 1; i <= 12; i++) {
355  
    final int _i = i;
356  
    registerFunctionKey(frame, i, new Runnable() { public void run() { try {
357  
      chooseSuggestionForEditing(_i-1);
358  
    } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
359  
    registerShiftFunctionKey(frame, i, new Runnable() { public void run() { try {
360  
      chooseSuggestion(_i-1);
361  
    } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
362  
  }
363  
  
364  
  onUpdate(input, new Runnable() { public void run() { try { updateOnce(); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
365  
  
366  
  loadDialog();
367  
  logEvent("Starting");
368  
  
369  
  updateOnce();
370  
  
371  
  input.requestFocus();
372  
  
373  
  if (isAction(last(log)) && confirmYesNo(input, "Run action? " + last(log)))
374  
    action(last(log));
375  
}
376  
377  
static String getInput() {
378  
  return joinLines(" # ", input.getText().trim());
379  
}
380  
381  
static void post() {
382  
  postAsUser(getInput(), null);
383  
}
384  
385  
static void postAsUser(String i, Map infos) {
386  
  if (inputAllowedByUser(i))
387  
    post(i, infos);
388  
}
389  
390  
static void chooseSuggestionForEditing(int row) {
391  
  Map<String, String> map = getTableLineAsMap(table, row);
392  
  if (map == null) return;
393  
  rankToTop(map);
394  
  String s = trim(unnull(map.get("Suggestion")));
395  
  logEvent("Suggestion chosen for editing", mapPlus(map, "Row", row+1, "Input", getInput(), "Top Suggesters", topSuggesters()));
396  
  setInput(s);
397  
}
398  
399  
static void setInput(final String s) {
400  
  swingNowOrLater(r {
401  
    lastInput = input.getText();
402  
    input.setText(s);
403  
    input.selectAll();
404  
    input.requestFocus();
405  
  });
406  
}
407  
408  
static void rankToTop(Map map) {
409  
  // Table cells have been structure'd by dataToTable
410  
  thinker.rankToTop(first((List<String>) unstructure(getString(map, "Suggesters"))));
411  
}
412  
413  
static void chooseSuggestion(int row) {
414  
  Map<String, String> map = getTableLineAsMap(table, row);
415  
  if (map == null) return;
416  
  rankToTop(map);
417  
  String s = trim(unnull(map.get("Suggestion")));
418  
  if (empty(s)) return;
419  
420  
  //logEvent("Suggestion chosen", mapPlus(map, "Row", row+1, "Input", getInput(), "Top Suggesters", topSuggesters));
421  
  setInput(s);
422  
  postAsUser(s, mapPlus(map, "Index", row+1));
423  
}
424  
425  
static List topSuggesters() {
426  
  int n = 20;
427  
  n = min(n, tableRows(table));
428  
  new List topSuggesters;
429  
  for (int i = 0; i < n; i++)
430  
    topSuggesters.add(getTableLineAsMap(table, i));
431  
  //if (empty(topSuggesters)) topSuggesters = null;
432  
  return topSuggesters;
433  
}
434  
435  
static void logEvent(String type) {
436  
  logEvent(type, litmap());
437  
}
438  
439  
static void logEvent(String type, Map map) {
440  
  logStructure(new File(dialogDir(), "event.log"),
441  
    ll(type, chatTime(), map));
442  
}
443  
444  
static boolean inputAllowedByUser(String i) {
445  
  return !swic(i, systemPrefix);
446  
}
447  
448  
// may be called from other thread
449  
static void postSystemMessage(final String msg) {
450  
  if (empty(msg)) return;
451  
  swingNowOrLater(r {
452  
    post(systemPrefix + " " + msg, litmap("By", "System"));
453  
  });
454  
}
455  
456  
static void post(String i) {
457  
  post(i, null);
458  
}
459  
460  
static void post(String i, Map infos) {
461  
  try {
462  
    i = trim(i);
463  
    if (empty(i)) return;
464  
    //i = escapeNewLines(i);
465  
    infos = mapPlus(infos, "Top Suggesters", topSuggesters());
466  
    
467  
    boolean tooLong = l(i) > maxLongStringLength;
468  
    
469  
    if (l(i) > maxLineLength) {
470  
      String id = saveLongString(i);
471  
      i = substring(i, 0, maxLineLength) + "... [" + (tooLong ? "too " : "") + "long text " + id + "]";
472  
    }
473  
  } catch (Throwable e) {
474  
    printStackTrace(e);
475  
    i = systemPrefix + " " + exceptionToStringShort(e);
476  
  }
477  
  
478  
  String s = i + "\n";
479  
  //chat.append(escapeNewLines(i) + "\n");
480  
  appendToFile(logFile(), "[" + chatTime() + "] " + s);
481  
  logEvent("Posting", litmap("Text", i, "Infos", infos));
482  
  log.add(i);
483  
  updateChatTable();
484  
  input.selectAll();
485  
  updateOnce();
486  
  try {
487  
    action(i);
488  
  } catch (Throwable e) {
489  
    printStackTrace(e);
490  
    postSystemMessage(exceptionToStringShort(e));
491  
  }
492  
}
493  
494  
static String dropActionPrefix(String s) {
495  
  if (s == null) return null;
496  
  s = dropBracketPrefix(s); // e.g. "[bot]"
497  
  if (!s.startsWith("!")) return null;
498  
  return s.substring(1);
499  
}
500  
501  
static boolean isAction(String s) {
502  
  return dropActionPrefix(s) != null;
503  
}
504  
505  
static void action(String s) {
506  
  s = dropActionPrefix(s);
507  
  if (s == null) return;
508  
509  
  final String _s = s;
510  
  { Thread _t_0 = new Thread("Action") {
511  
public void run() {
512  
try  {
513  
    { JWindow _loading_window = showLoadingAnimation(); try {
514  
      try {
515  
        genLog_set(getLog()); // 'case user needs it
516  
        randomsOwnCmds(_s);
517  
        systemCommands(_s);
518  
      } catch (Throwable e) {
519  
        printStackTrace(e);
520  
        postSystemMessage("Error - " + exceptionToStringShort(e));
521  
      }
522  
    } finally { disposeWindow(_loading_window); }}
523  
  } catch (Exception _e) {
524  
  throw _e instanceof RuntimeException ? (RuntimeException) _e : new RuntimeException(_e); } }
525  
};
526  
_t_0.start(); }
527  
}
528  
529  
static volatile boolean again;
530  
531  
// This logic is bad...
532  
static void fillList(boolean force) {
533  
  boolean t = force || shouldUpdateList();
534  
  if (neq(t, thinking)) {
535  
    thinking = t;
536  
    setFrameIcon(table, t ? "#1003603" : "#1003593");
537  
  }
538  
  
539  
  if (!t) {
540  
    if (!force)
541  
      againl8r();
542  
  } else {
543  
    if (nempty(thinkThreads)) { again = true; return; }
544  
    fillListImpl();
545  
  }
546  
}
547  
548  
static void fillListImpl() {
549  
  { Thread _t_1 = new Thread("Fill List") {
550  
public void run() {
551  
try  {
552  
    try {
553  
      thinkThreads.add(currentThread());
554  
      final new List<String> data;
555  
      thinker.makeListData(cloneList(log), getInput(), data);
556  
      
557  
      swingLater(new Runnable() { public void run() { try {
558  
        try {
559  
          dataToTable_uneditable(table, data);
560  
          tableColumnMaxWidth(table, 0, 30); // "Key" column
561  
        } catch (Throwable __e) { printStackTrace(__e); }
562  
        againl8r();
563  
      } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
564  
    } finally {
565  
      thinkThreads.remove(currentThread());
566  
    if (again) { again = false; fillListImpl(); }
567  
    }
568  
  } catch (Exception _e) {
569  
  throw _e instanceof RuntimeException ? (RuntimeException) _e : new RuntimeException(_e); } }
570  
};
571  
_t_1.start(); }
572  
}
573  
574  
static void updateOnce() { fillList(true); }
575  
576  
static void againl8r() {
577  
  swingAfter(table, listDelay, new Runnable() { public void run() { try { fillList(false); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
578  
}
579  
580  
static boolean shouldUpdateList() {
581  
  boolean result = false;
582  
  String text = " ";
583  
  if (getFrame(table).isFocused()) {
584  
    result = !mouseInComponent(table);
585  
    text = result ? " Thinking..." + (showCPU && thinker.load != 0 ? " (" + thinker.load + "%)" : "")
586  
      : "Not thinking cause you got the mouse in there";
587  
  }
588  
  status.setText(text);
589  
  return result;
590  
}
591  
592  
// also called from outside
593  
static List<String> loadLog() {
594  
  log.clear();
595  
  log.addAll(collect(scanEventLogForPosts(dialogDir()), "text"));
596  
  return log;
597  
}
598  
599  
synchronized static List<String> getLastFromLog(int n) {
600  
  return cloneList(getLast(log, n));
601  
}
602  
603  
synchronized static List<String> getLog() {
604  
  return cloneList(log);
605  
}
606  
607  
static File dialogDir() {
608  
  return prepareProgramFile(dialog);
609  
}
610  
611  
static File logFile() {
612  
  return new File(dialogDir(), "log.txt");
613  
}
614  
615  
static void switchDialog(final String name) {
616  
  swingAndWait(new Runnable() { public void run() { try {
617  
    dialog = name;
618  
    loadDialog();
619  
  } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
620  
}
621  
622  
static void loadDialog() {
623  
  loadLog();
624  
  thinker = new Thinker;
625  
  thinker.startUp(log);
626  
  //chat.setText(joinLines(log));
627  
  updateChatTable();
628  
}
629  
630  
static void randomsOwnCmds(String s) {
631  
  new Matches m;
632  
  if (match("dialog *", s, m)) {
633  
    switchDialog(m.unq(0));
634  
    // TODO: show current dialog somewhere else
635  
    //postSystemMessage("OK, dialog switched to " + quote(dialog));
636  
  }
637  
  
638  
  if (match("gen", s, m))
639  
    generators = null;
640  
  
641  
  if (match("delete", s, m))
642  
    updateChatTable();
643  
}
644  
645  
static void updateChatTable() {
646  
  swingNowOrLater(r {
647  
    new List data;
648  
    List<List> l = scanLog_safeUnstructure(new File(dialogDir(), "event.log"));
649  
    for (int i = 0; i < l(l); i++) try {
650  
      List a = l.get(i), prev = get(l, i-1);
651  
      if (firstIs(a, "Posting")) {
652  
        Map map = (Map) ( get(a, 2));
653  
        String text = getString(map, "Text").trim();
654  
        if (eq(text, "!delete")) { removeLast(data); continue; }
655  
        String idx = "";
656  
        Map infos = (Map) ( map.get("Infos"));
657  
        if (infos != null && infos.containsKey("Index"))
658  
          idx = str(infos.get("Index"));
659  
        else try {
660  
          //printStruct("prev: ", prev);
661  
          if (prev != null && firstIs(prev, "Suggestion chosen for editing")) {
662  
            Map m = getMap(prev, 2);
663  
            String suggestion = getString(m, "Suggestion");
664  
            //print("Suggestion: " + structure(suggestion));
665  
            idx = str(get(m, "Row"));
666  
            if (neq(suggestion, text))
667  
              idx += "?";
668  
          }
669  
        } catch (Throwable __e) { printStackTrace(__e); }
670  
        data.add(litorderedmap("Text", escapeNewLines(text), "Sugg." /* Suggestion Index */, idx));
671  
      }
672  
    } catch (Throwable __e) { printStackTrace(__e); }
673  
    dataToTable_uneditable(chatTable, data);
674  
    tableColumnMaxWidth(chatTable, 1, 40); // enough for 2 digits and a "?"
675  
    scrollTableDown(chatTable);
676  
  });
677  
}
678  
679  
static synchronized String saveLongString(String s) {
680  
  s = substring(s, 0, maxLongStringLength);
681  
  String id;
682  
  File f;
683  
  do {
684  
    id = randomID(10);
685  
    f = getProgramFile("long-strings/" + id);
686  
  } while (f.exists());
687  
  
688  
  saveTextFile(f, s);
689  
  return id;
690  
}
691  
692  
static Object generators;
693  
694  
static void makeGenerators(List<Gen> l, List<String> log) {
695  
  synchronized(main.class) {
696  
    if (!isSnippetID(generatorsID)) fail("No generators ID set");
697  
    if (generators == null)
698  
      generators = hotwire(generatorsID);
699  
  }
700  
  new List l2;
701  
  callOpt(generators, "makeGenerators", l2, log);
702  
  callOpt(generators, "deterministicGenerators", l2);
703  
  l.addAll((List) quickImport(l2));
704  
}
705  
706  
static String rawDialog() {
707  
  return fromLines(log);
708  
} // Random Main v9
709  
710  
p { swingLater(new Runnable() { public void run() { try {
711  
  generatorsID = "#1004039";
712  
  randomMain();
713  
} catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});}
714  
715  
716  
static JTextArea showText(final String title, final String text) {
717  
  return (JTextArea) swingAndWait(new Object { Object get() { 
718  
    JTextArea textArea = newTypeWriterTextArea(text);
719  
    makeFrame(title, new JScrollPane(textArea));
720  
    return textArea;
721  
   }
722  
  public String toString() { return "JTextArea textArea = newTypeWriterTextArea(text);\r\n    makeFrame(title, new JScrollPane(textArea));\r\n    ret textArea;"; }});
723  
}
724  
725  
static JTextArea showText(Object text) {
726  
  return showText(str(text));
727  
}
728  
729  
static JTextArea showText(String text) {
730  
  return showText(autoFrameTitle(), text);
731  
}
732  
733  
static Object callF(Object f, Object... args) {
734  
  return callFunction(f, args);
735  
}
736  
static String[] dropLast(String[] a, int n) {
737  
  n = Math.min(n, a.length);
738  
  String[] b = new String[a.length-n];
739  
  System.arraycopy(a, 0, b, 0, b.length);
740  
  return b;
741  
}
742  
743  
static <A> List<A> dropLast(List<A> l) {
744  
  return subList(l, 0, l(l)-1);
745  
}
746  
static Map<String, String> getTableLineAsMap(JTable tbl, int row) {
747  
  if (row >= 0 && row < tbl.getModel().getRowCount()) {
748  
    new Map<String, String> map;
749  
    for (int i = 0; i < tbl.getModel().getColumnCount(); i++)
750  
      map.put(tbl.getModel().getColumnName(i),
751  
        String.valueOf(tbl.getModel().getValueAt(row, i)));
752  
    return map;
753  
  }
754  
  return null;
755  
}
756  
static JPanel vgrid(List parts) {
757  
  return vgrid(asArray(parts));
758  
}
759  
760  
static JPanel vgrid(Object... parts) {
761  
  new JPanel panel;
762  
  panel.setLayout(new GridLayout(parts.length, 1));
763  
  smartAdd(panel, parts);
764  
  return panel;
765  
}
766  
static String trim(String s) { return s == null ? null : s.trim(); }
767  
static String trim(StringBuilder buf) { return buf.toString().trim(); }
768  
static String trim(StringBuffer buf) { return buf.toString().trim(); }
769  
// key = 1 to 12
770  
static void registerFunctionKey(JFrame frame, int key, final Runnable r) {
771  
  String name = "F" + key;
772  
  Action action = abstractAction(name, r);
773  
  JComponent pnl = frame.getRootPane();
774  
  KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F1+key-1, 0);
775  
  pnl.getActionMap().put(name, action);
776  
  pnl.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, name);
777  
}
778  
static String fsI(String id) {
779  
  return formatSnippetID(id);
780  
}
781  
static void swingAndWait(Runnable r) { try {
782  
 
783  
  if (isAWTThread())
784  
    r.run();
785  
  else
786  
    EventQueue.invokeAndWait(r);
787  
788  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
789  
790  
static Object swingAndWait(final Object f) {
791  
  if (isAWTThread())
792  
    return callF(f);
793  
  else {
794  
    final new Var result;
795  
    swingAndWait(new Runnable() { public void run() { try {
796  
      result.set(callF(f));
797  
    } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
798  
    return result.get();
799  
  }
800  
}
801  
static Thread currentThread() {
802  
  return Thread.currentThread();
803  
}
804  
static void printStackTrace(Throwable e) {
805  
  // we go to system.out now - system.err is nonsense
806  
  print(getStackTrace(e));
807  
}
808  
809  
static void printStackTrace() {
810  
  printStackTrace(new Throwable());
811  
}
812  
static JMenu addMenu(JFrame frame, String menuName, Object... items) {
813  
  JMenuBar bar = addMenuBar(frame);
814  
  JMenu menu = new JMenu(menuName);
815  
  fillJMenu(menu, items);
816  
  bar.add(menu);
817  
  return menu;
818  
}
819  
static boolean mouseInComponent(Component c) {
820  
  return boundsOnScreen(c).contains(mousePosition());
821  
}
822  
static <A> List<A> cloneList(Collection<A> l) {
823  
  //O mutex = getOpt(l, "mutex");
824  
  /*if (mutex != null)
825  
    synchronized(mutex) {
826  
      ret new ArrayList<A>(l);
827  
    }
828  
  else
829  
    ret new ArrayList<A>(l);*/
830  
  // assume mutex is equal to collection, which will be true unless you explicitly pass a mutex to synchronizedList() which no one ever does.
831  
  synchronized(l) {
832  
    return new ArrayList<A>(l);
833  
  }
834  
}
835  
static Map litmap(Object... x) {
836  
  new TreeMap map;
837  
  litmap_impl(map, x);
838  
  return map;
839  
}
840  
841  
static void litmap_impl(Map map, Object... x) {
842  
  for (int i = 0; i < x.length-1; i += 2)
843  
    if (x[i+1] != null)
844  
      map.put(x[i], x[i+1]);
845  
}
846  
// key = 1 to 12
847  
static void registerShiftFunctionKey(JFrame frame, int key, final Runnable r) {
848  
  String name = "Shift+F" + key;
849  
  Action action = abstractAction(name, r);
850  
  JComponent pnl = frame.getRootPane();
851  
  KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F1+key-1, InputEvent.SHIFT_MASK);
852  
  pnl.getActionMap().put(name, action);
853  
  pnl.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, name);
854  
}
855  
static String str(Object o) {
856  
  return String.valueOf(o);
857  
}
858  
  static RuntimeException fail() {
859  
    throw new RuntimeException("fail");
860  
  }
861  
  
862  
  static RuntimeException fail(Object msg) {
863  
    throw new RuntimeException(String.valueOf(msg));
864  
  }
865  
  
866  
  static RuntimeException fail(String msg) {
867  
    throw new RuntimeException(unnull(msg));
868  
  }
869  
   
870  
  // disabled for now to shorten some programs 
871  
  /*static RuntimeException fail(S msg, O... args) {
872  
    throw new RuntimeException(format(msg, args));
873  
  }*/
874  
static boolean contains(Collection c, Object o) {
875  
  return c != null && c.contains(o);
876  
}
877  
878  
static boolean contains(Object[] x, Object o) {
879  
  if (x != null)
880  
    for (Object a : x)
881  
      if (eq(a, o))
882  
        return true;
883  
  return false;
884  
}
885  
886  
static boolean contains(String s, char c) {
887  
  return s.indexOf(c) >= 0;
888  
}
889  
static void logStructure(File logFile, Object o) {
890  
  logQuoted(logFile, structure(o));
891  
}
892  
893  
// quick version - log to file in program directory
894  
static void logStructure(String fileName, Object o) {
895  
  logStructure(getProgramFile(fileName), o);
896  
}
897  
static String fsi(String id) {
898  
  return formatSnippetID(id);
899  
}
900  
901  
  static String unnull(String s) {
902  
    return s == null ? "" : s;
903  
  }
904  
  
905  
  static <A> List<A> unnull(List<A> l) {
906  
    return l == null ? emptyList() : l;
907  
  }
908  
  
909  
  static Object[] unnull(Object[] a) {
910  
    return a == null ? new Object[0] : a;
911  
  }
912  
static boolean swic(String a, String b) {
913  
  return startsWithIgnoreCase(a, b);
914  
}
915  
// runnable can be a func(O o) {} receving the selected item
916  
static void onDoubleClick(final JList list, final Object runnable) {
917  
  list.addMouseListener(new MouseAdapter() {
918  
    public void mouseClicked(MouseEvent evt) {
919  
      if (evt.getClickCount() == 2) {
920  
        int idx = list.locationToIndex(evt.getPoint());
921  
        Object item = list.getModel().getElementAt(idx);
922  
        list.setSelectedIndex(idx);
923  
        callF(runnable, item);
924  
      }
925  
    }
926  
  });
927  
}
928  
929  
// runnable can be a func(O o) {} receving the selected row index
930  
static void onDoubleClick(final JTable table, final Object runnable) {
931  
  table.addMouseListener(new MouseAdapter() {
932  
    public void mouseClicked(MouseEvent evt) {
933  
      if (evt.getClickCount() == 2) {
934  
        int idx = table.rowAtPoint(evt.getPoint());
935  
        table.setRowSelectionInterval(idx, idx);
936  
        callF(runnable, idx);
937  
      }
938  
    }
939  
  });
940  
}
941  
static class DynamicObject {
942  
  String className;
943  
  new Map<String, Object> fieldValues;
944  
}
945  
946  
static Object unstructure(String text) {
947  
  return unstructure(text, false);
948  
}
949  
950  
// TODO: backrefs for hashmap{} etc
951  
static Object unstructure(String text, final boolean allDynamic) {
952  
  if (text == null) return null;
953  
  final List<String> tok = javaTok(text);
954  
  final boolean debug = unstructure_debug;
955  
  
956  
  class X {
957  
    int i = 1;
958  
    new HashMap<Integer, Object> refs;
959  
960  
    Object parse() {
961  
      String t = tok.get(i);
962  
      
963  
      int refID = 0;
964  
      if (t.startsWith("m") && isInteger(t.substring(1))) {
965  
        refID = parseInt(t.substring(1));
966  
        i += 2;
967  
        t = tok.get(i);
968  
      }
969  
      
970  
      if (debug)
971  
        print("parse: " + quote(t));
972  
        
973  
      if (t.startsWith("\"")) {
974  
        String s = unquote(tok.get(i));
975  
        i += 2;
976  
        return s;
977  
      }
978  
      if (t.startsWith("'")) {
979  
        char c = unquoteCharacter(tok.get(i));
980  
        i += 2;
981  
        return c;
982  
      }
983  
      if (t.equals("bigint"))
984  
        return parseBigInt();
985  
      if (t.equals("d"))
986  
        return parseDouble();
987  
      if (t.equals("false") || t.equals("f")) {
988  
        i += 2; return false;
989  
      }
990  
      if (t.equals("true") || t.equals("t")) {
991  
        i += 2; return true;
992  
      }
993  
      if (t.equals("-")) {
994  
        t = tok.get(i+2);
995  
        i += 4;
996  
        return isLongConstant(t) ? (Object) (-parseLong(t)) : (Object) (-parseInt(t));
997  
      }
998  
      if (isInteger(t) || isLongConstant(t)) {
999  
        i += 2;
1000  
        if (debug)
1001  
          print("isLongConstant " + quote(t) + " => " + isLongConstant(t));
1002  
        if (isLongConstant(t)) return parseLong(t);
1003  
        long l = parseLong(t);
1004  
        return l != (int) l ? new Long(l) : new Integer((int) l);
1005  
      }
1006  
      
1007  
      if (t.equals("File")) {
1008  
        File f = new File(unquote(tok.get(i+2)));
1009  
        i += 4;
1010  
        return f;
1011  
      }
1012  
      
1013  
      if (t.startsWith("r") && isInteger(t.substring(1))) {
1014  
        i += 2;
1015  
        int ref = Integer.parseInt(t.substring(1));
1016  
        Object o = refs.get(ref);
1017  
        if (o == null)
1018  
          print("Warning: unsatisfied back reference " + ref);
1019  
        return o;
1020  
      }
1021  
      
1022  
      return parse_inner(refID);
1023  
    }
1024  
    
1025  
    // everything that can be backreferenced
1026  
    Object parse_inner(int refID) {
1027  
      String t = tok.get(i);
1028  
      
1029  
      if (debug)
1030  
        print("parse_inner: " + quote(t));
1031  
        
1032  
      if (t.equals("hashset"))
1033  
        return parseHashSet();
1034  
      if (t.equals("treeset"))
1035  
        return parseTreeSet();
1036  
      if (t.equals("hashmap"))
1037  
        return parseHashMap();
1038  
      if (t.equals("{"))
1039  
        return parseMap();
1040  
      if (t.equals("["))
1041  
        return parseList();
1042  
      if (t.equals("array"))
1043  
        return parseArray();
1044  
      if (t.equals("class"))
1045  
        return parseClass();
1046  
      if (t.equals("l"))
1047  
        return parseLisp();
1048  
      if (t.equals("null")) {
1049  
        i += 2; return null;
1050  
      }
1051  
      if (isJavaIdentifier(t)) {
1052  
        Class c = allDynamic ? null : findClass(t);
1053  
        DynamicObject dO = null;
1054  
        Object o = null;
1055  
        if (c != null)
1056  
          o = nuObject(c);
1057  
        else {
1058  
          dO = new DynamicObject;
1059  
          dO.className = t;
1060  
        }
1061  
        
1062  
        if (refID != 0)
1063  
          refs.put(refID, o);
1064  
          
1065  
        i += 2;
1066  
        if (i < tok.size() && tok.get(i).equals("(")) {
1067  
          consume("(");
1068  
          while (!tok.get(i).equals(")")) {
1069  
            // It's like parsing a map.
1070  
            //Object key = parse();
1071  
            //if (tok.get(i).equals(")"))
1072  
            //  key = onlyField();
1073  
            String key = unquote(tok.get(i));
1074  
            i += 2;
1075  
            consume("=");
1076  
            Object value = parse();
1077  
            if (o != null)
1078  
              setOpt(o, key, value);
1079  
            else
1080  
              dO.fieldValues.put(key, value);
1081  
            if (tok.get(i).equals(",")) i += 2;
1082  
          }
1083  
          consume(")");
1084  
        }
1085  
        return o != null ? o : dO;
1086  
      }
1087  
      throw new RuntimeException("Unknown token " + (i+1) + ": " + t);
1088  
    }
1089  
    
1090  
    Object parseSet(Set set) {
1091  
      set.addAll((List) parseList());
1092  
      return set;
1093  
    }
1094  
    
1095  
    Object parseLisp() {
1096  
      consume("l");
1097  
      consume("(");
1098  
      List list = new ArrayList;
1099  
      while (!tok.get(i).equals(")")) {
1100  
        list.add(parse());
1101  
        if (tok.get(i).equals(",")) i += 2;
1102  
      }
1103  
      consume(")");
1104  
      return newObject("main$Lisp", (String) list.get(0), subList(list, 1));
1105  
    }
1106  
    
1107  
    Object parseList() {
1108  
      consume("[");
1109  
      List list = new ArrayList;
1110  
      while (!tok.get(i).equals("]")) {
1111  
        list.add(parse());
1112  
        if (tok.get(i).equals(",")) i += 2;
1113  
      }
1114  
      consume("]");
1115  
      return list;
1116  
    }
1117  
    
1118  
    Object parseArray() {
1119  
      consume("array");
1120  
      consume("{");
1121  
      List list = new ArrayList;
1122  
      while (!tok.get(i).equals("}")) {
1123  
        list.add(parse());
1124  
        if (tok.get(i).equals(",")) i += 2;
1125  
      }
1126  
      consume("}");
1127  
      return list.toArray();
1128  
    }
1129  
    
1130  
    Object parseClass() {
1131  
      consume("class");
1132  
      consume("(");
1133  
      String name = tok.get(i);
1134  
      i += 2;
1135  
      consume(")");
1136  
      Class c = allDynamic ? null : findClass(name);
1137  
      if (c != null) return c;
1138  
      new DynamicObject dO;
1139  
      dO.className = "java.lang.Class";
1140  
      dO.fieldValues.put("name", name);
1141  
      return dO;
1142  
    }
1143  
    
1144  
    Object parseBigInt() {
1145  
      consume("bigint");
1146  
      consume("(");
1147  
      String val = tok.get(i);
1148  
      i += 2;
1149  
      if (eq(val, "-")) {
1150  
        val = "-" + tok.get(i);
1151  
        i += 2;
1152  
      }
1153  
      consume(")");
1154  
      return new BigInteger(val);
1155  
    }
1156  
    
1157  
    Object parseDouble() {
1158  
      consume("d");
1159  
      consume("(");
1160  
      String val = unquote(tok.get(i));
1161  
      i += 2;
1162  
      consume(")");
1163  
      return Double.parseDouble(val);
1164  
    }
1165  
    
1166  
    Object parseHashMap() {
1167  
      consume("hashmap");
1168  
      return parseMap(new HashMap);
1169  
    }
1170  
    
1171  
    Object parseHashSet() {
1172  
      consume("hashset");
1173  
      return parseSet(new HashSet);
1174  
    }
1175  
    
1176  
    Object parseTreeSet() {
1177  
      consume("treeset");
1178  
      return parseSet(new TreeSet);
1179  
    }
1180  
    
1181  
    Object parseMap() {
1182  
      return parseMap(new TreeMap);
1183  
    }
1184  
    
1185  
    Object parseMap(Map map) {
1186  
      consume("{");
1187  
      while (!tok.get(i).equals("}")) {
1188  
        Object key = parse();
1189  
        consume("=");
1190  
        Object value = parse();
1191  
        map.put(key, value);
1192  
        if (tok.get(i).equals(",")) i += 2;
1193  
      }
1194  
      consume("}");
1195  
      return map;
1196  
    }
1197  
    
1198  
    void consume(String s) {
1199  
      if (!tok.get(i).equals(s)) {
1200  
        String prevToken = i-2 >= 0 ? tok.get(i-2) : "";
1201  
        String nextTokens = join(tok.subList(i, Math.min(i+4, tok.size())));
1202  
        fail(quote(s) + " expected: " + prevToken + " " + nextTokens + " (" + i + "/" + tok.size() + ")");
1203  
      }
1204  
      i += 2;
1205  
    }
1206  
  }
1207  
  
1208  
  return new X().parse();
1209  
}
1210  
1211  
static boolean unstructure_debug;
1212  
static void removeLast(List l) {
1213  
  if (!l.isEmpty())
1214  
    l.remove(l(l)-1);
1215  
}
1216  
  public static boolean isSnippetID(String s) {
1217  
    try {
1218  
      parseSnippetID(s);
1219  
      return true;
1220  
    } catch (RuntimeException e) {
1221  
      return false;
1222  
    }
1223  
  }
1224  
static int min(int a, int b) {
1225  
  return Math.min(a, b);
1226  
}
1227  
1228  
static double min(double[] c) {
1229  
  double x = Double.MAX_VALUE;
1230  
  for (double d : c) x = Math.min(x, d);
1231  
  return x;
1232  
}
1233  
1234  
static byte min(byte[] c) {
1235  
  byte x = 127;
1236  
  for (byte d : c) if (d < x) x = d;
1237  
  return x;
1238  
}
1239  
static void scrollTableDown(JTable table) {
1240  
  table.scrollRectToVisible(table.getCellRect(table.getRowCount()-1, 0, true));
1241  
}
1242  
// get purpose 1: access a list/array (safer version of x.get(y))
1243  
1244  
static <A> A get(List<A> l, int idx) {
1245  
  return idx >= 0 && idx < l(l) ? l.get(idx) : null;
1246  
}
1247  
1248  
static <A> A get(A[] l, int idx) {
1249  
  return idx >= 0 && idx < l(l) ? l[idx] : null;
1250  
}
1251  
1252  
// get purpose 2: access a field by reflection or a map
1253  
1254  
static Object get(Object o, String field) {
1255  
  if (o instanceof Class) return get((Class) o, field);
1256  
  
1257  
  if (o instanceof Map)
1258  
    return ((Map) o).get(field);
1259  
    
1260  
  if (o.getClass().getName().equals("main$DynamicObject"))
1261  
    return call(get_raw(o, "fieldValues"), "get", field);
1262  
    
1263  
  return get_raw(o, field);
1264  
}
1265  
1266  
static Object get_raw(Object o, String field) {
1267  
  try {
1268  
    Field f = get_findField(o.getClass(), field);
1269  
    f.setAccessible(true);
1270  
    return f.get(o);
1271  
  } catch (Exception e) {
1272  
    throw new RuntimeException(e);
1273  
  }
1274  
}
1275  
1276  
static Object get(Class c, String field) {
1277  
  try {
1278  
    Field f = get_findStaticField(c, field);
1279  
    f.setAccessible(true);
1280  
    return f.get(null);
1281  
  } catch (Exception e) {
1282  
    throw new RuntimeException(e);
1283  
  }
1284  
}
1285  
1286  
static Field get_findStaticField(Class<?> c, String field) {
1287  
  Class _c = c;
1288  
  do {
1289  
    for (Field f : _c.getDeclaredFields())
1290  
      if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0)
1291  
        return f;
1292  
    _c = _c.getSuperclass();
1293  
  } while (_c != null);
1294  
  throw new RuntimeException("Static field '" + field + "' not found in " + c.getName());
1295  
}
1296  
1297  
static Field get_findField(Class<?> c, String field) {
1298  
  Class _c = c;
1299  
  do {
1300  
    for (Field f : _c.getDeclaredFields())
1301  
      if (f.getName().equals(field))
1302  
        return f;
1303  
    _c = _c.getSuperclass();
1304  
  } while (_c != null);
1305  
  throw new RuntimeException("Field '" + field + "' not found in " + c.getName());
1306  
}
1307  
static Object quickImport(Object o) {
1308  
  return quickExport(o, mc());
1309  
}
1310  
static String escapeNewLines(String s) {
1311  
  return s.replace("\n", " | ");
1312  
}
1313  
static JFrame showFrame() {
1314  
  return makeFrame();
1315  
}
1316  
1317  
static JFrame showFrame(Object content) {
1318  
  return makeFrame(content);
1319  
}
1320  
1321  
static JFrame showFrame(String title) {
1322  
  return makeFrame(title);
1323  
}
1324  
1325  
static JFrame showFrame(String title, Object content) {
1326  
  return makeFrame(title, content);
1327  
}
1328  
static List<String> scanLog(String progID, String fileName) {
1329  
  return scanLog(getProgramFile(progID, fileName));
1330  
}
1331  
1332  
static List<String> scanLog(String fileName) {
1333  
  return scanLog(getProgramFile(fileName));
1334  
}
1335  
1336  
static List<String> scanLog(File file) {
1337  
  new List<String> l;
1338  
  for (String s : toLines(file))
1339  
    if (isProperlyQuoted(s))
1340  
      l.add(unquote(s));
1341  
  return l;
1342  
}
1343  
static <A> List<A> subList(List<A> l, int startIndex) {
1344  
  return subList(l, startIndex, l(l));
1345  
}
1346  
1347  
static <A> List<A> subList(List<A> l, int startIndex, int endIndex) {
1348  
  startIndex = max(0, min(l(l), startIndex));
1349  
  endIndex = max(0, min(l(l), endIndex));
1350  
  if (startIndex > endIndex) return litlist();
1351  
  return l.subList(startIndex, endIndex);
1352  
}
1353  
static <A> List<A> listPlus(List<A> l, A... more) {
1354  
  return concatLists(l, asList(more));
1355  
}
1356  
static int l(Object[] array) {
1357  
  return array == null ? 0 : array.length;
1358  
}
1359  
1360  
static int l(byte[] array) {
1361  
  return array == null ? 0 : array.length;
1362  
}
1363  
1364  
static int l(int[] array) {
1365  
  return array == null ? 0 : array.length;
1366  
}
1367  
1368  
static int l(char[] array) {
1369  
  return array == null ? 0 : array.length;
1370  
}
1371  
1372  
static int l(Collection c) {
1373  
  return c == null ? 0 : c.size();
1374  
}
1375  
1376  
static int l(Map m) {
1377  
  return m == null ? 0 : m.size();
1378  
}
1379  
1380  
static int l(String s) {
1381  
  return s == null ? 0 : s.length();
1382  
} 
1383  
1384  
static int l(Object o) {
1385  
  return l((List) o); // incomplete
1386  
}
1387  
1388  
static String exceptionToStringShort(Throwable e) {
1389  
  e = getInnerException(e);
1390  
  String msg = unnull(e.getMessage());
1391  
  if (msg.indexOf("Error") < 0 && msg.indexOf("Exception") < 0)
1392  
    return dropPrefix("java.lang.", str(e));
1393  
  else
1394  
    return msg;
1395  
}
1396  
static ThreadLocal<Boolean> gCompleting;
1397  
1398  
static boolean gCompleting() {
1399  
  gCompleting_init();
1400  
  Boolean b = gCompleting.get();
1401  
  /*if (b == null)
1402  
    b = (Bool) callOpt(creator(), "gCompleting");*/
1403  
  return isTrue(b);
1404  
}
1405  
1406  
static void gCompleting_set(Boolean b) {
1407  
  gCompleting_init();
1408  
  gCompleting.set(b);
1409  
}
1410  
1411  
static void gCompleting_init() {
1412  
  if (gCompleting == null) {
1413  
    gCompleting = (ThreadLocal) getOpt(creator(), "gCompleting");
1414  
    if (gCompleting == null) gCompleting = new ThreadLocal;
1415  
  }
1416  
}
1417  
static String gMode() {
1418  
  return gCompleting() ? "/i" : "";
1419  
}
1420  
// action = runnable or method name
1421  
static void onUpdate(JTextComponent c, final Object r) {
1422  
  c.getDocument().addDocumentListener(new DocumentListener() {
1423  
    public void insertUpdate(DocumentEvent e) {
1424  
      callFunction(r);
1425  
    }
1426  
    public void removeUpdate(DocumentEvent e) {
1427  
      callFunction(r);
1428  
    }
1429  
    public void changedUpdate(DocumentEvent e) {
1430  
      callFunction(r);
1431  
    }
1432  
  });
1433  
}
1434  
static Object first(Object list) {
1435  
  return ((List) list).isEmpty() ? null : ((List) list).get(0);
1436  
}
1437  
1438  
static <A> A first(List<A> list) {
1439  
  return list.isEmpty() ? null : list.get(0);
1440  
}
1441  
1442  
static <A> A first(A[] bla) {
1443  
  return bla == null || bla.length == 0 ? null : bla[0];
1444  
}
1445  
static void setFrameIcon(JFrame frame, String imageID) {
1446  
  try {
1447  
    if (frame != null)
1448  
      frame.setIconImage(imageIcon(imageID).getImage());
1449  
  } catch (Throwable __e) { printStackTrace(__e); }
1450  
}
1451  
1452  
static void setFrameIcon(Component c, String imageID) {
1453  
  setFrameIcon(getFrame(c), imageID);
1454  
}
1455  
static <A> ArrayList<A> ll(A... a) {
1456  
  return litlist(a);
1457  
}
1458  
static LinkedHashMap litorderedmap(Object... x) {
1459  
  new LinkedHashMap map;
1460  
  litmap_impl(map, x);
1461  
  return map;
1462  
}
1463  
static String dropBracketPrefix(String s) {
1464  
  s = s.trim();
1465  
  if (s.startsWith("[")) {
1466  
    int i = s.indexOf(']');
1467  
    return s.substring(i+1).trim();
1468  
  }
1469  
  return s;
1470  
}
1471  
static File prepareProgramFile(String name) {
1472  
  return mkdirsForFile(getProgramFile(name));
1473  
}
1474  
static String joinLines(List<String> lines) {
1475  
  return fromLines(lines);
1476  
}
1477  
1478  
static String joinLines(String glue, String text) {
1479  
  return join(glue, toLines(text));
1480  
}
1481  
static <A> List<A> getLast(List<A> l, int n) {
1482  
  return subList(l, l(l)-n);
1483  
}
1484  
static boolean empty(Collection c) {
1485  
  return isEmpty(c);
1486  
}
1487  
1488  
static boolean empty(String s) {
1489  
  return isEmpty(s);
1490  
}
1491  
1492  
static boolean empty(Map map) {
1493  
  return map == null || map.isEmpty();
1494  
}
1495  
1496  
static boolean empty(Object o) {
1497  
  if (o instanceof Collection) return empty((Collection) o);
1498  
  if (o instanceof String) return empty((String) o);
1499  
  if (o instanceof Map) return empty((Map) o);
1500  
  return false;
1501  
}
1502  
static boolean confirmYesNo(Component owner, String msg) {
1503  
  return JOptionPane.showConfirmDialog(owner,
1504  
    msg, "JavaX", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
1505  
}
1506  
 // Let's just generally synchronize this to be safe.
1507  
 static synchronized void appendToFile(String path, String s) { try {
1508  
 
1509  
    new File(path).getParentFile().mkdirs();
1510  
    //print("[Logging to " + path + "]");
1511  
    Writer writer = new BufferedWriter(new OutputStreamWriter(
1512  
      new FileOutputStream(path, true), "UTF-8"));
1513  
    writer.write(s);
1514  
    writer.close();
1515  
  
1516  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
1517  
  
1518  
  static void appendToFile(File path, String s) {
1519  
    if (path != null)
1520  
      appendToFile(path.getPath(), s);
1521  
  }
1522  
1523  
static <A> A findByField(Collection<A> c, String field, Object value) {
1524  
  for (A a : c)
1525  
    if (eq(getOpt(a, field), value))
1526  
      return a;
1527  
  return null;
1528  
}
1529  
static boolean neq(Object a, Object b) {
1530  
  return !eq(a, b);
1531  
}
1532  
static ThreadLocal<List<String>> genLog_log;
1533  
1534  
static List<String> genLog() {
1535  
  genLog_init();
1536  
  List<String> log = genLog_log.get();
1537  
  /*if (log == null)
1538  
    log = (L) callOpt(creator(), "genLog");*/
1539  
  return assertNotNull("No log set for this thread", log);
1540  
}
1541  
1542  
static void genLog_set(List<String> log) {
1543  
  genLog_init();
1544  
  genLog_log.set(log);
1545  
}
1546  
1547  
static void genLog_clear() {
1548  
  genLog_init();
1549  
  genLog_log.set(null);
1550  
}
1551  
1552  
static void genLog_init() {
1553  
  if (genLog_log == null) {
1554  
    genLog_log = (ThreadLocal) getOpt(creator(), "genLog_log");
1555  
    if (genLog_log == null) genLog_log = new ThreadLocal;
1556  
  }
1557  
}
1558  
static <A> boolean firstIs(List<A> l, A a) {
1559  
  return eq(get(l, 0), a);
1560  
}
1561  
// automatic conversion to string (for returning numbers etc.)
1562  
static String callGen(Gen gen) {
1563  
  return strPreserveNull(callF(gen.func));
1564  
}
1565  
static <A> A last(List<A> l) {
1566  
  return l.isEmpty() ? null : l.get(l.size()-1);
1567  
}
1568  
static boolean eq(Object a, Object b) {
1569  
  if (a == null) return b == null;
1570  
  if (a.equals(b)) return true;
1571  
  if (a instanceof BigInteger) {
1572  
    if (b instanceof Integer) return a.equals(BigInteger.valueOf((Integer) b));
1573  
    if (b instanceof Long) return a.equals(BigInteger.valueOf((Long) b));
1574  
  }
1575  
  return false;
1576  
}
1577  
static TableWithTooltips tableWithTooltips() {
1578  
  return new TableWithTooltips;
1579  
}
1580  
1581  
static class TableWithTooltips extends JTable {
1582  
  public String getToolTipText(MouseEvent e) {
1583  
    String tip = null;
1584  
    Point p = e.getPoint();
1585  
    int rowIndex = rowAtPoint(p);
1586  
    int colIndex = columnAtPoint(p);
1587  
1588  
    try {
1589  
      return str(getValueAt(rowIndex, colIndex));
1590  
    } catch (Throwable _e) { return null;
1591  
    }
1592  
  }
1593  
}
1594  
static Map getMap(Map map, Object key) {
1595  
  return map == null ? null : (Map) map.get(key);
1596  
}
1597  
1598  
static Map getMap(List l, int idx) {
1599  
  return (Map) get(l, idx);
1600  
}
1601  
1602  
static Map getMap(Object o, Object key) {
1603  
  if (o instanceof Map) return getMap((Map) o, key);
1604  
  if (key instanceof String)
1605  
    return (Map) get(o, (String) key);
1606  
  throw fail("Not a string key: " + getClassName(key));
1607  
}
1608  
static void onEnter(JTextField tf, final Runnable action) {
1609  
  tf.addActionListener(new ActionListener() {
1610  
    public void actionPerformed(ActionEvent evt) {
1611  
      try {
1612  
        action.run();
1613  
      } catch (Throwable e) {
1614  
        e.printStackTrace();
1615  
      }
1616  
    }
1617  
  });
1618  
}
1619  
  /** writes safely (to temp file, then rename) */
1620  
  public static void saveTextFile(String fileName, String contents) throws IOException {
1621  
    File file = new File(fileName);
1622  
    File parentFile = file.getParentFile();
1623  
    if (parentFile != null)
1624  
      parentFile.mkdirs();
1625  
    String tempFileName = fileName + "_temp";
1626  
    if (contents != null) {
1627  
      FileOutputStream fileOutputStream = new FileOutputStream(tempFileName);
1628  
      OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "UTF-8");
1629  
      PrintWriter printWriter = new PrintWriter(outputStreamWriter);
1630  
      printWriter.print(contents);
1631  
      printWriter.close();
1632  
    }
1633  
    
1634  
    if (file.exists() && !file.delete())
1635  
      throw new IOException("Can't delete " + fileName);
1636  
1637  
    if (contents != null)
1638  
      if (!new File(tempFileName).renameTo(file))
1639  
        throw new IOException("Can't rename " + tempFileName + " to " + fileName);
1640  
  }
1641  
  
1642  
  public static void saveTextFile(File fileName, String contents) {
1643  
    try {
1644  
      saveTextFile(fileName.getPath(), contents);
1645  
    } catch (IOException e) {
1646  
      throw new RuntimeException(e);
1647  
    }
1648  
  }
1649  
1650  
static List scanLog_safeUnstructure(String progID, String fileName) {
1651  
  return scanLog_safeUnstructure(getProgramFile(progID, fileName));
1652  
}
1653  
1654  
static List scanLog_safeUnstructure(String fileName) {
1655  
  return scanLog_safeUnstructure(getProgramFile(fileName));
1656  
}
1657  
1658  
static List scanLog_safeUnstructure(File file) {
1659  
  new List l;
1660  
  for (String s : scanLog(file)) try {
1661  
    l.add(safeUnstructure(s));
1662  
  } catch (Throwable __e) { printStackTrace(__e); }
1663  
  return l;
1664  
}
1665  
static void readLocally(String progID, String varNames) {
1666  
  readLocally2(mc(), progID, varNames);
1667  
}
1668  
1669  
static void readLocally(String varNames) {
1670  
  readLocally2(mc(), programID(), varNames);
1671  
}
1672  
1673  
static void readLocally2(Object obj, String varNames) {
1674  
  readLocally2(obj, programID(), varNames);
1675  
}
1676  
1677  
// read a string variable from standard storage
1678  
// does not overwrite variable contents if there is no file
1679  
static synchronized void readLocally2(Object obj, String progID, String varNames) {
1680  
  for (String variableName : codeTokensOnly(javaTok(varNames))) {
1681  
    File textFile = new File(programDir(progID), variableName + ".text");
1682  
    File structureFile = new File(programDir(progID), variableName + ".structure");
1683  
    
1684  
    String value = loadTextFile(textFile);
1685  
    if (value != null)
1686  
      set(main.class, variableName, value);
1687  
    else {
1688  
      value = loadTextFile(structureFile);
1689  
      if (value != null)
1690  
      readLocally_set(obj, variableName, unstructure(value));
1691  
    }
1692  
  }
1693  
}
1694  
1695  
static void readLocally_set(Object c, String varName, Object value) {
1696  
  Object oldValue = get(c, varName);
1697  
  if (oldValue instanceof List && !(oldValue instanceof ArrayList) && value != null) {
1698  
    // Assume it's a synchroList.
1699  
    value = synchroList((List) value);
1700  
  }
1701  
  set(c, varName, value);
1702  
}
1703  
1704  
static List collect(Collection c, String field) {
1705  
  return collectField(c, field);
1706  
}
1707  
static int tableRows(JTable table) {
1708  
  return table.getRowCount();
1709  
}
1710  
  static Object callOpt(Object o, String method, Object... args) {
1711  
    try {
1712  
      if (o == null) return null;
1713  
      if (o instanceof Class) {
1714  
        Method m = callOpt_findStaticMethod((Class) o, method, args, false);
1715  
        if (m == null) return null;
1716  
        m.setAccessible(true);
1717  
        return m.invoke(null, args);
1718  
      } else {
1719  
        Method m = callOpt_findMethod(o, method, args, false);
1720  
        if (m == null) return null;
1721  
        m.setAccessible(true);
1722  
        return m.invoke(o, args);
1723  
      }
1724  
    } catch (Exception e) {
1725  
      throw new RuntimeException(e);
1726  
    }
1727  
  }
1728  
1729  
  static Method callOpt_findStaticMethod(Class c, String method, Object[] args, boolean debug) {
1730  
    Class _c = c;
1731  
    while (c != null) {
1732  
      for (Method m : c.getDeclaredMethods()) {
1733  
        if (debug)
1734  
          System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
1735  
        if (!m.getName().equals(method)) {
1736  
          if (debug) System.out.println("Method name mismatch: " + method);
1737  
          continue;
1738  
        }
1739  
1740  
        if ((m.getModifiers() & Modifier.STATIC) == 0 || !callOpt_checkArgs(m, args, debug))
1741  
          continue;
1742  
1743  
        return m;
1744  
      }
1745  
      c = c.getSuperclass();
1746  
    }
1747  
    return null;
1748  
  }
1749  
1750  
  static Method callOpt_findMethod(Object o, String method, Object[] args, boolean debug) {
1751  
    Class c = o.getClass();
1752  
    while (c != null) {
1753  
      for (Method m : c.getDeclaredMethods()) {
1754  
        if (debug)
1755  
          System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
1756  
        if (m.getName().equals(method) && callOpt_checkArgs(m, args, debug))
1757  
          return m;
1758  
      }
1759  
      c = c.getSuperclass();
1760  
    }
1761  
    return null;
1762  
  }
1763  
1764  
  private static boolean callOpt_checkArgs(Method m, Object[] args, boolean debug) {
1765  
    Class<?>[] types = m.getParameterTypes();
1766  
    if (types.length != args.length) {
1767  
      if (debug)
1768  
        System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
1769  
      return false;
1770  
    }
1771  
    for (int i = 0; i < types.length; i++)
1772  
      if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
1773  
        if (debug)
1774  
          System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
1775  
        return false;
1776  
      }
1777  
    return true;
1778  
  }
1779  
1780  
1781  
static <A, B> Collection<B> values(Map<A, B> map) {
1782  
  return map.values();
1783  
}
1784  
1785  
static JFrame getFrame(Object o) {
1786  
  if (!(o instanceof Component)) return null;
1787  
  Component c = (Component) o;
1788  
  while (c != null) {
1789  
    if (c instanceof JFrame) return (JFrame) c;
1790  
    c = c.getParent();
1791  
  }
1792  
  return null;
1793  
}
1794  
static JPanel centerAndSouth(Component c, Component s) {
1795  
  JPanel panel = new JPanel(new BorderLayout);
1796  
  panel.add(BorderLayout.CENTER, wrap(c));
1797  
  panel.add(BorderLayout.SOUTH, wrap(s));
1798  
  return panel;
1799  
}
1800  
static JTable dataToTable_uneditable(final JTable table, final Object data) {
1801  
  swingNowOrLater(r {
1802  
    dataToTable(table, data, true);
1803  
    makeTableUneditable(table);
1804  
  });
1805  
  return table;
1806  
}
1807  
1808  
static <A, B> Map<A, B> mapPlus(Map<A, B> m, Object... data) {
1809  
  m = cloneTreeMap(m);
1810  
  litmap_impl(m, data);
1811  
  return m;
1812  
}
1813  
  public static String fromLines(List<String> lines) {
1814  
    StringBuilder buf = new StringBuilder();
1815  
    if (lines != null)
1816  
      for (String line : lines)
1817  
        buf.append(line).append('\n');
1818  
    return buf.toString();
1819  
  }
1820  
static void logQuoted(String logFile, String line) {
1821  
  logQuoted(getProgramFile(logFile), line);
1822  
}
1823  
1824  
static void logQuoted(File logFile, String line) {
1825  
  appendToFile(logFile, quote(line) + "\n");
1826  
}
1827  
static String substring(String s, int x) {
1828  
  return safeSubstring(s, x);
1829  
}
1830  
1831  
static String substring(String s, int x, int y) {
1832  
  return safeSubstring(s, x, y);
1833  
}
1834  
static <A> List<A> synchroList() {
1835  
  return Collections.synchronizedList(new ArrayList<A>());
1836  
}
1837  
1838  
static <A> List<A> synchroList(List<A> l) {
1839  
  return Collections.synchronizedList(l);
1840  
}
1841  
1842  
static long now_virtualTime;
1843  
static long now() {
1844  
  return now_virtualTime != 0 ? now_virtualTime : System.currentTimeMillis();
1845  
}
1846  
1847  
static void systemCommands(String s) {
1848  
  postSystemMessage(systemCommands_impl(s));
1849  
}
1850  
1851  
static String systemCommands_impl(String s) {
1852  
  new Matches m;
1853  
  
1854  
  // SYSTEM COMMANDS
1855  
  
1856  
  if (matchOneOf(s, m, "start program *", "start *")
1857  
    && isSnippetID(m.unq(0))) {
1858  
    String progID = m.fsi(0);
1859  
    String title = getSnippetTitle(progID);
1860  
    // TODO: Show author!
1861  
    String msg = "Run program " + progID + " - " + title + "?";
1862  
    if (confirmOKCancel(frame, msg)) {
1863  
      postSystemMessage("Starting program " + progID + " - " + quote(title));
1864  
      nohupJavax(progID);
1865  
    } else
1866  
      postSystemMessage("Program start cancelled by user (was: " + progID + ")");
1867  
  }
1868  
  
1869  
  if (matchOneOf(s, m, "hotwire *", "hotwire * with argument *")) {
1870  
    String progID = m.fsi(0), arg = unnull(m.unq(1));
1871  
    String title = getSnippetTitle(progID);
1872  
    
1873  
    String msg = "Hotwire & run program " + progID + " - " + quote(title) + (empty(arg) ? "" : " with argument " + quote(arg)) + "?";
1874  
    if (confirmOKCancel(frame, msg)) {
1875  
      postSystemMessage("Hotwiring & running program " + progID + " - " + quote(title) + (empty(arg) ? "" : " with argument " + quote(arg)));
1876  
      run(progID, arg);
1877  
    } else
1878  
      postSystemMessage("Program start cancelled by user (was: " + progID + ")");
1879  
  }
1880  
  
1881  
  if (matchOneOf(s, "jfresh", "fresh")) {
1882  
    return veryQuickJava_refresh() ? "OK, translator dropped." : "Nothing to do";
1883  
  }
1884  
  
1885  
  if (startsWithOneOf(s, "java ", "j ")) {
1886  
    String code = onlyAfter(s, ' ');
1887  
    return systemCommands_evalJava(code);
1888  
  }
1889  
  
1890  
  if (startsWith(s, "jfresh ")) {
1891  
    veryQuickJava_refresh();
1892  
    String code = dropPrefix("jfresh", s);
1893  
    return systemCommands_evalJava(code);
1894  
  }
1895  
  
1896  
  if (match("restart", s, m)) {
1897  
    postSystemMessage("Restarting...");
1898  
    restart();
1899  
  }
1900  
  
1901  
  if (match("pop", s, m)) { // pop up last chat line in a window
1902  
    String text = nextToLast(log);
1903  
    if (empty(text))
1904  
      return "Nothing to show";
1905  
    else
1906  
      showText(text);
1907  
  } return null;
1908  
}
1909  
1910  
static Object systemCommands_lastResult;
1911  
1912  
static String systemCommands_evalJava(String code) {
1913  
  code = trim(code);
1914  
  code = tok_addReturn(code);
1915  
  String returnType = containsReturnWithArgument(code) ? "O" : "void";
1916  
  String main = "!include #1003911\n" + // functions for quick eval
1917  
    "static " + returnType + " calc() { " + code + "\n" + "}";
1918  
  Object obj = veryQuickJava(main);
1919  
  long time = now();
1920  
  Object result = callCalc(obj);
1921  
  systemCommands_lastResult = result;
1922  
  time = now()-time;
1923  
  return time + " ms\n" + systemCommands_prettyPrint(result);
1924  
}
1925  
1926  
static String systemCommands_prettyPrint(Object o) {
1927  
  if (o instanceof List)
1928  
    return fromLines(map(new Object { Object get(Object o) { return  systemCommands_prettyPrint(o) ; }
1929  
  public String toString() { return "systemCommands_prettyPrint(o)"; }}, (List) o));
1930  
    
1931  
  if (eq(getClassName(o), "main$Snippet"))
1932  
    return formatSnippetID(getString(o, "id")) + " - " + getString(o, "title");
1933  
    
1934  
  return structureOrText(o);
1935  
}
1936  
static <A> boolean setAdd(Collection<A> c, A a) {
1937  
  if (c.contains(a)) return false;
1938  
  c.add(a);
1939  
  return true;
1940  
}
1941  
  // compile JavaX source, load classes & return main class
1942  
  // src can be a snippet ID or actual source code
1943  
  // TODO: record injection?
1944  
  
1945  
  static Class<?> hotwire(String src) {
1946  
    try {
1947  
      Class j = getJavaX();
1948  
      
1949  
      synchronized(j) { // hopefully this goes well...
1950  
        List<File> libraries = new ArrayList<File>();
1951  
        File srcDir = (File) call(j, "transpileMain", src, libraries);
1952  
        if (srcDir == null)
1953  
          fail("transpileMain returned null (src=" + quote(src) + ")");
1954  
        
1955  
        Object androidContext = get(j, "androidContext");
1956  
        if (androidContext != null)
1957  
          return (Class) call(j, "loadx2android", srcDir, src);
1958  
          
1959  
        File classesDir = (File) call(j, "TempDirMaker_make");
1960  
        String javacOutput = (String) call(j, "compileJava", srcDir, libraries, classesDir);
1961  
        System.out.println(javacOutput);
1962  
        
1963  
        URL[] urls = new URL[libraries.size()+1];
1964  
        urls[0] = classesDir.toURI().toURL();
1965  
        for (int i = 0; i < libraries.size(); i++)
1966  
          urls[i+1] = libraries.get(i).toURI().toURL();
1967  
  
1968  
        // make class loader
1969  
        URLClassLoader classLoader = new URLClassLoader(urls);
1970  
    
1971  
        // load & return main class
1972  
        Class<?> theClass = classLoader.loadClass("main");
1973  
        
1974  
        callOpt(j, "registerSourceCode", theClass, loadTextFile(new File(srcDir, "main.java")));
1975  
1976  
        call(j, "setVars", theClass, isSnippetID(src) ? src: null);
1977  
        
1978  
        if (isSnippetID(src))
1979  
          callOpt(j, "addInstance", src, theClass);
1980  
          
1981  
        if (!_inCore())
1982  
          hotwire_copyOver(theClass);
1983  
  
1984  
        return theClass;
1985  
      }
1986  
    } catch (Exception e) {
1987  
      throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
1988  
    }
1989  
  }
1990  
static File getProgramFile(String progID, String fileName) {
1991  
  return new File(getProgramDir(progID), fileName);
1992  
}
1993  
1994  
static File getProgramFile(String fileName) {
1995  
  return getProgramFile(getProgramID(), fileName);
1996  
}
1997  
1998  
static void saveLocally(String variableName) {
1999  
  saveLocally(programID(), variableName);
2000  
}
2001  
2002  
static void saveLocally(String progID, String variableName) {
2003  
  saveLocally2(mc(), progID, variableName);
2004  
}
2005  
2006  
static void saveLocally2(Object obj, String variableName) {
2007  
  saveLocally2(obj, programID(), variableName);
2008  
}
2009  
2010  
static synchronized void saveLocally2(Object obj, String progID, String variableName) {
2011  
  File textFile = new File(programDir(progID), variableName + ".text");
2012  
  File structureFile = new File(programDir(progID), variableName + ".structure");
2013  
  Object x = get(obj, variableName);
2014  
  
2015  
  if (x == null) {
2016  
    textFile.delete();
2017  
    structureFile.delete();
2018  
  } else if (x instanceof String) {
2019  
    saveTextFile(textFile, (String) x);
2020  
    structureFile.delete();
2021  
  } else {
2022  
    saveTextFile(structureFile, structure(x));
2023  
    textFile.delete();
2024  
  }
2025  
}
2026  
static void swingAfter(JFrame base, int delay, Runnable r) {
2027  
  installTimer((JComponent) base.getContentPane(), r, delay, delay, false);
2028  
}
2029  
2030  
static void swingAfter(JComponent base, int delay, Runnable r) {
2031  
  installTimer(base, r, delay, delay, false);
2032  
}
2033  
static void substance() {
2034  
  substanceLAF();
2035  
}
2036  
2037  
static void substance(String skinName) {
2038  
  substanceLAF(skinName);
2039  
}
2040  
static boolean match(String pat, String s) {
2041  
  return match3(pat, s);
2042  
}
2043  
2044  
static boolean match(String pat, String s, Matches matches) {
2045  
  return match3(pat, s, matches);
2046  
}
2047  
2048  
static boolean nempty(Collection c) {
2049  
  return !isEmpty(c);
2050  
}
2051  
2052  
static boolean nempty(CharSequence s) {
2053  
  return !isEmpty(s);
2054  
}
2055  
2056  
static boolean nempty(Object[] o) {
2057  
  return !isEmpty(o);
2058  
}
2059  
2060  
static boolean eqic(String a, String b) {
2061  
  if ((a == null) != (b == null)) return false;
2062  
  if (a == null) return true;
2063  
  return a.equalsIgnoreCase(b);
2064  
}
2065  
static String chatTime() {
2066  
  return formatInt(month(), 2) + "/" + formatInt(days(), 2) + " " + formatInt(hours(), 2) + ":" + formatInt(minutes(), 2) + ":" + formatInt(seconds(), 2);
2067  
}
2068  
static String getString(Map map, Object key) {
2069  
  return map == null ? null : (String) map.get(key);
2070  
}
2071  
2072  
static String getString(List l, int idx) {
2073  
  return (String) get(l, idx);
2074  
}
2075  
2076  
static String getString(Object o, Object key) {
2077  
  if (o instanceof Map) return getString((Map) o, key);
2078  
  if (key instanceof String)
2079  
    return (String) get(o, (String) key);
2080  
  throw fail("Not a string key: " + getClassName(key));
2081  
}
2082  
static String structure(Object o) {
2083  
  new HashSet refd;
2084  
  return structure_2(structure_1(o, 0, new IdentityHashMap, refd), refd);
2085  
}
2086  
2087  
// leave to false, unless unstructure() breaks
2088  
static boolean structure_allowShortening = false;
2089  
2090  
static String structure_1(Object o, int stringSizeLimit, IdentityHashMap<Object, Integer> seen, HashSet<Integer> refd) {
2091  
  if (o == null) return "null";
2092  
  
2093  
  // these are never back-referenced (for readability)
2094  
  
2095  
  if (o instanceof String)
2096  
    return quote(stringSizeLimit != 0 ? shorten((String) o, stringSizeLimit) : (String) o);
2097  
    
2098  
  if (o instanceof BigInteger)
2099  
    return "bigint(" + o + ")";
2100  
  
2101  
  if (o instanceof Double)
2102  
    return "d(" + quote(str(o)) + ")";
2103  
    
2104  
  if (o instanceof Long)
2105  
    return o + "L";
2106  
  
2107  
  if (o instanceof Integer)
2108  
    return str(o);
2109  
    
2110  
  if (o instanceof Boolean)
2111  
    return ((Boolean) o).booleanValue() ? "t" : "f";
2112  
    
2113  
  if (o instanceof Character)
2114  
    return quoteCharacter((Character) o);
2115  
    
2116  
  if (o instanceof File)
2117  
    return "File " + quote(((File) o).getPath());
2118  
    
2119  
  // referencable objects follow
2120  
  
2121  
  Integer ref = seen.get(o);
2122  
  if (ref != null) {
2123  
    refd.add(ref);
2124  
    return "r" + ref;
2125  
  }
2126  
      
2127  
  ref = seen.size()+1;
2128  
  seen.put(o, ref);
2129  
  String r = "m" + ref + " "; // marker
2130  
2131  
  String name = o.getClass().getName();
2132  
2133  
  StringBuilder buf = new StringBuilder();
2134  
  
2135  
  if (o instanceof HashSet)
2136  
    return r + "hashset " + structure_1(new ArrayList((Set) o), stringSizeLimit, seen, refd);
2137  
2138  
  if (o instanceof TreeSet)
2139  
    return r + "treeset " + structure_1(new ArrayList((Set) o), stringSizeLimit, seen, refd);
2140  
  
2141  
  if (o instanceof Collection) {
2142  
    for (Object x : (Collection) o) {
2143  
      if (buf.length() != 0) buf.append(", ");
2144  
      buf.append(structure_1(x, stringSizeLimit, seen, refd));
2145  
    }
2146  
    return r + "[" + buf + "]";
2147  
  }
2148  
  
2149  
  if (o instanceof Map) {
2150  
    for (Object e : ((Map) o).entrySet()) {
2151  
      if (buf.length() != 0) buf.append(", ");
2152  
      buf.append(structure_1(((Map.Entry) e).getKey(), stringSizeLimit, seen, refd));
2153  
      buf.append("=");
2154  
      buf.append(structure_1(((Map.Entry) e).getValue(), stringSizeLimit, seen, refd));
2155  
    }
2156  
    return r + (o instanceof HashMap ? "hashmap" : "") + "{" + buf + "}";
2157  
  }
2158  
  
2159  
  if (o.getClass().isArray()) {
2160  
    int n = Array.getLength(o);
2161  
    for (int i = 0; i < n; i++) {
2162  
      if (buf.length() != 0) buf.append(", ");
2163  
      buf.append(structure_1(Array.get(o, i), stringSizeLimit, seen, refd));
2164  
    }
2165  
    return r + "array{" + buf + "}";
2166  
  }
2167  
2168  
  if (o instanceof Class)
2169  
    return r + "class(" + quote(((Class) o).getName()) + ")";
2170  
    
2171  
  if (o instanceof Throwable)
2172  
    return r + "exception(" + quote(((Throwable) o).getMessage()) + ")";
2173  
    
2174  
  if (o instanceof BitSet) {
2175  
    BitSet bs = (BitSet) o;
2176  
    for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
2177  
      if (buf.length() != 0) buf.append(", ");
2178  
       buf.append(i);
2179  
    }
2180  
    return "bitset{" + buf + "}";
2181  
  }
2182  
    
2183  
  // Need more cases? This should cover all library classes...
2184  
  if (name.startsWith("java.") || name.startsWith("javax."))
2185  
    return r + String.valueOf(o);
2186  
    
2187  
  String shortName = o.getClass().getName().replaceAll("^main\\$", "");
2188  
  
2189  
  if (shortName.equals("Lisp")) {
2190  
    buf.append("l(" + structure_1(getOpt(o, "head"), stringSizeLimit, seen, refd));
2191  
    List args = (List) ( getOpt(o, "args"));
2192  
    if (nempty(args))
2193  
      for (int i = 0; i < l(args); i++) {
2194  
        buf.append(", ");
2195  
        Object arg = args.get(i);
2196  
        
2197  
        // sweet shortening
2198  
        if (arg != null && eq(arg.getClass().getName(), "main$Lisp") && isTrue(call(arg, "isEmpty")))
2199  
          arg = get(arg, "head");
2200  
          
2201  
        buf.append(structure_1(arg, stringSizeLimit, seen, refd));
2202  
      }
2203  
    buf.append(")");
2204  
    return r + str(buf);
2205  
  }
2206  
    
2207  
  int numFields = 0;
2208  
  String fieldName = "";
2209  
  if (shortName.equals("DynamicObject")) {
2210  
    shortName = (String) get(o, "className");
2211  
    Map<String, Object> fieldValues = (Map) get(o, "fieldValues");
2212  
    
2213  
    for (String _fieldName : fieldValues.keySet()) {
2214  
      fieldName = _fieldName;
2215  
      Object value = fieldValues.get(fieldName);
2216  
      if (value != null) {
2217  
        if (buf.length() != 0) buf.append(", ");
2218  
        buf.append(fieldName + "=" + structure_1(value, stringSizeLimit, seen, refd));
2219  
      }
2220  
      ++numFields;
2221  
   }
2222  
  } else {
2223  
    // regular class
2224  
    
2225  
    Class c = o.getClass();
2226  
    while (c != Object.class) {
2227  
      Field[] fields = c.getDeclaredFields();
2228  
      for (Field field : fields) {
2229  
        if ((field.getModifiers() & Modifier.STATIC) != 0)
2230  
          continue;
2231  
        fieldName = field.getName();
2232  
        
2233  
        // skip outer object reference
2234  
        if (fieldName.indexOf("$") >= 0) continue;
2235  
  
2236  
        Object value;
2237  
        try {
2238  
          field.setAccessible(true);
2239  
          value = field.get(o);
2240  
        } catch (Exception e) {
2241  
          value = "?";
2242  
        }
2243  
        
2244  
        // put special cases here...
2245  
    
2246  
        if (value != null) {
2247  
          if (buf.length() != 0) buf.append(", ");
2248  
          buf.append(fieldName + "=" + structure_1(value, stringSizeLimit, seen, refd));
2249  
        }
2250  
        ++numFields;
2251  
      }
2252  
      c = c.getSuperclass();
2253  
    }
2254  
  }
2255  
  
2256  
  String b = buf.toString();
2257  
  
2258  
  if (numFields == 1 && structure_allowShortening)
2259  
    b = b.replaceAll("^" + fieldName + "=", ""); // drop field name if only one
2260  
  String s = shortName;
2261  
  if (buf.length() != 0)
2262  
    s += "(" + b + ")";
2263  
  return r + s;
2264  
}
2265  
2266  
// drop unused markers
2267  
static String structure_2(String s, HashSet<Integer> refd) {
2268  
  List<String> tok = javaTok(s);
2269  
  new StringBuilder out;
2270  
  for (int i = 1; i < l(tok); i += 2) {
2271  
    String t = tok.get(i);
2272  
    if (t.startsWith("m") && isInteger(t.substring(1))
2273  
      && !refd.contains(parseInt(t.substring(1))))
2274  
      continue;
2275  
    out.append(t).append(tok.get(i+1));
2276  
  }
2277  
  return str(out);
2278  
}
2279  
2280  
// does not store null values
2281  
static Map indexByField(Collection c, String field) {
2282  
  new HashMap map;
2283  
  for (Object a : c) {
2284  
    Object val = getOpt(a, field);
2285  
    if (val != null)
2286  
      map.put(val, a);
2287  
  }
2288  
  return map;
2289  
}
2290  
static volatile new StringBuffer local_log; // not redirected
2291  
static volatile StringBuffer print_log = local_log; // might be redirected, e.g. to main bot
2292  
2293  
// in bytes - will cut to half that
2294  
static volatile int print_log_max = 1024*1024;
2295  
static volatile int local_log_max = 100*1024;
2296  
2297  
static boolean print_silent; // total mute if set
2298  
2299  
static void print() {
2300  
  print("");
2301  
}
2302  
2303  
// slightly overblown signature to return original object...
2304  
static <A> A print(A o) {
2305  
  if (print_silent) return o;
2306  
  String s = String.valueOf(o) + "\n";
2307  
  StringBuffer loc = local_log;
2308  
  StringBuffer buf = print_log;
2309  
  int loc_max = print_log_max;
2310  
  if (buf != loc && buf != null) {
2311  
    print_append(buf, s, print_log_max);
2312  
    loc_max = local_log_max;
2313  
  }
2314  
  if (loc != null) 
2315  
    print_append(loc, s, loc_max);
2316  
  System.out.print(s);
2317  
  return o;
2318  
}
2319  
2320  
static void print(long l) {
2321  
  print(String.valueOf(l));
2322  
}
2323  
2324  
static void print(char c) {
2325  
  print(String.valueOf(c));
2326  
}
2327  
2328  
static void print_append(StringBuffer buf, String s, int max) {
2329  
  synchronized(buf) {
2330  
    buf.append(s);
2331  
    max /= 2;
2332  
    if (buf.length() > max) try {
2333  
      int newLength = max/2;
2334  
      int ofs = buf.length()-newLength;
2335  
      String newString = buf.substring(ofs);
2336  
      buf.setLength(0);
2337  
      buf.append("[...] ").append(newString);
2338  
    } catch (Exception e) {
2339  
      buf.setLength(0);
2340  
    }
2341  
  }
2342  
}
2343  
static void tableColumnMaxWidth(JTable table, int columnIdx, int width) {
2344  
  try {
2345  
    if (inRange(columnIdx, table.getColumnCount()))
2346  
      table.getColumnModel().getColumn(columnIdx).setMaxWidth(width);
2347  
  } catch (Throwable __e) { printStackTrace(__e); }
2348  
}
2349  
static String randomID(int length) {
2350  
  return makeRandomID(length);
2351  
}
2352  
static class ELPost {
2353  
  String text;
2354  
  int suggestionIndex; // Which suggestion was taken?
2355  
  String suggester;
2356  
}
2357  
2358  
static List<ELPost> scanEventLogForPosts(String progID, String dialogName) {
2359  
  return scanEventLogForPosts(getProgramFile(progID, dialogName));
2360  
}
2361  
2362  
// dialogDir can also be the log file
2363  
static List<ELPost> scanEventLogForPosts(File dialogDir) {
2364  
  if (dialogDir == null) return null;
2365  
  List<List> l = scanLog_safeUnstructure(fileFromDir(dialogDir, "event.log"));
2366  
  new List<ELPost> data;
2367  
  for (int i = 0; i < l(l); i++) try {
2368  
    List a = l.get(i), prev = get(l, i-1);
2369  
    if (firstIs(a, "Posting")) {
2370  
      Map map = (Map) ( get(a, 2));
2371  
      String text = getString(map, "Text").trim();
2372  
      if (eq(text, "!delete")) { removeLast(data); continue; }
2373  
      new ELPost post;
2374  
      post.text = text;
2375  
      try {
2376  
        if (prev != null && firstIs(prev, "Suggestion chosen")) {
2377  
          Map m = getMap(prev, 2);
2378  
          String suggestion = getString(m, "Suggestion");
2379  
          if (eq(suggestion, post.text)) {
2380  
            post.suggestionIndex = toInt(get(m, "Row"));
2381  
            post.suggester = getString(m, "Suggester");
2382  
          }
2383  
        }
2384  
      } catch (Throwable __e) { printStackTrace(__e); }
2385  
      data.add(post);
2386  
    }
2387  
  } catch (Throwable __e) { printStackTrace(__e); }
2388  
  return data;
2389  
}
2390  
2391  
2392  
2393  
static boolean startsWithOneOf(String s, String... l) {
2394  
  for (String x : l) if (startsWith(s, x)) return true; return false;
2395  
}
2396  
static Object[] asArray(List l) {
2397  
  return toObjectArray(l);
2398  
}
2399  
2400  
static Object[] asArray(Class type, List l) {
2401  
  return l.toArray((Object[]) Array.newInstance(type, l.size()));
2402  
}
2403  
static JFrame makeFrame() {
2404  
  return makeFrame((Component) null);
2405  
}
2406  
2407  
static JFrame makeFrame(Object content) {
2408  
  return makeFrame(programTitle(), content);
2409  
}
2410  
2411  
static JFrame makeFrame(String title) {
2412  
  return makeFrame(title, null);
2413  
}
2414  
2415  
static JFrame makeFrame(String title, Object content) {
2416  
  return makeFrame(title, content, true);
2417  
}
2418  
2419  
static JFrame makeFrame(String title, Object content, boolean showIt) {
2420  
  JFrame frame = new JFrame(title);
2421  
  if (content != null)
2422  
    frame.getContentPane().add(wrap(content));
2423  
  frame.setBounds(300, 100, 500, 400);
2424  
  if (showIt)
2425  
    frame.setVisible(true);
2426  
  //callOpt(content, "requestFocus");
2427  
  //exitOnFrameClose(frame);
2428  
  
2429  
  // standard right-click behavior on titles
2430  
  if (isSubstanceLAF())
2431  
    onTitleRightClick(frame, new Runnable() { public void run() { try { showConsole(); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
2432  
  return frame;
2433  
}
2434  
static Object callFunction(Object f, Object... args) {
2435  
  if (f == null) return null;
2436  
  if (f instanceof Runnable) {
2437  
    ((Runnable) f).run();
2438  
    return null;
2439  
  } else if (f instanceof String)
2440  
    return call(mc(), (String) f, args);
2441  
  else
2442  
    return call(f, "get", args);
2443  
  //else throw fail("Can't call a " + getClassName(f));
2444  
}
2445  
static <A> ArrayList<A> asList(A[] a) {
2446  
  return new ArrayList<A>(Arrays.asList(a));
2447  
}
2448  
2449  
static ArrayList<Integer> asList(int[] a) {
2450  
  ArrayList<Integer> l = new ArrayList();
2451  
  for (int i : a) l.add(i);
2452  
  return l;
2453  
}
2454  
2455  
static <A> ArrayList<A> asList(Collection<A> s) {
2456  
  return s == null ? new ArrayList() 
2457  
    : s instanceof ArrayList ? (ArrayList) s : new ArrayList(s);
2458  
}
2459  
  static String quote(String s) {
2460  
    if (s == null) return "null";
2461  
    return "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\r", "\\r").replace("\n", "\\n") + "\"";
2462  
  }
2463  
  
2464  
  static String quote(long l) {
2465  
    return quote("" + l);
2466  
  }
2467  
  
2468  
  static String quote(char c) {
2469  
    return quote("" + c);
2470  
  }
2471  
2472  
static <A> A assertNotNull(A a) {
2473  
  assertTrue(a != null);
2474  
  return a;
2475  
}
2476  
2477  
static <A> A assertNotNull(String msg, A a) {
2478  
  assertTrue(msg, a != null);
2479  
  return a;
2480  
}
2481  
static String quoteCharacter(char c) {
2482  
  if (c == '\'') return "'\\''";
2483  
  if (c == '\\') return "'\\\\'";
2484  
  return "'" + c + "'";
2485  
}
2486  
2487  
static boolean isAWTThread() {
2488  
  return SwingUtilities.isEventDispatchThread();
2489  
}
2490  
static void smartAdd(JPanel panel, Object... parts) {
2491  
  for (Object o : parts) {
2492  
    Component c;
2493  
    if (o instanceof String)
2494  
      c = new JLabel((String) o);
2495  
    else
2496  
      c = wrap(o);
2497  
    panel.add(c);
2498  
  }
2499  
}
2500  
static boolean isProperlyQuoted(String s) {
2501  
  return s.length() >= 2
2502  
    && s.startsWith("\"")
2503  
    && s.endsWith("\"")
2504  
    && !s.endsWith("\\\"");
2505  
}
2506  
static String strPreserveNull(Object s) {
2507  
  return s == null ? null : str(s);
2508  
}
2509  
static Point mousePosition() {
2510  
  return MouseInfo.getPointerInfo().getLocation();
2511  
}
2512  
static JMenuBar addMenuBar(JFrame f) {
2513  
  JMenuBar bar = f.getJMenuBar();
2514  
  if (bar == null)
2515  
    f.setJMenuBar(bar = new JMenuBar());
2516  
  return bar;
2517  
}
2518  
static String programID;
2519  
2520  
static String getProgramID() {
2521  
  return nempty(programID) ? formatSnippetID(programID) : "?";
2522  
}
2523  
2524  
// TODO: ask JavaX instead
2525  
static String getProgramID(Class c) {
2526  
  String id = (String) getOpt(c, "programID");
2527  
  if (nempty(id))
2528  
    return formatSnippetID(id);
2529  
  return "?";
2530  
}
2531  
2532  
static String getProgramID(Object o) {
2533  
  return getProgramID(getMainClass(o));
2534  
}
2535  
// replacement for class JavaTok
2536  
// maybe incomplete, might want to add floating point numbers
2537  
// todo also: extended multi-line strings
2538  
2539  
static int javaTok_n, javaTok_elements;
2540  
static boolean javaTok_opt;
2541  
2542  
static List<String> javaTok(String s) {
2543  
  return javaTok(s, null);
2544  
}
2545  
2546  
static List<String> javaTok(String s, List<String> existing) {
2547  
  ++javaTok_n;
2548  
  int nExisting = javaTok_opt && existing != null ? existing.size() : 0;
2549  
  List<String> tok = existing != null ? new ArrayList(nExisting) : new ArrayList();
2550  
  int l = s.length();
2551  
  
2552  
  int i = 0, n = 0;
2553  
  while (i < l) {
2554  
    int j = i;
2555  
    char c; String cc;
2556  
    
2557  
    // scan for whitespace
2558  
    while (j < l) {
2559  
      c = s.charAt(j);
2560  
      cc = s.substring(j, Math.min(j+2, l));
2561  
      if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
2562  
        ++j;
2563  
      else if (cc.equals("/*")) {
2564  
        do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/"));
2565  
        j = Math.min(j+2, l);
2566  
      } else if (cc.equals("//")) {
2567  
        do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0);
2568  
      } else
2569  
        break;
2570  
    }
2571  
    
2572  
    if (n < nExisting && javaTok_isCopyable(existing.get(n), s, i, j))
2573  
      tok.add(existing.get(n));
2574  
    else
2575  
      tok.add(quickSubstring(s, i, j));
2576  
    ++n;
2577  
    i = j;
2578  
    if (i >= l) break;
2579  
    c = s.charAt(i); // cc is not needed in rest of loop body
2580  
    cc = s.substring(i, Math.min(i+2, l));
2581  
2582  
    // scan for non-whitespace
2583  
    if (c == '\'' || c == '"') {
2584  
      char opener = c;
2585  
      ++j;
2586  
      while (j < l) {
2587  
        if (s.charAt(j) == opener || s.charAt(j) == '\n') { // end at \n to not propagate unclosed string literal errors
2588  
          ++j;
2589  
          break;
2590  
        } else if (s.charAt(j) == '\\' && j+1 < l)
2591  
          j += 2;
2592  
        else
2593  
          ++j;
2594  
      }
2595  
    } else if (Character.isJavaIdentifierStart(c))
2596  
      do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || "'".indexOf(s.charAt(j)) >= 0)); // for stuff like "don't"
2597  
    else if (Character.isDigit(c)) {
2598  
      do ++j; while (j < l && Character.isDigit(s.charAt(j)));
2599  
      if (j < l && s.charAt(j) == 'L') ++j; // Long constants like 1L
2600  
    } else if (cc.equals("[[")) {
2601  
      do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]"));
2602  
      j = Math.min(j+2, l);
2603  
    } else if (cc.equals("[=") && i+2 < l && s.charAt(i+2) == '[') {
2604  
      do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]"));
2605  
      j = Math.min(j+3, l);
2606  
    } else
2607  
      ++j;
2608  
2609  
    if (n < nExisting && javaTok_isCopyable(existing.get(n), s, i, j))
2610  
      tok.add(existing.get(n));
2611  
    else
2612  
      tok.add(quickSubstring(s, i, j));
2613  
    ++n;
2614  
    i = j;
2615  
  }
2616  
  
2617  
  if ((tok.size() % 2) == 0) tok.add("");
2618  
  javaTok_elements += tok.size();
2619  
  return tok;
2620  
}
2621  
2622  
static List<String> javaTok(List<String> tok) {
2623  
  return javaTok(join(tok), tok);
2624  
}
2625  
2626  
static boolean javaTok_isCopyable(String t, String s, int i, int j) {
2627  
  return t.length() == j-i
2628  
    && s.regionMatches(i, t, 0, j-i); // << could be left out, but that's brave
2629  
}
2630  
// patterns last so we can use var args
2631  
static boolean matchOneOf(String s, Matches m, String... pats) {
2632  
  for (String pat : pats)
2633  
    if (match(pat, s, m)) return true; return false;
2634  
}
2635  
2636  
static boolean matchOneOf(String s, String... pats) {
2637  
  return matchOneOf(s, null, pats);
2638  
}
2639  
static Object newObject(Class c, Object... args) {
2640  
  return nuObject(c, args);
2641  
}
2642  
2643  
static Object newObject(String className, Object... args) {
2644  
  return nuObject(className, args);
2645  
}
2646  
2647  
// We'd be really fancy if we filtered out return statements in
2648  
// inner blocks.
2649  
static boolean containsReturnWithArgument(String code) {
2650  
  List<String> tok = javaTok(code);
2651  
  for (int i = 1; i+2 < l(tok); i += 2)
2652  
    if (eqOneOf(tok.get(i), "ret", "return") && neq(tok.get(i+2), ";")) return true; return false;
2653  
}
2654  
static String onlyAfter(String s, char c) {
2655  
  int i = s.indexOf(c);
2656  
  return i >= 0 ? s.substring(i+1) : "";
2657  
}
2658  
static Class __javax;
2659  
2660  
static Class getJavaX() {
2661  
  return __javax;
2662  
}
2663  
  static void set(Object o, String field, Object value) {
2664  
    if (o instanceof Class) set((Class) o, field, value);
2665  
    else try {
2666  
      Field f = set_findField(o.getClass(), field);
2667  
      smartSet(f, o, value);
2668  
    } catch (Exception e) {
2669  
      throw new RuntimeException(e);
2670  
    }
2671  
  }
2672  
  
2673  
  static void set(Class c, String field, Object value) {
2674  
    try {
2675  
      Field f = set_findStaticField(c, field);
2676  
      smartSet(f, null, value);
2677  
    } catch (Exception e) {
2678  
      throw new RuntimeException(e);
2679  
    }
2680  
  }
2681  
  
2682  
  static Field set_findField(Class<?> c, String field) {
2683  
    for (Field f : c.getDeclaredFields())
2684  
      if (f.getName().equals(field))
2685  
        return f;
2686  
    throw new RuntimeException("Field '" + field + "' not found in " + c.getName());
2687  
  }
2688  
  
2689  
  static Field set_findStaticField(Class<?> c, String field) {
2690  
    for (Field f : c.getDeclaredFields())
2691  
      if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0)
2692  
        return f;
2693  
    throw new RuntimeException("Static field '" + field + "' not found in " + c.getName());
2694  
  }
2695  
static List collectField(Collection c, String field) {
2696  
  new List l;
2697  
  for (Object a : c)
2698  
    l.add(getOpt(a, field));
2699  
  return l;
2700  
}
2701  
static Throwable getInnerException(Throwable e) {
2702  
  while (e.getCause() != null)
2703  
    e = e.getCause();
2704  
  return e;
2705  
}
2706  
  static Object call(Object o) {
2707  
    return callFunction(o);
2708  
  }
2709  
  
2710  
  // varargs assignment fixer for a single string array argument
2711  
  static Object call(Object o, String method, String[] arg) {
2712  
    return call(o, method, new Object[] {arg});
2713  
  }
2714  
  
2715  
  static Object call(Object o, String method, Object... args) {
2716  
    try {
2717  
      if (o instanceof Class) {
2718  
        Method m = call_findStaticMethod((Class) o, method, args, false);
2719  
        m.setAccessible(true);
2720  
        return m.invoke(null, args);
2721  
      } else {
2722  
        Method m = call_findMethod(o, method, args, false);
2723  
        m.setAccessible(true);
2724  
        return m.invoke(o, args);
2725  
      }
2726  
    } catch (Exception e) {
2727  
      throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
2728  
    }
2729  
  }
2730  
2731  
  static Method call_findStaticMethod(Class c, String method, Object[] args, boolean debug) {
2732  
    Class _c = c;
2733  
    while (c != null) {
2734  
      for (Method m : c.getDeclaredMethods()) {
2735  
        if (debug)
2736  
          System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
2737  
        if (!m.getName().equals(method)) {
2738  
          if (debug) System.out.println("Method name mismatch: " + method);
2739  
          continue;
2740  
        }
2741  
2742  
        if ((m.getModifiers() & Modifier.STATIC) == 0 || !call_checkArgs(m, args, debug))
2743  
          continue;
2744  
2745  
        return m;
2746  
      }
2747  
      c = c.getSuperclass();
2748  
    }
2749  
    throw new RuntimeException("Method '" + method + "' (static) with " + args.length + " parameter(s) not found in " + _c.getName());
2750  
  }
2751  
2752  
  static Method call_findMethod(Object o, String method, Object[] args, boolean debug) {
2753  
    Class c = o.getClass();
2754  
    while (c != null) {
2755  
      for (Method m : c.getDeclaredMethods()) {
2756  
        if (debug)
2757  
          System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
2758  
        if (m.getName().equals(method) && call_checkArgs(m, args, debug))
2759  
          return m;
2760  
      }
2761  
      c = c.getSuperclass();
2762  
    }
2763  
    throw new RuntimeException("Method '" + method + "' (non-static) with " + args.length + " parameter(s) not found in " + o.getClass().getName());
2764  
  }
2765  
2766  
  private static boolean call_checkArgs(Method m, Object[] args, boolean debug) {
2767  
    Class<?>[] types = m.getParameterTypes();
2768  
    if (types.length != args.length) {
2769  
      if (debug)
2770  
        System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
2771  
      return false;
2772  
    }
2773  
    for (int i = 0; i < types.length; i++)
2774  
      if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
2775  
        if (debug)
2776  
          System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
2777  
        return false;
2778  
      }
2779  
    return true;
2780  
  }
2781  
2782  
2783  
static boolean isTrue(Object o) {
2784  
  return booleanValue(o);
2785  
}
2786  
static int days() {
2787  
  return Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
2788  
}
2789  
// c = Component or something implementing swing()
2790  
static Component wrap(Object swingable) {
2791  
  Component c = (Component) ( swingable instanceof Component ? swingable : call(swingable, "swing"));
2792  
  if (c instanceof JTable || c instanceof JList || c instanceof JTextArea)
2793  
    return new JScrollPane(c);
2794  
  return c;
2795  
}
2796  
2797  
static Object callCalc(Object o) {
2798  
  return call(o, "calc");
2799  
}
2800  
static boolean startsWithIgnoreCase(String a, String b) {
2801  
  return a != null && a.regionMatches(true, 0, b, 0, b.length());
2802  
}
2803  
static <A> A nextToLast(List<A> l) {
2804  
  return get(l, l(l)-2);
2805  
}
2806  
  // class Matches is added by #752
2807  
 
2808  
  static boolean match3(String pat, String s) {
2809  
    return match3(pat, s, null);
2810  
  }
2811  
  
2812  
  static boolean match3(String pat, String s, Matches matches) {
2813  
    if (s == null) return false;
2814  
    return match3(pat, parse3(s), matches);
2815  
  }
2816  
    
2817  
  static boolean match3(String pat, List<String> toks, Matches matches) {
2818  
    List<String> tokpat = parse3(pat);
2819  
    return match3(tokpat,toks,matches);
2820  
  }
2821  
2822  
  static boolean match3(List<String> tokpat, List<String> toks, Matches matches) {
2823  
2824  
    String[] m = match2(tokpat, toks);
2825  
    //print(structure(tokpat) + " on " + structure(toks) + " => " + structure(m));
2826  
    if (m == null)
2827  
      return false;
2828  
    else {
2829  
      if (matches != null) matches.m = m;
2830  
      return true;
2831  
    }
2832  
  }
2833  
static Class run(String progID, String... args) {
2834  
  Class main = hotwire(progID);
2835  
  callMain(main, args);
2836  
  return main;
2837  
}
2838  
static boolean isInteger(String s) {
2839  
  return s != null && Pattern.matches("\\-?\\d+", s);
2840  
}
2841  
static String getStackTrace(Throwable throwable) {
2842  
  StringWriter writer = new StringWriter();
2843  
  throwable.printStackTrace(new PrintWriter(writer));
2844  
  return writer.toString();
2845  
}
2846  
static void makeTableUneditable(JTable table) {
2847  
  for (int c = 0; c < table.getColumnCount(); c++) {
2848  
    Class<?> col_class = table.getColumnClass(c);
2849  
    table.setDefaultEditor(col_class, null); // remove editor
2850  
  }
2851  
}
2852  
static File programDir() {
2853  
  return programDir(getProgramID());
2854  
}
2855  
2856  
static File programDir(String snippetID) {
2857  
  return new File(javaxDataDir(), formatSnippetID(snippetID));
2858  
}
2859  
2860  
static String formatSnippetID(String id) {
2861  
  return "#" + parseSnippetID(id);
2862  
}
2863  
2864  
static String formatSnippetID(long id) {
2865  
  return "#" + id;
2866  
}
2867  
// returns true if a translator had been loaded
2868  
static synchronized boolean veryQuickJava_refresh() {
2869  
  if (getOpt(mc(), "transpileRaw_trans") == null) return false;
2870  
  setOpt(mc(), "transpileRaw_trans", null); return true;
2871  
}
2872  
static int month() {
2873  
  return Calendar.getInstance().get(Calendar.MONTH)+1;
2874  
}
2875  
// optionally convert expression to return statement
2876  
static String tok_addReturn(List<String> tok) {
2877  
  String lastToken = get(tok, l(tok)-2);
2878  
  //print("addReturn: " + structure(tok) + ", lastToken: " + quote(lastToken));
2879  
  if (eq(lastToken, "}") || eq(lastToken, ";")) return join(tok);
2880  
  return "ret " + join(tok) + ";";
2881  
}
2882  
2883  
static String tok_addReturn(String s) {
2884  
  return tok_addReturn(javaTok(s));
2885  
}
2886  
public static File mkdirsForFile(File file) {
2887  
  File dir = file.getParentFile();
2888  
  if (dir != null) // is null if file is in current dir
2889  
    dir.mkdirs();
2890  
  return file;
2891  
}
2892  
2893  
static void substanceLAF() {
2894  
  substanceLAF(null);
2895  
}
2896  
2897  
static void substanceLAF(String skinName) {
2898  
  try {
2899  
    if (!substanceLookAndFeelEnabled()) {
2900  
      Object x = hotwire("#1003448");
2901  
      if (skinName != null)
2902  
        set(x, "skinName", skinName);
2903  
      runMain(x);
2904  
      JFrame.setDefaultLookAndFeelDecorated(substanceLookAndFeelEnabled());
2905  
    }
2906  
  } catch (Throwable __e) { printStackTrace(__e); }
2907  
}
2908  
static List emptyList() {
2909  
  return new ArrayList;
2910  
  //ret Collections.emptyList();
2911  
}
2912  
static File fileFromDir(File f, String name) {
2913  
  return f.isDirectory() ? new File(f, name) : f;
2914  
}
2915  
2916  
// first delay = delay
2917  
static void installTimer(JComponent component, Runnable r, int delay) {
2918  
  installTimer(component, r, delay, delay);
2919  
}
2920  
2921  
// first delay = delay
2922  
static void installTimer(JFrame frame, int delay, Runnable r) {
2923  
  installTimer(frame.getRootPane(), r, delay, delay);
2924  
}
2925  
2926  
// first delay = delay
2927  
static void installTimer(JComponent component, int delay, Runnable r) {
2928  
  installTimer(component, r, delay, delay);
2929  
}
2930  
2931  
static void installTimer(final JComponent component, final Runnable r, final int delay, final int firstDelay) {
2932  
  installTimer(component, r, delay, firstDelay, true);
2933  
}
2934  
2935  
static void installTimer(final JComponent component, final Runnable r, final int delay, final int firstDelay, final boolean repeats) {
2936  
  swingLater(new Runnable() { public void run() { try {
2937  
    final Timer timer = new Timer(delay, new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent _evt) {
2938  
      r.run();
2939  
    }});
2940  
    timer.setInitialDelay(firstDelay);
2941  
    timer.setRepeats(repeats);
2942  
    
2943  
    if (component.isShowing())
2944  
      timer.start();
2945  
  
2946  
    component.addAncestorListener(new AncestorListener() {
2947  
      public void ancestorAdded(AncestorEvent event) {
2948  
        timer.start();
2949  
      }
2950  
  
2951  
      public void ancestorRemoved(AncestorEvent event) {
2952  
        timer.stop();
2953  
      }
2954  
  
2955  
      public void ancestorMoved(AncestorEvent event) {
2956  
      }
2957  
    });
2958  
  } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
2959  
}
2960  
2961  
  public static String unquote(String s) {
2962  
    if (s == null) return null;
2963  
    if (s.startsWith("[")) {
2964  
      int i = 1;
2965  
      while (i < s.length() && s.charAt(i) == '=') ++i;
2966  
      if (i < s.length() && s.charAt(i) == '[') {
2967  
        String m = s.substring(1, i);
2968  
        if (s.endsWith("]" + m + "]"))
2969  
          return s.substring(i+1, s.length()-i-1);
2970  
      }
2971  
    }
2972  
    
2973  
    if (s.startsWith("\"") /*&& s.endsWith("\"")*/ && s.length() > 1) {
2974  
      String st = s.substring(1, s.endsWith("\"") ? s.length()-1 : s.length());
2975  
      StringBuilder sb = new StringBuilder(st.length());
2976  
  
2977  
      for (int i = 0; i < st.length(); i++) {
2978  
        char ch = st.charAt(i);
2979  
        if (ch == '\\') {
2980  
          char nextChar = (i == st.length() - 1) ? '\\' : st
2981  
                  .charAt(i + 1);
2982  
          // Octal escape?
2983  
          if (nextChar >= '0' && nextChar <= '7') {
2984  
              String code = "" + nextChar;
2985  
              i++;
2986  
              if ((i < st.length() - 1) && st.charAt(i + 1) >= '0'
2987  
                      && st.charAt(i + 1) <= '7') {
2988  
                  code += st.charAt(i + 1);
2989  
                  i++;
2990  
                  if ((i < st.length() - 1) && st.charAt(i + 1) >= '0'
2991  
                          && st.charAt(i + 1) <= '7') {
2992  
                      code += st.charAt(i + 1);
2993  
                      i++;
2994  
                  }
2995  
              }
2996  
              sb.append((char) Integer.parseInt(code, 8));
2997  
              continue;
2998  
          }
2999  
          switch (nextChar) {
3000  
          case '\\':
3001  
              ch = '\\';
3002  
              break;
3003  
          case 'b':
3004  
              ch = '\b';
3005  
              break;
3006  
          case 'f':
3007  
              ch = '\f';
3008  
              break;
3009  
          case 'n':
3010  
              ch = '\n';
3011  
              break;
3012  
          case 'r':
3013  
              ch = '\r';
3014  
              break;
3015  
          case 't':
3016  
              ch = '\t';
3017  
              break;
3018  
          case '\"':
3019  
              ch = '\"';
3020  
              break;
3021  
          case '\'':
3022  
              ch = '\'';
3023  
              break;
3024  
          // Hex Unicode: u????
3025  
          case 'u':
3026  
              if (i >= st.length() - 5) {
3027  
                  ch = 'u';
3028  
                  break;
3029  
              }
3030  
              int code = Integer.parseInt(
3031  
                      "" + st.charAt(i + 2) + st.charAt(i + 3)
3032  
                              + st.charAt(i + 4) + st.charAt(i + 5), 16);
3033  
              sb.append(Character.toChars(code));
3034  
              i += 5;
3035  
              continue;
3036  
          default:
3037  
            ch = nextChar; // added by Stefan
3038  
          }
3039  
          i++;
3040  
        }
3041  
        sb.append(ch);
3042  
      }
3043  
      return sb.toString();      
3044  
    } else
3045  
      return s; // return original
3046  
  }
3047  
static String programID() {
3048  
  return getProgramID();
3049  
}
3050  
static int hours() {
3051  
  return Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
3052  
}
3053  
static boolean isEmpty(Collection c) {
3054  
  return c == null || c.isEmpty();
3055  
}
3056  
3057  
static boolean isEmpty(CharSequence s) {
3058  
  return s == null || s.length() == 0;
3059  
}
3060  
3061  
static boolean isEmpty(Object[] a) {
3062  
  return a == null || a.length == 0;
3063  
}
3064  
3065  
static boolean isEmpty(Map map) {
3066  
  return map == null || map.isEmpty();
3067  
}
3068  
static String makeRandomID(int length) {
3069  
  Random random = new Random();
3070  
  char[] id = new char[length];
3071  
  for (int i = 0; i < id.length; i++)
3072  
    id[i] = (char) ((int) 'a' + random.nextInt(26));
3073  
  return new String(id);
3074  
}
3075  
static char unquoteCharacter(String s) {
3076  
  assertTrue(s.startsWith("'") && s.length() > 1);
3077  
  return unquote("\"" + s.substring(1, s.endsWith("'") ? s.length()-1 : s.length()) + "\"").charAt(0);
3078  
}
3079  
static int parseInt(String s) {
3080  
  return empty(s) ? 0 : Integer.parseInt(s);
3081  
}
3082  
static String structureOrText(Object o) {
3083  
  return o instanceof String ? (String) o : structure(o);
3084  
}
3085  
  static void setOpt(Object o, String field, Object value) {
3086  
    if (o instanceof Class) setOpt((Class) o, field, value);
3087  
    else try {
3088  
      Field f = setOpt_findField(o.getClass(), field);
3089  
      if (f != null)
3090  
        smartSet(f, o, value);
3091  
    } catch (Exception e) {
3092  
      throw new RuntimeException(e);
3093  
    }
3094  
  }
3095  
  
3096  
  static void setOpt(Class c, String field, Object value) {
3097  
    try {
3098  
      Field f = setOpt_findStaticField(c, field);
3099  
      if (f != null)
3100  
        smartSet(f, null, value);
3101  
    } catch (Exception e) {
3102  
      throw new RuntimeException(e);
3103  
    }
3104  
  }
3105  
  
3106  
  static Field setOpt_findField(Class<?> c, String field) {
3107  
    for (Field f : c.getDeclaredFields())
3108  
      if (f.getName().equals(field))
3109  
        return f;
3110  
    return null;
3111  
  }
3112  
  
3113  
  static Field setOpt_findStaticField(Class<?> c, String field) {
3114  
    for (Field f : c.getDeclaredFields())
3115  
      if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0)
3116  
        return f;
3117  
    return null;
3118  
  }
3119  
static Object getOpt(Object o, String field) {
3120  
  if (o instanceof String) o = getBot ((String) o);
3121  
  if (o == null) return null;
3122  
  if (o instanceof Class) return getOpt((Class) o, field);
3123  
  
3124  
  if (o.getClass().getName().equals("main$DynamicObject"))
3125  
    return ((Map) getOpt_raw(o, "fieldValues")).get(field);
3126  
  
3127  
  if (o instanceof Map) return ((Map) o).get(field);
3128  
  
3129  
  return getOpt_raw(o, field);
3130  
}
3131  
3132  
static Object getOpt_raw(Object o, String field) {
3133  
  try {
3134  
    Field f = getOpt_findField(o.getClass(), field);
3135  
    if (f == null) return null;
3136  
    f.setAccessible(true);
3137  
    return f.get(o);
3138  
  } catch (Exception e) {
3139  
    throw new RuntimeException(e);
3140  
  }
3141  
}
3142  
3143  
static Object getOpt(Class c, String field) {
3144  
  try {
3145  
    if (c == null) return null;
3146  
    Field f = getOpt_findStaticField(c, field);
3147  
    if (f == null) return null;
3148  
    f.setAccessible(true);
3149  
    return f.get(null);
3150  
  } catch (Exception e) {
3151  
    throw new RuntimeException(e);
3152  
  }
3153  
}
3154  
3155  
static Field getOpt_findStaticField(Class<?> c, String field) {
3156  
  Class _c = c;
3157  
  do {
3158  
    for (Field f : _c.getDeclaredFields())
3159  
      if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0)
3160  
        return f;
3161  
    _c = _c.getSuperclass();
3162  
  } while (_c != null);
3163  
  return null;
3164  
}
3165  
3166  
static Field getOpt_findField(Class<?> c, String field) {
3167  
  Class _c = c;
3168  
  do {
3169  
    for (Field f : _c.getDeclaredFields())
3170  
      if (f.getName().equals(field))
3171  
        return f;
3172  
    _c = _c.getSuperclass();
3173  
  } while (_c != null);
3174  
  return null;
3175  
}
3176  
// hopefully covers all cases :)
3177  
static String safeSubstring(String s, int x, int y) {
3178  
  if (s == null) return null;
3179  
  if (x < 0) x = 0;
3180  
  if (x > s.length()) return "";
3181  
  if (y < x) y = x;
3182  
  if (y > s.length()) y = s.length();
3183  
  return s.substring(x, y);
3184  
}
3185  
3186  
static String safeSubstring(String s, int x) {
3187  
  return safeSubstring(s, x, l(s));
3188  
}
3189  
3190  
static int seconds() {
3191  
  return Calendar.getInstance().get(Calendar.SECOND);
3192  
}
3193  
static String shorten(String s, int max) {
3194  
  if (s == null) return "";
3195  
  return s.length() <= max ? s : s.substring(0, Math.min(s.length(), max)) + "...";
3196  
}
3197  
  public static String join(String glue, Iterable<String> strings) {
3198  
    StringBuilder buf = new StringBuilder();
3199  
    Iterator<String> i = strings.iterator();
3200  
    if (i.hasNext()) {
3201  
      buf.append(i.next());
3202  
      while (i.hasNext())
3203  
        buf.append(glue).append(i.next());
3204  
    }
3205  
    return buf.toString();
3206  
  }
3207  
  
3208  
  public static String join(String glue, String[] strings) {
3209  
    return join(glue, Arrays.asList(strings));
3210  
  }
3211  
  
3212  
  public static String join(Iterable<String> strings) {
3213  
    return join("", strings);
3214  
  }
3215  
  
3216  
  public static String join(String[] strings) {
3217  
    return join("", strings);
3218  
  }
3219  
3220  
static String dropPrefix(String prefix, String s) {
3221  
  return s.startsWith(prefix) ? s.substring(l(prefix)) : s;
3222  
}
3223  
  static List<String> codeTokensOnly(List<String> tok) {
3224  
    new List<String> l;
3225  
    for (int i = 1; i < tok.size(); i += 2)
3226  
      l.add(tok.get(i));
3227  
    return l;
3228  
  }
3229  
// currently finds only inner classes of class "main"
3230  
// returns null on not found
3231  
// this is the simple version that is not case-tolerant
3232  
static Class findClass(String name) {
3233  
  try {
3234  
    return Class.forName("main$" + name);
3235  
  } catch (ClassNotFoundException e) {
3236  
    return null;
3237  
  }
3238  
}
3239  
static Object safeUnstructure(String s) {
3240  
  return unstructure(s, true);
3241  
}
3242  
static boolean isJavaIdentifier(String s) {
3243  
  if (s.length() == 0 || !Character.isJavaIdentifierStart(s.charAt(0)))
3244  
    return false;
3245  
  for (int i = 1; i < s.length(); i++)
3246  
    if (!Character.isJavaIdentifierPart(s.charAt(i)))
3247  
      return false;
3248  
  return true;
3249  
}
3250  
static boolean _inCore() {
3251  
  return false;
3252  
}
3253  
  static JTable dataToTable(Object data) {
3254  
    return dataToTable(showTable(), data);
3255  
  }
3256  
  
3257  
  static JTable dataToTable(Object data, String title) {
3258  
    return dataToTable(showTable(title), data);
3259  
  }
3260  
  
3261  
  static JTable dataToTable(JTable table, Object data) {
3262  
    return dataToTable(table, data, false);
3263  
  }
3264  
  
3265  
  static JTable dataToTable(JTable table, Object data, boolean now) {
3266  
    new List<List<String>> rows;
3267  
    new List<String> cols;
3268  
3269  
    if (data instanceof List) {
3270  
      for (Object x : (List) data) try {
3271  
        rows.add(dataToTable_makeRow(x, cols));
3272  
      } catch (Throwable __e) { printStackTrace(__e); }
3273  
    } else if (data instanceof Map) {
3274  
      Map map = (Map) ( data);
3275  
      for (Object key : map.keySet()) {
3276  
        Object value = map.get(key);
3277  
        rows.add(litlist(structureOrText(key), structureOrText(value)));
3278  
      }
3279  
    } else
3280  
      print("Unknown data type: " + data);
3281  
3282  
    if (now)
3283  
      table.setModel(fillTableWithStrings_makeModel(rows, toStringArray(cols)));
3284  
    else
3285  
      fillTableWithStrings(table, rows, cols);
3286  
    return table;
3287  
  }
3288  
3289  
static Rectangle boundsOnScreen(Component c) {
3290  
  if (c.getParent() instanceof JViewport
3291  
    && c.getParent().getParent() instanceof JScrollPane)
3292  
    c = c.getParent().getParent();
3293  
  return new Rectangle(c.getLocationOnScreen(), c.getSize());
3294  
}
3295  
static <A> ArrayList<A> litlist(A... a) {
3296  
  return new ArrayList<A>(Arrays.asList(a));
3297  
}
3298  
static boolean isLongConstant(String s) {
3299  
  if (!s.endsWith("L")) return false;
3300  
  s = s.substring(0, l(s)-1);
3301  
  return isInteger(s);
3302  
}
3303  
static List<String> toLines(File f) {
3304  
  return toLines(loadTextFile(f));
3305  
}
3306  
3307  
  public static List<String> toLines(String s) {
3308  
    List<String> lines = new ArrayList<String>();
3309  
    if (s == null) return lines;
3310  
    int start = 0;
3311  
    while (true) {
3312  
      int i = toLines_nextLineBreak(s, start);
3313  
      if (i < 0) {
3314  
        if (s.length() > start) lines.add(s.substring(start));
3315  
        break;
3316  
      }
3317  
3318  
      lines.add(s.substring(start, i));
3319  
      if (s.charAt(i) == '\r' && i+1 < s.length() && s.charAt(i+1) == '\n')
3320  
        i += 2;
3321  
      else
3322  
        ++i;
3323  
3324  
      start = i;
3325  
    }
3326  
    return lines;
3327  
  }
3328  
3329  
  private static int toLines_nextLineBreak(String s, int start) {
3330  
    for (int i = start; i < s.length(); i++) {
3331  
      char c = s.charAt(i);
3332  
      if (c == '\r' || c == '\n')
3333  
        return i;
3334  
    }
3335  
    return -1;
3336  
  }
3337  
static void nohupJavax(String javaxargs) {
3338  
  nohupJavax(javaxargs, "");
3339  
}
3340  
3341  
// vm args are ignored if pre-spun VM found...
3342  
static void nohupJavax(String javaxargs, String vmArgs) {
3343  
  javaxargs = javaxargs.trim();
3344  
  if (javaxargs.startsWith("#")) javaxargs = javaxargs.substring(1);
3345  
  String snippetID = javaTok(javaxargs).get(1);
3346  
  int idx = javaxargs.indexOf(' ');
3347  
  String args = idx < 0 ? "" : javaxargs.substring(idx+1).trim();
3348  
  
3349  
  String line;
3350  
  if (args.length() != 0)
3351  
    line = format3("please start program * with arguments *", snippetID, args);
3352  
  else
3353  
    line = format3("please start program *", snippetID);
3354  
  String answer = sendToLocalBotOpt("A pre-spun VM.", line);
3355  
  if (match3("ok", answer)) {
3356  
    print("OK, used pre-spun VM.");
3357  
  } else {
3358  
    if (answer != null)
3359  
      print("> " + answer);
3360  
    print("Using standard nohup.");
3361  
    classicNohupJavax(javaxargs, vmArgs);
3362  
  }
3363  
}
3364  
static String autoFrameTitle() {
3365  
  return getProgramTitle();
3366  
}
3367  
static List map(Object f, List l) {
3368  
  new List x;
3369  
  Object mc = mc();
3370  
  for (Object o : unnull(l))
3371  
    x.add(callFunction(f, o));
3372  
  return x;
3373  
}
3374  
static WeakReference<Class> creator_class;
3375  
3376  
static Class creator() {
3377  
  return creator_class == null ? null : creator_class.get();
3378  
}
3379  
static void fillJMenu(JMenu m, Object... x) {
3380  
  if (x == null) return;
3381  
  for (int i = 0; i < l(x); i++) {
3382  
    Object o = x[i], y = get(x, i+1);
3383  
    if (eqOneOf(o, "***", "---", "===", ""))
3384  
      m.addSeparator();
3385  
    else if (o instanceof String && y instanceof Runnable) {
3386  
      m.add(jmenuItem((String) o, (Runnable) y));
3387  
      ++i;
3388  
    } else if (o instanceof JMenuItem)
3389  
      m.add((JMenuItem) o); // "call" might use wrong method
3390  
    else if (o instanceof String || o instanceof Action || o instanceof Component)
3391  
      call(m, "add", o);
3392  
    else
3393  
      print("Unknown menu item: " + o);
3394  
  }
3395  
}
3396  
static int max(int a, int b) {
3397  
  return Math.max(a, b);
3398  
}
3399  
3400  
static long max(int a, long b) {
3401  
  return Math.max((long) a, b);
3402  
}
3403  
3404  
static long max(long a, long b) {
3405  
  return Math.max(a, b);
3406  
}
3407  
3408  
static double max(int a, double b) {
3409  
  return Math.max((double) a, b);
3410  
}
3411  
3412  
static int max(Collection<Integer> c) {
3413  
  int x = Integer.MIN_VALUE;
3414  
  for (int i : c) x = max(x, i);
3415  
  return x;
3416  
}
3417  
3418  
static double max(double[] c) {
3419  
  if (c.length == 0) return Double.MIN_VALUE;
3420  
  double x = c[0];
3421  
  for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]);
3422  
  return x;
3423  
}
3424  
3425  
static byte max(byte[] c) {
3426  
  byte x = -128;
3427  
  for (byte d : c) if (d > x) x = d;
3428  
  return x;
3429  
}
3430  
static void restart() {
3431  
  nohupJavax(programID());
3432  
  System.exit(0);
3433  
}
3434  
static File getProgramDir() {
3435  
  return programDir();
3436  
}
3437  
3438  
static File getProgramDir(String snippetID) {
3439  
  return programDir(snippetID);
3440  
}
3441  
static Object quickExport(Object o, Object dest) { try {
3442  
 
3443  
  return quickExport_impl(o, dest, new IdentityHashMap);
3444  
3445  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
3446  
3447  
static Object quickExport_impl(Object o, Object dest, IdentityHashMap seen) { try {
3448  
 
3449  
  if (o == null || o instanceof String || o instanceof Number) return o;
3450  
  
3451  
  Object oo = seen.get(o);
3452  
  if (oo != null) return oo;
3453  
  
3454  
  if (o instanceof List) {
3455  
    List l = (List) ( o);
3456  
    List destO = new ArrayList(l.size());
3457  
    seen.put(o, destO); 
3458  
    for (int i = 0; i < l.size(); i++)
3459  
      destO.add(quickExport_impl(l.get(i), dest, seen));
3460  
    return destO;
3461  
  }
3462  
  
3463  
  if (o instanceof Map) {
3464  
    Map m = (Map) ( o);
3465  
    Map destO = new HashMap();
3466  
    seen.put(o, destO);
3467  
    for (Object e : ((Map) o).entrySet())
3468  
      destO.put(
3469  
        quickExport_impl(((Map.Entry) e).getKey(), dest, seen),
3470  
        quickExport_impl(((Map.Entry) e).getValue(), dest, seen));
3471  
    return destO;
3472  
  }
3473  
  
3474  
  String className = o.getClass().getName();
3475  
  if (className.startsWith("main$") && !isAnonymousClassName(className)) {
3476  
    Class destClass = getClass(dest, className);
3477  
    //print(o.getClass() + " => " + destClass);
3478  
    
3479  
    if (o.getClass() == destClass)
3480  
      return o; // no export necessary
3481  
      
3482  
    // actually make a new object, copy fields
3483  
    
3484  
    Object destO = nuObject(destClass);
3485  
    seen.put(o, destO);
3486  
    
3487  
    // TODO: superclasses
3488  
    Field[] fields = o.getClass().getDeclaredFields();
3489  
    for (Field field : fields) {
3490  
      if ((field.getModifiers() & Modifier.STATIC) != 0)
3491  
        continue;
3492  
      field.setAccessible(true);
3493  
      Object value = field.get(o);
3494  
      setOpt(destO, field.getName(), quickExport_impl(value, dest, seen));
3495  
    }
3496  
    
3497  
    return destO;
3498  
  }
3499  
  
3500  
  // assume it's a shared library object
3501  
  return o;
3502  
3503  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
3504  
static long parseLong(String s) {
3505  
  if (s == null) return 0;
3506  
  return Long.parseLong(dropSuffix("L", s));
3507  
}
3508  
3509  
static long parseLong(Object s) {
3510  
  return Long.parseLong((String) s);
3511  
}
3512  
static JTextArea newTypeWriterTextArea() {
3513  
  new JTextArea textArea;
3514  
  textArea.setFont(typeWriterFont());
3515  
  return textArea;
3516  
}
3517  
3518  
static JTextArea newTypeWriterTextArea(String text) {
3519  
  JTextArea textArea = newTypeWriterTextArea();
3520  
  textArea.setText(text);
3521  
  return textArea;
3522  
}
3523  
static String getSnippetTitle(String id) { try {
3524  
 
3525  
  if (!isSnippetID(id)) return "?";
3526  
  return loadPageSilently(new URL("http://tinybrain.de:8080/tb-int/getfield.php?id=" + parseSnippetID(id) + "&field=title"));
3527  
3528  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
3529  
static String formatInt(int i, int digits) {
3530  
  return padLeft(str(i), '0', digits);
3531  
}
3532  
3533  
static void hotwire_copyOver(Class c) {
3534  
  synchronized(StringBuffer.class) {
3535  
    for (String field : litlist("print_log", "print_silent")) {
3536  
      Object o = get(mc(), field);
3537  
      if (o != null)
3538  
        setOpt(c, field, o);
3539  
    }
3540  
      
3541  
    Object mainBot = getMainBot();
3542  
    if (mainBot != null)
3543  
      setOpt(c, "mainBot", mainBot);
3544  
3545  
    setOpt(c, "creator_class", new WeakReference(mc()));
3546  
  }
3547  
}
3548  
static Class mc() {
3549  
  return getMainClass();
3550  
}
3551  
// extended over Class.isInstance() to handle primitive types
3552  
static boolean isInstanceX(Class type, Object arg) {
3553  
  if (type == boolean.class) return arg instanceof Boolean;
3554  
  if (type == int.class) return arg instanceof Integer;
3555  
  if (type == long.class) return arg instanceof Long;
3556  
  if (type == float.class) return arg instanceof Float;
3557  
  if (type == short.class) return arg instanceof Short;
3558  
  if (type == char.class) return arg instanceof Character;
3559  
  if (type == byte.class) return arg instanceof Byte;
3560  
  if (type == double.class) return arg instanceof Double;
3561  
  return type.isInstance(arg);
3562  
}
3563  
static int minutes() {
3564  
  return Calendar.getInstance().get(Calendar.MINUTE);
3565  
}
3566  
  static <A> List<A> concatLists(List<A>... lists) {
3567  
    new List<A> l;
3568  
    for (List<A> list : lists)
3569  
      if (list != null)
3570  
        l.addAll(list);
3571  
    return l;
3572  
  }
3573  
3574  
  static <A> List<A> concatLists(Collection<List<A>> lists) {
3575  
    new List<A> l;
3576  
    for (List<A> list : lists)
3577  
      if (list != null)
3578  
        l.addAll(list);
3579  
    return l;
3580  
  }
3581  
3582  
static Object nuObject(String className, Object... args) { try {
3583  
 
3584  
  return nuObject(Class.forName(className), args);
3585  
3586  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
3587  
3588  
static Object nuObject(Object realm, String className, Object... args) {
3589  
  return nuObject(_getClass(realm, className), args);
3590  
}
3591  
3592  
static <A> A nuObject(Class<A> c, Object... args) { try {
3593  
 
3594  
  Constructor m = nuObject_findConstructor(c, args);
3595  
  m.setAccessible(true);
3596  
  return (A) m.newInstance(args);
3597  
3598  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
3599  
3600  
static Constructor nuObject_findConstructor(Class c, Object... args) {
3601  
  for (Constructor m : c.getDeclaredConstructors()) {
3602  
    if (!nuObject_checkArgs(m.getParameterTypes(), args, false))
3603  
      continue;
3604  
    return m;
3605  
  }
3606  
  throw new RuntimeException("Constructor with " + args.length + " matching parameter(s) not found in " + c.getName());
3607  
}
3608  
3609  
 static boolean nuObject_checkArgs(Class[] types, Object[] args, boolean debug) {
3610  
    if (types.length != args.length) {
3611  
      if (debug)
3612  
        System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
3613  
      return false;
3614  
    }
3615  
    for (int i = 0; i < types.length; i++)
3616  
      if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
3617  
        if (debug)
3618  
          System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
3619  
        return false;
3620  
      }
3621  
    return true;
3622  
  }
3623  
static String getClassName(Object o) {
3624  
  return o == null ? "null" : o.getClass().getName();
3625  
}
3626  
static boolean confirmOKCancel(final Component owner, final String msg) {
3627  
  return isTrue(swingAndWait(new Object { Object get() { return 
3628  
    JOptionPane.showConfirmDialog(owner,
3629  
      msg, "JavaX", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION
3630  
  ; }
3631  
  public String toString() { return "JOptionPane.showConfirmDialog(owner,\r\n      msg, \"JavaX\", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION"; }}));
3632  
}
3633  
static AbstractAction abstractAction(String name, final Runnable r) {
3634  
  return new AbstractAction(name) {
3635  
    public void actionPerformed(ActionEvent evt) {
3636  
      r.run();
3637  
    }
3638  
  };
3639  
}
3640  
static boolean inRange(int x, int n) {
3641  
  return x >= 0 && x < n;
3642  
}
3643  
static double parseDouble(String s) {
3644  
  return Double.parseDouble(s);
3645  
}
3646  
public static long parseSnippetID(String snippetID) {
3647  
  long id = Long.parseLong(shortenSnippetID(snippetID));
3648  
  if (id == 0) fail("0 is not a snippet ID");
3649  
  return id;
3650  
}
3651  
static <A, B> Map<A, B> cloneTreeMap(Map<A, B> map) {
3652  
  // assume mutex is equal to collection, which will be true unless you explicitly pass a mutex to synchronizedList() which no one ever does.
3653  
  if (map == null) return new TreeMap;
3654  
  else synchronized(map) {
3655  
    return new TreeMap(map);
3656  
  }
3657  
}
3658  
static ImageIcon imageIcon(String imageID) { try {
3659  
 
3660  
  return new ImageIcon(loadLibrary(imageID).toURI().toURL());
3661  
3662  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
3663  
static int toInt(Object o) {
3664  
  if (o == null) return 0;
3665  
  if (o instanceof Number)
3666  
    return ((Number) o).intValue();
3667  
  if (o instanceof String)
3668  
    return parseInt((String) o);
3669  
  throw fail("woot not int: " + getClassName(o));
3670  
}
3671  
  public static String loadTextFile(String fileName) {
3672  
    try {
3673  
      return loadTextFile(fileName, null);
3674  
    } catch (IOException e) {
3675  
      throw new RuntimeException(e);
3676  
    }
3677  
  }
3678  
  
3679  
  public static String loadTextFile(String fileName, String defaultContents) throws IOException {
3680  
    if (!new File(fileName).exists())
3681  
      return defaultContents;
3682  
3683  
    FileInputStream fileInputStream = new FileInputStream(fileName);
3684  
    InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
3685  
    return loadTextFile(inputStreamReader);
3686  
  }
3687  
  
3688  
  public static String loadTextFile(File fileName) {
3689  
    try {
3690  
      return loadTextFile(fileName, null);
3691  
    } catch (IOException e) {
3692  
      throw new RuntimeException(e);
3693  
    }
3694  
  }
3695  
3696  
  public static String loadTextFile(File fileName, String defaultContents) throws IOException {
3697  
    try {
3698  
      return loadTextFile(fileName.getPath(), defaultContents);
3699  
    } catch (IOException e) {
3700  
      throw new RuntimeException(e);
3701  
    }
3702  
  }
3703  
  
3704  
  public static String loadTextFile(Reader reader) throws IOException {
3705  
    StringBuilder builder = new StringBuilder();
3706  
    try {
3707  
      char[] buffer = new char[1024];
3708  
      int n;
3709  
      while (-1 != (n = reader.read(buffer)))
3710  
        builder.append(buffer, 0, n);
3711  
        
3712  
    } finally {
3713  
      reader.close();
3714  
    }
3715  
    return builder.toString();
3716  
  }
3717  
// mainJava is a complete program, but without the !752/!759 at the top
3718  
// returns link to main class
3719  
static Class veryQuickJava(String mainJava) {
3720  
  return veryQuickJava2(mainJava); // It's just better.
3721  
}
3722  
static boolean startsWith(String a, String b) {
3723  
  return a != null && a.startsWith(b);
3724  
}
3725  
3726  
static boolean startsWith(List a, List b) {
3727  
  if (a == null || l(b) > l(a)) return false;
3728  
  for (int i = 0; i < l(b); i++)
3729  
    if (neq(a.get(i), b.get(i)))
3730  
      return false;
3731  
  return true;
3732  
}
3733  
3734  
3735  
static void onTitleRightClick(final JFrame frame, final Runnable r) {
3736  
  swingLater(new Runnable() { public void run() { try {
3737  
    if (!isSubstanceLAF())
3738  
      print("Can't add title right click!");
3739  
    else {
3740  
      JComponent titleBar = getTitlePaneComponent(frame);
3741  
      titleBar.addMouseListener(new MouseAdapter() {
3742  
        public void mousePressed(MouseEvent evt) {
3743  
          if (evt.getButton() != MouseEvent.BUTTON1)
3744  
            r.run();
3745  
        }
3746  
      });
3747  
    }
3748  
  } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
3749  
}
3750  
static Font typeWriterFont() {
3751  
  return new Font("Courier", Font.PLAIN, 14);
3752  
}
3753  
static String shortenSnippetID(String snippetID) {
3754  
  if (snippetID.startsWith("#"))
3755  
    snippetID = snippetID.substring(1);
3756  
  String httpBlaBla = "http://tinybrain.de/";
3757  
  if (snippetID.startsWith(httpBlaBla))
3758  
    snippetID = snippetID.substring(httpBlaBla.length());
3759  
  return "" + parseLong(snippetID);
3760  
}
3761  
static String quickSubstring(String s, int i, int j) {
3762  
  if (i == j) return "";
3763  
  return s.substring(i, j);
3764  
}
3765  
static void showConsole() {
3766  
  JFrame frame = consoleFrame();
3767  
  if (frame != null)
3768  
    frame.setVisible(true);
3769  
}
3770  
static Object mainBot;
3771  
3772  
static Object getMainBot() {
3773  
  return mainBot;
3774  
}
3775  
static Class getMainClass() { try {
3776  
 
3777  
  return Class.forName("main");
3778  
3779  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
3780  
3781  
static Class getMainClass(Object o) { try {
3782  
 
3783  
  return (o instanceof Class ? (Class) o : o.getClass()).getClassLoader().loadClass("main");
3784  
3785  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
3786  
static String[] toStringArray(List<String> list) {
3787  
  return list.toArray(new String[list.size()]);
3788  
}
3789  
3790  
static String[] toStringArray(Object o) {
3791  
  if (o instanceof String[])
3792  
    return (String[]) o;
3793  
  else if (o instanceof List)
3794  
    return toStringArray((List<String>) o);
3795  
  else
3796  
    throw fail("Not a list or array: " + structure(o));
3797  
}
3798  
3799  
static boolean isAnonymousClassName(String s) {
3800  
  for (int i = 0; i < l(s)-1; i++)
3801  
    if (s.charAt(i) == '$' && Character.isDigit(s.charAt(i+1))) return true; return false;
3802  
}
3803  
// match2 matches multiple "*" (matches a single token) wildcards and zero or one "..." wildcards (matches multiple tokens)
3804  
3805  
static String[] match2(List<String> pat, List<String> tok) {
3806  
  // standard case (no ...)
3807  
  int i = pat.indexOf("...");
3808  
  if (i < 0) return match2_match(pat, tok);
3809  
  
3810  
  pat = new ArrayList<String>(pat); // We're modifying it, so copy first
3811  
  pat.set(i, "*");
3812  
  while (pat.size() < tok.size()) {
3813  
    pat.add(i, "*");
3814  
    pat.add(i+1, ""); // doesn't matter
3815  
  }
3816  
  
3817  
  return match2_match(pat, tok);
3818  
}
3819  
3820  
static String[] match2_match(List<String> pat, List<String> tok) {
3821  
  List<String> result = new ArrayList<String>();
3822  
  if (pat.size() != tok.size()) {
3823  
    /*if (debug)
3824  
      print("Size mismatch: " + structure(pat) + " vs " + structure(tok));*/
3825  
    return null;
3826  
  }
3827  
  for (int i = 1; i < pat.size(); i += 2) {
3828  
    String p = pat.get(i), t = tok.get(i);
3829  
    /*if (debug)
3830  
      print("Checking " + p + " against " + t);*/
3831  
    if (eq(p, "*"))
3832  
      result.add(t);
3833  
    else if (!equalsIgnoreCase(unquote(p), unquote(t))) // bold change - match quoted and unquoted now
3834  
      return null;
3835  
  }
3836  
  return result.toArray(new String[result.size()]);
3837  
}
3838  
3839  
  static String format3(String pat, Object... args) {
3840  
    if (args.length == 0) return pat;
3841  
    
3842  
    List<String> tok = javaTokPlusPeriod(pat);
3843  
    int argidx = 0;
3844  
    for (int i = 1; i < tok.size(); i += 2)
3845  
      if (tok.get(i).equals("*"))
3846  
        tok.set(i, format3_formatArg(argidx < args.length ? args[argidx++] : "null"));
3847  
    return join(tok);
3848  
  }
3849  
  
3850  
  static String format3_formatArg(Object arg) {
3851  
    if (arg == null) return "null";
3852  
    if (arg instanceof String) {
3853  
      String s = (String) arg;
3854  
      return isIdentifier(s) || isNonNegativeInteger(s) ? s : quote(s);
3855  
    }
3856  
    if (arg instanceof Integer || arg instanceof Long) return String.valueOf(arg);
3857  
    return quote(structure(arg));
3858  
  }
3859  
  
3860  
3861  
static void callMain(Object c, String... args) {
3862  
  callOpt(c, "main", new Object[] {args});
3863  
}
3864  
static Class<?> _getClass(String name) {
3865  
  try {
3866  
    return Class.forName(name);
3867  
  } catch (ClassNotFoundException e) {
3868  
    return null;
3869  
  }
3870  
}
3871  
3872  
static Class _getClass(Object o) {
3873  
  return o instanceof Class ? (Class) o : o.getClass();
3874  
}
3875  
3876  
static Class _getClass(Object realm, String name) { try {
3877  
 
3878  
  return getClass(realm).getClassLoader().loadClass(classNameToVM(name));
3879  
3880  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
3881  
  static void dataToTable_dynSet(List<String> l, int i, String s) {
3882  
    while (i >= l.size()) l.add("");
3883  
    l.set(i, s);
3884  
  }
3885  
  
3886  
  static List<String> dataToTable_makeRow(Object x, List<String> cols) {
3887  
    if (instanceOf(x, "DynamicObject"))
3888  
      x = get_raw(x, "fieldValues");
3889  
3890  
    if (x instanceof Map) {
3891  
      Map m = (Map) ( x);
3892  
      new List<String> row;
3893  
      for (Object _field : m.keySet()) {
3894  
        String field = (String) ( _field);
3895  
        Object value = m.get(field);
3896  
        int col = cols.indexOf(field);
3897  
        if (col < 0) {
3898  
          cols.add(field);
3899  
          col = cols.size()-1;
3900  
        }
3901  
        dataToTable_dynSet(row, col, structureOrText(value));
3902  
      }
3903  
      return row;
3904  
    }
3905  
    
3906  
    return litlist(structureOrText(x));
3907  
  }
3908  
static String getProgramTitle() {
3909  
  return getProgramName();
3910  
}
3911  
static void runMain(Object c, String... args) {
3912  
  callMain(c, args);
3913  
}
3914  
static String padLeft(String s, char c, int n) {
3915  
  return rep(c, n-l(s)) + s;
3916  
}
3917  
static boolean veryQuickJava_silent = true;
3918  
3919  
// mainJava is a complete program, but without the !752/!759 at the top
3920  
// returns link to main class
3921  
static Class veryQuickJava2(String mainJava) {
3922  
  transpileRaw_silent = veryQuickJava_silent;
3923  
  String src = transpileRaw(mainJava); // transpiled, with lib references
3924  
  new List<String> libs;
3925  
  src = findTranslators2(src, libs);
3926  
  //print("Libs found: " + struct(libs));
3927  
  return hotwireCore(concatLists(ll(javaCompile(src, join(" ", libs))), loadLibraries(libs)));
3928  
}
3929  
static void fillTableWithStrings(final JTable table, List<List<String>> rows, List<String> colNames) {
3930  
  fillTableWithStrings(table, rows, toStringArray(colNames));
3931  
}
3932  
3933  
// thread-safe
3934  
static void fillTableWithStrings(final JTable table, List<List<String>> rows, String... colNames) {
3935  
  final DefaultTableModel model = fillTableWithStrings_makeModel(rows, colNames);
3936  
  
3937  
  swingNowOrLater(r {
3938  
    setTableModel(table, model);
3939  
  });
3940  
}
3941  
3942  
static DefaultTableModel fillTableWithStrings_makeModel(List<List<String>> rows, String... colNames) {
3943  
  Object[][] data = new Object[rows.size()][];
3944  
  int w = 0;
3945  
  for (int i = 0; i < rows.size(); i++) {
3946  
    List<String> l = rows.get(i);
3947  
    Object[] r = new Object[l.size()];
3948  
    for (int j = 0; j < l.size(); j++)
3949  
      r[j] = l.get(j);
3950  
    data[i] = r;
3951  
    w = Math.max(w, l.size());
3952  
  }
3953  
  Object[] columnNames = new Object[w];
3954  
  for (int i = 0; i < w; i++)
3955  
    columnNames[i] = i < l(colNames) ? colNames[i] : "?";
3956  
  return new DefaultTableModel(data, columnNames);
3957  
}
3958  
3959  
static void classicNohupJavax(String javaxargs) {
3960  
  classicNohupJavax(javaxargs, "");
3961  
}
3962  
3963  
static void classicNohupJavax(String javaxargs, String vmArgs) { try {
3964  
 
3965  
  int x = latestInstalledJavaX();
3966  
  File xfile = new File(userHome(), ".javax/x" + Math.max(x, 30) + ".jar");
3967  
  if (!xfile.isFile()) {
3968  
    String url = "http://tinybrain.de/x30.jar";
3969  
    byte[] data = loadBinaryPage(url);
3970  
    if (data.length < 1000000)
3971  
      fail("Could not load " + url);
3972  
    saveBinaryFile(xfile.getPath(), data);
3973  
  }
3974  
  String jarPath = xfile.getPath();
3975  
  if (javaxargs.startsWith("#")) javaxargs = javaxargs.substring(1);
3976  
  nohup("java " + vmArgs + " -jar " + (isWindows() ? winQuote(jarPath) : bashQuote(jarPath)) + " " + javaxargs);
3977  
3978  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
3979  
static Object getBot(String botID) {
3980  
  return callOpt(getMainBot(), "getBot", botID);
3981  
}
3982  
3983  
static boolean isSubstanceLAF() {
3984  
  return substanceLookAndFeelEnabled();
3985  
}
3986  
static boolean substanceLookAndFeelEnabled() {
3987  
  return startsWith(getLookAndFeel(), "org.pushingpixels.");
3988  
}
3989  
static JMenuItem jmenuItem(String text, final Runnable r) {
3990  
  JMenuItem mi = new JMenuItem(text);
3991  
  mi.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent _evt) { r.run(); }});
3992  
  return mi;
3993  
}
3994  
static JTable showTable(Object data) {
3995  
  return dataToTable(data);
3996  
}
3997  
3998  
static JTable showTable(Object data, String title) {
3999  
  return dataToTable(data, title);
4000  
}
4001  
4002  
static JTable showTable() {
4003  
  return showTable(new ArrayList<List<String>>(), new ArrayList<String>());
4004  
}
4005  
4006  
static JTable showTable(String title) {
4007  
  return showTable(new ArrayList<List<String>>(), new ArrayList<String>(), title);
4008  
}
4009  
4010  
static JTable showTable(List<List<String>> rows, List<String> cols) {
4011  
  return showTable(rows, cols, autoFrameTitle());
4012  
}
4013  
  
4014  
static JTable showTable(List<List<String>> rows, List<String> cols, String title) {
4015  
  JFrame frame = new JFrame(title);
4016  
  frame.setBounds(10, 10, 500, 400);
4017  
  centerFrame(frame);
4018  
4019  
  JTable tbl = tableWithToolTips();
4020  
  fillTableWithStrings(tbl, rows, cols);
4021  
4022  
  frame.getContentPane().add(new JScrollPane(tbl));
4023  
  frame.setVisible(true);
4024  
  
4025  
  return tbl;
4026  
}
4027  
  static List<String> parse3(String s) {
4028  
    return dropPunctuation(javaTokPlusPeriod(s));
4029  
  }
4030  
  static new ThreadLocal<String> loadPage_charset;
4031  
  static boolean loadPage_allowGzip = true, loadPage_debug;
4032  
  static boolean loadPage_anonymous; // don't send computer ID
4033  
  static int loadPage_verboseness = 100000;
4034  
4035  
  public static String loadPageSilently(String url) {
4036  
    try {
4037  
      return loadPageSilently(new URL(loadPage_preprocess(url)));
4038  
    } catch (IOException e) { throw new RuntimeException(e); }
4039  
  }
4040  
4041  
  public static String loadPageSilently(URL url) {
4042  
    try {
4043  
      IOException e = null;
4044  
      for (int tries = 0; tries < 60; tries++)
4045  
        try {
4046  
          URLConnection con = url.openConnection();
4047  
          return loadPage(con, url);
4048  
        } catch (IOException _e) {
4049  
          e = _e;
4050  
          print("Retrying because of: " + e);
4051  
          sleepSeconds(1);
4052  
        }
4053  
      throw e;
4054  
    } catch (IOException e) { throw new RuntimeException(e); }
4055  
  }
4056  
4057  
  static String loadPage_preprocess(String url) {  
4058  
    if (url.startsWith("tb/"))
4059  
      url = "tinybrain.de:8080/" + url;
4060  
    if (url.indexOf("://") < 0)
4061  
      url = "http://" + url;
4062  
    return url;
4063  
  }
4064  
  
4065  
  public static String loadPage(String url) {
4066  
    try {
4067  
      return loadPage(new URL(loadPage_preprocess(url)));
4068  
    } catch (IOException e) { throw new RuntimeException(e); }
4069  
  }
4070  
  
4071  
  public static String loadPage(URL url) {
4072  
    print("Loading: " + url.toExternalForm());
4073  
    return loadPageSilently(url);
4074  
  }
4075  
4076  
  public static String loadPage(URLConnection con, URL url) throws IOException {
4077  
    try {
4078  
      if (!loadPage_anonymous) {
4079  
        String computerID = getComputerID();
4080  
        if (computerID != null)
4081  
          con.setRequestProperty("X-ComputerID", computerID);
4082  
      }
4083  
      if (loadPage_allowGzip)
4084  
        con.setRequestProperty("Accept-Encoding", "gzip");
4085  
    } catch (Throwable e) {} // fails if within doPost
4086  
    String contentType = con.getContentType();
4087  
    if (contentType == null)
4088  
      throw new IOException("Page could not be read: " + url);
4089  
    //print("Content-Type: " + contentType);
4090  
    String charset = loadPage_charset == null ? null : loadPage_charset.get();
4091  
    if (charset == null) charset = loadPage_guessCharset(contentType);
4092  
    
4093  
    InputStream in = con.getInputStream();
4094  
    if ("gzip".equals(con.getContentEncoding())) {
4095  
      if (loadPage_debug)
4096  
        print("loadPage: Using gzip.");
4097  
      in = new GZIPInputStream(in);
4098  
    }
4099  
    Reader r = new InputStreamReader(in, charset);
4100  
    
4101  
    StringBuilder buf = new StringBuilder();
4102  
    int n = 0;
4103  
    while (true) {
4104  
      int ch = r.read();
4105  
      if (ch < 0)
4106  
        break;
4107  
      buf.append((char) ch);
4108  
      ++n;
4109  
      if ((n % loadPage_verboseness) == 0) print("  " + n + " chars read");
4110  
    }
4111  
    return buf.toString();
4112  
  }
4113  
  
4114  
  static String loadPage_guessCharset(String contentType) {
4115  
    Pattern p = Pattern.compile("text/[a-z]+;\\s+charset=([^\\s]+)\\s*");
4116  
    Matcher m = p.matcher(contentType);
4117  
    /* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */
4118  
    return m.matches() ? m.group(1) : "ISO-8859-1";
4119  
  }
4120  
4121  
static void assertTrue(Object o) {
4122  
  assertEquals(true, o);
4123  
}
4124  
  
4125  
static boolean assertTrue(String msg, boolean b) {
4126  
  if (!b)
4127  
    fail(msg);
4128  
  return b;
4129  
}
4130  
4131  
static boolean assertTrue(boolean b) {
4132  
  if (!b)
4133  
    fail("oops");
4134  
  return b;
4135  
}
4136  
static String programTitle() {
4137  
  return getProgramName();
4138  
}
4139  
static Class<?> getClass(String name) {
4140  
  try {
4141  
    return Class.forName(name);
4142  
  } catch (ClassNotFoundException e) {
4143  
    return null;
4144  
  }
4145  
}
4146  
4147  
static Class getClass(Object o) {
4148  
  return o instanceof Class ? (Class) o : o.getClass();
4149  
}
4150  
4151  
static Class getClass(Object realm, String name) { try {
4152  
 
4153  
  return getClass(realm).getClassLoader().loadClass(classNameToVM(name));
4154  
4155  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4156  
static File loadLibrary(String snippetID) {
4157  
  return loadBinarySnippet(snippetID);
4158  
}
4159  
static boolean eqOneOf(Object o, Object... l) {
4160  
  for (Object x : l) if (eq(o, x)) return true; return false;
4161  
}
4162  
static boolean booleanValue(Object o) {
4163  
  return eq(true, o);
4164  
}
4165  
static File javaxDataDir_dir; // can be set to work on different base dir
4166  
4167  
static File javaxDataDir() {
4168  
  return javaxDataDir_dir != null ? javaxDataDir_dir : new File(userHome(), "JavaX-Data");
4169  
}
4170  
static Object[] toObjectArray(List list) {
4171  
  return list.toArray(new Object[list.size()]);
4172  
}
4173  
static String dropSuffix(String suffix, String s) {
4174  
  return s.endsWith(suffix) ? s.substring(0, l(s)-l(suffix)) : s;
4175  
}
4176  
static void smartSet(Field f, Object o, Object value) throws Exception {
4177  
  f.setAccessible(true);
4178  
  
4179  
  // take care of common case (long to int)
4180  
  if (f.getType() == int.class && value instanceof Long)
4181  
    value = ((Long) value).intValue();
4182  
    
4183  
  f.set(o, value);
4184  
}
4185  
static String sendToLocalBotOpt(String bot, String text) {
4186  
  if (bot == null) return null;
4187  
  DialogIO channel = findBot(bot);
4188  
  if (channel == null) {
4189  
    print(quote(bot) + " not found, skipping send: " + quote(text));
4190  
    return null;
4191  
  }
4192  
  try {
4193  
    channel.readLine();
4194  
    print(bot + "> " + text);
4195  
    channel.sendLine(text);
4196  
    String s = channel.readLine();
4197  
    print(bot + "< " + s);
4198  
    return s;
4199  
  } catch (Throwable e) {
4200  
    e.printStackTrace();
4201  
    return null;
4202  
  } finally {
4203  
    channel.close();
4204  
  }
4205  
}
4206  
4207  
4208  
public static boolean isWindows() {
4209  
  return System.getProperty("os.name").contains("Windows");
4210  
}
4211  
static boolean equalsIgnoreCase(String a, String b) {
4212  
  return a == null ? b == null : a.equalsIgnoreCase(b);
4213  
}
4214  
/** possibly improvable */
4215  
public static String bashQuote(String text) {
4216  
  if (text == null) return null;
4217  
  return "\"" + text
4218  
    .replace("\\", "\\\\")
4219  
    .replace("\"", "\\\"")
4220  
    .replace("\n", "\\n")
4221  
    .replace("\r", "\\r") + "\"";
4222  
}
4223  
4224  
static Object transpileRaw_trans;
4225  
static Object transpileRaw_silent = true;
4226  
4227  
static synchronized String transpileRaw(String mainJava) {
4228  
  if (transpileRaw_trans == null)
4229  
    // Note: we sync the whole main class on this
4230  
    transpileRaw_trans = hotwire("#759");
4231  
    
4232  
  setOpt(transpileRaw_trans, "print_silent", transpileRaw_silent);
4233  
4234  
  set(transpileRaw_trans, "mainJava", mainJava);
4235  
  callMain(transpileRaw_trans);
4236  
  return (String) get(transpileRaw_trans, "mainJava");
4237  
}
4238  
static File loadBinarySnippet(String snippetID) { try {
4239  
 
4240  
  long id = parseSnippetID(snippetID);
4241  
  File f = DiskSnippetCache_getLibrary(id);
4242  
  if (f == null) {
4243  
    byte[] data = loadDataSnippetImpl(snippetID);
4244  
    DiskSnippetCache_putLibrary(id, data);
4245  
    f = DiskSnippetCache_getLibrary(id);
4246  
  }
4247  
  return f;
4248  
4249  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4250  
static JComponent getTitlePaneComponent(Window window) {
4251  
  if (!substanceLookAndFeelEnabled()) return null;
4252  
  
4253  
	JRootPane rootPane = null;
4254  
	if (window instanceof JFrame) {
4255  
		JFrame f = (JFrame) window;
4256  
		rootPane = f.getRootPane();
4257  
	}
4258  
	if (window instanceof JDialog) {
4259  
		JDialog d = (JDialog) window;
4260  
		rootPane = d.getRootPane();
4261  
	}
4262  
	if (rootPane != null) {
4263  
		Object /*SubstanceRootPaneUI*/ ui = rootPane.getUI();
4264  
		return (JComponent) call(ui, "getTitlePane");
4265  
	}
4266  
	return null;
4267  
}
4268  
4269  
static void setTableModel(JTable table, TableModel model) {
4270  
  int i = table.getSelectedRow();
4271  
  table.setModel(model);
4272  
  if (i >= 0 && i < model.getRowCount())
4273  
    table.setRowSelectionInterval(i, i);
4274  
}
4275  
4276  
static String findTranslators2(String src, List<String> libsOut) {
4277  
  List<String> tok = javaTok(src);
4278  
  int i;
4279  
  while ((i = jfind(tok, "!<int>")) >= 0) {
4280  
    setAdd(libsOut, tok.get(i+2));
4281  
    clearTokens(tok, i, i+3);
4282  
  }
4283  
  return join(tok);
4284  
}
4285  
static void centerFrame(JFrame frame) {
4286  
  frame.setLocationRelativeTo(null); // magic trick
4287  
}
4288  
static new Map<String, Integer> findBot_cache;
4289  
static int findBot_timeout = 5000;
4290  
4291  
static DialogIO findBot(String searchPattern) {
4292  
  // first split off sub-bot suffix
4293  
  String subBot = null;
4294  
  int i = searchPattern.indexOf('/');
4295  
  if (i >= 0 && (isJavaIdentifier(searchPattern.substring(0, i)) || isInteger(searchPattern.substring(0, i)))) {
4296  
    subBot = searchPattern.substring(i+1);
4297  
    searchPattern = searchPattern.substring(0, i);
4298  
    if (!isInteger(searchPattern))
4299  
      searchPattern = "Multi-Port at " + searchPattern + ".";
4300  
  }
4301  
  
4302  
  // assume it's a port if it's an integer
4303  
  if (isInteger(searchPattern))
4304  
    return talkToSubBot(subBot, talkTo(parseInt(searchPattern)));
4305  
    
4306  
  if (eq(searchPattern, "remote"))
4307  
    return talkToSubBot(subBot, talkTo("second.tinybrain.de", 4999));
4308  
    
4309  
  Integer port = findBot_cache.get(searchPattern);
4310  
  if (port != null) try {
4311  
    DialogIO io = talkTo("localhost", port);
4312  
    io.waitForLine(/*findBot_timeout*/); // TODO: implement
4313  
    String line = io.readLineNoBlock();
4314  
    if (indexOfIgnoreCase(line, searchPattern) == 0) {
4315  
      call(io, "pushback", line); // put hello string back in
4316  
      return talkToSubBot(subBot, io);
4317  
    }
4318  
  } catch (Exception e) {
4319  
    e.printStackTrace();
4320  
  }
4321  
  
4322  
  List<ProgramScan.Program> bots = quickBotScan();
4323  
  
4324  
  // find top-level bots
4325  
  for (ProgramScan.Program p : bots) {
4326  
    if (indexOfIgnoreCase(p.helloString, searchPattern) == 0) { // strict matching - start of hello string only, but case-insensitive
4327  
      findBot_cache.put(searchPattern, p.port);
4328  
      return talkToSubBot(subBot, talkTo("localhost", p.port));
4329  
    }
4330  
  }
4331  
  
4332  
  // find sub-bots
4333  
  for (ProgramScan.Program p : bots) {
4334  
    String botName = firstPartOfHelloString(p.helloString);
4335  
    boolean isVM = startsWithIgnoreCase(p.helloString, "This is a JavaX VM.");
4336  
    boolean shouldRecurse = startsWithIgnoreCase(botName, "Multi-Port") || isVM;
4337  
        
4338  
    if (shouldRecurse) try {
4339  
      Map<Number, String> subBots = (Map) unstructure(sendToLocalBot(p.port, "list bots"));
4340  
      for (Number vport : subBots.keySet()) {
4341  
        String name = subBots.get(vport);
4342  
        if (startsWithIgnoreCase(name, searchPattern))
4343  
          return talkToSubBot(vport.longValue(), talkTo("localhost", p.port));
4344  
      }
4345  
    } catch (Exception e) { e.printStackTrace(); }
4346  
  }
4347  
        
4348  
  return null;
4349  
}
4350  
/** possibly improvable */
4351  
public static String winQuote(String text) {
4352  
  if (text == null) return null;
4353  
  return "\"" + text
4354  
    .replace("\\", "\\\\")
4355  
    .replace("\"", "\\\"")
4356  
    .replace("\n", "\\n")
4357  
    .replace("\r", "\\r") + "\"";
4358  
}
4359  
4360  
static boolean instanceOf(Object o, String className) {
4361  
  if (o == null) return false;
4362  
  String c = o.getClass().getName();
4363  
  return eq(c, className) || eq(c, "main$" + className);
4364  
}
4365  
static String rep(int n, char c) {
4366  
  return repeat(c, n);
4367  
}
4368  
4369  
static String rep(char c, int n) {
4370  
  return repeat(c, n);
4371  
}
4372  
4373  
static <A> List<A> rep(A a, int n) {
4374  
  return repeat(a, n);
4375  
}
4376  
4377  
static boolean isNonNegativeInteger(String s) {
4378  
  return s != null && Pattern.matches("\\d+", s);
4379  
}
4380  
static String classNameToVM(String name) {
4381  
  return name.replace(".", "$");
4382  
}
4383  
// This is made for NL parsing.
4384  
// It's javaTok extended with "..." token, "$n" and "#n" and
4385  
// special quotes (which are converted to normal ones).
4386  
4387  
static List<String> javaTokPlusPeriod(String s) {
4388  
  List<String> tok = new ArrayList<String>();
4389  
  int l = s.length();
4390  
  
4391  
  int i = 0;
4392  
  while (i < l) {
4393  
    int j = i;
4394  
    char c; String cc;
4395  
    
4396  
    // scan for whitespace
4397  
    while (j < l) {
4398  
      c = s.charAt(j);
4399  
      cc = s.substring(j, Math.min(j+2, l));
4400  
      if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
4401  
        ++j;
4402  
      else if (cc.equals("/*")) {
4403  
        do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/"));
4404  
        j = Math.min(j+2, l);
4405  
      } else if (cc.equals("//")) {
4406  
        do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0);
4407  
      } else
4408  
        break;
4409  
    }
4410  
    
4411  
    tok.add(s.substring(i, j));
4412  
    i = j;
4413  
    if (i >= l) break;
4414  
    c = s.charAt(i);
4415  
    cc = s.substring(i, Math.min(i+2, l));
4416  
4417  
    // scan for non-whitespace
4418  
    if (c == '\u201C' || c == '\u201D') c = '"'; // normalize quotes
4419  
    if (c == '\'' || c == '"') {
4420  
      char opener = c;
4421  
      ++j;
4422  
      while (j < l) {
4423  
        char _c = s.charAt(j);
4424  
        if (_c == '\u201C' || _c == '\u201D') _c = '"'; // normalize quotes
4425  
        if (_c == opener) {
4426  
          ++j;
4427  
          break;
4428  
        } else if (s.charAt(j) == '\\' && j+1 < l)
4429  
          j += 2;
4430  
        else
4431  
          ++j;
4432  
      }
4433  
      if (j-1 >= i+1) {
4434  
        tok.add(opener + s.substring(i+1, j-1) + opener);
4435  
        i = j;
4436  
        continue;
4437  
      }
4438  
    } else if (Character.isJavaIdentifierStart(c))
4439  
      do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || s.charAt(j) == '\'')); // for things like "this one's"
4440  
    else if (Character.isDigit(c))
4441  
      do ++j; while (j < l && Character.isDigit(s.charAt(j)));
4442  
    else if (cc.equals("[[")) {
4443  
      do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]"));
4444  
      j = Math.min(j+2, l);
4445  
    } else if (cc.equals("[=") && i+2 < l && s.charAt(i+2) == '[') {
4446  
      do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]"));
4447  
      j = Math.min(j+3, l);
4448  
    } else if (s.substring(j, Math.min(j+3, l)).equals("..."))
4449  
      j += 3;
4450  
    else if (c == '$' || c == '#')
4451  
      do ++j; while (j < l && Character.isDigit(s.charAt(j)));
4452  
    else
4453  
      ++j;
4454  
4455  
    tok.add(s.substring(i, j));
4456  
    i = j;
4457  
  }
4458  
  
4459  
  if ((tok.size() % 2) == 0) tok.add("");
4460  
  return tok;
4461  
}
4462  
4463  
  /** writes safely (to temp file, then rename) */
4464  
  public static void saveBinaryFile(String fileName, byte[] contents) throws IOException {
4465  
    File file = new File(fileName);
4466  
    File parentFile = file.getParentFile();
4467  
    if (parentFile != null)
4468  
      parentFile.mkdirs();
4469  
    String tempFileName = fileName + "_temp";
4470  
    FileOutputStream fileOutputStream = new FileOutputStream(tempFileName);
4471  
    fileOutputStream.write(contents);
4472  
    fileOutputStream.close();
4473  
    if (file.exists() && !file.delete())
4474  
      throw new IOException("Can't delete " + fileName);
4475  
4476  
    if (!new File(tempFileName).renameTo(file))
4477  
      throw new IOException("Can't rename " + tempFileName + " to " + fileName);
4478  
  }
4479  
4480  
  static void saveBinaryFile(File fileName, byte[] contents) {
4481  
    try {
4482  
      saveBinaryFile(fileName.getPath(), contents);
4483  
    } catch (IOException e) {
4484  
      throw new RuntimeException(e);
4485  
    }
4486  
  }
4487  
static List<File> loadLibraries(List<String> snippetIDs) {
4488  
  return map("loadLibrary", snippetIDs);
4489  
}
4490  
static JFrame consoleFrame() {
4491  
  return (JFrame) getOpt(get(getJavaX(), "console"), "frame");
4492  
}
4493  
static Class hotwireCore(List urlsOrFiles) {
4494  
  List<URL> urls = map("toURL", urlsOrFiles);
4495  
  return hotwireCore((URL[]) asArray(URL.class, urls));
4496  
}
4497  
4498  
static Class hotwireCore(URL... urls) { try {
4499  
 
4500  
  // make class loader
4501  
  URLClassLoader classLoader = new URLClassLoader(urls);
4502  
4503  
  // load & return main class
4504  
  Class<?> theClass = classLoader.loadClass("main");
4505  
  
4506  
  if (!_inCore())
4507  
    hotwire_copyOver(theClass);
4508  
  
4509  
  return theClass;
4510  
4511  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4512  
static TableWithTooltips tableWithToolTips() {
4513  
  return tableWithTooltips();
4514  
}
4515  
4516  
static String getComputerID() { try {
4517  
 
4518  
  return computerID();
4519  
4520  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4521  
static String _userHome;
4522  
static String userHome() {
4523  
  if (_userHome == null) {
4524  
    if (isAndroid())
4525  
      _userHome = "/storage/sdcard0/";
4526  
    else
4527  
      _userHome = System.getProperty("user.home");
4528  
    //System.out.println("userHome: " + _userHome);
4529  
  }
4530  
  return _userHome;
4531  
}
4532  
4533  
static File userHome(String path) {
4534  
  return new File(userDir(), path);
4535  
}
4536  
static <A> A assertEquals(Object x, A y) {
4537  
  return assertEquals(null, x, y);
4538  
}
4539  
4540  
static <A> A assertEquals(String msg, Object x, A y) {
4541  
  if (!(x == null ? y == null : x.equals(y)))
4542  
    fail((msg != null ? msg + ": " : "") + structure(x) + " != " + structure(y));
4543  
  return y;
4544  
}
4545  
static boolean isIdentifier(String s) {
4546  
  return isJavaIdentifier(s);
4547  
}
4548  
static String getLookAndFeel() {
4549  
  return getClassName(UIManager.getLookAndFeel());
4550  
}
4551  
static void sleepSeconds(double s) {
4552  
  if (s > 0) sleep(round(s*1000));
4553  
}
4554  
static int latestInstalledJavaX() {
4555  
  File[] files = new File(userHome(), ".javax").listFiles();
4556  
  int v = 0;
4557  
  if (files != null) for (File f : files) {
4558  
    Matcher m = Pattern.compile("x(\\d\\d\\d?)\\.jar").matcher(f.getName());
4559  
    if (m.matches())
4560  
      v = Math.max(v, Integer.parseInt(m.group(1)));
4561  
  }
4562  
  return v;
4563  
}
4564  
public static File nohup(String cmd) throws IOException {
4565  
  File outFile = File.createTempFile("nohup_" + nohup_sanitize(cmd), ".out");
4566  
  nohup(cmd, outFile, false);
4567  
  return outFile;
4568  
}
4569  
4570  
static String nohup_sanitize(String s) {
4571  
  return s.replaceAll("[^a-zA-Z0-9\\-_]", "");
4572  
}
4573  
4574  
/** outFile takes stdout and stderr. */
4575  
public static void nohup(String cmd, File outFile, boolean append) throws IOException {
4576  
  String command = nohup_makeNohupCommand(cmd, outFile, append);
4577  
4578  
  File scriptFile = File.createTempFile("_realnohup", isWindows() ? ".bat" : "");
4579  
  System.out.println("[Nohup] " + command);
4580  
  try {
4581  
    //System.out.println("[RealNohup] Script file: " + scriptFile.getPath());
4582  
    saveTextFile(scriptFile.getPath(), command);
4583  
    String[] command2;
4584  
    if (isWindows())
4585  
      command2 = new String[] {"cmd", "/c", "start", "/b", scriptFile.getPath() };
4586  
    else
4587  
      command2 = new String[] {"/bin/bash", scriptFile.getPath() };
4588  
      
4589  
    Process process = Runtime.getRuntime().exec(command2);
4590  
    try {
4591  
      process.waitFor();
4592  
    } catch (InterruptedException e) {
4593  
      throw new RuntimeException(e);
4594  
    }
4595  
    int value = process.exitValue();
4596  
    //System.out.println("exit value: " + value);
4597  
  } finally {
4598  
    if (!isWindows())
4599  
      scriptFile.delete();
4600  
  }
4601  
}
4602  
4603  
public static String nohup_makeNohupCommand(String cmd, File outFile, boolean append) {
4604  
  mkdirsForFile(outFile);
4605  
4606  
  String command;
4607  
  if (isWindows())
4608  
    command = cmd + (append ? " >>" : " >") + winQuote(outFile.getPath()) + " 2>&1";
4609  
  else
4610  
    command = "nohup " + cmd + (append ? " >>" : " >") + bashQuote(outFile.getPath()) + " 2>&1 &";
4611  
  return command;
4612  
}
4613  
4614  
static List<String> dropPunctuation_keep = litlist("*", "<", ">");
4615  
4616  
static List<String> dropPunctuation(List<String> tok) {
4617  
  tok = new ArrayList<String>(tok);
4618  
  for (int i = 1; i < tok.size(); i += 2) {
4619  
    String t = tok.get(i);
4620  
    if (t.length() == 1 && !Character.isLetter(t.charAt(0)) && !Character.isDigit(t.charAt(0)) && !dropPunctuation_keep.contains(t)) {
4621  
      tok.set(i-1, tok.get(i-1) + tok.get(i+1));
4622  
      tok.remove(i);
4623  
      tok.remove(i);
4624  
      i -= 2;
4625  
    }
4626  
  }
4627  
  return tok;
4628  
}
4629  
4630  
static String dropPunctuation(String s) {
4631  
  return join(dropPunctuation(nlTok(s)));
4632  
}
4633  
static byte[] loadBinaryPage(String url) throws IOException {
4634  
  return loadBinaryPage(new URL(url).openConnection());
4635  
}
4636  
4637  
public static byte[] loadBinaryPage(URLConnection con) throws IOException {
4638  
  //setHeaders(con);
4639  
  ByteArrayOutputStream buf = new ByteArrayOutputStream();
4640  
  InputStream inputStream = con.getInputStream();
4641  
  int n = 0;
4642  
  while (true) {
4643  
    int ch = inputStream.read();
4644  
    if (ch < 0)
4645  
      break;
4646  
    buf.write(ch);
4647  
    if (++n % 100000 == 0)
4648  
      System.err.println("  " + n + " bytes loaded.");
4649  
  }
4650  
  inputStream.close();
4651  
  return buf.toByteArray();
4652  
}
4653  
4654  
static File javaCompile(String src) {
4655  
  return javaCompile(src, "");
4656  
}
4657  
4658  
// returns path to classes dir
4659  
static synchronized File javaCompile(String src, String dehlibs) {
4660  
  String javaTarget = null; // use default target
4661  
  
4662  
  //print("Compiling " + l(src) + " chars");
4663  
4664  
  Class j = getJavaX();
4665  
  if (javaTarget != null)
4666  
    setOpt(j, "javaTarget", javaTarget);
4667  
  //setOpt(j, "verbose", true);
4668  
  File srcDir = (File) ( call(j, "TempDirMaker_make"));
4669  
  String className = getNameOfPublicClass(javaTok(src));
4670  
  String fileName = className + ".java";
4671  
  File mainJava = new File(srcDir, fileName);
4672  
  //print("main java: " + mainJava.getAbsolutePath());
4673  
  saveTextFile(mainJava, src);
4674  
  File classesDir = (File) call(j, "TempDirMaker_make");
4675  
  new List<File> libraries;
4676  
  
4677  
  Matcher m = Pattern.compile("\\d+").matcher(dehlibs);
4678  
  while (m.find()) {
4679  
    String libID = m.group();
4680  
    print("libID=" + quote(libID));
4681  
    assertTrue(isSnippetID(libID));
4682  
    libraries.add(loadLibrary(libID));
4683  
  }
4684  
    
4685  
  try {
4686  
     // This seems to be empty in case of success with Eclipse compiler.
4687  
     String compilerOutput = (String) ( call(j, "compileJava", srcDir, libraries, classesDir));
4688  
     if (nempty(compilerOutput)) print("Compiler said: " + quote(compilerOutput));
4689  
      
4690  
      // sanity test
4691  
      if (!new File(classesDir, className + ".class").exists())
4692  
        fail("No class generated (" + className + ")");
4693  
  } catch (Exception e) {
4694  
    //e.printStackTrace();
4695  
    fail("Compile Error\n" + getOpt(j, "javaCompilerOutput"));
4696  
  }
4697  
  
4698  
  return classesDir;
4699  
}
4700  
4701  
static String getProgramName_cache;
4702  
4703  
static synchronized String getProgramName() {
4704  
  if (getProgramName_cache == null)
4705  
    getProgramName_cache = getSnippetTitle(getProgramID());
4706  
  return getProgramName_cache;
4707  
}
4708  
4709  
4710  
static DialogIO talkToSubBot(final long vport, final DialogIO io) {
4711  
  return talkToSubBot(String.valueOf(vport), io);
4712  
}
4713  
4714  
static DialogIO talkToSubBot(final String subBot, final DialogIO io) {
4715  
  if (subBot == null) return io;
4716  
  
4717  
  return new DialogIO() {
4718  
    // delegate all but sendLine
4719  
    boolean isStillConnected() { return io.isStillConnected(); }
4720  
    String readLineImpl() { return io.readLineImpl(); }
4721  
    boolean isLocalConnection() { return io.isLocalConnection(); }
4722  
    Socket getSocket() { return io.getSocket(); }
4723  
    void close() { io.close(); }
4724  
4725  
    void sendLine(String line) {
4726  
      io.sendLine(format3("please forward to bot *: *", subBot, line));
4727  
    }
4728  
  };
4729  
}
4730  
static void sleep(long ms) {
4731  
  try {
4732  
    Thread.sleep(ms);
4733  
  } catch (Exception e) { throw new RuntimeException(e); }
4734  
}
4735  
4736  
static void sleep() { try {
4737  
 
4738  
  print("Sleeping.");
4739  
  synchronized(main.class) { main.class.wait(); }
4740  
4741  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4742  
  
4743  
  // Data files are immutable, use centralized cache
4744  
public static File DiskSnippetCache_getLibrary(long snippetID) throws IOException {
4745  
  File file = new File(getGlobalCache(), "data_" + snippetID + ".jar");
4746  
  return file.exists() ? file : null;
4747  
}
4748  
4749  
public static void DiskSnippetCache_putLibrary(long snippetID, byte[] data) throws IOException {
4750  
  saveBinaryFile(new File(getGlobalCache(), "data_" + snippetID).getPath() + ".jar", data);
4751  
}
4752  
4753  
static byte[] loadDataSnippetImpl(String snippetID) throws IOException {
4754  
  byte[] data;
4755  
  try {
4756  
    URL url = new URL("http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_"
4757  
      + parseSnippetID(snippetID) + "&contentType=application/binary");
4758  
    System.err.println("Loading library: " + url);
4759  
    try {
4760  
      data = loadBinaryPage(url.openConnection());
4761  
    } catch (IOException e) {
4762  
      data = null;
4763  
    }
4764  
    
4765  
    if (data == null || data.length == 0) {
4766  
      url = new URL("http://data.tinybrain.de/blobs/"
4767  
        + parseSnippetID(snippetID));
4768  
      System.err.println("Loading library: " + url);
4769  
      data = loadBinaryPage(url.openConnection());
4770  
    }
4771  
    System.err.println("Bytes loaded: " + data.length);
4772  
  } catch (FileNotFoundException e) {
4773  
    throw new IOException("Binary snippet #" + snippetID + " not found or not public");
4774  
  }
4775  
  return data;
4776  
}
4777  
static URL toURL(Object o) { try {
4778  
 
4779  
  if (o instanceof URL) return (URL) o;
4780  
  if (o instanceof String) return new URL((String) o);
4781  
  if (o instanceof File) return fileToURL((File) o);
4782  
  fail("Can't convert to URL: " + o);
4783  
4784  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4785  
static String _computerID;
4786  
public static String computerID() { try {
4787  
 
4788  
  if (_computerID == null) {
4789  
    File file = new File(userHome(), ".tinybrain/computer-id");
4790  
    _computerID = loadTextFile(file.getPath(), null);
4791  
    if (_computerID == null) {
4792  
      _computerID = makeRandomID(12);
4793  
      saveTextFile(file.getPath(), _computerID);
4794  
    }
4795  
  }
4796  
  return _computerID;
4797  
4798  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4799  
static String firstPartOfHelloString(String s) {
4800  
  int i = s.lastIndexOf('/');
4801  
  return i < 0 ? s : rtrim(s.substring(0, i));
4802  
}
4803  
static String getNameOfPublicClass(List<String> tok) {
4804  
  for (List<String> c : allClasses(tok))
4805  
    if (hasModifier(c, "public"))
4806  
      return getClassDeclarationName(c);
4807  
  return null;
4808  
}
4809  
4810  
  static void clearTokens(List<String> tok) {
4811  
    clearAllTokens(tok);
4812  
  }
4813  
  
4814  
  static void clearTokens(List<String> tok, int i, int j) {
4815  
    clearAllTokens(tok, i, j);
4816  
  }
4817  
static List<ProgramScan.Program> quickBotScan() {
4818  
  return ProgramScan.quickBotScan();
4819  
}
4820  
4821  
static List<ProgramScan.Program> quickBotScan(int[] preferredPorts) {
4822  
  return ProgramScan.quickBotScan(preferredPorts);
4823  
}
4824  
4825  
static List<ProgramScan.Program> quickBotScan(String searchPattern) {
4826  
  List<ProgramScan.Program> l = new ArrayList<ProgramScan.Program>();
4827  
  for (ProgramScan.Program p : ProgramScan.quickBotScan())
4828  
    if (indexOfIgnoreCase(p.helloString, searchPattern) == 0)
4829  
      l.add(p);
4830  
  return l;
4831  
}
4832  
4833  
static List<String> nlTok(String s) {
4834  
  return javaTokPlusPeriod(s);
4835  
}
4836  
static int jfind(List<String> tok, String in) {
4837  
  List<String> tokin = javaTok(in);
4838  
  jfind_preprocess(tokin);
4839  
  return findCodeTokens(tok, false, toStringArray(codeTokensOnly(tokin)));
4840  
}
4841  
4842  
static void jfind_preprocess(List<String> tok) {
4843  
  for (String type : litlist("quoted", "id", "int"))
4844  
    replaceSublist(tok, litlist("<", "", type, "", ">"), litlist("<" + type + ">"));
4845  
}
4846  
static DialogIO talkTo(int port) {
4847  
  return talkTo("localhost", port);
4848  
}
4849  
4850  
static DialogIO talkTo(String ip, int port) { try {
4851  
 
4852  
  final Socket s = new Socket(ip, port);    
4853  
  //print("Talking to " + ip + ":" + port);
4854  
4855  
  final Writer w = new OutputStreamWriter(s.getOutputStream(), "UTF-8");
4856  
  final BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"));
4857  
  return new DialogIO() {
4858  
    boolean isLocalConnection() {
4859  
      return s.getInetAddress().isLoopbackAddress();
4860  
    }
4861  
    
4862  
    boolean isStillConnected() {
4863  
      return !(eos || s.isClosed());
4864  
    }
4865  
    
4866  
    void sendLine(String line) { try {
4867  
 
4868  
      w.write(line + "\n");
4869  
      w.flush();
4870  
    
4871  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4872  
    
4873  
    String readLineImpl() { try {
4874  
 
4875  
      return in.readLine();
4876  
    
4877  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4878  
    
4879  
    void close() {
4880  
      try {
4881  
        s.close();
4882  
      } catch (IOException e) {
4883  
        // whatever
4884  
      }
4885  
    }
4886  
    
4887  
    Socket getSocket() {
4888  
      return s;
4889  
    }
4890  
  };
4891  
4892  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4893  
static String sendToLocalBot(String bot, String text, Object... args) {
4894  
  text = format3(text, args);
4895  
  
4896  
  DialogIO channel = findBot(bot);
4897  
  if (channel == null)
4898  
    fail(quote(bot) + " not found");
4899  
  try {
4900  
    channel.readLine();
4901  
    print(bot + "> " + shorten(text, 80));
4902  
    channel.sendLine(text);
4903  
    String s = channel.readLine();
4904  
    print(bot + "< " + shorten(s, 80));
4905  
    return s;
4906  
  } catch (Throwable e) {
4907  
    e.printStackTrace();
4908  
    return null;
4909  
  } finally {
4910  
    channel.close();
4911  
  }
4912  
}
4913  
4914  
static String sendToLocalBot(int port, String text, Object... args) {
4915  
  text = format3(text, args);
4916  
  DialogIO channel = talkTo(port);
4917  
  try {
4918  
    channel.readLine();
4919  
    print(port + "> " + shorten(text, 80));
4920  
    channel.sendLine(text);
4921  
    String s = channel.readLine();
4922  
    print(port + "< " + shorten(s, 80));
4923  
    return s;
4924  
  } catch (Throwable e) {
4925  
    e.printStackTrace();
4926  
    return null;
4927  
  } finally {
4928  
    if (channel != null)
4929  
      channel.close();
4930  
  }
4931  
}
4932  
// works on lists and strings and null
4933  
4934  
static int indexOfIgnoreCase(Object a, Object b) {
4935  
  if (a == null) return -1;
4936  
  if (a instanceof String) {
4937  
     Matcher m = Pattern.compile((String) b, Pattern.CASE_INSENSITIVE + Pattern.LITERAL).matcher((String) a);
4938  
     if (m.find()) return m.start(); else return -1;
4939  
  }
4940  
  if (a instanceof List) {
4941  
    for (int i = 0; i < ((List) a).size(); i++) {
4942  
      Object o = ((List) a).get(i);
4943  
      if (o != null && ((String) o).equalsIgnoreCase((String) b))
4944  
        return i;
4945  
    }
4946  
    return -1;
4947  
  }
4948  
  throw fail("Unknown type: " + a);
4949  
}
4950  
  static String repeat(char c, int n) {
4951  
    n = max(n, 0);
4952  
    char[] chars = new char[n];
4953  
    for (int i = 0; i < n; i++)
4954  
      chars[i] = c;
4955  
    return new String(chars);
4956  
  }
4957  
4958  
  static <A> List<A> repeat(A a, int n) {
4959  
    new List<A> l;
4960  
    for (int i = 0; i < n; i++)
4961  
      l.add(a);
4962  
    return l;
4963  
  }
4964  
4965  
static long round(double d) {
4966  
  return Math.round(d);
4967  
}
4968  
static File userDir() {
4969  
  return new File(userHome());
4970  
}
4971  
4972  
static File userDir(String path) {
4973  
  return new File(userHome(), path);
4974  
}
4975  
static boolean isAndroid() { return System.getProperty("java.vendor").toLowerCase().indexOf("android") >= 0; }
4976  
4977  
4978  
  static String getClassDeclarationName(List<String> c) {
4979  
    for (int i = 1; i+2 < c.size(); i += 2)
4980  
      if (c.get(i).equals("class"))
4981  
        return c.get(i+2);
4982  
    return null;
4983  
  }
4984  
  
4985  
4986  
static URL fileToURL(File f) { try {
4987  
 
4988  
  return f.toURI().toURL();
4989  
4990  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
4991  
static File getGlobalCache() {
4992  
  File file = new File(userHome(), ".tinybrain/snippet-cache");
4993  
  file.mkdirs();
4994  
  return file;
4995  
}
4996  
4997  
// lists returned are actual CNC (N/C/N/.../C/N) - and connected to
4998  
// original list
4999  
static List<List<String>> allClasses(List<String> tok) {
5000  
  List<List<String>> l = new ArrayList();
5001  
  for (int i = 1; i < tok.size(); i += 2) {
5002  
    if (tok.get(i).equals("class") && (i == 1 || !tok.get(i-2).equals("."))) {
5003  
      int j = i;
5004  
      while (j < tok.size() && !tok.get(j).equals("{"))
5005  
        j += 2;
5006  
      j = findEndOfBlock(tok, j)+1;
5007  
      i = leftScanModifiers(tok, i);
5008  
      l.add(tok.subList(i-1, Math.min(tok.size(), j)));
5009  
      i = j-2;
5010  
    }
5011  
  }
5012  
  return l;
5013  
}
5014  
5015  
static List<List<String>> allClasses(String text) {
5016  
  return allClasses(javaTok(text));
5017  
}
5018  
static List<String> replaceSublist(List<String> l, List<String> x, List<String> y) {
5019  
  if (x == null) return l;
5020  
  
5021  
  int i = 0;
5022  
  while (true) {
5023  
    i = indexOfSubList(l, x, i);
5024  
    if (i < 0) break;
5025  
    
5026  
    // It's inefficient :D
5027  
    for (int j = 0; j < l(x); j++) l.remove(i);
5028  
    l.addAll(i, y);
5029  
    i += l(y);
5030  
  }
5031  
  return l;
5032  
}
5033  
// scans a Java construct (class, method) and checks its modifiers
5034  
static boolean hasModifier(List<String> tok, String modifier) {
5035  
  for (int i = 1; i < tok.size() && getJavaModifiers().contains(tok.get(i)); i += 2)
5036  
    if (tok.get(i).equals(modifier))
5037  
      return true;
5038  
  return false;
5039  
}
5040  
5041  
  static void clearAllTokens(List<String> tok) {
5042  
    for (int i = 0; i < tok.size(); i++)
5043  
      tok.set(i, "");
5044  
  }
5045  
  
5046  
  static void clearAllTokens(List<String> tok, int i, int j) {
5047  
    for (; i < j; i++)
5048  
      tok.set(i, "");
5049  
  }
5050  
static int findCodeTokens(List<String> tok, String... tokens) {
5051  
  return findCodeTokens(tok, 1, false, tokens);
5052  
}
5053  
5054  
static int findCodeTokens(List<String> tok, boolean ignoreCase, String... tokens) {
5055  
  return findCodeTokens(tok, 1, ignoreCase, tokens);
5056  
}
5057  
5058  
static int findCodeTokens(List<String> tok, int startIdx, boolean ignoreCase, String... tokens) {
5059  
  return findCodeTokens(tok, startIdx, ignoreCase, tokens, null);
5060  
}
5061  
5062  
static List<String> findCodeTokens_specials = litlist("*", "<quoted>", "<id>", "<int>", "\\*");
5063  
static boolean findCodeTokens_debug;
5064  
static int findCodeTokens_indexed, findCodeTokens_unindexed;
5065  
5066  
static int findCodeTokens(List<String> tok, int startIdx, boolean ignoreCase, String[] tokens, Object condition) {
5067  
  if (findCodeTokens_debug) {
5068  
    if (eq(getClassName(tok), "main$IndexedList2"))
5069  
      findCodeTokens_indexed++;
5070  
    else
5071  
      findCodeTokens_unindexed++;
5072  
  }
5073  
  // bail out early if first token not found (works great with IndexedList)
5074  
  if (!findCodeTokens_specials.contains(tokens[0])
5075  
    && !tok.contains(tokens[0] /*, startIdx << no signature in List for this, unfortunately */)) return -1;
5076  
  
5077  
  outer: for (int i = startIdx | 1; i+tokens.length*2-2 < tok.size(); i += 2) {
5078  
    for (int j = 0; j < tokens.length; j++) {
5079  
      String p = tokens[j], t = tok.get(i+j*2);
5080  
      boolean match;
5081  
      if (eq(p, "*")) match = true;
5082  
      else if (eq(p, "<quoted>")) match = isQuoted(t);
5083  
      else if (eq(p, "<id>")) match = isIdentifier(t);
5084  
      else if (eq(p, "<int>")) match = isInteger(t);
5085  
      else if (eq(p, "\\*")) match = eq("*", t);
5086  
      else match = ignoreCase ? eqic(p, t) : eq(p, t);
5087  
      
5088  
      if (!match)
5089  
        continue outer;
5090  
    }
5091  
    
5092  
    if (condition == null || checkCondition(condition, tok, i-1)) // pass N index
5093  
      return i;
5094  
  }
5095  
  return -1;
5096  
}
5097  
public static String rtrim(String s) {
5098  
  int i = s.length();
5099  
  while (i > 0 && " \t\r\n".indexOf(s.charAt(i-1)) >= 0)
5100  
    --i;
5101  
  return i < s.length() ? s.substring(0, i) : s;
5102  
}
5103  
5104  
5105  
static <A> int indexOfSubList(List<A> x, List<A> y, int i) {
5106  
  outer: for (; i+l(y) <= l(x); i++) {
5107  
    for (int j = 0; j < l(y); j++)
5108  
      if (neq(x.get(i+j), y.get(j)))
5109  
        continue outer;
5110  
    return i;
5111  
  }
5112  
  return -1;
5113  
}
5114  
// supports the usual quotings (', ", variable length double brackets)
5115  
static boolean isQuoted(String s) {
5116  
  if (s.startsWith("'") || s.startsWith("\"")) return true;
5117  
  if (!s.startsWith("[")) return false;
5118  
  int i = 1;
5119  
  while (i < s.length() && s.charAt(i) == '=') ++i;
5120  
  return i < s.length() && s.charAt(i) == '[';
5121  
  //return Pattern.compile("^\\[=*\\[").matcher(s).find();
5122  
}
5123  
static boolean checkCondition(Object condition, Object... args) {
5124  
  return isTrue(call(condition, "check", args));
5125  
}
5126  
static int leftScanModifiers(List<String> tok, int i) {
5127  
  List<String> mod = getJavaModifiers();
5128  
  while (i > 1 && mod.contains(tok.get(i-2)))
5129  
    i -= 2;
5130  
  return i;
5131  
}
5132  
5133  
static List<String> getJavaModifiers_list = litlist("static", "abstract", "public", "private", "protected", "final", "native", "volatile", "synchronized", "transient");
5134  
5135  
static List<String> getJavaModifiers() {
5136  
  return getJavaModifiers_list;
5137  
}
5138  
// i must point at the opening bracket ("{")
5139  
// index returned is index of closing bracket + 1
5140  
static int findEndOfBlock(List<String> cnc, int i) {
5141  
  int j = i+2, level = 1;
5142  
  while (j < cnc.size()) {
5143  
    if (cnc.get(j).equals("{")) ++level;
5144  
    else if (cnc.get(j).equals("}")) --level;
5145  
    if (level == 0)
5146  
      return j+1;
5147  
    ++j;
5148  
  }
5149  
  return cnc.size();
5150  
}
5151  
5152  
5153  
static class Gen {
5154  
  String name;
5155  
  Object func;
5156  
  
5157  
  *() {}
5158  
  *(String *name, Object *func) {}
5159  
  
5160  
  public String toString() {
5161  
    return name;
5162  
  }
5163  
}
5164  
5165  
static class Var<A> {
5166  
  A v;
5167  
  
5168  
  *() {}
5169  
  *(A *v) {}
5170  
  
5171  
  synchronized void set(A a) { v = a; }
5172  
  synchronized A get() { return v; }
5173  
}
5174  
5175  
static class ProgramScan {
5176  
  static int threads = isWindows() ? 500 : 10;
5177  
  static int timeout = 5000; // hmm...
5178  
  static String ip = "127.0.0.1";
5179  
  static int quickScanFrom = 10000, quickScanTo = 10999;
5180  
  static int maxNumberOfBotPorts = 100;
5181  
  static boolean verbose;
5182  
  
5183  
  static class Program {
5184  
    int port;
5185  
    String helloString;
5186  
    
5187  
    *(int *port, String *helloString) {}
5188  
  }
5189  
  
5190  
  static List<Program> scan() { try {
5191  
 
5192  
    return scan(1, 65535);
5193  
  
5194  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
5195  
  
5196  
  static List<Program> scan(int fromPort, int toPort) {
5197  
    return scan(fromPort, toPort, new int[0]);
5198  
  }
5199  
  
5200  
  static List<Program> scan(int fromPort, int toPort, int[] preferredPorts) { try {
5201  
 
5202  
    Set<Integer> preferredPortsSet = new HashSet<Integer>(asList(preferredPorts));
5203  
    String name = toPort < 10000 ? "bot" : "program";
5204  
    final ExecutorService es = Executors.newFixedThreadPool(threads);
5205  
    if (verbose) print(firstToUpper(name) + "-scanning " + ip + " with timeout " + timeout + " ms in " + threads + " threads.");
5206  
    startTiming();
5207  
    new List<Future<Program>> futures;
5208  
    for (int port : preferredPorts)
5209  
      futures.add(checkPort(es, ip, port, timeout));
5210  
    for (int port = fromPort; port <= toPort; port++)
5211  
      if (!preferredPortsSet.contains(port))
5212  
        futures.add(checkPort(es, ip, port, timeout));
5213  
    es.shutdown();
5214  
    new List<Program> programs;
5215  
    for (final Future<Program> f : futures) {
5216  
      Program p = f.get();
5217  
      if (p != null)
5218  
        programs.add(p);
5219  
    }
5220  
    stopTiming();
5221  
    if (verbose) print("Found " + programs.size() + " " + name + "(s) on " + ip);
5222  
    return programs;
5223  
  
5224  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
5225  
5226  
  static Future<Program> checkPort(final ExecutorService es, final String ip, final int port, final int timeout) {
5227  
    return es.submit(new Callable<Program>() {
5228  
        @Override public Program call() {
5229  
          try {
5230  
            Socket socket = new Socket();
5231  
            socket.setSoTimeout(timeout);
5232  
            socket.connect(new InetSocketAddress(ip, port), timeout);
5233  
            if (verbose) print("Connected to " + ip + ":" + port);
5234  
            BufferedReader in = new BufferedReader(
5235  
              new InputStreamReader(socket.getInputStream(), "UTF-8"));
5236  
            String hello = or(in.readLine(), "?");
5237  
            socket.close();
5238  
            return new Program(port, hello);
5239  
          } catch (Exception ex) {
5240  
            return null;
5241  
          }
5242  
        }
5243  
     });
5244  
  }
5245  
  
5246  
  static List<Program> quickScan() {
5247  
    return scan(quickScanFrom, quickScanTo);
5248  
  }
5249  
  
5250  
  static List<Program> quickBotScan() {
5251  
    return quickBotScan(new int[0]);
5252  
  }
5253  
  
5254  
  static List<Program> quickBotScan(int[] preferredPorts) {
5255  
    return scan(4990, 5000+maxNumberOfBotPorts-1, preferredPorts);
5256  
  }
5257  
}
5258  
5259  
  static abstract class DialogIO {
5260  
    String line;
5261  
    boolean eos;
5262  
    
5263  
    abstract String readLineImpl();
5264  
    abstract boolean isStillConnected();
5265  
    abstract void sendLine(String line);
5266  
    abstract boolean isLocalConnection();
5267  
    abstract Socket getSocket();
5268  
    abstract void close();
5269  
    
5270  
    int getPort() { return getSocket().getPort(); }
5271  
    
5272  
    boolean helloRead;
5273  
    
5274  
    String readLineNoBlock() {
5275  
      String l = line;
5276  
      line = null;
5277  
      return l;
5278  
    }
5279  
    
5280  
    boolean waitForLine() { try {
5281  
 
5282  
      if (line != null) return true;
5283  
      //print("Readline");
5284  
      line = readLineImpl();
5285  
      //print("Readline done: " + line);
5286  
      if (line == null) eos = true;
5287  
      return line != null;
5288  
    
5289  
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
5290  
    
5291  
    String readLine() {
5292  
      waitForLine();
5293  
      helloRead = true;
5294  
      return readLineNoBlock();
5295  
    }
5296  
    
5297  
    String ask(String s, Object... args) {
5298  
      if (!helloRead) readLine();
5299  
      if (args.length != 0) s = format3(s, args);
5300  
      sendLine(s);
5301  
      return readLine();
5302  
    }
5303  
    
5304  
    String askLoudly(String s, Object... args) {
5305  
      if (!helloRead) readLine();
5306  
      if (args.length != 0) s = format3(s, args);
5307  
      print("> " + s);
5308  
      sendLine(s);
5309  
      String answer = readLine();
5310  
      print("< " + answer);
5311  
      return answer;
5312  
    }
5313  
    
5314  
    void pushback(String l) {
5315  
      if (line != null)
5316  
        fail();
5317  
      line = l;
5318  
      helloRead = false;
5319  
    }
5320  
  }
5321  
  
5322  
  static abstract class DialogHandler {
5323  
    abstract void run(DialogIO io);
5324  
  }
5325  
5326  
  static class Matches {
5327  
    String[] m;
5328  
    String get(int i) { return i < m.length ? m[i] : null; }
5329  
    String unq(int i) { return unquote(get(i)); }
5330  
    String fsi(int i) { return formatSnippetID(unq(i)); }
5331  
    String fsi() { return fsi(0); }
5332  
    String tlc(int i) { return unq(i).toLowerCase(); }
5333  
    boolean bool(int i) { return "true".equals(unq(i)); }
5334  
    String rest() { return m[m.length-1]; } // for matchStart
5335  
    int psi(int i) { return Integer.parseInt(unq(i)); }
5336  
  }
5337  
5338  
5339  
// Now uses TreeMap for nicer sorting (i.e., A must be a orderable type)
5340  
static class MultiSet<A> {
5341  
  Map<A, Integer> map = new TreeMap<A, Integer>();
5342  
  
5343  
  public MultiSet(boolean useTreeMap) {
5344  
    if (!useTreeMap)
5345  
      map = new HashMap;
5346  
  }
5347  
  
5348  
  public MultiSet() {
5349  
  }
5350  
  
5351  
  public MultiSet(Collection<A> c) {
5352  
    addAll(c);
5353  
  }
5354  
5355  
  public void add(A key) {
5356  
    add(key, 1);
5357  
  }
5358  
  
5359  
  public void addAll(Collection<A> c) {
5360  
    if (c != null) for (A a : c)
5361  
      add(a);
5362  
  }
5363  
5364  
  public void add(A key, int count) {
5365  
    if (map.containsKey(key))
5366  
      map.put(key, map.get(key)+count);
5367  
    else
5368  
      map.put(key, count);
5369  
  }
5370  
5371  
  public int get(A key) {
5372  
    return key != null && map.containsKey(key) ? map.get(key) : 0;
5373  
  }
5374  
  
5375  
  public boolean contains(A key) {
5376  
    return map.containsKey(key);
5377  
  }
5378  
5379  
  public void remove(A key) {
5380  
    Integer i = map.get(key);
5381  
    if (i != null && i > 1)
5382  
      map.put(key, i - 1);
5383  
    else
5384  
      map.remove(key);
5385  
  }
5386  
5387  
  public List<A> getTopTen() {
5388  
    return getTopTen(10);
5389  
  }
5390  
  
5391  
  public List<A> getTopTen(int maxSize) {
5392  
    List<A> list = getSortedListDescending();
5393  
    return list.size() > maxSize ? list.subList(0, maxSize) : list;
5394  
  }
5395  
5396  
  public List<A> getSortedListDescending() {
5397  
    List<A> list = new ArrayList<A>(map.keySet());
5398  
    Collections.sort(list, new Comparator<A>() {
5399  
      public int compare(A a, A b) {
5400  
        return map.get(b).compareTo(map.get(a));
5401  
      }
5402  
    });
5403  
    return list;
5404  
  }
5405  
5406  
  public int getNumberOfUniqueElements() {
5407  
    return map.size();
5408  
  }
5409  
5410  
  public Set<A> asSet() {
5411  
    return map.keySet();
5412  
  }
5413  
5414  
  public A getMostPopularEntry() {
5415  
    int max = 0;
5416  
    A a = null;
5417  
    for (Map.Entry<A,Integer> entry : map.entrySet()) {
5418  
      if (entry.getValue() > max) {
5419  
        max = entry.getValue();
5420  
        a = entry.getKey();
5421  
      }
5422  
    }
5423  
    return a;
5424  
  }
5425  
5426  
  public void removeAll(A key) {
5427  
    map.remove(key);
5428  
  }
5429  
5430  
  public int size() {
5431  
    int size = 0;
5432  
    for (int i : map.values())
5433  
      size += i;
5434  
    return size;
5435  
  }
5436  
5437  
  public MultiSet<A> mergeWith(MultiSet<A> set) {
5438  
    MultiSet<A> result = new MultiSet<A>();
5439  
    for (A a : set.asSet()) {
5440  
      result.add(a, set.get(a));
5441  
    }
5442  
    return result;
5443  
  }
5444  
  
5445  
  public boolean isEmpty() {
5446  
    return map.isEmpty();
5447  
  }
5448  
  
5449  
  public String toString() {
5450  
    return structure(this);
5451  
  }
5452  
  
5453  
  public void clear() {
5454  
    map.clear();
5455  
  }
5456  
}
5457  
5458  
static long startTiming_startTime;
5459  
static void startTiming() {
5460  
  startTiming_startTime = now();
5461  
}
5462  
5463  
static void stopTiming() {
5464  
  long end = now();
5465  
  print("Time: " + (end-startTiming_startTime) + " ms");
5466  
}
5467  
static JWindow showLoadingAnimation() {
5468  
  ret showAnimationInTopRightCorner("#1003543", "Hold on user...");
5469  
}
5470  
static BufferedReader readLine_reader;
5471  
5472  
static String readLine() {
5473  
  ret (String) call(getJavaX(), "readLine");
5474  
}
5475  
static void swingLater(int delay, final Runnable r) {
5476  
  javax.swing.Timer timer = new javax.swing.Timer(delay, actionListener {
5477  
    r.run();
5478  
  });
5479  
  timer.setRepeats(false);
5480  
  timer.start();
5481  
}
5482  
5483  
static void swingLater(Runnable r) {
5484  
  SwingUtilities.invokeLater(r);
5485  
}
5486  
5487  
static void swingNowOrLater(Runnable r) {
5488  
  if (isAWTThread())
5489  
    r.run();
5490  
  else
5491  
    swingLater(r);
5492  
}
5493  
static Set asSet(O[] array) {
5494  
  new HashSet set;
5495  
  for (O o : array)
5496  
    if (o != null)
5497  
      set.add(o);
5498  
  ret set;
5499  
}
5500  
5501  
static Set<S> asSet(S[] array) {
5502  
  new TreeSet<S> set;
5503  
  for (S o : array)
5504  
    if (o != null)
5505  
      set.add(o);
5506  
  ret set;
5507  
}
5508  
5509  
static Set<S> asSet(Collection<S> l) {
5510  
  new TreeSet<S> set;
5511  
  for (S o : l)
5512  
    if (o != null)
5513  
      set.add(o);
5514  
  ret set;
5515  
}
5516  
static <A> A or(A a, A b) {
5517  
  return a != null ? a : b;
5518  
}
5519  
static void disposeWindow(final Window window) {
5520  
  awt {
5521  
    window.dispose();
5522  
  }
5523  
}
5524  
static String firstToUpper(String s) {
5525  
  if (s.length() == 0) return s;
5526  
  return Character.toUpperCase(s.charAt(0)) + s.substring(1);
5527  
}
5528  
5529  
}

download  show line numbers   

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

No comments. add comment

Snippet ID: #1004053
Snippet name: Bug
Eternal ID of this version: #1004053/1
Text MD5: 23e79db20826ee367ee750471d6824b3
Author: stefan
Category:
Type: Document
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2016-08-05 02:21:09
Source code size: 168409 bytes / 5529 lines
Pitched / IR pitched: No / No
Views / Downloads: 688 / 356
Referenced in: [show references]