import java.math.*;
import javax.imageio.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.*;
import java.security.spec.*;
import java.security.*;
import java.lang.management.*;
import java.lang.ref.*;
import java.lang.reflect.*;
import java.net.*;
import java.io.*;
import javax.swing.table.*;
import javax.swing.text.*;
import javax.swing.event.*;
import javax.swing.*;
import java.util.concurrent.atomic.*;
import java.util.concurrent.*;
import java.util.regex.*;
import java.util.List;
import java.util.zip.*;
import java.util.*;
public class main {
static class MultiMap {
Map> data = new HashMap>();
public void put(A key, B value) {
List list = data.get(key);
if (list == null)
data.put(key, list = new ArrayList());
list.add(value);
}
public void putAll(A key, Collection values) {
for (B value : values)
put(key, value);
}
public List get(A key) {
List list = data.get(key);
return list == null ? Collections. emptyList() : list;
}
public Set keySet() {
return data.keySet();
}
public void remove(A key) {
data.remove(key);
}
public void remove(A key, B value) {
List list = data.get(key);
if (list != null) {
list.remove(value);
if (list.isEmpty())
data.remove(key);
}
}
public void clear() {
data.clear();
}
public boolean containsKey(A key) {
return data.containsKey(key);
}
public B getFirst(A key) {
List list = get(key);
return list.isEmpty() ? null : list.get(0);
}
public void putAll(MultiMap map) {
for (A key : map.keySet())
putAll(key, map.get(key));
}
}
static class Thing {
String name, type, file;
}
static String masterURL = "https://github.com/mcheese/cheesebase/archive/master.zip";
static File zipFile;
static MultiMap map = new MultiMap();
static MultiMap definitions = new MultiMap();
public static void main(String[] args) throws Exception {
zipFile = getProgramFile("master.zip");
if (!zipFile.exists())
loadMaster();
analyze();
makeBot("Cheesebase Bot.");
}
static void loadMaster() { try {
saveBinaryFile(zipFile, loadBinaryPage(masterURL));
print("master.zip loaded from github.");
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
static void analyze() {
findStuff("namespace", "class", "using", "template", "struct", "union", "auto");
}
synchronized static String answer(String s) {
Matches m = new Matches();
if (match("what is *", s, m)) {
String name = m.unq(0);
List things = lookupPossiblyIgnoreCase(map, name);
List defs = lookupPossiblyIgnoreCase(definitions, name);
if (!things.isEmpty() || !empty(defs)) {
List types = list(getSortedSet(things, "type"));
List files = list(getSortedSet(things, "file"));
types = replace(types, "using", "alias");
types = replace(types, "auto", "variable");
String theTypes = isEmpty(types) ? "unknown something" : join("/", types);
String a = (empty(things) ? name : things.get(0).name) + " is " + a(theTypes) + " in cheesebase. It is defined ";
if (!empty(defs))
a += "as " + join("/", quoteAll(defs)) + " ";
if (!empty(files)) {
a += "in ";
if (l(files) == 1)
a += "file " + quote(files.get(0));
else if (l(files) == 2)
a += "files " + quote(files.get(0)) + " and " + quote(files .get(1));
else
a += quote(files.get(0)) + " and " + n(l(files)-1, " other file");
}
return a + ".";
}
}
if (match("all things", s))
return structure(map);
if (match("cheesebase reload", s)) {
loadMaster();
analyze();
return "OK, reloaded from GitHub.";
}
return null;
}
static void findStuff(String... keywords) {
map.clear();
definitions.clear();
for (String file : listZip(zipFile)) {
if (endsWithOneOf(file, ".h", ".cc")) try {
String text = loadTextFileFromZip(zipFile, file);
print("Scanning " + file);
List tok = javaTok(text);
for (String keyword : keywords) {
int i = 0;
while ((i = findCodeTokens(tok, i+1, keyword, "")) >= 0) {
Thing t = new Thing();
t.name = tok.get(i+2);
t.type = keyword;
t.file = dropPrefix("cheesebase-master/" , file);
map.put(t.name, t);
}
}
definitions.putAll(findInitializers(text));
} catch (Throwable __e) { __e.printStackTrace(); }
}
}
static List replace(List in, Object a, Object b) {
List l = new ArrayList();
for (Object x: in)
l.add(eq(x, a) ? b : x);
return l;
}
static String a(String s) {
return ("aeiou".contains(substr(s,0, 1)) ? "an " : "a ")+s;
}
static List quoteAll(List l) {
List x = new ArrayList();
for (String s : l)
x.add(quote(s));
return x;
}
static MultiMap findInitializers(String s) {
List tok = javaTok(s);
Map bracketMap = getBracketMap(tok);
MultiMap map = new MultiMap();
int i = 0;
while ((i = findCodeTokens(tok, i+1, "", "=")) >= 0) {
String name = tok.get(i);
if (eq(get(tok, i+4), "=")) continue; // it's ==, not =
if (litlist(">", ".").contains(get(tok, i-2))) continue; // it's -> or .
int j = scanToEndOfInitializer(tok, bracketMap, i+4);
map.put(name, join(tok.subList(i+4, j)));
}
return map;
}
static String n(long l, String name) {
return l + (l == 1 ? name : getPlural(name));
}
static Set getSortedSet(List l, String field) {
TreeSet set = new TreeSet();
for (Object o : l) {
Object x = (Object) ( getOpt(o, field));
if (x != null)
set.add(x);
}
return set;
}
static String dropPrefix(String prefix, String s) {
return s.startsWith(prefix) ? s.substring(l(prefix)) : s;
}
static boolean empty(Collection c) {
return isEmpty(c);
}
static boolean empty(String s) {
return isEmpty(s);
}
static List lookupPossiblyIgnoreCase(MultiMap map, String key) {
List value = map.get(key);
return !value.isEmpty() ? value : lookupIgnoreCase(map, key);
}
static A lookupPossiblyIgnoreCase(Map map, String key) {
A value = map.get(key);
return value != null ? value : lookupIgnoreCase(map, key);
}
static boolean endsWithOneOf(String s, String... suffixes) {
for (String x : suffixes) if (s.endsWith(x)) return true;
return false;
}
static String loadTextFileFromZip(File inZip, String fileName) {
return loadTextFileFromZipFile(inZip, fileName);
}
// lists files only - who needs to list directories?!
// lists in typical .zip fashion - dir1/dir2/bla.txt
static List listZip(File inZip) {
return listZipFile(inZip);
}
static ArrayList list(A[] a) {
return asList(a);
}
static ArrayList list(int[] a) {
return asList(a);
}
static ArrayList list(Set s) {
return asList(s);
}
static boolean isEmpty(Collection c) {
return c == null || c.isEmpty();
}
static boolean isEmpty(String s) {
return s == null || s.length() == 0;
}
static File getProgramFile(String progID, String fileName) {
return new File(getProgramDir(progID), fileName);
}
static File getProgramFile(String fileName) {
return getProgramFile(getProgramID(), fileName);
}
static String substr(String s, int x) {
return safeSubstring(s, x);
}
static String substr(String s, int x, int y) {
return safeSubstring(s, x, y);
}
static boolean match(String pat, String s) {
return match3(pat, s);
}
static boolean match(String pat, String s, Matches matches) {
return match3(pat, s, matches);
}
static int makeBot(String greeting) {
return makeAndroid3(greeting).port;
}
static void makeBot(Android3 a) {
makeAndroid3(a);
}
static int l(Object[] array) {
return array == null ? 0 : array.length;
}
static int l(Collection c) {
return c == null ? 0 : c.size();
}
static int l(Map m) {
return m == null ? 0 : m.size();
}
static int l(String s) {
return s == null ? 0 : s.length();
}
static String quote(String s) {
if (s == null) return "null";
return "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\r", "\\r").replace("\n", "\\n") + "\"";
}
static String quote(long l) {
return quote("" + l);
}
static int findCodeTokens(List tok, String... tokens) {
return findCodeTokens(tok, 1, tokens);
}
static int findCodeTokens(List tok, int startIdx, String... tokens) {
outer: for (int i = startIdx | 1; i+tokens.length*2-2 < tok.size(); i += 2) {
for (int j = 0; j < tokens.length; j++) {
String p = tokens[j], t = tok.get(i+j*2);
boolean match;
if (eq(p, "*")) match = true;
else if (eq(p, "")) match = isQuoted(t);
else if (eq(p, "")) match = isIdentifier(t);
else match = eq(p, t);
if (!match)
continue outer;
}
return i;
}
return -1;
}
static boolean eq(Object a, Object b) {
if (a == null) return b == null;
if (a.equals(b)) return true;
if (a instanceof BigInteger) {
if (b instanceof Integer) return a.equals(BigInteger.valueOf((Integer) b));
if (b instanceof Long) return a.equals(BigInteger.valueOf((Long) b));
}
return false;
}
// replacement for class JavaTok
// maybe incomplete, might want to add floating point numbers
// todo also: extended multi-line strings
static List javaTok(String s) {
List tok = new ArrayList();
int l = s.length();
int i = 0;
while (i < l) {
int j = i;
char c; String cc;
// scan for whitespace
while (j < l) {
c = s.charAt(j);
cc = s.substring(j, Math.min(j+2, l));
if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
++j;
else if (cc.equals("/*")) {
do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/"));
j = Math.min(j+2, l);
} else if (cc.equals("//")) {
do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0);
} else
break;
}
tok.add(s.substring(i, j));
i = j;
if (i >= l) break;
c = s.charAt(i); // cc is not needed in rest of loop body
cc = s.substring(i, Math.min(i+2, l));
// scan for non-whitespace
if (c == '\'' || c == '"') {
char opener = c;
++j;
while (j < l) {
if (s.charAt(j) == opener) {
++j;
break;
} else if (s.charAt(j) == '\\' && j+1 < l)
j += 2;
else
++j;
}
} else if (Character.isJavaIdentifierStart(c))
do ++j; while (j < l && Character.isJavaIdentifierPart(s.charAt(j)));
else if (Character.isDigit(c)) {
do ++j; while (j < l && Character.isDigit(s.charAt(j)));
if (j < l && s.charAt(j) == 'L') ++j; // Long constants like 1L
} else if (cc.equals("[[")) {
do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]"));
j = Math.min(j+2, l);
} else
++j;
tok.add(s.substring(i, j));
i = j;
}
if ((tok.size() % 2) == 0) tok.add("");
return tok;
}
static List javaTok(List tok) {
return javaTok(join(tok));
}
static StringBuffer print_log;
static void print() {
print("");
}
static void print(Object o) {
String s = String.valueOf(o) + "\n";
synchronized(StringBuffer.class) {
if (print_log == null) print_log = new StringBuffer();
}
print_log.append(s);
System.out.print(s);
}
static void print(long l) {
print(String.valueOf(l));
}
static byte[] loadBinaryPage(String url) throws IOException {
return loadBinaryPage(new URL(url).openConnection());
}
public static byte[] loadBinaryPage(URLConnection con) throws IOException {
//setHeaders(con);
ByteArrayOutputStream buf = new ByteArrayOutputStream();
InputStream inputStream = con.getInputStream();
int n = 0;
while (true) {
int ch = inputStream.read();
if (ch < 0)
break;
buf.write(ch);
if (++n % 100000 == 0)
System.err.println(" " + n + " bytes loaded.");
}
inputStream.close();
return buf.toByteArray();
}
/** writes safely (to temp file, then rename) */
public static void saveBinaryFile(String fileName, byte[] contents) throws IOException {
File file = new File(fileName);
File parentFile = file.getParentFile();
if (parentFile != null)
parentFile.mkdirs();
String tempFileName = fileName + "_temp";
FileOutputStream fileOutputStream = new FileOutputStream(tempFileName);
fileOutputStream.write(contents);
fileOutputStream.close();
if (file.exists() && !file.delete())
throw new IOException("Can't delete " + fileName);
if (!new File(tempFileName).renameTo(file))
throw new IOException("Can't rename " + tempFileName + " to " + fileName);
}
static void saveBinaryFile(File fileName, byte[] contents) {
try {
saveBinaryFile(fileName.getPath(), contents);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static String join(String glue, Iterable strings) {
StringBuilder buf = new StringBuilder();
Iterator i = strings.iterator();
if (i.hasNext()) {
buf.append(i.next());
while (i.hasNext())
buf.append(glue).append(i.next());
}
return buf.toString();
}
public static String join(String glue, String[] strings) {
return join(glue, Arrays.asList(strings));
}
public static String join(Iterable strings) {
return join("", strings);
}
public static String join(String[] strings) {
return join("", strings);
}
static String structure(Object o) {
return structure(o, 0);
}
// leave to false, unless unstructure() breaks
static boolean structure_allowShortening = false;
static String structure(Object o, int stringSizeLimit) {
if (o == null) return "null";
String name = o.getClass().getName();
StringBuilder buf = new StringBuilder();
if (o instanceof Collection) { // TODO: store the type (e.g. HashSet/TreeSet)
for (Object x : (Collection) o) {
if (buf.length() != 0) buf.append(", ");
buf.append(structure(x, stringSizeLimit));
}
return "[" + buf + "]";
}
if (o instanceof Map) {
for (Object e : ((Map) o).entrySet()) {
if (buf.length() != 0) buf.append(", ");
buf.append(structure(((Map.Entry) e).getKey(), stringSizeLimit));
buf.append("=");
buf.append(structure(((Map.Entry) e).getValue(), stringSizeLimit));
}
return "{" + buf + "}";
}
if (o.getClass().isArray()) {
int n = Array.getLength(o);
for (int i = 0; i < n; i++) {
if (buf.length() != 0) buf.append(", ");
buf.append(structure(Array.get(o, i), stringSizeLimit));
}
return "array{" + buf + "}";
}
if (o instanceof String)
return quote(stringSizeLimit != 0 ? shorten((String) o, stringSizeLimit) : (String) o);
if (o instanceof Class)
return "class(" + quote(((Class) o).getName()) + ")";
if (o instanceof Throwable)
return "exception(" + quote(((Throwable) o).getMessage()) + ")";
if (o instanceof BigInteger)
return "bigint(" + o + ")";
// Need more cases? This should cover all library classes...
if (name.startsWith("java.") || name.startsWith("javax."))
return String.valueOf(o);
String shortName = o.getClass().getName().replaceAll("^main\\$", "");
int numFields = 0;
String fieldName = "";
if (shortName.equals("DynamicObject")) {
shortName = (String) get(o, "className");
Map fieldValues = (Map) get(o, "fieldValues");
for (String _fieldName : fieldValues.keySet()) {
fieldName = _fieldName;
Object value = fieldValues.get(fieldName);
if (value != null) {
if (buf.length() != 0) buf.append(", ");
buf.append(fieldName + "=" + structure(value, stringSizeLimit));
}
++numFields;
}
} else {
// regular class
// TODO: go to superclasses too
Field[] fields = o.getClass().getDeclaredFields();
for (Field field : fields) {
if ((field.getModifiers() & Modifier.STATIC) != 0)
continue;
Object value;
try {
field.setAccessible(true);
value = field.get(o);
} catch (Exception e) {
value = "?";
}
fieldName = field.getName();
// put special cases here...
if (value != null) {
if (buf.length() != 0) buf.append(", ");
buf.append(fieldName + "=" + structure(value, stringSizeLimit));
}
++numFields;
}
}
String b = buf.toString();
if (numFields == 1 && structure_allowShortening)
b = b.replaceAll("^" + fieldName + "=", ""); // drop field name if only one
String s = shortName;
if (buf.length() != 0)
s += "(" + b + ")";
return s;
}
static int scanToEndOfInitializer(List tok, Map bracketMap, int i) {
while (i < l(tok)) {
if (litlist(";", ",", ")", "}").contains(tok.get(i)))
return i-1;
Integer j = bracketMap.get(i);
if (j != null)
i = j+1;
else
i++;
}
return i;
}
static Map getBracketMap(List tok) {
Map map = new TreeMap();
List stack = new ArrayList();
for (int i = 1; i < l(tok); i+= 2) {
if (litlist("{", "(").contains(tok.get(i)))
stack.add(i);
else if (litlist("}", ")").contains(tok.get(i))) {
if (!empty(stack))
map.put(liftLast(stack), i);
}
}
return map;
}
static String getPlural(String s) {
return s + "s";
}
static String loadTextFileFromZipFile(File inZip, String fileName) { try {
ZipFile zip = new ZipFile(inZip);
try {
ZipEntry entry = zip.getEntry(fileName);
if (entry == null)
fail("Entryx " + fileName + " not found in zip file: " + inZip.getAbsolutePath());
InputStream fin = zip.getInputStream(entry);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
copyStream(fin, baos);
fin.close();
return fromUTF8(baos.toByteArray());
} finally {
zip.close();
}
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
// lists files only - who needs to list directories?!
// lists in typical .zip fashion - dir1/dir2/bla.txt
static List listZipFile(File inZip) { try {
ZipFile zipFile = new ZipFile(inZip);
try {
List list = new ArrayList();
Enumeration entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = (ZipEntry) entries.nextElement();
if (!entry.isDirectory())
list.add(entry.getName());
}
return list;
} finally {
zipFile.close();
}
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
static A lookupIgnoreCase(Map map, String key) {
for (String s : map.keySet())
if (eqic(s, key))
return map.get(s);
return null;
}
static List lookupIgnoreCase(MultiMap map, String key) {
for (String s : map.keySet())
if (eqic(s, key))
return map.get(s);
return litlist();
}
static boolean isIdentifier(String s) {
return isJavaIdentifier(s);
}
static File getProgramDir() {
return programDir();
}
static File getProgramDir(String snippetID) {
return programDir(snippetID);
}
static abstract class DialogIO {
String line;
boolean eos;
abstract String readLineImpl();
abstract boolean isStillConnected();
abstract void sendLine(String line);
abstract boolean isLocalConnection();
abstract Socket getSocket();
abstract void close();
int getPort() { return getSocket().getPort(); }
boolean helloRead;
String readLineNoBlock() {
String l = line;
line = null;
return l;
}
boolean waitForLine() { try {
if (line != null) return true;
//print("Readline");
line = readLineImpl();
//print("Readline done: " + line);
if (line == null) eos = true;
return line != null;
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
String readLine() {
waitForLine();
helloRead = true;
return readLineNoBlock();
}
String ask(String s, Object... args) {
if (!helloRead) readLine();
if (args.length != 0) s = format3(s, args);
sendLine(s);
return readLine();
}
String askLoudly(String s, Object... args) {
if (!helloRead) readLine();
if (args.length != 0) s = format3(s, args);
print("> " + s);
sendLine(s);
String answer = readLine();
print("< " + answer);
return answer;
}
void pushback(String l) {
if (line != null)
fail();
line = l;
helloRead = false;
}
}
static abstract class DialogHandler {
abstract void run(DialogIO io);
} // Dialog classes
static class Android3 {
String greeting;
boolean publicOverride; // optionally set this in client
int startPort = 5000; // optionally set this in client
Responder responder;
boolean console = true;
boolean daemon = false;
boolean incomingSilent = false;
boolean useMultiPort = true;
// set by system
int port;
long vport;
DialogHandler handler;
ServerSocket server;
Android3(String greeting) {
this.greeting = greeting;}
Android3() {}
synchronized void dispose() {
if (server == null) return;
try {
server.close();
} catch (IOException e) {
print("[internal] " + e);
}
server = null;
}
}
static abstract class Responder {
abstract String answer(String s, List history);
}
static Android3 makeAndroid3(final String greeting) {
return makeAndroid3(new Android3(greeting));
}
static Android3 makeAndroid3(final String greeting, Responder responder) {
Android3 android = new Android3(greeting);
android.responder = responder;
return makeAndroid3(android);
}
static Android3 makeAndroid3(final Android3 a) {
if (a.responder == null)
a.responder = new Responder() {
String answer(String s, List history) {
return callStaticAnswerMethod(s, history);
}
};
if (a.useMultiPort) {
a.vport = addToMultiPort(a.greeting, a.responder);
if (a.vport == 1)
makeAndroid3_handleConsole(a);
return a;
}
print(a.greeting);
a.handler = makeAndroid3_makeDialogHandler(a);
a.port = a.daemon
? startDialogServerOnPortAboveDaemon(a.startPort, a.handler)
: startDialogServerOnPortAbove(a.startPort, a.handler);
a.server = startDialogServer_serverSocket;
if (a.console && makeAndroid3_consoleInUse()) a.console = false;
if (a.console)
makeAndroid3_handleConsole(a);
record(a);
return a;
}
static void makeAndroid3_handleConsole(final Android3 a) {
// Console handling stuff
print("You may also type on this console.");
Thread _t_0 = new Thread() {
public void run() {
try {
List history = new ArrayList();
String line;
while ((line = readLine()) != null) {
if ("bye".equals(line)) {
print("> bye stranger");
history = new ArrayList();
} else {
history.add(line);
history.add(makeAndroid3_getAnswer(line, history, a)); // prints answer on console too
}
}
} catch (Exception _e) {
throw _e instanceof RuntimeException ? (RuntimeException) _e : new RuntimeException(_e); } }
};
_t_0.start();
}
static DialogHandler makeAndroid3_makeDialogHandler(final Android3 a) {
return new DialogHandler() {
public void run(final DialogIO io) {
if (!a.publicOverride && !(publicCommOn() || io.isLocalConnection())) {
io.sendLine("Sorry, not allowed");
return;
}
String dialogID = randomID(8);
io.sendLine(a.greeting + " / Your ID: " + dialogID);
List history = new ArrayList();
while (io.isStillConnected()) {
if (io.waitForLine()) {
final String line = io.readLineNoBlock();
String s = dialogID + " at " + now() + ": " + quote(line);
if (!a.incomingSilent)
print(s);
if ("bye".equals(line)) {
io.sendLine("bye stranger");
return;
}
Matches m = new Matches();
history.add(line);
String answer;
if (match3("this is a continuation of talk *", s, m)
|| match3("hello bot! this is a continuation of talk *", s, m)) {
dialogID = unquote(m.m[0]);
answer = "ok";
} else
answer = makeAndroid3_getAnswer(line, history, a);
history.add(answer);
io.sendLine(answer);
//appendToLog(logFile, s);
}
}
}};
}
static String makeAndroid3_getAnswer(String line, List history, Android3 a) {
String answer;
try {
answer = makeAndroid3_fallback(line, history, a.responder.answer(line, history));
} catch (Throwable e) {
e = getInnerException(e);
e.printStackTrace();
answer = e.toString();
}
if (!a.incomingSilent)
print("> " + shorten(answer, 500));
return answer;
}
static String makeAndroid3_fallback(String s, List history, String answer) {
// Now we only do the safe thing instead of VM inspection - give out our process ID
if (answer == null && match3("what is your pid", s))
return getPID();
if (answer == null && match3("what is your program id", s)) // should be fairly safe, right?
return getProgramID();
if (match3("get injection id", s))
return getInjectionID();
if (answer == null) answer = "?";
if (answer.indexOf('\n') >= 0 || answer.indexOf('\r') >= 0)
answer = quote(answer);
return answer;
}
static boolean makeAndroid3_consoleInUse() {
for (Object o : record_list)
if (o instanceof Android3 && ((Android3) o).console)
return true;
return false;
}
// supports the usual quotings (', ", variable length double brackets)
static boolean isQuoted(String s) {
if (s.startsWith("'") || s.startsWith("\"")) return true;
if (!s.startsWith("[")) return false;
int i = 1;
while (i < s.length() && s.charAt(i) == '=') ++i;
return i < s.length() && s.charAt(i) == '[';
//return Pattern.compile("^\\[=*\\[").matcher(s).find();
}
static String programID;
static String getProgramID() {
return programID;
}
// TODO: ask JavaX instead
static String getProgramID(Class c) {
return or((String) getOpt(c, "programID"), "?");
}
static class Matches {
String[] m;
String get(int i) { return m[i]; }
String unq(int i) { return unquote(m[i]); }
String fsi(int i) { return formatSnippetID(unq(i)); }
boolean bool(int i) { return "true".equals(unq(i)); }
String rest() { return m[m.length-1]; } // for matchStart
}
// class Matches
static boolean match3(String pat, String s) {
return match3(pat, s, null);
}
static boolean match3(String pat, String s, Matches matches) {
if (s == null) return false;
return match3(pat, parse3(s), matches);
}
static boolean match3(String pat, List toks, Matches matches) {
List tokpat = parse3(pat);
return match3(tokpat,toks,matches);
}
static boolean match3(List tokpat, List toks, Matches matches) {
String[] m = match2(tokpat, toks);
//print(structure(tokpat) + " on " + structure(toks) + " => " + structure(m));
if (m == null)
return false;
else {
if (matches != null) matches.m = m;
return true;
}
}
static Object getOpt(Object o, String field) {
if (o == null) return null;
if (o instanceof Class) return getOpt((Class) o, field);
if (o.getClass().getName().equals("main$DynamicObject"))
return call(getOpt_raw(o, "fieldValues"), "get", field);
return getOpt_raw(o, field);
}
static Object getOpt_raw(Object o, String field) {
try {
Field f = getOpt_findField(o.getClass(), field);
if (f == null) return null;
f.setAccessible(true);
return f.get(o);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static Object getOpt(Class c, String field) {
try {
Field f = getOpt_findStaticField(c, field);
if (f == null) return null;
f.setAccessible(true);
return f.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static Field getOpt_findStaticField(Class> c, String field) {
for (Field f : c.getDeclaredFields())
if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0)
return f;
return null;
}
static Field getOpt_findField(Class> c, String field) {
for (Field f : c.getDeclaredFields())
if (f.getName().equals(field))
return f;
return null;
}
static ArrayList litlist(A... a) {
return new ArrayList(Arrays.asList(a));
}
// hopefully covers all cases :)
static String safeSubstring(String s, int x, int y) {
if (s == null) return null;
if (x < 0) x = 0;
if (x > s.length()) return "";
if (y < x) y = x;
if (y > s.length()) y = s.length();
return s.substring(x, y);
}
static String safeSubstring(String s, int x) {
return safeSubstring(s, x, l(s));
}
static ArrayList asList(A[] a) {
return new ArrayList(Arrays.asList(a));
}
static ArrayList asList(int[] a) {
ArrayList l = new ArrayList();
for (int i : a) l.add(i);
return l;
}
static ArrayList asList(Set s) {
return new ArrayList(s);
}
// get purpose 1: access a list (safer version of x.get(y))
static A get(List l, int idx) {
return idx >= 0 && idx < l(l) ? l.get(idx) : null;
}
// get purpose 2: access a field by reflection
static Object get(Object o, String field) {
if (o instanceof Class) return get((Class) o, field);
if (o.getClass().getName().equals("main$DynamicObject"))
return call(get_raw(o, "fieldValues"), "get", field);
return get_raw(o, field);
}
static Object get_raw(Object o, String field) {
try {
Field f = get_findField(o.getClass(), field);
f.setAccessible(true);
return f.get(o);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static Object get(Class c, String field) {
try {
Field f = get_findStaticField(c, field);
f.setAccessible(true);
return f.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static Field get_findStaticField(Class> c, String field) {
for (Field f : c.getDeclaredFields())
if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0)
return f;
throw new RuntimeException("Static field '" + field + "' not found in " + c.getName());
}
static Field get_findField(Class> c, String field) {
for (Field f : c.getDeclaredFields())
if (f.getName().equals(field))
return f;
throw new RuntimeException("Field '" + field + "' not found in " + c.getName());
}
static String shorten(String s, int max) {
return s.length() <= max ? s : s.substring(0, Math.min(s.length(), max)) + "...";
}
static A liftLast(List l) {
int i = l(l)-1;
A a = l.get(i);
l.remove(i);
return a;
}
static String fromUTF8(byte[] bytes) {
return fromUtf8(bytes);
}
static String callStaticAnswerMethod(List bots, String s) {
for (Class c : bots) try {
String answer = callStaticAnswerMethod(c, s);
if (answer != null) return answer;
} catch (Throwable e) {
print("Error calling " + getProgramID(c));
e.printStackTrace();
}
return null;
}
static String callStaticAnswerMethod(Class c, String s) {
String answer = (String) callOpt(c, "answer", s, litlist(s));
if (answer == null)
answer = (String) callOpt(c, "answer", s);
return emptyToNull(answer);
}
static String callStaticAnswerMethod(String s, List history) {
String answer = (String) callOpt(getMainClass(), "answer", s, history);
if (answer == null)
answer = (String) callOpt(getMainClass(), "answer", s);
return emptyToNull(answer);
}
static String getInjectionID() {
return (String) call(getJavaX(), "getInjectionID", getMainClass());
}
static A or(A a, A b) {
return a != null ? a : b;
}
static Object addToMultiPort_responder;
static long addToMultiPort(final String botName) {
return addToMultiPort(botName, new Object() {
public String answer(String s, List history) {
String answer = (String) ( callOpt(getMainClass(), "answer", s, history));
if (answer != null) return answer;
answer = (String) callOpt(getMainClass(), "answer", s);
if (answer != null) return answer;
if (match3("get injection id", s))
return getInjectionID();
return null;
}
});
}
static long addToMultiPort(final String botName, final Object responder) {
print(botName);
addToMultiPort_responder = responder;
startMultiPort();
List ports = getMultiPorts();
if (ports.isEmpty())
fail("No multiports!");
if (ports.size() > 1)
print("Multiple multi-ports. Using last one.");
Object port = last(ports);
Object responder2 = new Object() {
public String answer(String s, List history) {
if (match3("get injection id", s))
return getInjectionID();
if (match3("your name", s))
return botName;
return (String) call(responder, "answer", s, history);
}
};
record(responder2);
return (Long) call(port, "addResponder", botName, responder2);
}
static boolean eqic(String a, String b) {
if ((a == null) != (b == null)) return false;
if (a == null) return true;
return a.equalsIgnoreCase(b);
}
static Throwable getInnerException(Throwable e) {
while (e.getCause() != null)
e = e.getCause();
return e;
}
static boolean isJavaIdentifier(String s) {
if (s.length() == 0 || !Character.isJavaIdentifierStart(s.charAt(0)))
return false;
for (int i = 1; i < s.length(); i++)
if (!Character.isJavaIdentifierPart(s.charAt(i)))
return false;
return true;
}
static boolean publicCommOn() {
return "1".equals(loadTextFile(new File(userHome(), ".javax/public-communication")));
}
static List