import java.util.*;
import java.util.zip.*;
import java.util.List;
import java.util.regex.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.table.*;
import java.io.*;
import java.net.*;
import java.lang.reflect.*;
import java.lang.ref.*;
import java.lang.management.*;
import java.security.*;
import java.security.spec.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.imageio.*;
import java.math.*;
public class main {
static String mail;
static boolean error;
// returns false if done, otherwise calls whenDone later
static boolean action(String s, final Runnable whenDone) {
Matches m = new Matches();
if (match("Bot sets email address to *", s, m)) {
String mail = m.unq(0).toLowerCase();
assertTrue(mail.endsWith("@gmail.com"));
main.mail = mail;
save("mail"); return false;
}
if (match("Bot starts password saver.", s, m)) {
load("mail");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
String pass = swingEnterPassword("Please enter GMail password for " + mail);
if (pass == null)
error = true;
if (whenDone != null) whenDone.run();
} catch (Exception _e) {
throw _e instanceof RuntimeException ? (RuntimeException) _e : new RuntimeException(_e); } }
}); return true;
}
throw fail("unknown command: " + quote(s));
}
static String swingEnterPassword(String msg) {
JPasswordField pf = new JPasswordField();
int okCxl = JOptionPane.showConfirmDialog(null, pf, msg, JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
return okCxl == JOptionPane.OK_OPTION ? str(pf.getPassword()) : null;
}
static RuntimeException fail() {
throw new RuntimeException("fail");
}
static RuntimeException fail(Object msg) {
throw new RuntimeException(String.valueOf(msg));
}
static RuntimeException fail(String msg) {
throw new RuntimeException(unnull(msg));
}
static RuntimeException fail(String msg, Object... args) {
throw new RuntimeException(format(msg, args));
}
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 String quote(char c) {
return quote("" + c);
}
static void load(String varName) {
readLocally(varName);
}
static void load(String progID, String varName) {
readLocally(progID, varName);
}
static void assertTrue(Object o) {
assertEquals(true, o);
}
static boolean assertTrue(String msg, boolean b) {
if (!b)
fail(msg);
return b;
}
static boolean assertTrue(boolean b) {
if (!b)
fail("oops");
return b;
}
static void save(String varName) {
saveLocally(varName);
}
static void save(String progID, String varName) {
saveLocally(progID, varName);
}
static String str(Object o) {
return String.valueOf(o);
}
static String unnull(String s) {
return s == null ? "" : s;
}
static List unnull(List l) {
return l == null ? emptyList() : l;
}
static String format(String pat, Object... args) {
return format3(pat, args);
}
static void assertEquals(Object x, Object y) {
assertEquals(null, x, y);
}
static void assertEquals(String msg, Object x, Object y) {
if (!(x == null ? y == null : x.equals(y)))
fail((msg != null ? msg + ": " : "") + structure(x) + " != " + structure(y));
}
static void readLocally(String varNames) {
readLocally(programID(), varNames);
}
// read a string variable from standard storage
// does not overwrite variable contents if there is no file
static synchronized void readLocally(String progID, String varNames) {
for (String variableName : codeTokensOnly(javaTok(varNames))) {
File textFile = new File(programDir(progID), variableName + ".text");
File structureFile = new File(programDir(progID), variableName + ".structure");
String value = loadTextFile(textFile);
if (value != null)
set(main.class, variableName, value);
else {
value = loadTextFile(structureFile);
if (value != null)
readLocally_set(main.class, variableName, unstructure(value));
}
}
}
static void readLocally_set(Class c, String varName, Object value) {
Object oldValue = get(c, varName);
if (oldValue instanceof List && !(oldValue instanceof ArrayList) && value != null) {
// Assume it's a synchroList.
value = synchroList((List) value);
}
set(c, varName, value);
}
static void saveLocally(String variableName) {
saveLocally(programID(), variableName);
}
static synchronized void saveLocally(String progID, String variableName) {
File textFile = new File(programDir(progID), variableName + ".text");
File structureFile = new File(programDir(progID), variableName + ".structure");
Object x = get(main.class, variableName);
if (x == null) {
textFile.delete();
structureFile.delete();
} else if (x instanceof String) {
structureFile.delete();
saveTextFile(textFile, (String) x);
} else {
textFile.delete();
saveTextFile(structureFile, structure(x));
}
}
static String format3(String pat, Object... args) {
if (args.length == 0) return pat;
List tok = javaTokPlusPeriod(pat);
int argidx = 0;
for (int i = 1; i < tok.size(); i += 2)
if (tok.get(i).equals("*"))
tok.set(i, format3_formatArg(argidx < args.length ? args[argidx++] : "null"));
return join(tok);
}
static String format3_formatArg(Object arg) {
if (arg == null) return "null";
if (arg instanceof String) {
String s = (String) arg;
return isIdentifier(s) || isNonNegativeInteger(s) ? s : quote(s);
}
if (arg instanceof Integer || arg instanceof Long) return String.valueOf(arg);
return quote(structure(arg));
}
// 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 || s.charAt(j) == '\n') { // end at \n to not propagate unclosed string literal errors
++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)) || "'".indexOf(s.charAt(j)) >= 0)); // for stuff like "don't"
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 if (cc.equals("[=") && i+2 < l && s.charAt(i+2) == '[') {
do ++j; while (j+2 < l && !s.substring(j, j+3).equals("]=]"));
j = Math.min(j+3, 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 class DynamicObject {
String className;
Map fieldValues = new TreeMap();
}
static Object unstructure(String text) {
return unstructure(text, false);
}
// TODO: backrefs for hashmap{} etc
static Object unstructure(String text, final boolean allDynamic) {
if (text == null) return null;
final List tok = javaTok(text);
final boolean debug = unstructure_debug;
class X {
int i = 1;
HashMap refs = new HashMap();
Object parse() {
String t = tok.get(i);
int refID = 0;
if (t.startsWith("m") && isInteger(t.substring(1))) {
refID = parseInt(t.substring(1));
i += 2;
t = tok.get(i);
}
if (debug)
print("parse: " + quote(t));
if (t.startsWith("\"")) {
String s = unquote(tok.get(i));
i += 2;
return s;
}
if (t.startsWith("'")) {
char c = unquoteCharacter(tok.get(i));
i += 2;
return c;
}
if (t.equals("bigint"))
return parseBigInt();
if (t.equals("d"))
return parseDouble();
if (t.equals("false") || t.equals("f")) {
i += 2; return false;
}
if (t.equals("true") || t.equals("t")) {
i += 2; return true;
}
if (t.equals("-")) {
t = tok.get(i+2);
i += 4;
return isLongConstant(t) ? (Object) (-parseLong(t)) : (Object) (-parseInt(t));
}
if (isInteger(t) || isLongConstant(t)) {
i += 2;
if (debug)
print("isLongConstant " + quote(t) + " => " + isLongConstant(t));
return isLongConstant(t) ? (Object) parseLong(t) : (Object) parseInt(t);
}
if (t.startsWith("r") && isInteger(t.substring(1))) {
i += 2;
int ref = Integer.parseInt(t.substring(1));
Object o = refs.get(ref);
if (o == null)
print("Warning: unsatisfied back reference " + ref);
return o;
}
return parse_inner(refID);
}
// everything that can be backreferenced
Object parse_inner(int refID) {
String t = tok.get(i);
if (debug)
print("parse_inner: " + quote(t));
if (t.equals("hashset"))
return parseHashSet();
if (t.equals("treeset"))
return parseTreeSet();
if (t.equals("hashmap"))
return parseHashMap();
if (t.equals("{"))
return parseMap();
if (t.equals("["))
return parseList();
if (t.equals("array"))
return parseArray();
if (t.equals("class"))
return parseClass();
if (t.equals("l"))
return parseLisp();
if (t.equals("null")) {
i += 2; return null;
}
if (isJavaIdentifier(t)) {
Class c = allDynamic ? null : findClass(t);
DynamicObject dO = null;
Object o = null;
if (c != null)
o = nuObject(c);
else {
dO = new DynamicObject();
dO.className = t;
}
if (refID != 0)
refs.put(refID, o);
i += 2;
if (i < tok.size() && tok.get(i).equals("(")) {
consume("(");
while (!tok.get(i).equals(")")) {
// It's like parsing a map.
//Object key = parse();
//if (tok.get(i).equals(")"))
// key = onlyField();
String key = unquote(tok.get(i));
i += 2;
consume("=");
Object value = parse();
if (o != null)
setOpt(o, key, value);
else
dO.fieldValues.put(key, value);
if (tok.get(i).equals(",")) i += 2;
}
consume(")");
}
return o != null ? o : dO;
}
throw new RuntimeException("Unknown token " + (i+1) + ": " + t);
}
Object parseSet(Set set) {
set.addAll((List) parseList());
return set;
}
Object parseLisp() {
consume("l");
consume("(");
List list = new ArrayList();
while (!tok.get(i).equals(")")) {
list.add(parse());
if (tok.get(i).equals(",")) i += 2;
}
consume(")");
return newObject("main$Lisp", (String) list.get(0), subList(list, 1));
}
Object parseList() {
consume("[");
List list = new ArrayList();
while (!tok.get(i).equals("]")) {
list.add(parse());
if (tok.get(i).equals(",")) i += 2;
}
consume("]");
return list;
}
Object parseArray() {
consume("array");
consume("{");
List list = new ArrayList();
while (!tok.get(i).equals("}")) {
list.add(parse());
if (tok.get(i).equals(",")) i += 2;
}
consume("}");
return list.toArray();
}
Object parseClass() {
consume("class");
consume("(");
String name = tok.get(i);
i += 2;
consume(")");
Class c = allDynamic ? null : findClass(name);
if (c != null) return c;
DynamicObject dO = new DynamicObject();
dO.className = "java.lang.Class";
dO.fieldValues.put("name", name);
return dO;
}
Object parseBigInt() {
consume("bigint");
consume("(");
String val = tok.get(i);
i += 2;
if (eq(val, "-")) {
val = "-" + tok.get(i);
i += 2;
}
consume(")");
return new BigInteger(val);
}
Object parseDouble() {
consume("d");
consume("(");
String val = unquote(tok.get(i));
i += 2;
consume(")");
return Double.parseDouble(val);
}
Object parseHashMap() {
consume("hashmap");
return parseMap(new HashMap());
}
Object parseHashSet() {
consume("hashset");
return parseSet(new HashSet());
}
Object parseTreeSet() {
consume("treeset");
return parseSet(new TreeSet());
}
Object parseMap() {
return parseMap(new TreeMap());
}
Object parseMap(Map map) {
consume("{");
while (!tok.get(i).equals("}")) {
Object key = parse();
consume("=");
Object value = parse();
map.put(key, value);
if (tok.get(i).equals(",")) i += 2;
}
consume("}");
return map;
}
void consume(String s) {
if (!tok.get(i).equals(s)) {
String prevToken = i-2 >= 0 ? tok.get(i-2) : "";
String nextTokens = join(tok.subList(i, Math.min(i+4, tok.size())));
fail(quote(s) + " expected: " + prevToken + " " + nextTokens + " (" + i + "/" + tok.size() + ")");
}
i += 2;
}
}
return new X().parse();
}
static boolean unstructure_debug;
static List emptyList() {
return new ArrayList();
//ret Collections.emptyList();
}
// get purpose 1: access a list/array (safer version of x.get(y))
static A get(List l, int idx) {
return idx >= 0 && idx < l(l) ? l.get(idx) : null;
}
static A get(A[] l, int idx) {
return idx >= 0 && idx < l(l) ? l[idx] : null;
}
// get purpose 2: access a field by reflection or a map
static Object get(Object o, String field) {
if (o instanceof Class) return get((Class) o, field);
if (o instanceof Map)
return ((Map) o).get(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) {
Class _c = c;
do {
for (Field f : _c.getDeclaredFields())
if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0)
return f;
_c = _c.getSuperclass();
} while (_c != null);
throw new RuntimeException("Static field '" + field + "' not found in " + c.getName());
}
static Field get_findField(Class> c, String field) {
Class _c = c;
do {
for (Field f : _c.getDeclaredFields())
if (f.getName().equals(field))
return f;
_c = _c.getSuperclass();
} while (_c != null);
throw new RuntimeException("Field '" + field + "' not found in " + c.getName());
}
static List synchroList() {
return Collections.synchronizedList(new ArrayList());
}
static List synchroList(List l) {
return Collections.synchronizedList(l);
}
static File programDir() {
return programDir(getProgramID());
}
static File programDir(String snippetID) {
return new File(javaxDataDir(), formatSnippetID(snippetID));
}
static String programID() {
return getProgramID();
}
public static String loadTextFile(String fileName) {
try {
return loadTextFile(fileName, null);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static String loadTextFile(String fileName, String defaultContents) throws IOException {
if (!new File(fileName).exists())
return defaultContents;
FileInputStream fileInputStream = new FileInputStream(fileName);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
return loadTextFile(inputStreamReader);
}
public static String loadTextFile(File fileName) {
try {
return loadTextFile(fileName, null);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static String loadTextFile(File fileName, String defaultContents) throws IOException {
try {
return loadTextFile(fileName.getPath(), defaultContents);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static String loadTextFile(Reader reader) throws IOException {
StringBuilder builder = new StringBuilder();
try {
char[] buffer = new char[1024];
int n;
while (-1 != (n = reader.read(buffer)))
builder.append(buffer, 0, n);
} finally {
reader.close();
}
return builder.toString();
}
static void set(Object o, String field, Object value) {
if (o instanceof Class) set((Class) o, field, value);
else try {
Field f = set_findField(o.getClass(), field);
smartSet(f, o, value);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static void set(Class c, String field, Object value) {
try {
Field f = set_findStaticField(c, field);
smartSet(f, null, value);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static Field set_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 Field set_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 List codeTokensOnly(List tok) {
List l = new ArrayList();
for (int i = 1; i < tok.size(); i += 2)
l.add(tok.get(i));
return l;
}
static String structure(Object o) {
HashSet refd = new HashSet();
return structure_2(structure_1(o, 0, new IdentityHashMap(), refd), refd);
}
// leave to false, unless unstructure() breaks
static boolean structure_allowShortening = false;
static String structure_1(Object o, int stringSizeLimit, IdentityHashMap