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 { public static void main(String[] args) throws Exception { remotePriv("please stop bot *", "I'm Jack's Identity Manager"); } static String remotePriv_masterKey; static String remotePriv(String text, Object... data) { if (remotePriv_masterKey == null) remotePriv_masterKey = loadSnippet("#1001582"); text = format(text, data); String signed = signWithComputerID(text); print(signed); print("OK? " + isSignedWithKey(signed, remotePriv_masterKey)); DialogIO io = talkTo("second.tinybrain.de", 4999); try { String greeting = io.readLine(); String line = format3("signed: *", signed); print (">> " + line); io.sendLine(line); String answer = io.readLine(); print ("<< " + answer); return answer; } finally { io.close(); } } static class PKI { static String getProvider() { return isAndroid() ? /*"AndroidOpenSSL"*/ "BC" : "SUN"; } public static boolean verifySignature(byte[] publicKey, byte[] signature, String file) throws InvalidKeyException, NoSuchProviderException, NoSuchAlgorithmException, IOException, SignatureException, InvalidKeySpecException { Signature sig = initPublicSignature(publicKey); FileInputStream datafis = new FileInputStream(file); BufferedInputStream bufin = new BufferedInputStream(datafis); byte[] buffer = new byte[1024]; while (bufin.available() != 0) { int len = bufin.read(buffer); sig.update(buffer, 0, len); } bufin.close(); return sig.verify(signature); } public static boolean verifySignature(byte[] publicKey, byte[] signature, byte[] data) { try { Signature sig = initPublicSignature(publicKey); sig.update(data); return sig.verify(signature); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} private static Signature initPublicSignature(byte[] publicKey) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, InvalidKeyException { Signature sig = Signature.getInstance("SHA1withDSA", getProvider()); PublicKey pub = KeyFactory.getInstance("DSA", getProvider()).generatePublic(new X509EncodedKeySpec(publicKey)); sig.initVerify(pub); return sig; } public static byte[] sign(String file, byte[] privateKey) { try { Signature dsa = initSignature(privateKey); FileInputStream fis = new FileInputStream(file); BufferedInputStream bufin = new BufferedInputStream(fis); byte[] buffer = new byte[1024]; int len; while ((len = bufin.read(buffer)) >= 0) dsa.update(buffer, 0, len); bufin.close(); return dsa.sign(); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} public static byte[] sign(byte[] data, byte[] privateKey) { try { Signature dsa = initSignature(privateKey); dsa.update(data); return dsa.sign(); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} private static Signature initSignature(byte[] privateKey) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, InvalidKeyException { Signature dsa = Signature.getInstance("SHA1withDSA", getProvider()); //X509EncodedKeySpec keySpec = new X509EncodedKeySpec(privateKey); EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey); PrivateKey priv = KeyFactory.getInstance("DSA", getProvider()).generatePrivate(keySpec); dsa.initSign(priv); return dsa; } public static KeyPair makeKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", getProvider()); SecureRandom random = SecureRandom.getInstance("SHA1PRNG", getProvider()); keyGen.initialize(1024, random); return keyGen.generateKeyPair(); } public static boolean makeStandardKeyPairIfNecessary() { try { File publicKeyPath = getStandardPublicKeyPath(); File privateKeyPath = getStandardPrivateKeyPath(); if (!publicKeyPath.exists()) { print("PKI: Making standard key pair"); KeyPair keyPair = makeKeyPair(); byte[] privateKey = keyPair.getPrivate().getEncoded(); print("PKI: Private key hex (debug) - " + bytesToHex(privateKey)); saveTextFile(privateKeyPath, privateKeyToString(privateKey)); String publicKey = publicKeyToString(keyPair.getPublic()); saveTextFile(publicKeyPath, publicKey); print("PKI: Standard key pair made!"); print(); printInfo(); return true; } return false; } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static void printInfo() { print("PKI: Public key: " + publicKeyToString(getStandardPublicKey())); print("PKI: Private key in: " + getStandardPrivateKeyPath()); print("PKI: Public key also in: " + getStandardPublicKeyPath()); } public static File getStandardPrivateKeyPath() { return new File(getSecretProgramDir("#1001547"), "Computer-Private-Key"); } public static File getStandardPublicKeyPath() { return new File(getProgramDir("#1001547"), "Computer-Public-Key"); } public static byte[] getStandardPrivateKey() { makeStandardKeyPairIfNecessary(); return privateKeyFromString(loadTextFile(getStandardPrivateKeyPath())); } public static byte[] getStandardPublicKey() { makeStandardKeyPairIfNecessary(); return publicKeyFromString(loadTextFile(getStandardPublicKeyPath())); } private static String publicKeyToString(PublicKey publicKey) { return publicKeyToString(publicKey.getEncoded()); } public static String privateKeyToString(PrivateKey privateKey) { return privateKeyToString(privateKey.getEncoded()); } public static byte[] publicKeyFromString(String key) { return base64decode(dropPrefixMandatory("publickey:", key)); } public static byte[] privateKeyFromString(String key) { return base64decode(dropPrefixMandatory("privatekey:", key)); } public static byte[] signatureFromString(String key) { return base64decode(key); } public static byte[] dataFromString(String text) { return toUtf8(text); } public static String signatureToString(byte[] signature) { return base64encode(signature); } public static String publicKeyToString(byte[] key) { return "publickey:" + base64encode(key); } public static String privateKeyToString(byte[] key) { return "privatekey:" + base64encode(key); } } // PKI // appends a new line with computer id and signature static String signWithComputerID(String s) { String computerID = getComputerID(); s = rtrim(s) + "\n\n" + "-" + computerID(); s = fromLines(toLines(s)); String signature = s + "sig: " + getMySignatureForText(s); signature = fromLines(toLines(signature)); return signature; } 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_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 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)); } static String format(String pat, Object... args) { return format3(pat, args); } static boolean preferCached = false; public static String loadSnippet(String snippetID) { try { return loadSnippet(parseSnippetID(snippetID), preferCached); } catch (IOException e) { throw new RuntimeException(e); } } public static String loadSnippet(String snippetID, boolean preferCached) throws IOException { return loadSnippet(parseSnippetID(snippetID), preferCached); } public static String loadSnippet(long snippetID, boolean preferCached) throws IOException { String text; // boss bot disabled for now for shorter transpilations /*text = getSnippetFromBossBot(snippetID); if (text != null) return text;*/ initSnippetCache(); text = DiskSnippetCache_get(snippetID); if (preferCached && text != null) return text; try { if (text != null) System.err.println("md5: " + md5(text)); URL url = new URL("http://tinybrain.de:8080/getraw.php?id=" + snippetID + "&utf8=1"); text = loadPage(url); } catch (RuntimeException e) { e.printStackTrace(); throw new IOException("Snippet #" + snippetID + " not found or not public"); } try { initSnippetCache(); DiskSnippetCache_put(snippetID, text); } catch (IOException e) { System.err.println("Minor warning: Couldn't save snippet to cache (" + DiskSnippetCache_getDir() + ")"); } return text; } static File DiskSnippetCache_dir; public static void initDiskSnippetCache(File dir) { DiskSnippetCache_dir = dir; dir.mkdirs(); } public static synchronized String DiskSnippetCache_get(long snippetID) throws IOException { return loadTextFile(DiskSnippetCache_getFile(snippetID).getPath(), null); } private static File DiskSnippetCache_getFile(long snippetID) { return new File(DiskSnippetCache_dir, "" + snippetID); } public static synchronized void DiskSnippetCache_put(long snippetID, String snippet) throws IOException { saveTextFile(DiskSnippetCache_getFile(snippetID).getPath(), snippet); } public static File DiskSnippetCache_getDir() { return DiskSnippetCache_dir; } public static void initSnippetCache() { if (DiskSnippetCache_dir == null) initDiskSnippetCache(new File(System.getProperty("user.home"), ".tinybrain/snippet-cache")); } static DialogIO talkTo(int port) { return talkTo("localhost", port); } static DialogIO talkTo(String ip, int port) { try { final Socket s = new Socket(ip, port); //print("Talking to " + ip + ":" + port); final Writer w = new OutputStreamWriter(s.getOutputStream(), "UTF-8"); final BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8")); return new DialogIO() { boolean isLocalConnection() { return s.getInetAddress().isLoopbackAddress(); } boolean isStillConnected() { return !(eos || s.isClosed()); } void sendLine(String line) { try { w.write(line + "\n"); w.flush(); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} String readLineImpl() { try { return in.readLine(); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} void close() { try { s.close(); } catch (IOException e) { // whatever } } Socket getSocket() { return s; } }; } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} // TODO: replace fullTrim with something else!! static boolean isSignedWithKey(String signed, String key) { try { List lines = toLines(signed); String sigLine = lines.get(lines.size()-1); String text = fromLines(lines.subList(0, lines.size()-1)); String sig = dropPrefixMandatory("sig: ", sigLine); return PKI.verifySignature(PKI.publicKeyFromString(key), PKI.signatureFromString(sig), toUtf8(text)); } catch (RuntimeException e) { return false; } } static boolean isIdentifier(String s) { return isJavaIdentifier(s); } static String getComputerID() { try { return computerID(); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} public 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 _computerID; public static String computerID() { try { if (_computerID == null) { File file = new File(userHome(), ".tinybrain/computer-id"); _computerID = loadTextFile(file.getPath(), null); if (_computerID == null) { _computerID = makeRandomID(12); saveTextFile(file.getPath(), _computerID); } } return _computerID; } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} public static long parseSnippetID(String snippetID) { long id = Long.parseLong(shortenSnippetID(snippetID)); if (id == 0) fail("0 is not a snippet ID"); return id; } 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 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 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 boolean isNonNegativeInteger(String s) { return s != null && Pattern.matches("\\d+", s); } 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(); } public static String rtrim(String s) { int i = s.length(); while (i > 0 && " \t\r\n".indexOf(s.charAt(i-1)) >= 0) --i; return i < s.length() ? s.substring(0, i) : s; } static ThreadLocal loadPage_charset = new ThreadLocal(); public static String loadPageSilently(String url) { try { return loadPageSilently(new URL(loadPage_preprocess(url))); } catch (IOException e) { throw new RuntimeException(e); } } public static String loadPageSilently(URL url) { try { IOException e = null; for (int tries = 0; tries < 60; tries++) try { URLConnection con = url.openConnection(); return loadPage(con, url); } catch (IOException _e) { e = _e; print("Retrying because of: " + e); sleepSeconds(1); } throw e; } catch (IOException e) { throw new RuntimeException(e); } } static String loadPage_preprocess(String url) { if (url.startsWith("tb/")) url = "tinybrain.de:8080/" + url; if (url.indexOf("://") < 0) url = "http://" + url; return url; } public static String loadPage(String url) { try { return loadPage(new URL(loadPage_preprocess(url))); } catch (IOException e) { throw new RuntimeException(e); } } public static String loadPage(URL url) { print("Loading: " + url.toExternalForm()); return loadPageSilently(url); } public static String loadPage(URLConnection con, URL url) throws IOException { String contentType = con.getContentType(); if (contentType == null) throw new IOException("Page could not be read: " + url); //print("Content-Type: " + contentType); String charset = loadPage_charset == null ? null : loadPage_charset.get(); if (charset == null) charset = loadPage_guessCharset(contentType); Reader r = new InputStreamReader(con.getInputStream(), charset); StringBuilder buf = new StringBuilder(); while (true) { int ch = r.read(); if (ch < 0) break; //Log.info("Chars read: " + buf.length()); buf.append((char) ch); } return buf.toString(); } static String loadPage_guessCharset(String contentType) { Pattern p = Pattern.compile("text/[a-z]+;\\s+charset=([^\\s]+)\\s*"); Matcher m = p.matcher(contentType); /* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */ return m.matches() ? m.group(1) : "ISO-8859-1"; } 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"; 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 String getMySignatureForText(String s) { return base64encode(PKI.sign(toUtf8(s), PKI.getStandardPrivateKey())); } static String dropPrefixMandatory(String prefix, String s) { if (s.startsWith(prefix)) return s.substring(prefix.length()); else throw fail("Prefix " + prefix + " not found in: " + s); } /** writes safely (to temp file, then rename) */ public static void saveTextFile(String fileName, String contents) throws IOException { File file = new File(fileName); File parentFile = file.getParentFile(); if (parentFile != null) parentFile.mkdirs(); String tempFileName = fileName + "_temp"; if (contents != null) { FileOutputStream fileOutputStream = new FileOutputStream(tempFileName); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "UTF-8"); PrintWriter printWriter = new PrintWriter(outputStreamWriter); printWriter.print(contents); printWriter.close(); } if (file.exists() && !file.delete()) throw new IOException("Can't delete " + fileName); if (contents != null) if (!new File(tempFileName).renameTo(file)) throw new IOException("Can't rename " + tempFileName + " to " + fileName); } public static void saveTextFile(File fileName, String contents) { try { saveTextFile(fileName.getPath(), contents); } catch (IOException e) { throw new RuntimeException(e); } } // 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 byte[] toUtf8(String s) { try { return s.getBytes("UTF-8"); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static String md5(String text) { try { if (text == null) return "-"; return bytesToHex(md5_impl(text.getBytes("UTF-8"))); // maybe different than the way PHP does it... } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static String md5(byte[] data) { return bytesToHex(md5_impl(data)); } static byte[] md5_impl(byte[] data) { try { return MessageDigest.getInstance("MD5").digest(data); } catch (Exception e) { throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e); } } static String md5(File file) { try { return md5(loadBinaryFile(file)); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} 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 shorten(String s, int max) { if (s == null) return ""; return s.length() <= max ? s : s.substring(0, Math.min(s.length(), max)) + "..."; } 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 String base64encode(byte[] a) { int aLen = a.length; int numFullGroups = aLen/3; int numBytesInPartialGroup = aLen - 3*numFullGroups; int resultLen = 4*((aLen + 2)/3); StringBuffer result = new StringBuffer(resultLen); char[] intToAlpha = intToBase64; // Translate all full groups from byte array elements to Base64 int inCursor = 0; for (int i=0; i> 2]); result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]); result.append(intToAlpha[(byte1 << 2)&0x3f | (byte2 >> 6)]); result.append(intToAlpha[byte2 & 0x3f]); } // Translate partial group if present if (numBytesInPartialGroup != 0) { int byte0 = a[inCursor++] & 0xff; result.append(intToAlpha[byte0 >> 2]); if (numBytesInPartialGroup == 1) { result.append(intToAlpha[(byte0 << 4) & 0x3f]); result.append("=="); } else { // assert numBytesInPartialGroup == 2; int byte1 = a[inCursor++] & 0xff; result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]); result.append(intToAlpha[(byte1 << 2)&0x3f]); result.append('='); } } // assert inCursor == a.length; // assert result.length() == resultLen; return result.toString(); } /** * This array is a lookup table that translates 6-bit positive integer * index values into their "Base64 Alphabet" equivalents as specified * in Table 1 of RFC 2045. */ static final char intToBase64[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; 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 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 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 void sleepSeconds(long s) { if (s > 0) sleep(s*1000); } // 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 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; } // 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 String makeRandomID(int length) { Random random = new Random(); char[] id = new char[length]; for (int i = 0; i < id.length; i++) id[i] = (char) ((int) 'a' + random.nextInt(26)); return new String(id); } static boolean nempty(Collection c) { return !isEmpty(c); } static boolean nempty(String s) { return !isEmpty(s); } 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(); } // 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 int parseInt(String s) { return empty(s) ? 0 : Integer.parseInt(s); } static boolean isTrue(Object o) { return booleanValue(o); } public static byte[] loadBinaryFile(String fileName) throws IOException { if (!new File(fileName).exists()) return null; FileInputStream in = new FileInputStream(fileName); byte buf[] = new byte[1024]; ByteArrayOutputStream out = new ByteArrayOutputStream(); int l; while (true) { l = in.read(buf); if (l <= 0) break; out.write(buf, 0, l); } in.close(); return out.toByteArray(); } public static byte[] loadBinaryFile(File file) throws IOException { return loadBinaryFile(file.getPath()); } 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 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 Object getBot(String botID) { return call(getMainBot(), "getBot", botID); } // 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 booleanValue(Object o) { return eq(true, o); } static String unnull(String s) { return s == null ? "" : s; } static List unnull(List l) { return l == null ? emptyList() : l; } static void sleep(long ms) { 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 boolean isEmpty(Collection c) { return c == null || c.isEmpty(); } static boolean isEmpty(String s) { return s == null || s.length() == 0; } static long parseLong(String s) { return Long.parseLong(s); } static boolean isAndroid() { return System.getProperty("java.vendor").toLowerCase().indexOf("android") >= 0; } static Object mainBot; static Object getMainBot() { return mainBot; } static List emptyList() { return Collections.emptyList(); } static abstract class DialogIO { String line; boolean eos; abstract String readLineImpl(); abstract boolean isStillConnected(); abstract void sendLine(String line); abstract boolean isLocalConnection(); abstract Socket getSocket(); abstract void close(); int getPort() { return getSocket().getPort(); } boolean helloRead; String readLineNoBlock() { String l = line; line = null; return l; } boolean waitForLine() { try { if (line != null) return true; //print("Readline"); line = readLineImpl(); //print("Readline done: " + line); if (line == null) eos = true; return line != null; } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} String readLine() { waitForLine(); helloRead = true; return readLineNoBlock(); } String ask(String s, Object... args) { if (!helloRead) readLine(); if (args.length != 0) s = format3(s, args); sendLine(s); return readLine(); } String askLoudly(String s, Object... args) { if (!helloRead) readLine(); if (args.length != 0) s = format3(s, args); print("> " + s); sendLine(s); String answer = readLine(); print("< " + answer); return answer; } void pushback(String l) { if (line != null) fail(); line = l; helloRead = false; } } static abstract class DialogHandler { abstract void run(DialogIO io); } static File getSecretProgramDir() { return getSecretProgramDir(getProgramID()); } static File getSecretProgramDir(String snippetID) { return new File(userHome(), "JavaX-Secret/" + formatSnippetID(snippetID)); } static byte[] base64decode(String s) { byte[] alphaToInt = base64decode_base64toint; int sLen = s.length(); int numGroups = sLen/4; if (4*numGroups != sLen) throw new IllegalArgumentException( "String length must be a multiple of four."); int missingBytesInLastGroup = 0; int numFullGroups = numGroups; if (sLen != 0) { if (s.charAt(sLen-1) == '=') { missingBytesInLastGroup++; numFullGroups--; } if (s.charAt(sLen-2) == '=') missingBytesInLastGroup++; } byte[] result = new byte[3*numGroups - missingBytesInLastGroup]; // Translate all full groups from base64 to byte array elements int inCursor = 0, outCursor = 0; for (int i=0; i> 4)); result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2)); result[outCursor++] = (byte) ((ch2 << 6) | ch3); } // Translate partial group, if present if (missingBytesInLastGroup != 0) { int ch0 = base64decode_base64toint(s.charAt(inCursor++), alphaToInt); int ch1 = base64decode_base64toint(s.charAt(inCursor++), alphaToInt); result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4)); if (missingBytesInLastGroup == 1) { int ch2 = base64decode_base64toint(s.charAt(inCursor++), alphaToInt); result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2)); } } // assert inCursor == s.length()-missingBytesInLastGroup; // assert outCursor == result.length; return result; } static int base64decode_base64toint(char c, byte[] alphaToInt) { int result = alphaToInt[c]; if (result < 0) throw new IllegalArgumentException("Illegal character " + c); return result; } static final byte base64decode_base64toint[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }; static BufferedReader readLine_reader; static String readLine() { return (String) call(getJavaX(), "readLine"); } static File getProgramDir() { return programDir(); } static File getProgramDir(String snippetID) { return programDir(snippetID); } static File programDir() { return programDir(getProgramID()); } static File programDir(String snippetID) { return new File(javaxDataDir(), formatSnippetID(snippetID)); } static String formatSnippetID(String id) { return "#" + parseSnippetID(id); } static String formatSnippetID(long id) { return "#" + id; } 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 Class __javax; static Class getJavaX() { return __javax; } 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 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); }} }