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 List data = toLinesFullTrim("\n If A likes B then A will greet B.\n If X then Y.\n If U then V. && U. => V.\n John likes Paul.\n"); static List> log; static String toCheck = "John will greet Paul."; static class Flow { StringBuilder desc = new StringBuilder(); List subs = new ArrayList(); Flow sub(String desc) { Flow flow = new Flow(); flow.append(desc); subs.add(flow); return flow; } void append(Object o) { desc.append(o).append("\n"); } void x(Object o) { append(o); } public String toString() { return str(desc) + indentx(allToStringWithLineBreaks(subs)); } } public static void main(String[] args) throws Exception { typeWriterConsole(); // Parse data log = map("tok", data); TreeSet newData = new TreeSet(); // Go through all rules Flow flow = new Flow(); for (List tok : log) { Map m = matchSingle("I => O", tok); if (m == null) continue; String i = m.get("I"), o = m.get("O"); // Parse left-hand List tokI = tok(i); List> is = splitAtAmpersands(tokI); flow.x("Processing LHS: " + struct(is)); // Apply rule to input for (Map m2 : gSatAnd(is, flow)) newData.add(join(" ", replaceVars(tok(o), m2))); } print(("Lines made (" + (l(newData)) + "):")); psl(asList(newData)); printWithAsciiHeading("FLOW", flow); } // null = no satisfaction // otherwise return var map static Iterable> gSatAnd(List> statements, Flow flow) { flow = flow.sub("gSatAnd" + struct(statements)); assertTrue(l(statements) >= 1); if (l(statements) == 1) return gSat(first(statements), flow); List> l = new ArrayList>(); for (Map map : gSat(first(statements), flow)) { flow.x("First clause satisfied. " + struct(map)); List> s2 = mapReplaceVars(dropFirst(statements), map); flow.x("Now looking for: " + struct(s2)); for (Map map2 : gSatAnd(s2, flow)) { flow.x("Sub gSatAnd returned: " + struct(map2)); addIfNotEmpty(l, mergeMappings(map, map2)); } } return l; } static IterableIterator> gSat(List pat, Flow flow) { flow = flow.sub("gSat" + struct(pat)); return gMatch(pat, flow); } static IterableIterator> gMatch(final List pat, final Flow flow) { return new IterableIterator>() { int i = l(log); Iterator> m; public boolean hasNext() { if (m != null && m.hasNext()) return true; m = null; while (--i >= 0) { List> l = match(pat, get(log, i)); if (nempty(l)) { flow.x("gMatch found: " + struct(l)); m = l.iterator(); return true; } } return false; } public Map next() { return m.next(); } }; } static List> splitAtAmpersands(List tok) { List> l = new ArrayList>(); int iAmp; while ((iAmp = indexOfSubList(tok, ll("&", "&"))) >= 0) { //print("&& found at " + iAmp); l.add(subList(tok, 0, iAmp)); tok = subList(tok, iAmp+2); } l.add(tok); return l; } static Map matchSingle(String pat, List input) { return getSingletonOpt(match(tok(pat), input)); } static Map matchSingle(String pat, String input) { return getSingletonOpt(match(pat, input)); } static List tok(String s) { return s == null ? null : codeTokens(nlTok(s)); } static List> match(String pat, String input) { return match(tok(pat), tok(input)); } static List> match(List pat, List input) { Map vars = singleCharacterVars(pat); List> matches = new ArrayList>(); matchImpl(pat, vars, 0, input, 0, new HashMap(), matches); return matches; } static void matchImpl(List pat, Map vars, int iPat, List input, int iInput, Map values, List> matches) { if (iPat >= l(pat)) { if (iInput < l(input)) return; // fail, too much input //print("Match! " + struct(values)); matches.add(cloneMap(values)); return; } if (iInput >= l(input)) return; // out of input String t = pat.get(iPat); String var = vars.get(iPat); if (var != null) { // it's a variable, try different lengths of input as match for (int jInput = iInput+1; jInput <= l(input); jInput++) { String value = join(" ", subList(input, iInput, jInput)); String oldValue = values.get(var); if (oldValue != null && !eqic(value, oldValue)) return; // fail, bad multi-assignment if (oldValue == null) values.put(var, value); // proceed matchImpl(pat, vars, iPat+1, input, jInput, values, matches); // delete assignment if (oldValue == null) values.remove(var); else values.put(var, oldValue); } } else { // it's a literal if (!eqic(t, input.get(iInput))) return; // fail // match, proceed matchImpl(pat, vars, iPat+1, input, iInput+1, values, matches); } } static Map singleCharacterVars(List tok) { Map vars = new HashMap(); for (int i = 0; i < l(tok); i++) { String t = tok.get(i); if (l(t) == 1 && isUpperCaseLetter(t.charAt(0))) vars.put(i, t); } return vars; } static List> mapReplaceVars(List> patterns, final Map map) { return map(new Object() { Object get(List pat) { return replaceVars(pat, map) ; } public String toString() { return "replaceVars(pat, map)"; }}, patterns); } static List replaceVars(List tok, final Map map) { return flattenList(map(tok, new Object() { Object get(String t) { return or((Object) tok(map.get(t)), t) ; } public String toString() { return "or((O) tok(map.get(t)), t)"; }})); } static String struct(Object o) { return structure(o); } static ArrayList ll(A... a) { return litlist(a); } static boolean isUpperCaseLetter(char c) { return Character.isUpperCase(c); } static void psl(Object o) { print(structureLines(o)); } static void psl(String indent, Object o) { printIndent(indent, structureLines(o)); } static Map mergeMappings(Map a, Map b) { for (A var : keys(a)) if (b.containsKey(var) && neq(a.get(var), b.get(var))) return null; // fail return mergeMaps(a, b); } static int indexOfSubList(List x, List y) { return indexOfSubList(x, y, 0); } static int indexOfSubList(List x, List y, int i) { outer: for (; i+l(y) <= l(x); i++) { for (int j = 0; j < l(y); j++) if (neq(x.get(i+j), y.get(j))) continue outer; return i; } return -1; } 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(Iterable s) { if (s instanceof ArrayList) return (ArrayList) s; ArrayList l = new ArrayList(); if (s != null) for (A a : s) l.add(a); return l; } static void addIfNotEmpty(List l, String s) { if (nempty(s)) l.add(s); } static void addIfNotEmpty(List l, Map m) { if (nempty(m)) l.add(m); } static void assertTrue(Object o) { assertEquals(true, o); } static boolean assertTrue(String msg, boolean b) { if (!b) throw fail(msg); return b; } static boolean assertTrue(boolean b) { if (!b) throw fail("oops"); return b; } // 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; } // default to false static boolean get(boolean[] l, int idx) { return idx >= 0 && idx < l(l) ? l[idx] : false; } static Class get_dynamicObject = findClass("DynamicObject"); // get purpose 2: access a field by reflection or a map static Object get(Object o, String field) { try { if (o instanceof Class) return get((Class) o, field); if (o instanceof Map) return ((Map) o).get(field); Field f = getOpt_findField(o.getClass(), field); if (f != null) { f.setAccessible(true); return f.get(o); } if (get_dynamicObject != null && get_dynamicObject.isInstance(o)) return call(get_raw(o, "fieldValues"), "get", field); } catch (Exception e) { throw asRuntimeException(e); } throw new RuntimeException("Field '" + field + "' not found in " + o.getClass().getName()); } 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 String indentx(String s) { return indentx(indent_default, s); } static String indentx(int n, String s) { return dropSuffix(repeat(' ', n), indent(n, s)); } static String indentx(String indent, String s) { return dropSuffix(indent, indent(indent, s)); } 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 List map(Iterable l, Object f) { return map(f, l); } static List map(Object f, Iterable l) { List x = new ArrayList(); Object mc = mc(); for (Object o : unnull(l)) x.add(callFunction(f, o)); return x; } static List map(Object f, Object[] l) { return map(f, asList(l)); } static List map(Map map, Object f) { List x = new ArrayList(); for (Object _e : map.entrySet()) { Map.Entry e = (Map.Entry) _e; x.add(callFunction(f, e.getKey(), e.getValue())); } return x; } static List subList(List l, int startIndex) { return subList(l, startIndex, l(l)); } static List subList(List l, int startIndex, int endIndex) { startIndex = max(0, min(l(l), startIndex)); endIndex = max(0, min(l(l), endIndex)); if (startIndex > endIndex) return litlist(); return l.subList(startIndex, endIndex); } static Map cloneMap(Map map) { if (map == null) return litmap(); // assume mutex is equal to collection, which will be true unless you explicitly pass a mutex to synchronizedList() which no one ever does. synchronized(map) { return new HashMap(map); } } static A or(A a, A b) { return a != null ? a : b; } static A getSingletonOpt(List l) { return l(l) == 1 ? first(l) : null; } static List codeTokens(List tok) { return codeTokensOnly(tok); } static boolean nempty(Collection c) { return !isEmpty(c); } static boolean nempty(CharSequence s) { return !isEmpty(s); } static boolean nempty(Object[] o) { return !isEmpty(o); } static boolean nempty(Map m) { return !isEmpty(m); } static boolean nempty(Iterator i) { return i != null && i.hasNext(); } static boolean eqic(String a, String b) { if ((a == null) != (b == null)) return false; if (a == null) return true; return a.equalsIgnoreCase(b); } static int l(Object[] a) { return a == null ? 0 : a.length; } static int l(boolean[] a) { return a == null ? 0 : a.length; } static int l(byte[] a) { return a == null ? 0 : a.length; } static int l(int[] a) { return a == null ? 0 : a.length; } static int l(float[] a) { return a == null ? 0 : a.length; } static int l(char[] a) { return a == null ? 0 : a.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(CharSequence s) { return s == null ? 0 : s.length(); } static int l(Object o) { return l((List) o); // incomplete } static List flattenList(List a) { List l = new ArrayList(); for (Object x : a) if (x instanceof List) l.addAll(flattenList((List) x)); else l.add(x); return l; } static String str(Object o) { return String.valueOf(o); } static String allToStringWithLineBreaks(List l) { StringBuilder buf = new StringBuilder(); for (Object o : l) buf.append(o).append("\n"); return str(buf); } static volatile StringBuffer local_log = new StringBuffer(); // not redirected static volatile StringBuffer print_log = local_log; // might be redirected, e.g. to main bot // in bytes - will cut to half that static volatile int print_log_max = 1024*1024; static volatile int local_log_max = 100*1024; //static int print_maxLineLength = 0; // 0 = unset static boolean print_silent; // total mute if set static void print() { print(""); } // slightly overblown signature to return original object... static A print(A o) { ping(); if (print_silent) return o; String s = String.valueOf(o) + "\n"; // TODO if (print_maxLineLength != 0) StringBuffer loc = local_log; StringBuffer buf = print_log; int loc_max = print_log_max; if (buf != loc && buf != null) { print_append(buf, s, print_log_max); loc_max = local_log_max; } if (loc != null) print_append(loc, s, loc_max); System.out.print(s); return o; } static void print(long l) { print(String.valueOf(l)); } static void print(char c) { print(String.valueOf(c)); } static void print_append(StringBuffer buf, String s, int max) { synchronized(buf) { buf.append(s); max /= 2; if (buf.length() > max) try { int newLength = max/2; int ofs = buf.length()-newLength; String newString = buf.substring(ofs); buf.setLength(0); buf.append("[...] ").append(newString); } catch (Exception e) { buf.setLength(0); } } } static List nlTok(String s) { return javaTokPlusPeriod(s); } static List toLinesFullTrim(String s) { List l = toLines(s); for (ListIterator i = l.listIterator(); i.hasNext(); ) { String line = i.next().trim(); if (line.length() == 0) i.remove(); else i.set(line); } return l; } static List toLinesFullTrim(File f) { return toLinesFullTrim(loadTextFile(f)); } static void printWithAsciiHeading(String heading, Object o) { printAsciiHeading2(heading); print(o); } static Object first(Object list) { return ((List) list).isEmpty() ? null : ((List) list).get(0); } static A first(List list) { return list.isEmpty() ? null : list.get(0); } static A first(A[] bla) { return bla == null || bla.length == 0 ? null : bla[0]; } static A first(Iterable i) { if (i == null) return null; Iterator it = i.iterator(); return it.hasNext() ? it.next() : null; } static String[] dropFirst(int n, String[] a) { return drop(n, a); } static String[] dropFirst(String[] a) { return drop(1, a); } static Object[] dropFirst(Object[] a) { return drop(1, a); } static List dropFirst(List l) { return dropFirst(1, l); } static List dropFirst(int n, List l) { return new ArrayList(l.subList(Math.min(n, l.size()), l.size())); } static String dropFirst(int n, String s) { return substring(s, n); } static Object callFunction(Object f, Object... args) { if (f == null) return null; if (f instanceof Runnable) { ((Runnable) f).run(); return null; } else if (f instanceof String) return call(mc(), (String) f, args); else return call(f, "get", args); //else throw fail("Can't call a " + getClassName(f)); } static void printIndent(Object o) { print(indentx(str(o))); } static void printIndent(String indent, Object o) { print(indentx(indent, str(o))); } static void printIndent(int indent, Object o) { print(indentx(indent, str(o))); } static RuntimeException asRuntimeException(Throwable t) { return t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t); } static Object mc() { return getMainClass(); } static Map mergeMaps(Map... maps) { Map map = new HashMap(); for (Map m : maps) map.putAll(m); return map; } static boolean neq(Object a, Object b) { return !eq(a, b); } static void printAsciiHeading2(String text) { print(asciiHeading2(text)); } 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; } // currently finds only inner classes of class "main" // returns null on not found // this is the simple version that is not case-tolerant static Class findClass(String name) { if (!isJavaIdentifier(name)) return null; try { return Class.forName("main$" + name); } catch (ClassNotFoundException e) { return null; } } static Map litmap(Object... x) { TreeMap map = new TreeMap(); litmap_impl(map, x); return map; } static void litmap_impl(Map map, Object... x) { for (int i = 0; i < x.length-1; i += 2) if (x[i+1] != null) map.put(x[i], x[i+1]); } 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)); } // disabled for now to shorten some programs /*static RuntimeException fail(S msg, O... args) { throw new RuntimeException(format(msg, args)); }*/ // This is made for NL parsing. // It's javaTok extended with "..." token, "$n" and "#n" and // special quotes (which are converted to normal ones). static List javaTokPlusPeriod(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 = s.substring(i, Math.min(i+2, l)); // scan for non-whitespace if (c == '\u201C' || c == '\u201D') c = '"'; // normalize quotes if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { char _c = s.charAt(j); if (_c == '\u201C' || _c == '\u201D') _c = '"'; // normalize quotes if (_c == opener) { ++j; break; } else if (s.charAt(j) == '\\' && j+1 < l) j += 2; else ++j; } if (j-1 >= i+1) { tok.add(opener + s.substring(i+1, j-1) + opener); i = j; continue; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || s.charAt(j) == '\'')); // for things like "this one's" else if (Character.isDigit(c)) do ++j; while (j < l && Character.isDigit(s.charAt(j))); 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 if (s.substring(j, Math.min(j+3, l)).equals("...")) j += 3; else if (c == '$' || c == '#') do ++j; while (j < l && Character.isDigit(s.charAt(j))); else ++j; tok.add(s.substring(i, j)); i = j; } if ((tok.size() % 2) == 0) tok.add(""); return tok; } static String[] drop(int n, String[] a) { n = Math.min(n, a.length); String[] b = new String[a.length-n]; System.arraycopy(a, n, b, 0, b.length); return b; } static Object[] drop(int n, Object[] a) { n = Math.min(n, a.length); Object[] b = new Object[a.length-n]; System.arraycopy(a, n, b, 0, b.length); return b; } static int indent_default = 2; static String indent(int indent) { return repeat(' ', indent); } static String indent(int indent, String s) { return indent(repeat(' ', indent), s); } static String indent(String indent, String s) { return indent + s.replace("\n", "\n" + indent); } static String indent(String s) { return indent(indent_default, s); } static List indent(String indent, List lines) { List l = new ArrayList(); for (String s : lines) l.add(indent + s); return l; } static Set keys(Map map) { return map.keySet(); } static Set keys(Object map) { return keys((Map) map); } static volatile boolean ping_pauseAll; static int ping_sleep = 100; // poll pauseAll flag every 100 static volatile boolean ping_anyActions; static Map ping_actions = synchroMap(new WeakHashMap()); // returns true if it did anything static boolean ping() { if (ping_pauseAll) { do sleep(ping_sleep); while (ping_pauseAll); return true; } if (ping_anyActions) { Object action; synchronized(mc()) { action = ping_actions.get(currentThread()); if (action instanceof Runnable) ping_actions.remove(currentThread()); if (ping_actions.isEmpty()) ping_anyActions = false; } if (action instanceof Runnable) ((Runnable) action).run(); else if (eq(action, "cancelled")) throw fail("Thread cancelled."); } return false; } static String unnull(String s) { return s == null ? "" : s; } static List unnull(List l) { return l == null ? emptyList() : l; } static Iterable unnull(Iterable i) { return i == null ? emptyList() : i; } static Object[] unnull(Object[] a) { return a == null ? new Object[0] : a; } static BitSet unnull(BitSet b) { return b == null ? new BitSet() : b; } static String substring(String s, int x) { return safeSubstring(s, x); } static String substring(String s, int x, int y) { return safeSubstring(s, x, y); } static int min(int a, int b) { return Math.min(a, b); } static long min(long a, long b) { return Math.min(a, b); } static double min(double a, double b) { return Math.min(a, b); } static double min(double[] c) { double x = Double.MAX_VALUE; for (double d : c) x = Math.min(x, d); return x; } static byte min(byte[] c) { byte x = 127; for (byte d : c) if (d < x) x = d; return x; } static ArrayList litlist(A... a) { return new ArrayList(Arrays.asList(a)); } static String repeat(char c, int n) { n = max(n, 0); char[] chars = new char[n]; for (int i = 0; i < n; i++) chars[i] = c; return new String(chars); } static List repeat(A a, int n) { List l = new ArrayList(); for (int i = 0; i < n; i++) l.add(a); return l; } static List toLines(File f) { return toLines(loadTextFile(f)); } public static List toLines(String s) { List lines = new ArrayList(); if (s == null) return lines; int start = 0; while (true) { int i = toLines_nextLineBreak(s, start); if (i < 0) { if (s.length() > start) lines.add(s.substring(start)); break; } lines.add(s.substring(start, i)); if (s.charAt(i) == '\r' && i+1 < s.length() && s.charAt(i+1) == '\n') i += 2; else ++i; start = i; } return lines; } private static int toLines_nextLineBreak(String s, int start) { for (int i = start; i < s.length(); i++) { char c = s.charAt(i); if (c == '\r' || c == '\n') return i; } return -1; } 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 int max(int a, int b) { return Math.max(a, b); } static int max(int a, int b, int c) { return max(max(a, b), c); } static long max(int a, long b) { return Math.max((long) a, b); } static long max(long a, long b) { return Math.max(a, b); } static double max(int a, double b) { return Math.max((double) a, b); } static float max(float a, float b) { return Math.max(a, b); } static int max(Collection c) { int x = Integer.MIN_VALUE; for (int i : c) x = max(x, i); return x; } static double max(double[] c) { if (c.length == 0) return Double.MIN_VALUE; double x = c[0]; for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]); return x; } static byte max(byte[] c) { byte x = -128; for (byte d : c) if (d > x) x = d; return x; } static String dropSuffix(String suffix, String s) { return s.endsWith(suffix) ? s.substring(0, l(s)-l(suffix)) : s; } static boolean isEmpty(Collection c) { return c == null || c.isEmpty(); } static boolean isEmpty(CharSequence s) { return s == null || s.length() == 0; } static boolean isEmpty(Object[] a) { return a == null || a.length == 0; } static boolean isEmpty(Map map) { return map == null || map.isEmpty(); } static A assertEquals(Object x, A y) { return assertEquals(null, x, y); } static A assertEquals(String msg, Object x, A y) { if (!(x == null ? y == null : x.equals(y))) throw fail((msg != null ? msg + ": " : "") + structure(x) + " != " + structure(y)); return y; } static String structure(Object o) { HashSet refd = new HashSet(); StringBuilder out = new StringBuilder(); structure_1(out, o, new structure_Data(refd)); return structure_2(str(out), refd); } // leave to false, unless unstructure() breaks static boolean structure_allowShortening = false; static int structure_shareStringsLongerThan = 20; static class structure_Data { int stringSizeLimit; IdentityHashMap seen = new IdentityHashMap(); HashSet refd; HashMap strings = new HashMap(); HashSet concepts = new HashSet(); Class conceptClass = findClass("Concept"); structure_Data(HashSet refd) { this.refd = refd;} } static void structure_1(StringBuilder out, Object o, structure_Data d) { if (o == null) { out.append("null"); return; } // these are never back-referenced (for readability) if (o instanceof BigInteger) { out.append("bigint(").append(o).append(")"); return; } if (o instanceof Double) { out.append("d(").append(quote(str(o))).append(")"); return; } if (o instanceof Float) { out.append("fl ").append(quote(str(o))); return; } if (o instanceof Long) { out.append(o).append("L"); return; } if (o instanceof Integer) { out.append(str(o)); return; } if (o instanceof Boolean) { out.append(((Boolean) o).booleanValue() ? "t" : "f"); return; } if (o instanceof Character) { out.append(quoteCharacter((Character) o)); return; } if (o instanceof File) { out.append("File ").append(quote(((File) o).getPath())); return; } // referencable objects follow Integer ref = d.seen.get(o); if (ref != null) { d.refd.add(ref); out.append("r").append(ref); return; } if (o instanceof String && (ref = d.strings.get((String) o)) != null) { d.refd.add(ref); out.append("r").append(ref); return; } ref = d.seen.size()+1; d.seen.put(o, ref); out.append("m").append(ref).append(" "); // marker if (o instanceof String) { String s = d.stringSizeLimit != 0 ? shorten((String) o, d.stringSizeLimit) : (String) o; if (l(s) >= structure_shareStringsLongerThan) d.strings.put(s, ref); out.append(quote(s)); return; } String name = o.getClass().getName(); if (o instanceof HashSet) { out.append("hashset "); structure_1(out, new ArrayList((Set) o), d); return; } if (o instanceof TreeSet) { out.append("treeset "); structure_1(out, new ArrayList((Set) o), d); return; } if (o instanceof Collection && neq(name, "main$Concept$RefL")) { out.append("["); int l = out.length(); for (Object x : (Collection) o) { if (out.length() != l) out.append(", "); structure_1(out, x, d); } out.append("]"); return; } if (o instanceof Map) { if (o instanceof HashMap) out.append("hm"); out.append("{"); int l = out.length(); for (Object e : ((Map) o).entrySet()) { if (out.length() != l) out.append(", "); structure_1(out, ((Map.Entry) e).getKey(), d); out.append("="); structure_1(out, ((Map.Entry) e).getValue(), d); } out.append("}"); return; } if (o.getClass().isArray()) { if (o instanceof byte[]) { out.append("ba ").append(quote(bytesToHex((byte[]) o))); return; } int n = Array.getLength(o); if (o instanceof boolean[]) { String hex = boolArrayToHex((boolean[]) o); int i = l(hex); while (i > 0 && hex.charAt(i-1) == '0' && hex.charAt(i-2) == '0') i -= 2; out.append("boolarray ").append(n).append(" ").append(quote(substring(hex, 0, i))); return; } String atype = "array", sep = ", "; if (o instanceof int[]) { //ret "intarray " + quote(intArrayToHex((int[]) o)); atype = "intarray"; sep = " "; } out.append(atype).append("{"); for (int i = 0; i < n; i++) { if (i != 0) out.append(sep); structure_1(out, Array.get(o, i), d); } out.append("}"); return; } if (o instanceof Class) { out.append("class(").append(quote(((Class) o).getName())).append(")"); return; } if (o instanceof Throwable) { out.append("exception(").append(quote(((Throwable) o).getMessage())).append(")"); return; } if (o instanceof BitSet) { BitSet bs = (BitSet) o; out.append("bitset{"); int l = out.length(); for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) { if (out.length() != l) out.append(", "); out.append(i); } out.append("}"); return; } // Need more cases? This should cover all library classes... if (name.startsWith("java.") || name.startsWith("javax.")) { out.append(str(o)); return; } String shortName = o.getClass().getName().replaceAll("^main\\$", ""); if (shortName.equals("Lisp")) { out.append("l("); structure_1(out, getOpt(o, "head"), d); List args = (List) ( getOpt(o, "args")); if (nempty(args)) for (int i = 0; i < l(args); i++) { out.append(", "); Object arg = args.get(i); // sweet shortening if (arg != null && eq(arg.getClass().getName(), "main$Lisp") && isTrue(call(arg, "isEmpty"))) arg = get(arg, "head"); structure_1(out, arg, d); } out.append(")"); return; } Class c = o.getClass(); boolean concept = d.conceptClass != null && d.conceptClass.isInstance(o); String dynName = shortDynamicClassName(o); if (concept && !d.concepts.contains(dynName)) { d.concepts.add(dynName); out.append("c "); } // serialize an object with fields. // first, collect all fields and values in fv. TreeMap fv = new TreeMap(); while (c != Object.class) { for (Field field : c.getDeclaredFields()) { if ((field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) != 0) continue; String fieldName = field.getName(); Object value; try { field.setAccessible(true); value = field.get(o); } catch (Exception e) { value = "?"; } // omit field "className" if equal to class's name if (concept && eq(fieldName, "className") && eq(value, shortName)) value = null; // put special cases here... if (value != null) fv.put(fieldName, value); } c = c.getSuperclass(); } // Now we have fields & values. Process fieldValues if it's a DynamicObject. if (o instanceof DynamicObject) { fv.putAll((Map) fv.get("fieldValues")); fv.remove("fieldValues"); shortName = dynName; fv.remove("className"); } String singleField = fv.size() == 1 ? first(fv.keySet()) : null; // Render this$1 first because unstructure needs it for constructor call. out.append(shortName).append("("); int l = out.length(); if (fv.containsKey("this$1")) { out.append("this$1="); structure_1(out, fv.get("this$1"), d); fv.remove("this$1"); } // Render the other fields. for (String fieldName : fv.keySet()) { if (out.length() != l) out.append(", "); out.append(fieldName).append("="); structure_1(out, fv.get(fieldName), d); } /*if (structure_allowShortening && singleField != null) b = b.replaceAll("^" + singleField + "=", ""); // drop field name if only one*/ if (out.length() == l) out.setLength(l-1); // drop "(" else out.append(")"); } // drop unused markers static String structure_2(String s, HashSet refd) { List tok = javaTok(s); StringBuilder out = new StringBuilder(); for (int i = 1; i < l(tok); i += 2) { String t = tok.get(i); if (t.startsWith("m") && isInteger(t.substring(1)) && !refd.contains(parseInt(t.substring(1)))) continue; out.append(t).append(tok.get(i+1)); } return str(out); } static Object call(Object o) { return callFunction(o); } // varargs assignment fixer for a single string array argument static Object call(Object o, String method, String[] arg) { return call(o, method, new Object[] {arg}); } static Object call(Object o, String method, Object... args) { try { if (o instanceof Class) { Method m = call_findStaticMethod((Class) o, method, args, false); m.setAccessible(true); return m.invoke(null, args); } else { Method m = call_findMethod(o, method, args, false); m.setAccessible(true); return m.invoke(o, args); } } catch (Exception e) { throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e); } } static Method call_findStaticMethod(Class c, String method, Object[] args, boolean debug) { Class _c = c; while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (!m.getName().equals(method)) { if (debug) System.out.println("Method name mismatch: " + method); continue; } if ((m.getModifiers() & Modifier.STATIC) == 0 || !call_checkArgs(m, args, debug)) continue; return m; } c = c.getSuperclass(); } throw new RuntimeException("Method '" + method + "' (static) with " + args.length + " parameter(s) not found in " + _c.getName()); } static Method call_findMethod(Object o, String method, Object[] args, boolean debug) { Class c = o.getClass(); while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (m.getName().equals(method) && call_checkArgs(m, args, debug)) return m; } c = c.getSuperclass(); } throw new RuntimeException("Method '" + method + "' (non-static) with " + args.length + " parameter(s) not found in " + o.getClass().getName()); } private static boolean call_checkArgs(Method m, Object[] args, boolean debug) { Class[] types = m.getParameterTypes(); if (types.length != args.length) { if (debug) System.out.println("Bad parameter length: " + args.length + " vs " + types.length); return false; } for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) { if (debug) System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]); return false; } return true; } // Try to put the structure in multiple lines // (works for List and Map) // For other values, defaults to structure() static String structureLines(Object data) { if (data instanceof Object[]) data = asList((Object[]) data); if (data instanceof List) { List l = new ArrayList(); for (Object x : (List) data) l.add(structure(x)); return fromLines(l); } if (data instanceof Map) { List l = new ArrayList(); for (Object key : ((Map) data).keySet()) { Object value = ((Map) data).get(key); l.add(structure(key) + " = " + structure(value)); } return fromLines(l); } return structure(data); } static Object getOpt(Object o, String field) { if (o instanceof String) o = getBot ((String) o); if (o == null) return null; if (o instanceof Class) return getOpt((Class) o, field); if (o.getClass().getName().equals("main$DynamicObject")) return ((Map) getOpt_raw(o, "fieldValues")).get(field); if (o instanceof Map) return ((Map) o).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 { if (c == null) return null; 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) { 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); return null; } static Field getOpt_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); return null; } // 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)); } public static String bytesToHex(byte[] bytes) { return bytesToHex(bytes, 0, bytes.length); } public static String bytesToHex(byte[] bytes, int ofs, int len) { StringBuilder stringBuilder = new StringBuilder(len*2); for (int i = 0; i < len; i++) { String s = "0" + Integer.toHexString(bytes[ofs+i]); stringBuilder.append(s.substring(s.length()-2, s.length())); } return stringBuilder.toString(); } static boolean isInteger(String s) { return s != null && Pattern.matches("\\-?\\d+", s); } static String quote(Object o) { if (o == null) return "null"; String s = str(o); return "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\r", "\\r").replace("\n", "\\n") + "\""; } static String shorten(String s, int max) { if (s == null) return ""; return s.length() <= max ? s : s.substring(0, Math.min(s.length(), max)) + "..."; } static String asciiHeading2(String title) { return asciiHeading(title) + "\n"; } static Object getBot(String botID) { return callOpt(getMainBot(), "getBot", botID); } static String quoteCharacter(char c) { if (c == '\'') return "'\\''"; if (c == '\\') return "'\\\\'"; return "'" + c + "'"; } static String shortDynamicClassName(Object o) { return shortenClassName(dynamicClassName(o)); } // extended over Class.isInstance() to handle primitive types static boolean isInstanceX(Class type, Object arg) { if (type == boolean.class) return arg instanceof Boolean; if (type == int.class) return arg instanceof Integer; if (type == long.class) return arg instanceof Long; if (type == float.class) return arg instanceof Float; if (type == short.class) return arg instanceof Short; if (type == char.class) return arg instanceof Character; if (type == byte.class) return arg instanceof Byte; if (type == double.class) return arg instanceof Double; return type.isInstance(arg); } static Thread currentThread() { return Thread.currentThread(); } 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; } 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 Map synchroMap() { return synchroHashMap(); } static Map synchroMap(Map map) { return Collections.synchronizedMap(map); } // replacement for class JavaTok // maybe incomplete, might want to add floating point numbers // todo also: extended multi-line strings static int javaTok_n, javaTok_elements; static boolean javaTok_opt; static List javaTok(String s) { return javaTok(s, null); } static List javaTok(String s, List existing) { ++javaTok_n; int nExisting = javaTok_opt && existing != null ? existing.size() : 0; List tok = existing != null ? new ArrayList(nExisting) : new ArrayList(); int l = s.length(); int i = 0, n = 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; } if (n < nExisting && javaTok_isCopyable(existing.get(n), s, i, j)) tok.add(existing.get(n)); else tok.add(quickSubstring(s, i, j)); ++n; 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; if (n < nExisting && javaTok_isCopyable(existing.get(n), s, i, j)) tok.add(existing.get(n)); else tok.add(quickSubstring(s, i, j)); ++n; i = j; } if ((tok.size() % 2) == 0) tok.add(""); javaTok_elements += tok.size(); return tok; } static List javaTok(List tok) { return javaTok(join(tok), tok); } static boolean javaTok_isCopyable(String t, String s, int i, int j) { return t.length() == j-i && s.regionMatches(i, t, 0, j-i); // << could be left out, but that's brave } static String fromLines(List lines) { StringBuilder buf = new StringBuilder(); if (lines != null) for (String line : lines) buf.append(line).append('\n'); return buf.toString(); } static String fromLines(String... lines) { return fromLines(asList(lines)); } static void sleep(long ms) { ping(); try { Thread.sleep(ms); } catch (Exception e) { throw new RuntimeException(e); } } static void sleep() { try { print("Sleeping."); synchronized(main.class) { main.class.wait(); } } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static List emptyList() { return new ArrayList(); //ret Collections.emptyList(); } static Class getMainClass() { try { return main.class; } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static Class getMainClass(Object o) { try { return (o instanceof Class ? (Class) o : o.getClass()).getClassLoader().loadClass("main"); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static int parseInt(String s) { return empty(s) ? 0 : Integer.parseInt(s); } // hmm, this shouldn't call functions really. That was just // for coroutines. static boolean isTrue(Object o) { if (o instanceof Boolean) return ((Boolean) o).booleanValue(); if (o == null) return false; return ((Boolean) callF(o)).booleanValue(); } static boolean isTrue(Object pred, Object arg) { return booleanValue(callF(pred, arg)); } static String boolArrayToHex(boolean[] a) { return bytesToHex(boolArrayToBytes(a)); } static Object callF(Object f, Object... args) { return callFunction(f, args); } static String asciiHeading(String title) { return "\n" + title + "\n" + rep(l(title), '-'); } static byte[] boolArrayToBytes(boolean[] a) { byte[] b = new byte[(l(a)+7)/8]; for (int i = 0; i < l(a); i++) if (a[i]) b[i/8] |= 1 << (i & 7); return b; } static String shortenClassName(String name) { return name == null ? null : substring(name, xIndexOf(name, '$')+1); } static String quickSubstring(String s, int i, int j) { if (i == j) return ""; return s.substring(i, j); } static Object mainBot; static Object getMainBot() { return mainBot; } static boolean empty(Collection c) { return isEmpty(c); } static boolean empty(String s) { return isEmpty(s); } static boolean empty(Map map) { return map == null || map.isEmpty(); } static boolean empty(Object[] o) { return o == null || o.length == 0; } static boolean empty(Object o) { if (o instanceof Collection) return empty((Collection) o); if (o instanceof String) return empty((String) o); if (o instanceof Map) return empty((Map) o); if (o instanceof Object[]) return empty((Object[]) o); throw fail("unknown type for 'empty': " + getType(o)); } static boolean booleanValue(Object o) { return eq(true, o); } static Object callOpt(Object o) { if (o == null) return null; return callF(o); } static Object callOpt(Object o, String method, Object... args) { try { if (o == null) return null; if (o instanceof Class) { Method m = callOpt_findStaticMethod((Class) o, method, args, false); if (m == null) return null; m.setAccessible(true); return m.invoke(null, args); } else { Method m = callOpt_findMethod(o, method, args, false); if (m == null) return null; m.setAccessible(true); return m.invoke(o, args); } } catch (Exception e) { throw new RuntimeException(e); } } static Method callOpt_findStaticMethod(Class c, String method, Object[] args, boolean debug) { Class _c = c; while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (!m.getName().equals(method)) { if (debug) System.out.println("Method name mismatch: " + method); continue; } if ((m.getModifiers() & Modifier.STATIC) == 0 || !callOpt_checkArgs(m, args, debug)) continue; return m; } c = c.getSuperclass(); } return null; } static Method callOpt_findMethod(Object o, String method, Object[] args, boolean debug) { Class c = o.getClass(); while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (m.getName().equals(method) && callOpt_checkArgs(m, args, debug)) return m; } c = c.getSuperclass(); } return null; } private static boolean callOpt_checkArgs(Method m, Object[] args, boolean debug) { Class[] types = m.getParameterTypes(); if (types.length != args.length) { if (debug) System.out.println("Bad parameter length: " + args.length + " vs " + types.length); return false; } for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) { if (debug) System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]); return false; } return true; } static String dynamicClassName(Object o) { if (o instanceof DynamicObject && ((DynamicObject) o).className != null) return "main$" + ((DynamicObject) o).className; return className(o); } static Map synchroHashMap() { return Collections.synchronizedMap(new HashMap()); } // returns l(s) if not found static int xIndexOf(String s, String sub, int i) { if (s == null) return 0; i = s.indexOf(sub, min(i, l(s))); return i >= 0 ? i : l(s); } static int xIndexOf(String s, String sub) { return xIndexOf(s, sub, 0); } static int xIndexOf(String s, char c) { if (s == null) return 0; int i = s.indexOf(c); return i >= 0 ? i : l(s); } static String getType(Object o) { return getClassName(o); } static String className(Object o) { return getClassName(o); } static String rep(int n, char c) { return repeat(c, n); } static String rep(char c, int n) { return repeat(c, n); } static List rep(A a, int n) { return repeat(a, n); } static String getClassName(Object o) { return o == null ? "null" : o.getClass().getName(); } static boolean DynamicObject_loading; static class DynamicObject { String className; // just the name, without the "main$" Map fieldValues = new TreeMap(); DynamicObject() {} // className = just the name, without the "main$" DynamicObject(String className) { this.className = className;} } // you still need to implement hasNext() and next() static abstract class IterableIterator implements Iterator, Iterable { public Iterator iterator() { return this; } public void remove() { unsupportedOperation(); } } static UnsupportedOperationException unsupportedOperation() { throw new UnsupportedOperationException(); } static void typeWriterConsole() { if (isHeadless()) return; Font f = typeWriterFont(); consoleFont(f); consoleInputFont(f); } static Font typeWriterFont() { return typeWriterFont(14); } static Font typeWriterFont(int size) { return new Font("Courier", Font.PLAIN, size); } static Boolean isHeadless_cache; static boolean isHeadless() { if (isHeadless_cache != null) return isHeadless_cache; if (GraphicsEnvironment.isHeadless()) return isHeadless_cache = true; // Also check if AWT actually works. // If DISPLAY variable is set but no X server up, this will notice. try { isAWTThread(); return isHeadless_cache = false; } catch (Throwable _e) { return isHeadless_cache = true; } } static void consoleFont(Font font) { callOpt(getConsoleTextArea_gen(), "setFont", font); } static void consoleInputFont(Font f) { JTextField input = consoleInputField(); if (input != null) { input.setFont(f); revalidateFrame(input); } } static boolean isAWTThread() { return SwingUtilities.isEventDispatchThread(); } static Object getConsoleTextArea_gen() { return getOpt(get(getJavaX(), "console"), "textArea"); } static void revalidateFrame(Component c) { revalidate(getFrame(c)); } static JTextField consoleInputField() { return (JTextField) getOpt(get(getJavaX(), "console"), "tfInput"); } static Class __javax; static Class getJavaX() { return __javax; } static void revalidate(Component c) { if (c == null || !c.isShowing()) return; // magic combo to actually relayout and repaint c.revalidate(); c.repaint(); } static JFrame getFrame(Object o) { if (!(o instanceof Component)) return null; Component c = (Component) o; while (c != null) { if (c instanceof JFrame) return (JFrame) c; c = c.getParent(); } return null; } }