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 {
// a persistent list that only grows
// Note: don't put in static initializer (programID not set yet)
static class PersistentLog extends AbstractList {
List l = new ArrayList();
File file;
PersistentLog(String fileName) {
file = getProgramFile(fileName);
for (String s : scanLog(file)) try {
l.add((A) unstructure(s));
} catch (Throwable __e) { __e.printStackTrace(); }
}
public int size() {
return l.size();
}
public A get(int i) {
return l.get(i);
}
public boolean add(A a) {
l.add(a);
logQuoted(file, structure(a));
return true;
}
}
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);
}
}
static class Msg {
String user, text;
}
// persistent
static PersistentLog msgs;
// built every time in memory
static MultiMap msgsByUser = new MultiMap();
public static void main(String[] args) throws Exception {
msgLog = new PersistentLog("msgs");
for (Msg m : msgLog) msgsByUser.put(m.user, m);
makeBot("I Have Bot.");
}
static synchronized String answer(String s) {
Matches m = new Matches();
if (matchStart("i have", s, m)) {
print(structure(matches.m));
String rest = m.rest();
print("Rest: " + quote(rest));
return "ok";
}
return null;
}
static boolean matchStart(String pat, String s) {
return matchStart(pat, s, null);
}
// matches are as you expect, plus an extra item for the rest string
static boolean matchStart(String pat, String s, Matches matches) {
if (s == null) return false;
List tokpat = parse3(pat), toks = parse3(s);
if (toks.size() < tokpat.size()) return false;
String[] m = match2(tokpat, toks.subList(0, tokpat.size()));
//print(structure(tokpat) + " on " + structure(toks) + " => " + structure(m));
if (m == null)
return false;
else {
if (matches != null) {
matches.m = new String[m.length+1];
arraycopy(m, matches.m);
matches.m[m.length] = join(toks.subList(tokpat.size(), toks.size())); // for Matches.rest()
}
return true;
}
}
static int makeBot(String greeting) {
return makeAndroid3(greeting).port;
}
static void makeBot(Android3 a) {
makeAndroid3(a);
}
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 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 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()) + ")";
// 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 void arraycopy(Object[] a, Object[] b) {
int n = min(a.length, b.length);
for (int i = 0; i < n; i++)
b[i] = a[i];
}
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;
}
static List parse3(String s) {
return dropPunctuation(javaTokPlusPeriod(s));
}
// match2 matches multiple "*" (matches a single token) wildcards and zero or one "..." wildcards (matches multiple tokens)
static String[] match2(List pat, List tok) {
// standard case (no ...)
int i = pat.indexOf("...");
if (i < 0) return match2_match(pat, tok);
pat = new ArrayList(pat); // We're modifying it, so copy first
pat.set(i, "*");
while (pat.size() < tok.size()) {
pat.add(i, "*");
pat.add(i+1, ""); // doesn't matter
}
return match2_match(pat, tok);
}
static String[] match2_match(List pat, List tok) {
List result = new ArrayList();
if (pat.size() != tok.size()) {
/*if (debug)
print("Size mismatch: " + structure(pat) + " vs " + structure(tok));*/
return null;
}
for (int i = 1; i < pat.size(); i += 2) {
String p = pat.get(i), t = tok.get(i);
/*if (debug)
print("Checking " + p + " against " + t);*/
if ("*".equals(p))
result.add(t);
else if (!p.equalsIgnoreCase(t))
return null;
}
return result.toArray(new String[result.size()]);
}
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 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 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 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 answer;
}
static int min(int a, int b) {
return Math.min(a, b);
}
static String getInjectionID() {
return (String) call(getJavaX(), "getInjectionID", getMainClass());
}
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 Throwable getInnerException(Throwable e) {
while (e.getCause() != null)
e = e.getCause();
return e;
}
static boolean publicCommOn() {
return "1".equals(loadTextFile(new File(userHome(), ".javax/public-communication")));
}
static List