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.*; import com.github.axet.lookup.*; import com.github.axet.lookup.common.GFirst; import com.github.axet.lookup.common.GPoint; import com.github.axet.lookup.common.ImageBinaryGreyScale; public class main { public static void main(String[] args) throws Exception { unzipSnippet("#1003720", programDir()); File dir = getProgramFile("lookup-examples"); BufferedImage image = loadBufferedImage(new File(dir, "desktop.png")); BufferedImage templateSmall = loadBufferedImage(new File(dir, "desktop_feature_small.png")); BufferedImage templateBig = loadBufferedImage(new File(dir, "desktop_feature_big.png")); LookupScale s = new LookupScale(0.2f, 10, 0.65f, 0.95f); ImageBinaryGreyScale si = new ImageBinaryGreyScale(image); ImageBinaryGreyScale stBig = new ImageBinaryGreyScale(templateBig); ImageBinaryGreyScale stSmall = new ImageBinaryGreyScale(templateSmall); for (int __twice = 0; __twice < 2; __twice++) { { long __time_startTime = now(); try { print("big"); { List pp = (List) s.lookupAll(si, stBig); Collections.sort(pp, new GFirst()); for (GPoint p : pp) { System.out.println(p); } } } finally { __time_startTime = now()-__time_startTime; saveTiming(__time_startTime); } }} for (int __twice = 0; __twice < 2; __twice++) { { long __time_startTime = now(); try { print("small"); { List pp = (List) s.lookupAll(si, stSmall); Collections.sort(pp, new GFirst()); for (GPoint p : pp) { System.out.println(p); } } } finally { __time_startTime = now()-__time_startTime; saveTiming(__time_startTime); } }} print("big"); for (int __twice = 0; __twice < 2; __twice++) { { long __time_startTime = now(); try { List pp = (List) s.lookupAll(si, stBig); Collections.sort(pp, new GFirst()); for (GPoint p : pp) { System.out.println(p); } } finally { __time_startTime = now()-__time_startTime; saveTiming(__time_startTime); } }} } static File getProgramFile(String progID, String fileName) { return new File(getProgramDir(progID), fileName); } static File getProgramFile(String fileName) { return getProgramFile(getProgramID(), fileName); } 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 void print() { print(""); } // slightly overblown signature to return original object... static A print(A o) { String s = String.valueOf(o) + "\n"; 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 void unzipSnippet(String snippetID, File toDir) { zip2dir(loadLibrary(snippetID), toDir); } static boolean loadBufferedImage_useImageCache = true; static BufferedImage loadBufferedImage(String snippetIDOrURL) { try { if (isURL(snippetIDOrURL)) return ImageIO.read(new URL(snippetIDOrURL)); if (!isSnippetID(snippetIDOrURL)) throw fail("Not a URL or snippet ID: " + snippetIDOrURL); String snippetID = "" + parseSnippetID(snippetIDOrURL); try { // TODO: androidify File dir = new File(System.getProperty("user.home"), ".tinybrain/image-cache"); if (loadBufferedImage_useImageCache) { dir.mkdirs(); File file = new File(dir, snippetID + ".png"); if (file.exists() && file.length() != 0) try { return ImageIO.read(file); } catch (Throwable e) { e.printStackTrace(); // fall back to loading from sourceforge } } String imageURL = snippetImageURL(snippetID); System.err.println("Loading image: " + imageURL); BufferedImage image = ImageIO.read(new URL(imageURL)); if (loadBufferedImage_useImageCache) { File tempFile = new File(dir, snippetID + ".tmp." + System.currentTimeMillis()); ImageIO.write(image, "png", tempFile); tempFile.renameTo(new File(dir, snippetID + ".png")); //Log.info("Cached image."); } //Log.info("Loaded image."); return image; } catch (IOException e) { throw new RuntimeException(e); } } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static BufferedImage loadBufferedImage(File file) { try { return ImageIO.read(file); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static File programDir() { return programDir(getProgramID()); } static File programDir(String snippetID) { return new File(javaxDataDir(), formatSnippetID(snippetID)); } static File loadLibrary(String snippetID) { return loadBinarySnippet(snippetID); } static File javaxDataDir_dir; // can be set to work on different base dir static File javaxDataDir() { return javaxDataDir_dir != null ? javaxDataDir_dir : new File(userHome(), "JavaX-Data"); } static String programID; static String getProgramID() { return nempty(programID) ? formatSnippetID(programID) : "?"; } // TODO: ask JavaX instead static String getProgramID(Class c) { String id = (String) getOpt(c, "programID"); if (nempty(id)) return formatSnippetID(id); return "?"; } static String getProgramID(Object o) { return getProgramID(getMainClass(o)); } static String snippetImageURL(String snippetID) { long id = parseSnippetID(snippetID); String url; if (id == 1000010 || id == 1000012) url = "http://tinybrain.de:8080/tb/show-blobimage.php?id=" + id; else url = "http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_" + id + "&contentType=image/png"; return url; } public static boolean isSnippetID(String s) { try { parseSnippetID(s); return true; } catch (RuntimeException e) { return false; } } static File getProgramDir() { return programDir(); } static File getProgramDir(String snippetID) { return programDir(snippetID); } 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)); } public static long parseSnippetID(String snippetID) { long id = Long.parseLong(shortenSnippetID(snippetID)); if (id == 0) throw fail("0 is not a snippet ID"); return id; } static boolean isURL(String s) { return s.startsWith("http://") || s.startsWith("https://"); } static void zip2dir(File inZip, File outDir) { zip2dir(inZip, outDir, ""); } static void zip2dir(File inZip, File outDir, String prefix) { try { if (prefix.length() != 0 && !prefix.endsWith("/")) prefix += "/"; ZipFile zipFile = new ZipFile(inZip); Enumeration entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = (ZipEntry) entries.nextElement(); if (entry.isDirectory()) continue; // We care about files only, really. Directories are made on the fly anyway. if (!entry.getName().startsWith(prefix)) continue; File outFile = new File(outDir, entry.getName()); System.out.println("Unzipping " + entry.getName() + " to " + outFile.getAbsolutePath()); stream2file(zipFile.getInputStream(entry), outFile); } zipFile.close(); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static String formatSnippetID(String id) { return "#" + parseSnippetID(id); } static String formatSnippetID(long id) { return "#" + id; } static String unnull(String s) { return s == null ? "" : s; } static List unnull(List l) { return l == null ? emptyList() : l; } static Object[] unnull(Object[] a) { return a == null ? new Object[0] : a; } static String _userHome; static String userHome() { if (_userHome == null) { if (isAndroid()) _userHome = "/storage/sdcard0/"; else _userHome = System.getProperty("user.home"); //System.out.println("userHome: " + _userHome); } return _userHome; } static File userHome(String path) { return new File(userDir(), path); } static String shortenSnippetID(String snippetID) { if (snippetID.startsWith("#")) snippetID = snippetID.substring(1); String httpBlaBla = "http://tinybrain.de/"; if (snippetID.startsWith(httpBlaBla)) snippetID = snippetID.substring(httpBlaBla.length()); return "" + parseLong(snippetID); } static Class getMainClass() { try { return Class.forName("main"); } 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 boolean nempty(Collection c) { return !isEmpty(c); } static boolean nempty(CharSequence s) { return !isEmpty(s); } static boolean nempty(Object[] o) { return !isEmpty(o); } static String format(String pat, Object... args) { return format3(pat, args); } // closes the input stream too. static void stream2file(InputStream in, File out) { try { mkdirsForFile(out); FileOutputStream fos = new FileOutputStream(out); copyStream(in, fos); in.close(); fos.close(); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} 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 call(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 { 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; } static File loadBinarySnippet(String snippetID) { try { long id = parseSnippetID(snippetID); File f = DiskSnippetCache_getLibrary(id); if (f == null) { byte[] data = loadDataSnippetImpl(snippetID); DiskSnippetCache_putLibrary(id, data); f = DiskSnippetCache_getLibrary(id); } return f; } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} 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)); } public static File mkdirsForFile(File file) { File dir = file.getParentFile(); if (dir != null) // is null if file is in current dir dir.mkdirs(); return file; } // Data files are immutable, use centralized cache public static File DiskSnippetCache_getLibrary(long snippetID) throws IOException { File file = new File(getGlobalCache(), "data_" + snippetID + ".jar"); return file.exists() ? file : null; } public static void DiskSnippetCache_putLibrary(long snippetID, byte[] data) throws IOException { saveBinaryFile(new File(getGlobalCache(), "data_" + snippetID).getPath() + ".jar", data); } static byte[] loadDataSnippetImpl(String snippetID) throws IOException { byte[] data; try { URL url = new URL("http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_" + parseSnippetID(snippetID) + "&contentType=application/binary"); System.err.println("Loading library: " + url); try { data = loadBinaryPage(url.openConnection()); } catch (IOException e) { data = null; } if (data == null || data.length == 0) { url = new URL("http://data.tinybrain.de/blobs/" + parseSnippetID(snippetID)); System.err.println("Loading library: " + url); data = loadBinaryPage(url.openConnection()); } System.err.println("Bytes loaded: " + data.length); } catch (FileNotFoundException e) { throw new IOException("Binary snippet #" + snippetID + " not found or not public"); } return data; } static List emptyList() { return new ArrayList(); //ret Collections.emptyList(); } static Object getBot(String botID) { return callOpt(getMainBot(), "getBot", botID); } 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 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; } static long parseLong(String s) { if (s == null) return 0; return Long.parseLong(dropSuffix("L", s)); } static long parseLong(Object s) { return Long.parseLong((String) s); } public static void copyStream(InputStream in, OutputStream out) throws IOException { byte[] buf = new byte[65536]; while (true) { int n = in.read(buf); if (n <= 0) return; out.write(buf, 0, n); } } static File userDir() { return new File(userHome()); } static File userDir(String path) { return new File(userHome(), path); } static boolean isAndroid() { return System.getProperty("java.vendor").toLowerCase().indexOf("android") >= 0; } static boolean isIdentifier(String s) { return isJavaIdentifier(s); } 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 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); } 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); } // 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 boolean isNonNegativeInteger(String s) { return s != null && Pattern.matches("\\d+", s); } // 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 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 Object mainBot; static Object getMainBot() { return mainBot; } /** 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); } } static String dropSuffix(String suffix, String s) { return s.endsWith(suffix) ? s.substring(0, l(s)-l(suffix)) : s; } 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(); } 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 seen, HashSet refd) { if (o == null) return "null"; // these are never back-referenced (for readability) if (o instanceof String) return quote(stringSizeLimit != 0 ? shorten((String) o, stringSizeLimit) : (String) o); if (o instanceof BigInteger) return "bigint(" + o + ")"; if (o instanceof Double) return "d(" + quote(str(o)) + ")"; if (o instanceof Long) return o + "L"; if (o instanceof Integer) return str(o); if (o instanceof Boolean) return ((Boolean) o).booleanValue() ? "t" : "f"; if (o instanceof Character) return quoteCharacter((Character) o); if (o instanceof File) return "File " + quote(((File) o).getPath()); // referencable objects follow Integer ref = seen.get(o); if (ref != null) { refd.add(ref); return "r" + ref; } ref = seen.size()+1; seen.put(o, ref); String r = "m" + ref + " "; // marker String name = o.getClass().getName(); StringBuilder buf = new StringBuilder(); if (o instanceof HashSet) return r + "hashset " + structure_1(new ArrayList((Set) o), stringSizeLimit, seen, refd); if (o instanceof TreeSet) return r + "treeset " + structure_1(new ArrayList((Set) o), stringSizeLimit, seen, refd); if (o instanceof Collection) { for (Object x : (Collection) o) { if (buf.length() != 0) buf.append(", "); buf.append(structure_1(x, stringSizeLimit, seen, refd)); } return r + "[" + buf + "]"; } if (o instanceof Map) { for (Object e : ((Map) o).entrySet()) { if (buf.length() != 0) buf.append(", "); buf.append(structure_1(((Map.Entry) e).getKey(), stringSizeLimit, seen, refd)); buf.append("="); buf.append(structure_1(((Map.Entry) e).getValue(), stringSizeLimit, seen, refd)); } return r + (o instanceof HashMap ? "hashmap" : "") + "{" + 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_1(Array.get(o, i), stringSizeLimit, seen, refd)); } return r + "array{" + buf + "}"; } if (o instanceof Class) return r + "class(" + quote(((Class) o).getName()) + ")"; if (o instanceof Throwable) return r + "exception(" + quote(((Throwable) o).getMessage()) + ")"; if (o instanceof BitSet) { BitSet bs = (BitSet) o; for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) { if (buf.length() != 0) buf.append(", "); buf.append(i); } return "bitset{" + buf + "}"; } // Need more cases? This should cover all library classes... if (name.startsWith("java.") || name.startsWith("javax.")) return r + String.valueOf(o); String shortName = o.getClass().getName().replaceAll("^main\\$", ""); if (shortName.equals("Lisp")) { buf.append("l(" + structure_1(getOpt(o, "head"), stringSizeLimit, seen, refd)); List args = (List) ( getOpt(o, "args")); if (nempty(args)) for (int i = 0; i < l(args); i++) { buf.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"); buf.append(structure_1(arg, stringSizeLimit, seen, refd)); } buf.append(")"); return r + str(buf); } 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_1(value, stringSizeLimit, seen, refd)); } ++numFields; } } else { // regular class Class c = o.getClass(); while (c != Object.class) { Field[] fields = c.getDeclaredFields(); for (Field field : fields) { if ((field.getModifiers() & Modifier.STATIC) != 0) continue; fieldName = field.getName(); // skip outer object reference if (fieldName.indexOf("$") >= 0) continue; Object value; try { field.setAccessible(true); value = field.get(o); } catch (Exception e) { value = "?"; } // put special cases here... if (value != null) { if (buf.length() != 0) buf.append(", "); buf.append(fieldName + "=" + structure_1(value, stringSizeLimit, seen, refd)); } ++numFields; } c = c.getSuperclass(); } } 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 r + s; } // 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 File getGlobalCache() { File file = new File(userHome(), ".tinybrain/snippet-cache"); file.mkdirs(); return file; } static boolean isInteger(String s) { return s != null && Pattern.matches("\\-?\\d+", s); } 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 Class mc() { return getMainClass(); } static String quoteCharacter(char c) { if (c == '\'') return "'\\''"; if (c == '\\') return "'\\\\'"; return "'" + c + "'"; } 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 String str(Object o) { return String.valueOf(o); } 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; } // 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)); } // 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 int l(Object[] array) { return array == null ? 0 : array.length; } static int l(byte[] array) { return array == null ? 0 : array.length; } static int l(int[] array) { return array == null ? 0 : array.length; } static int l(char[] 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 int parseInt(String s) { return empty(s) ? 0 : Integer.parseInt(s); } static boolean isTrue(Object o) { return booleanValue(o); } 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) { if (o instanceof Collection) return empty((Collection) o); if (o instanceof String) return empty((String) o); if (o instanceof Map) return empty((Map) o); return false; } static boolean booleanValue(Object o) { return eq(true, o); } static long now_virtualTime; static long now() { return now_virtualTime != 0 ? now_virtualTime : System.currentTimeMillis(); } static ThreadLocal saveTiming_last = new ThreadLocal(); static void saveTiming(long ms) { print(ms + " ms"); saveTiming_last.set(ms); } }