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 java.util.concurrent.locks.*; import java.util.function.*; 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 java.awt.geom.*; import javax.imageio.*; import java.math.*; import java.time.Duration; import java.nio.charset.Charset; import java.text.NumberFormat; import java.awt.geom.*; import java.text.SimpleDateFormat; import java.util.*; import java.io.*; import java.net.*; import java.nio.channels.FileChannel; import java.security.KeyStore; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPOutputStream; import javax.net.ssl.*; import java.util.function.BiConsumer; import java.util.function.BiFunction; import static x30_pkg.x30_util.DynamicObject; import java.nio.file.Path; import java.text.*; import java.util.TimeZone; import org.apache.bcel.classfile.ClassParser; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.Const; import org.apache.bcel.generic.*; import java.lang.reflect.Type; import java.util.jar.*; public class main { static public String mainBotID; static public int maxTypos = 1; static public String adminTitle = "Chat Bot Admin"; static public String shortLink; static public boolean enableWorkerChat = false; static public String embedderLink; static public String goDaddyEmbedCode; static public Cache> consistencyCheckResult = new Cache<>(() -> consistencyCheck()); static public class Category extends Concept { public int index; public String name; } static public class Language extends Concept { static final public String _fieldOrder = "index code"; public int index; public String code; } static public class QA extends Concept { public int index; public String language; public String questions; public String patterns; public String answers; public String category; transient public MMOPattern parsedPattern; static public String _fieldOrder = "language category index questions patterns answers"; public void change() { parsedPattern = null; super.change(); } public MMOPattern parsedPattern() { if (parsedPattern == null) parsedPattern = mmo2_parsePattern(patterns); return parsedPattern; } } static public class Defaults extends Concept { public String lastLanguage; } static public class Settings extends Concept { static final public String _fieldOrder = "botOn botAutoOpen"; public boolean botOn, botAutoOpen; } static public void pQADB() { print("fieldOrder", getFieldOrder(QA.class)); dbIndexing(Language.class, "index", Category.class, "index"); indexSingletonConcept(Defaults.class); indexSingletonConcept(Settings.class); cset(conceptsWhere(QA.class, "language", null), "language", "en"); uniq(Language.class, "code", "en"); removeConceptsWhere(Language.class, "code", "de"); int i = 0; for (String category : ll("business", "smalltalk")) cset(uniq(Category.class, "name", category), "index", i++); cset(conceptsWhere(QA.class, "category", null), "category", "business"); onConceptsChange(new Runnable() { public void run() { try { consistencyCheckResult.clear(); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "consistencyCheckResult.clear();"; } }); reindexQAs(); } static public Object html(String uri, final Map params) { try { try { if (swic(addSlash(uri), "/answer/")) { AutoCloseable __4 = tempSetTL(opt_noDefault, valueIs1("noDefault", params)); try { return serveText(unnull(answer(params.get("q"), "en"))); } finally { _close(__4); } } { String __3 = (String) callHtmlMethod2(mainBot(), "/auth-only", mapPlus(params, "uri", rawLink(uri))); if (!empty(__3)) return __3; } if (eq(uri, "/demo")) return hrefresh(appendQueryToURL(rawBotLink(mainBotID), "_botDemo", 1, "bot", 1)); if (eq(uri, "/download")) return subBot_serveText(conceptsStructure()); if (eq(uri, "/embedCode")) return hsansserif() + htitle_h2("Chat bot embed code") + (empty(goDaddyEmbedCode) ? "" : h3("GoDaddy Site Builder") + p("Add an HTML box with this code:") + pre(htmlEncode2(goDaddyEmbedCode)) + h3("Other")) + p("Add this code in front of your " + tt(htmlEncode2("")) + " tag:") + pre(htmlEncode2(hjavascript_src_withType(rawBotLink(mainBotID), "defer", html_valueLessParam()))); if (eq(uri, "/dbUploads/import")) { long id = parseLong(params.get("id")); DBUpload dbUpload = getConcept(DBUpload.class, id); if (dbUpload == null) return "Not found"; Map qaMap = (Map) (safeUnstructure(dbUpload.text)); Map existingByPattern = indexByFieldCI("patterns", list(QA.class)); List msgs = new ArrayList(); msgs.add("Importing..."); for (String _qaID : startingWith_dropPrefix("qa_", keys(params))) { long qaID = parseLong(_qaID); Object qa = qaMap.get(qaID); if (qa == null) continue; String patterns = getString("patterns", qa), answers = getString("answers", qa); QA existing = existingByPattern.get(patterns); if (existing != null) { msgs.add("QA item exists for patterns: " + patterns); msgs.add("Answers are " + (eq(answers, existing.answers) ? "identical" : "different")); } else { QA imported = cnew(QA.class); copyFields(qa, imported, "index", "language", "questions", "patterns", "answers", "category"); msgs.add("Imported item " + qaID + " as " + imported.id + " (patterns: " + patterns + ")"); } } return htmlEncode2_nlToBr(lines(msgs)); } if (eq(uri, "/dbUploads/view")) { long id = parseLong(params.get("id")); DBUpload dbUpload = getConcept(DBUpload.class, id); String contents; if (dbUpload == null) contents = "Not found"; else { List data = new ArrayList(); Map qaMap = (Map) (safeUnstructure(dbUpload.text)); qaMap = filterByValuePredicate(qaMap, c -> dynShortNameIs("QA", c)); qaMap = mapSortedByFunctionOnValue(qaMap, c -> neqic(getString("category", c), "smalltalk")); for (Map.Entry __0 : _entrySet(qaMap)) { long qaID = __0.getKey(); Object c = __0.getValue(); String category = getString("category", c); data.add(litorderedmap("ID", qaID, "Select", hcheckbox("qa_" + qaID, eqic(category, "smalltalk")), "Category", htmlEncode2(category), "Questions", htmlEncode2(getString("questions", c)), "Patterns", htmlEncode2(getString("patterns", c)), "Answers", htmlEncode2(getString("answers", c)))); } contents = hpostform(hhidden("id", id) + p(hsubmit("Import selected questions")) + htmlTable2_noHtmlEncode(data), "action", rawLink("dbUploads/import")); } String title = "Import questions"; return hhtml(hhead_title_decode(title) + hbody(h2(title) + p(makeNav()) + contents)); } if (eq(uri, "/dbUploads")) { HCRUD_Concepts data = new HCRUD_Concepts(DBUpload.class) { public Renderer getRenderer(String field) { if (eq(field, "text")) return new TextArea(80, 20); return super.getRenderer(field); } }; HCRUD crud = new HCRUD(rawLink("dbUploads"), data) { public String frame(String title, String contents) { title = ahref(or2(shortLink, rawLink("")), adminTitle) + " | " + title; return hhtml(hhead_title_decode(title) + hbody(h2(title) + p(makeNav()) + contents)); } public String renderCmds(Map item) { Object id = item.get(data.idField()); return joinNemptiesWithVBar(super.renderCmds(item), ahref(baseLink + "/view?id=" + urlencode(str(id)), "View questions")); } }; crud.tableClass = "responstable"; return hsansserif() + hcss_responstable() + crud.renderPage(params); } HCRUD_Concepts data = new HCRUD_Concepts(QA.class) { public String itemName() { return "question"; } public String fieldHelp(String field) { if (eq(field, "category")) return "smalltalk has a lower precedence than business"; if (eq(field, "index")) return "lower index = higher matching precedence"; if (eq(field, "patterns")) return "Phrases to match. Use \"+\" as \"and\" operator, commas as \"or\" operator. Round brackets for grouping. Quotes for special characters. Put exclamation mark after phrase to disable typo correction."; if (eq(field, "answers")) return "Text of answer. Use random { ... } for multiple answers (separated from each other by an empty line)"; return null; } public Renderer getRenderer(String field) { if (eqOneOf(field, "questions", "answers")) return new TextArea(80, 10); if (eq(field, "patterns")) return new TextField(80); if (eq(field, "language")) return new ComboBox(collect("code", conceptsSortedByField(Language.class, "index"))); if (eq(field, "category")) return new ComboBox(collect("name", conceptsSortedByField(Category.class, "index"))); return super.getRenderer(field); } public List defaultSort(List l) { return sortByFieldDesc("language", sortQAs(l)); } public Map emptyObject() { return mapPlus(super.emptyObject(), "language", uniq(Defaults.class).lastLanguage); } public Object createObject(Map map, String fieldPrefix) { String language = (String) (map.get("language")); if (language != null) cset(uniq(Defaults.class), "lastLanguage", language); return super.createObject(map, fieldPrefix); } }; data.onCreateOrUpdate.add(qa -> reindexQAs()); HCRUD crud = new HCRUD(rawLink(), data) { public String frame(String title, String contents) { String stats = (String) pcallOpt(mainBot(), "dbStats"); title = ahref(or2(shortLink, rawLink("")), adminTitle) + " | " + title; return hhtml(hhead_title_decode(title) + hbody(h2(title) + pIfNempty(stats) + p(makeNav()) + contents)); } public String renderTable(boolean withCmds) { Scorer scorer = consistencyCheckResult.get(); return (empty(scorer.errors) ? p("Pattern analysis: No problems found. " + nEntries(countConcepts(QA.class)) + ".") : joinMap(scorer.errors, __5 -> renderErrorAsParagraph(__5))) + super.renderTable(withCmds); } public String renderErrorAsParagraph(ConsistencyError error) { String fix = error.renderFix(); return p("Error: " + htmlEncode2(error.msg) + " " + joinMap(error.items, qa -> ahref(editLink(qa.id), "[item]")) + (empty(fix) ? "" : " " + fix)); } }; if (eqGet(params, "action", "reindex")) { long id = parseLong(params.get("id")); int newIndex = parseInt(params.get("newIndex")); QA qa = getConcept(QA.class, id); if (qa == null) return crud.refreshWithMsgs("Item not found"); cset(qa, "index", newIndex); reindexQAs(); return crud.refreshWithMsgs("Index of item " + qa.id + " changed"); } if (eqGet(params, "botOn", "1")) { cset(uniq(Settings.class), "botOn", true); return crud.refreshWithMsgs("Bot turned on!"); } if (eqGet(params, "botOff", "1")) { cset(uniq(Settings.class), "botOn", false); return crud.refreshWithMsgs("Bot turned off!"); } if (nemptyGet("botAutoOpen", params)) { cset(uniq(Settings.class), "botAutoOpen", eq("1", params.get("botAutoOpen"))); return crud.refreshWithMsgs("Bot auto-open turned " + onOff(botAutoOpen()) + "!"); } crud.tableClass = "responstable"; return hsansserif() + hcss_responstable() + crud.renderPage(params); } catch (Throwable e) { printStackTrace(e); return "ERROR."; } } catch (Exception __e) { throw rethrow(__e); } } static public ThreadLocal language_out = new ThreadLocal(); static public ThreadLocal opt_noDefault = new ThreadLocal(); static public String answer(String s, String language) { language_out.set(null); return trim(answer_main(s, language)); } static public String answer_main(String s, String language) { String raw = findRawAnswer(s, language, true); String contents = extractKeywordPlusBracketed_keepComments("random", raw); if (contents != null) return random(splitAtEmptyLines(contents)); return raw; } static public String findRawAnswer(String s, String language, boolean allowTypos) { return selectQA(findMatchingQA(s, language, allowTypos)); } static public QA findQAWithTypos(String s, String language) { Lowest qa = findClosestQA(s, language); if (!qa.has()) return null; if (qa.score() > maxTypos) { print("Rejecting " + nTypos((int) qa.score()) + ": " + s + " / " + qa.get().patterns); return null; } print("Accepting " + nTypos((int) qa.score()) + ": " + s + " / " + qa.get().patterns); return qa.get(); } static public QA findMatchingQA(String s, String language, boolean allowTypos) { { QA qa = findMatchingQA(s, conceptsWhere(QA.class, "language", language)); if (qa != null) return qa; } { QA qa = findMatchingQA(s, filter(list(QA.class), q -> neq(q.language, language))); if (qa != null) return qa; } if (allowTypos) { QA qa = findQAWithTypos(s, language); if (qa != null) return qa; } if (!eq(s, "#default") && !isTrue(opt_noDefault.get())) return findMatchingQA("#default", language, false); return null; } static public Lowest findClosestQA(String s, String language) { long _startTime_1 = sysNow(); Lowest qa = new Lowest(); findClosestQA(s, qa, conceptsWhere(QA.class, "language", language)); findClosestQA(s, qa, filter(list(QA.class), q -> neq(q.language, language))); done2_always("findClosestQA", _startTime_1); return qa; } static public List sortQAs(Collection qas) { Map categoryToIndex = fieldToFieldIndex("name", "index", list(Category.class)); return sortedByCalculatedField(qas, q -> pair(categoryToIndex.get(q.category), q.index)); } static public void reindexQAs() { for (Language lang : list(Language.class)) { int index = 1; for (QA qa : sortQAs(conceptsWhere(QA.class, "language", lang.code))) cset(qa, "index", index++); } } static public QA findMatchingQA(String s, Collection qas) { for (QA qa : sortQAs(qas)) if (mmo2_match(qa.parsedPattern(), s)) return qa; return null; } static public void findClosestQA(String s, Lowest best, Collection qas) { for (QA qa : sortQAs(qas)) { Integer score = mmo2_levenWithSwapsScore(qa.parsedPattern(), s); if (score != null) best.put(qa, score); } } static public String selectQA(QA qa) { if (qa == null) return null; language_out.set(qa.language); return qa.answers; } static public class ConsistencyError { public String msg; public List items; public ConsistencyError(String msg, QA... items) { this.items = asList(items); this.msg = msg; } public String renderFix() { return null; } } static public void checkLocalConsistency(QA qa, Scorer scorer) { List questions = tlft(qa.questions); for (String q : questions) if (mmo2_match(qa.parsedPattern(), q)) scorer.ok(); else scorer.error(new ConsistencyError("Question " + quote(q) + " not matched by patterns " + quote(qa.patterns), qa)); } static public void checkGlobalConsistency(QA qa, Scorer scorer) { for (String q : tlft(qa.questions)) { QA found = findMatchingQA(q, qa.language, false); if (found != null && found != qa) scorer.error(new ConsistencyError("Question " + quote(q) + " (item " + qa.id + ") shadowed by patterns " + quote(found.patterns) + " (item " + found.id + ")", qa, found) { public String renderFix() { return ahref(rawLink("?action=reindex&id=" + qa.id + "&newIndex=" + (found.index - 1)), "[fix by changing index]"); } }); else scorer.ok(); } } static public Scorer consistencyCheck() { Scorer scorer = new Scorer(); scorer.collectErrors(); for (QA qa : list(QA.class)) { checkLocalConsistency(qa, scorer); checkGlobalConsistency(qa, scorer); } return scorer; } static public boolean botOn() { return uniq(Settings.class).botOn; } static public boolean botAutoOpen() { return uniq(Settings.class).botAutoOpen; } static public void importQA(Object qa_external) { QA qa = shallowCloneToUnlistedConcept(QA.class, qa_external); uniq(QA.class, allConceptFieldsAsParams(qa)); } static public IF0 makeNav; static public String makeNav() { return makeNav != null ? makeNav.get() : makeNav_base(); } final static public String makeNav_fallback(IF0 _f) { return _f != null ? _f.get() : makeNav_base(); } static public String makeNav_base() { String s = joinWithVBar(ahref("?logout=1", "log out"), targetBlank(relativeRawBotLink(mainBotID, "/logs"), "chat logs"), targetBlank(rawLink("demo?bot=1"), "demo"), targetBlank(rawLink("download"), "export brain"), ahref(rawLink("embedCode"), "show embed code"), botOn() ? "Bot is ON (appears on home page) " + ahrefWithConfirm("Switch bot off?", "?botOff=1", "[switch bot off]") : "Bot is OFF (appears only with " + targetBlank(appendQueryToURL(embedderLink, "bot", 1), "?bot=1") + ") " + ahrefWithConfirm("Switch bot on?", "?botOn=1", "[switch bot on]"), ahref(rawLink("dbUploads"), "db uploads")); if (enableWorkerChat) s += " | " + ahref(rawBotLink(mainBotID, "workers-admin"), "workers admin") + " | " + targetBlank(rawBotLink(mainBotID, "worker"), "worker chat"); return s; } static public Object mainBot() { return getBot(mainBotID); } static public class DBUpload extends Concept { public String name; public String text; } public static void main(final String[] args) throws Exception { mainBotID = "#1028422"; adminTitle = "BookBetterNow.com Chat Bot Admin"; goDaddyEmbedCode = ""; shortLink = "https://botcompany.de/bookbetternow/admin"; makeNav = () -> makeNav_base() + " | " + ahref(rawBotLink(mainBotID, "booking-admin"), "booking admin") + " | " + ahref(rawBotLink(mainBotID, "testscripts"), "test scripts"); pQADB(); } static public MMOPattern mmo2_parsePattern(String s) { s = trim(tok_deRoundBracket(trim(s))); List tok = javaTokWithBrackets(s); List l = tok_splitAtComma(tok); if (l(l) > 1) return new MMOPattern.Or(lambdaMap(__32 -> mmo2_parsePattern(__32), l)); l = tok_splitAtPlus(tok); if (l(l) > 1) return new MMOPattern.And(lambdaMap(__33 -> mmo2_parsePattern(__33), l)); if (startsWith(s, "!")) return new MMOPattern.Not(mmo2_parsePattern(dropFirst(s))); if (startsWith(s, "^")) return new MMOPattern.StartOfLine(mmo2_parsePattern(dropFirst(s))); if (endsWith(s, "$")) return new MMOPattern.EndOfLine(mmo2_parsePattern(dropLast(s))); l = tok_splitAtAsterisk(tok); if (l(l) == 2) return new MMOPattern.Weighted(parseDouble(second(l)), mmo2_parsePattern(first(l))); return new MMOPattern.Phrase(unquote(s), isQuoted(s)); } static volatile public StringBuffer local_log = new StringBuffer(); static public boolean printAlsoToSystemOut = true; static volatile public Appendable print_log = local_log; static volatile public int print_log_max = 1024 * 1024; static volatile public int local_log_max = 100 * 1024; static public boolean print_silent = false; static public Object print_byThread_lock = new Object(); static volatile public ThreadLocal print_byThread; static volatile public Object print_allThreads; static volatile public Object print_preprocess; static public void print() { print(""); } static public A print(String s, A o) { print(combinePrintParameters(s, o)); return o; } static public A print(A o) { ping_okInCleanUp(); if (print_silent) return o; String s = o + "\n"; print_noNewLine(s); return o; } static public void print_noNewLine(String s) { try { Object f = getThreadLocal(print_byThread_dontCreate()); if (f == null) f = print_allThreads; if (f != null) if (isFalse(f instanceof F1 ? ((F1) f).get(s) : callF(f, s))) return; } catch (Throwable e) { System.out.println(getStackTrace(e)); } print_raw(s); } static public void print_raw(String s) { if (print_preprocess != null) s = (String) callF(print_preprocess, s); s = fixNewLines(s); Appendable loc = local_log; Appendable 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); if (printAlsoToSystemOut) System.out.print(s); vmBus_send("printed", mc(), s); } static public void print_autoRotate() { } static public Map> getFieldOrder_cache = weakMap(); static public List getFieldOrder(Object o) { return getFieldOrder(_getClass(o)); } static public List getFieldOrder(Class c) { if (c == null) return null; return getOrCreate(getFieldOrder_cache, c, () -> splitAtSpace(toStringOpt(getOpt(c, "_fieldOrder")))); } static public void dbIndexing(Object... params) { db(); indexConceptFields(params); } static public void indexSingletonConcept(Concepts cc, Class c) { indexConceptField(cc, c, "_dummy"); } static public void indexSingletonConcept(Class c) { indexSingletonConcept(db_mainConcepts(), c); } static public int cset(Concept c, Object... values) { try { if (c == null) return 0; warnIfOddCount(values = expandParams(c.getClass(), values)); int changes = 0; for (int i = 0; i + 1 < l(values); i += 2) if (_csetField(c, (String) values[i], values[i + 1])) ++changes; return changes; } catch (Exception __e) { throw rethrow(__e); } } static public int cset(Iterable l, Object... values) { int changes = 0; for (Concept c : unnullForIteration(l)) changes += cset(c, values); return changes; } static public int cset(Concept.Ref c, Object... values) { return cset(getVar(c), values); } static public Collection conceptsWhere(Class c, Object... params) { return findConceptsWhere(c, params); } static public Collection conceptsWhere(String c, Object... params) { return findConceptsWhere(c, params); } static public Collection conceptsWhere(Concepts concepts, Class c, Object... params) { return findConceptsWhere(concepts, c, params); } static public A uniq(Class c, Object... params) { return uniqueConcept(c, params); } static public A uniq(Concepts cc, Class c, Object... params) { return uniqueConcept(cc, c, params); } static public List removeConceptsWhere(Class c, Object... params) { return deleteConceptsWhere(c, params); } static public List ll(A... a) { ArrayList l = new ArrayList(a.length); if (a != null) for (A x : a) l.add(x); return l; } static public void onConceptsChange(Runnable r) { onConceptsChange(db_mainConcepts(), r); } static public void onConceptsChange(Concepts cc, Runnable r) { cc.addConceptIndex(simpleConceptIndex(r)); cc.onAllChanged.add(r); } static public RuntimeException rethrow(Throwable t) { if (t instanceof Error) _handleError((Error) t); throw t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t); } static public RuntimeException rethrow(String msg, Throwable t) { throw new RuntimeException(msg, t); } static public boolean swic(String a, String b) { return startsWithIgnoreCase(a, b); } static public boolean swic(String a, String b, Matches m) { if (!swic(a, b)) return false; m.m = new String[] { substring(a, l(b)) }; return true; } static public String addSlash(String s) { return empty(s) || s.endsWith("/") ? s : s + "/"; } static public AutoCloseable tempSetTL(ThreadLocal tl, A a) { return tempSetThreadLocal(tl, a); } static public AutoCloseable tempSetTL(BetterThreadLocal tl, A a) { return tempSetThreadLocalIfNecessary(tl, a); } static public boolean valueIs1(String key, Map map) { return eq("1", mapGet(map, key)); } static public Object serveText(Object s) { if (getMainBot() == null) return serveText_direct(str(s)); return call(getMainBot(), "serveByteArray", toUtf8(str(s)), "text/plain; charset=utf8"); } static public String unnull(String s) { return s == null ? "" : s; } static public Collection unnull(Collection l) { return l == null ? emptyList() : l; } static public List unnull(List l) { return l == null ? emptyList() : l; } static public int[] unnull(int[] l) { return l == null ? emptyIntArray() : l; } static public char[] unnull(char[] l) { return l == null ? emptyCharArray() : l; } static public double[] unnull(double[] l) { return l == null ? emptyDoubleArray() : l; } static public Map unnull(Map l) { return l == null ? emptyMap() : l; } static public Iterable unnull(Iterable i) { return i == null ? emptyList() : i; } static public A[] unnull(A[] a) { return a == null ? (A[]) emptyObjectArray() : a; } static public BitSet unnull(BitSet b) { return b == null ? new BitSet() : b; } static public Pt unnull(Pt p) { return p == null ? new Pt() : p; } static public Symbol unnull(Symbol s) { return s == null ? emptySymbol() : s; } static public Pair unnull(Pair p) { return p != null ? p : new Pair(null, null); } static public int unnull(Integer i) { return i == null ? 0 : i; } static public long unnull(Long l) { return l == null ? 0L : l; } static public double unnull(Double l) { return l == null ? 0.0 : l; } static public void _close(AutoCloseable c) { if (c != null) try { c.close(); } catch (Throwable e) { if (c instanceof javax.imageio.stream.ImageOutputStream) return; else throw rethrow(e); } } static public Object callHtmlMethod2(Object o, String uri) { return callHtmlMethod2(o, uri, null); } static public Object callHtmlMethod2(Object o, String uri, Map params) { Object s = callOpt(o, "html", uri, params); if (s == null) s = callOpt(o, "html", uri); if (s == null) s = callOpt(o, "html"); return s; } static public Map mapPlus(Map m, Object... data) { m = cloneMap(m); litmap_impl(m, data); return m; } static public String rawLink(String pageName) { return "/" + parseSnippetID(getProgramID()) + "/raw" + addPrefix("/", pageName); } static public String rawLink() { return "/" + parseSnippetID(getProgramID()) + "/raw"; } static public String rawLink(String pageName, String contents) { return ahref(rawLink(pageName), contents); } static public boolean empty(Collection c) { return c == null || c.isEmpty(); } static public boolean empty(Iterable c) { return c == null || !c.iterator().hasNext(); } static public boolean empty(CharSequence s) { return s == null || s.length() == 0; } static public boolean empty(Map map) { return map == null || map.isEmpty(); } static public boolean empty(Object[] o) { return o == null || o.length == 0; } static public boolean empty(BitSet bs) { return bs == null || bs.isEmpty(); } static public 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); if (o instanceof byte[]) return empty((byte[]) o); if (o == null) return true; throw fail("unknown type for 'empty': " + getType(o)); } static public boolean empty(Iterator i) { return i == null || !i.hasNext(); } static public boolean empty(double[] a) { return a == null || a.length == 0; } static public boolean empty(float[] a) { return a == null || a.length == 0; } static public boolean empty(int[] a) { return a == null || a.length == 0; } static public boolean empty(long[] a) { return a == null || a.length == 0; } static public boolean empty(byte[] a) { return a == null || a.length == 0; } static public boolean empty(short[] a) { return a == null || a.length == 0; } static public boolean empty(MultiSet ms) { return ms == null || ms.isEmpty(); } static public boolean empty(IMultiMap mm) { return mm == null || mm.size() == 0; } static public boolean empty(File f) { return getFileSize(f) == 0; } static public boolean empty(IntRange r) { return r == null || r.empty(); } static public boolean empty(Rect r) { return !(r != null && r.w != 0 && r.h != 0); } static public boolean empty(Chain c) { return c == null; } static public boolean empty(AppendableChain c) { return c == null; } static public boolean eq(Object a, Object b) { return a == b || a != null && b != null && a.equals(b); } static public boolean eq(Symbol a, String b) { return eq(str(a), b); } static public String hrefresh(String target) { return hrefresh(0, target); } static public String hrefresh(double seconds) { return hrefresh(seconds, ""); } static public String hrefresh(double seconds, String target) { return tag("meta", "", "http-equiv", "refresh", "content", iceil(seconds) + (nempty(target) ? "; url=" + target : "")); } static public String appendQueryToURL(String url, Map params) { if (url == null) return null; String data = makePostData(params); if (empty(data)) return url; int idx = smartIndexOf(url, '#'); String url2 = takeFirst(url, idx); return url2 + (url2.contains("?") ? "&" : "?") + data + substring(url, idx); } static public String appendQueryToURL(String url, Object... data) { return appendQueryToURL(url, paramsToMap(data)); } static public String rawBotLink() { return rawBotLink(programID()); } static public String rawBotLink(String botID) { return "https://" + myDomain() + "/" + parseSnippetID(botID) + "/raw"; } static public String rawBotLink(String botID, String uri) { return "https://" + myDomain() + "/" + parseSnippetID(botID) + "/raw" + addPrefix("/", uri); } static public Object subBot_serveText(Object s) { return call(getMainBot(), "serveByteArray", toUtf8(str(s)), "text/plain; charset=utf8"); } static public Object subBot_serveText(InputStream in) { return subBot_serveInputStream(in, "text/plain; charset=utf8"); } static public Object subBot_serveText(File f) { return subBot_serveFile(f, "text/plain; charset=utf8"); } static public String conceptsStructure() { db_mainConcepts().save(); return db_mainConcepts().fullStructure(); } static public String hsansserif() { return hcss("body { font-family: Sans-Serif; }"); } static public String htitle_h2(String s) { return htitle_noEncode(dropTags(s)) + h2(s); } static public String h3(String s, Object... params) { return tag("h3", s, params) + "\n"; } static public String p(Object contents, Object... params) { return hfulltag("p", contents, params) + "\n"; } static public String p() { return p(""); } static public String pre(Object contents, Object... params) { return tag("pre", contents, params); } static public String htmlEncode2(String s) { return htmlencode_noQuotes(s); } static public String htmlEncode2(Object o) { return htmlEncode2(strOrEmpty(o)); } static public void tt() { typeWriterConsole(); } static public String tt(Object contents, Object... params) { return tag("tt", contents, params); } static public String hjavascript_src_withType(String src, Object... __) { return hfulltag("script", "", paramsPlus_inFront(__, "src", src, "type", "text/javascript")); } static public Object html_valueLessParam_cache; static public Object html_valueLessParam() { if (html_valueLessParam_cache == null) html_valueLessParam_cache = html_valueLessParam_load(); return html_valueLessParam_cache; } static public Object html_valueLessParam_load() { return new Object(); } static public long parseLong(String s) { if (empty(s)) return 0; return Long.parseLong(dropSuffix("L", s)); } static public long parseLong(Object s) { return Long.parseLong((String) s); } static public Concept getConcept(long id) { return db_mainConcepts().getConcept(id); } static public Concept getConcept(Concepts concepts, long id) { return concepts.getConcept(id); } static public A getConcept(Class cc, long id) { return getConcept(db_mainConcepts(), cc, id); } static public A getConcept(Concepts concepts, Class cc, long id) { Concept c = concepts.getConcept(id); if (c == null) return null; if (!isInstance(cc, c)) throw fail("Can't convert concept: " + getClassName(c) + " -> " + getClassName(cc) + " (" + id + ")"); return (A) c; } static public Object safeUnstructure(String s) { return unstructure(s, true); } static public Object safeUnstructure(File f) { return safeUnstructureGZFile(f); } static public Map indexByFieldCI(Iterable c, String field) { Map map = ciMap(); for (A a : c) { String val = getString(a, field); if (val != null) map.put(val, a); } return map; } static public Map indexByFieldCI(String field, Iterable c) { return indexByFieldCI(c, field); } static public List list(Class type) { return list(type, db_mainConcepts()); } static public List list(Class type, Concepts cc) { return cc.list(type); } static public List list(Concepts concepts, Class type) { return concepts.list(type); } static public List list(String type) { return db_mainConcepts().list(type); } static public List list(Concepts concepts, String type) { return concepts.list(type); } static public List list(Concepts concepts) { return asList(concepts.allConcepts()); } static public List startingWith_dropPrefix(Collection l, final String prefix) { List out = new ArrayList(); for (String s : unnull(l)) if (startsWith(s, prefix)) out.add(substring(s, l(prefix))); return out; } static public List startingWith_dropPrefix(String prefix, Collection l) { return startingWith_dropPrefix(l, prefix); } static public Set keys(Map map) { return map == null ? new HashSet() : map.keySet(); } static public Set keys(Object map) { return keys((Map) map); } static public Set keys(MultiSet ms) { return ms.keySet(); } static public Set keys(IMultiMap mm) { return mm.keySet(); } static public String getString(Map map, Object key) { return map == null ? null : (String) map.get(key); } static public String getString(List l, int idx) { return (String) get(l, idx); } static public String getString(Object o, Object key) { if (o instanceof Map) return getString((Map) o, key); if (key instanceof String) return (String) getOpt(o, (String) key); throw fail("Not a string key: " + getClassName(key)); } static public String getString(String key, Object o) { return getString(o, (Object) key); } static public Concept cnew(String name, Object... values) { return cnew(db_mainConcepts(), name, values); } static public Concept cnew(Concepts concepts, String name, Object... values) { Class cc = findClass(name); concepts_unlisted.set(true); Concept c; try { c = cc != null ? nuObject(cc) : new Concept(name); } finally { concepts_unlisted.set(null); } csetAll(c, values); concepts.register(c); return c; } static public A cnew(Class cc, Object... values) { return cnew(db_mainConcepts(), cc, values); } static public A cnew(Concepts concepts, Class cc, Object... values) { concepts_unlisted.set(true); A c; try { c = nuObject(cc); } finally { concepts_unlisted.set(null); } csetAll(c, values); concepts.register(c); return c; } static public A copyFields(Object x, A y, String... fields) { if (empty(fields)) { Map map = objectToMap(x); for (String field : map.keySet()) setOpt(y, field, map.get(field)); } else for (String field : fields) { Object o = getOpt(x, field); if (o != null) setOpt(y, field, o); } return y; } static public A copyFields(Object x, A y, Collection fields) { return copyFields(x, y, asStringArray(fields)); } static public String htmlEncode2_nlToBr(String s) { return htmlEncode_nlToBr(s); } static public String lines(Iterable lines) { return fromLines(lines); } static public String lines(Object[] lines) { return fromLines(asList(lines)); } static public List lines(String s) { return toLines(s); } static public String lines(Iterable l, IF1 f) { return mapToLines(l, f); } static public Map filterByValuePredicate(IF1 pred, Map map) { if (map == null) return null; Map map2 = similarEmptyMap(map); for (Map.Entry e : map.entrySet()) if (pred.get(e.getValue())) map2.put(e.getKey(), e.getValue()); return map2; } static public Map filterByValuePredicate(Map map, IF1 pred) { return filterByValuePredicate(pred, map); } static public boolean dynShortNameIs(String name, Object o) { return eq(dynShortName(o), name); } static public boolean dynShortNameIs(Object o, String name) { return dynShortNameIs(name, o); } static public LinkedHashMap mapSortedByFunctionOnValue(Map map, IF1 f) { List l = new ArrayList(map.keySet()); sort(l, (a, b) -> cmp(f.get(map.get(a)), f.get(map.get(b)))); LinkedHashMap map2 = new LinkedHashMap(); for (A a : l) map2.put(a, map.get(a)); return map2; } static public boolean neqic(String a, String b) { return !eqic(a, b); } static public boolean neqic(char a, char b) { return !eqic(a, b); } static public Set> _entrySet(Map map) { return map == null ? Collections.EMPTY_SET : map.entrySet(); } static public LinkedHashMap litorderedmap(Object... x) { LinkedHashMap map = new LinkedHashMap(); litmap_impl(map, x); return map; } static public String hcheckbox(String name, boolean checked, Object... params) { return tag("input", "", paramsPlus(params, "type", "checkbox", "name", name, checked ? "checked" : null, "1")); } static public String hcheckbox(String name) { return hcheckbox(name, false); } static public String hcheckbox(String name, String text) { return hcheckboxWithText(name, text); } static public boolean eqic(String a, String b) { if ((a == null) != (b == null)) return false; if (a == null) return true; return a.equalsIgnoreCase(b); } static public boolean eqic(Symbol a, Symbol b) { return eq(a, b); } static public boolean eqic(Symbol a, String b) { return eqic(asString(a), b); } static public boolean eqic(char a, char b) { if (a == b) return true; char u1 = Character.toUpperCase(a); char u2 = Character.toUpperCase(b); if (u1 == u2) return true; return Character.toLowerCase(u1) == Character.toLowerCase(u2); } static public String hpostform(Object contents, Object... params) { return tag("form", contents, concatArrays(new Object[] { "method", "POST" }, params)); } static public String hhidden(String name, Object value, Object... params) { return tag("input", "", concatArrays(new Object[] { "type", "hidden", "name", name, "value", value }, params)); } static public String hhidden(Map map, String... keys) { return hiddenFields(map, keys); } static public String hsubmit(String text, Object... params) { return tag("input", "", concatArrays(new Object[] { "type", "submit", "value", text }, params)); } static public String hsubmit() { return hsubmit("Submit"); } static public String htmlTable2_noHtmlEncode(Object data, Object... __) { return htmlTable2(data, paramsPlus(__, "htmlEncode", false)); } static public String hhtml(Object contents) { return containerTag("html", contents); } static public String hhead_title_decode(String title) { return hhead_title(htmldecode_dropAllTags(title)); } static public String hbody(Object contents, Object... params) { return tag("body", contents, params); } static public String h2(String s, Object... params) { return tag("h2", s, params); } static public String ahref(String link, Object contents, Object... params) { return link == null ? str(contents) : href(link, contents, params); } static public String or2(String a, String b) { return nempty(a) ? a : b; } static public String or2(String a, String b, String c) { return or2(or2(a, b), c); } static public String joinNemptiesWithVBar(String... strings) { return joinNempties(" | ", strings); } static public String joinNemptiesWithVBar(Collection strings) { return joinNempties(" | ", strings); } static public String urlencode(String x) { try { return URLEncoder.encode(unnull(x), "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } static public String str(Object o) { return o == null ? "null" : o.toString(); } static public String str(char[] c) { return new String(c); } static public String str(char[] c, int offset, int count) { return new String(c, offset, count); } static public String hcss_responstable() { return hcss("\r\n .responstable {\r\n margin: 1em 0;\r\n width: 100%;\r\n overflow: visible;\r\n background: #FFF;\r\n color: #024457;\r\n border-radius: 10px;\r\n border: 1px solid #167F92;\r\n }\r\n \r\n .responstable tr {\r\n border: 1px solid #D9E4E6;\r\n }\r\n .responstable tr:nth-child(odd) {\r\n background-color: #EAF3F3;\r\n }\r\n .responstable th {\r\n display: none;\r\n border: 1px solid #FFF;\r\n background-color: #167F92;\r\n color: #FFF;\r\n padding: 1em;\r\n }\r\n .responstable th:first-child {\r\n display: table-cell;\r\n text-align: center;\r\n }\r\n .responstable th:nth-child(2) {\r\n display: table-cell;\r\n }\r\n .responstable th:nth-child(2) span {\r\n display: none;\r\n }\r\n .responstable th:nth-child(2):after {\r\n content: attr(data-th);\r\n }\r\n @media (min-width: 480px) {\r\n .responstable th:nth-child(2) span {\r\n display: block;\r\n }\r\n .responstable th:nth-child(2):after {\r\n display: none;\r\n }\r\n }\r\n .responstable td {\r\n display: block;\r\n word-wrap: break-word;\r\n max-width: 7em;\r\n }\r\n .responstable td:first-child {\r\n display: table-cell;\r\n text-align: center;\r\n border-right: 1px solid #D9E4E6;\r\n }\r\n @media (min-width: 480px) {\r\n .responstable td {\r\n border: 1px solid #D9E4E6;\r\n }\r\n }\r\n .responstable th, .responstable td {\r\n text-align: left;\r\n margin: .5em 1em;\r\n }\r\n @media (min-width: 480px) {\r\n .responstable th, .responstable td {\r\n display: table-cell;\r\n padding: 1em;\r\n }\r\n }\r\n "); } static public boolean eqOneOf(Object o, Object... l) { if (l != null) for (Object x : l) if (eq(o, x)) return true; return false; } static public List collect(Iterable c, String field) { return collectField(c, field); } static public List collect(String field, Iterable c) { return collectField(c, field); } static public boolean conceptsSortedByField_verbose = false; static public Collection conceptsSortedByField(Class c, String field) { return conceptsSortedByField(db_mainConcepts(), c, field); } static public Collection conceptsSortedByField(Concepts concepts, Class c, String field) { IFieldIndex index = concepts.getFieldIndex(c, field); if (index instanceof ConceptFieldIndexDesc) return reverseInPlace(asList(((ConceptFieldIndexDesc) index).objectIterator())); if (conceptsSortedByField_verbose) print("conceptsSortedByField_verbose: Manual sort of " + c + " for " + field); return sortedByField(field, concepts.list(c)); } static public List sortByFieldDesc(Collection c, final String field) { return sortedByFieldDesc(c, field); } static public List sortByFieldDesc(String field, Collection c) { return sortedByFieldDesc(field, c); } static public Object pcallOpt(Object o, String method, Object... args) { try { return callOpt(o, method, args); } catch (Throwable __e) { printStackTrace(__e); } return null; } static public String pIfNempty(String contents, Object... params) { return nempty(contents) ? p(contents, params) : ""; } static public String nEntries(long n) { return n2(n, "entry", "entries"); } static public String nEntries(Collection l) { return nEntries(l(l)); } static public String nEntries(Map map) { return nEntries(l(map)); } static public int countConcepts(Concepts concepts, Class c, Object... params) { return concepts.countConcepts(c, params); } static public int countConcepts(Class c, Object... params) { return db_mainConcepts().countConcepts(c, params); } static public int countConcepts() { return db_mainConcepts().countConcepts(); } static public int countConcepts(String className) { return db_mainConcepts().countConcepts(className); } static public int countConcepts(Concepts concepts, String className) { return concepts.countConcepts(className); } static public int countConcepts(Concepts concepts) { return concepts.countConcepts(); } static public String joinMap(Object f, Iterable l) { return join(map(f, l)); } static public String joinMap(Iterable l, Object f) { return joinMap(f, l); } static public String joinMap(Iterable l, IF1 f) { return joinMap(f, l); } static public String joinMap(A[] l, IF1 f) { return joinMap(f, l); } static public String joinMap(IF1 f, Iterable l) { return join(map(f, l)); } static public String joinMap(IF1 f, A[] l) { return join(map(f, l)); } static public String joinMap(String separator, Map map, IF2 f) { return join(separator, map(map, f)); } static public boolean eqGet(List l, int i, Object o) { return eq(get(l, i), o); } static public boolean eqGet(Map map, A key, Object o) { return eq(mapGet(map, key), o); } static public int parseInt(String s) { return emptyString(s) ? 0 : Integer.parseInt(s); } static public int parseInt(char c) { return Integer.parseInt(str(c)); } static public boolean nemptyGet(String field, Object o) { return nempty(get(field, o)); } static public String onOff(boolean b) { return b ? "on" : "off"; } static public A printStackTrace(A e) { if (e != null) print(getStackTrace(e)); return e; } static public void printStackTrace() { printStackTrace(new Throwable()); } static public void printStackTrace(String msg) { printStackTrace(new Throwable(msg)); } static public void printStackTrace(String msg, Throwable e) { printStackTrace(new Throwable(msg, e)); } static public String trim(String s) { return s == null ? null : s.trim(); } static public String trim(StringBuilder buf) { return buf.toString().trim(); } static public String trim(StringBuffer buf) { return buf.toString().trim(); } static public String extractKeywordPlusBracketed_keepComments(String keyword, String s) { List tok = javaTokWithCurlyBrackets(s); if (countCodeTokens(tok) == 2 && eq(firstCodeToken(tok), keyword) && tok_isRoundOrCurlyBracketed(secondCodeToken(tok))) return tok_deRoundOrCurlyBracket_keepSpaces(secondCodeToken(tok)); return null; } static public int random(int n) { return random(n, defaultRandomGenerator()); } static public int random(int n, Random r) { return random(r, n); } static public int random(Random r, int n) { return n <= 0 ? 0 : getRandomizer(r).nextInt(n); } static public double random(double max) { return random() * max; } static public double random() { return defaultRandomGenerator().nextInt(100001) / 100000.0; } static public double random(double min, double max) { return min + random() * (max - min); } static public int random(int min, int max) { return min + random(max - min); } static public int random(int min, int max, Random r) { return random(r, min, max); } static public int random(Random r, int min, int max) { return min + random(r, max - min); } static public A random(List l) { return oneOf(l); } static public A random(Collection c) { if (c instanceof List) return random((List) c); int i = random(l(c)); return collectionGet(c, i); } static public int random(IntRange r) { return random(r.start, r.end); } static public Pair random(Map map) { return entryToPair(random(entries(map))); } static public List splitAtEmptyLines(String text) { List lines = toLines(text); int n = l(lines), i = 0; List parts = new ArrayList(); while (true) { ping(); while (i < n && emptyAfterTrim(lines.get(i))) ++i; if (i >= n) break; int j = i; while (j < n && !emptyAfterTrim(lines.get(j))) ++j; parts.add(fromLines(subList(lines, i, j))); i = j; } return parts; } static public String nTypos(long n) { return n2(n, "typo"); } static public String nTypos(Collection l) { return nTypos(l(l)); } static public List filter(Iterable c, Object pred) { if (pred instanceof F1) return filter(c, (F1) pred); List x = new ArrayList(); if (c != null) for (Object o : c) if (isTrue(callF(pred, o))) x.add(o); return x; } static public List filter(Object pred, Iterable c) { return filter(c, pred); } static public List filter(Iterable c, F1 pred) { List x = new ArrayList(); if (c != null) for (B o : c) if (pred.get(o)) x.add(o); return x; } static public List filter(F1 pred, Iterable c) { return filter(c, pred); } static public List filter(Iterable c, IF1 pred) { List x = new ArrayList(); if (c != null) for (B o : c) if (pred.get(o)) x.add(o); return x; } static public List filter(B[] c, IF1 pred) { List x = new ArrayList(); if (c != null) for (B o : c) if (pred.get(o)) x.add(o); return x; } static public List filter(IF1 pred, Iterable c) { return filter(c, pred); } static public boolean neq(Object a, Object b) { return !eq(a, b); } static public boolean isTrue(Object o) { if (o instanceof Boolean) return ((Boolean) o).booleanValue(); if (o == null) return false; if (o instanceof ThreadLocal) return isTrue(((ThreadLocal) o).get()); throw fail(getClassName(o)); } static public boolean isTrue(Boolean b) { return b != null && b.booleanValue(); } static public long sysNow() { ping(); return System.nanoTime() / 1000000; } static public long done2_always(long startTime, String desc) { long time = sysNow() - startTime; saveTiming_noPrint(time); print(desc + " [" + time + " ms]"); return time; } static public long done2_always(String desc, long startTime) { return done2_always(startTime, desc); } static public long done2_always(long startTime) { return done2_always(startTime, ""); } static public Map fieldToFieldIndex(final String fieldA, final String fieldB, Iterable l) { return pairsToMap((List) collectTwoFieldsAsPair(fieldA, fieldB, l)); } static public List sortedByCalculatedField(Iterable c, Object f) { return sortByCalculatedField(c, f); } static public List sortedByCalculatedField(Object f, Iterable c) { return sortedByCalculatedField(c, f); } static public List sortedByCalculatedField(IF1 f, Iterable c) { return sortedByCalculatedField(c, f); } static public List sortedByCalculatedField(Iterable c, IF1 f) { List l = cloneList(c); sort(l, new Comparator() { public int compare(A a, A b) { return stdcompare(f.get(a), f.get(b)); } }); return l; } static public Pair pair(A a, B b) { return new Pair(a, b); } static public Pair pair(A a) { return new Pair(a, a); } static public boolean mmo2_match(MMOPattern pattern, String s) { return mmo2_match(pattern, s, false, false); } static public boolean mmo2_match(MMOPattern pattern, String s, boolean startOfLine, boolean endOfLine) { if (pattern == null) return false; String s2 = trim(s); if (pattern instanceof MMOPattern.StartOfLine) return mmo2_match(((MMOPattern.StartOfLine) pattern).p, s2, true, endOfLine); if (pattern instanceof MMOPattern.EndOfLine) return mmo2_match(((MMOPattern.EndOfLine) pattern).p, s2, startOfLine, true); if (pattern instanceof MMOPattern.Phrase) { String p = ((MMOPattern.Phrase) pattern).phrase; if (((MMOPattern.Phrase) pattern).quoted) return cicWithSmartWordBoundary(s2, p); if (startsWith(p, "#")) return eqic(p, s2); return match3_startOrEndOfLine(p, s2, startOfLine, endOfLine); } if (pattern instanceof MMOPattern.And) return all(((MMOPattern.And) pattern).l, pat -> mmo2_match(pat, s2, startOfLine, endOfLine)); if (pattern instanceof MMOPattern.Or) return any(((MMOPattern.Or) pattern).l, pat -> mmo2_match(pat, s2, startOfLine, endOfLine)); if (pattern instanceof MMOPattern.Not) return !mmo2_match(((MMOPattern.Not) pattern).p, s2, startOfLine, endOfLine); throw fail("what. " + pattern); } static public boolean mmo2_match(String pattern, String s) { return mmo2_match(mmo2_parsePattern(pattern), s); } static public Integer mmo2_levenWithSwapsScore(MMOPattern pattern, String s) { return mmo2_levenWithSwapsScore(pattern, s, false, false); } static public Integer mmo2_levenWithSwapsScore(MMOPattern pattern, String s, boolean startOfLine, boolean endOfLine) { String s2 = trim(s); if (pattern == null) return null; if (startsWith(s2, "#")) return null; if (pattern instanceof MMOPattern.StartOfLine) return mmo2_levenWithSwapsScore(((MMOPattern.StartOfLine) pattern).p, s2, true, endOfLine); if (pattern instanceof MMOPattern.EndOfLine) return mmo2_levenWithSwapsScore(((MMOPattern.EndOfLine) pattern).p, s2, startOfLine, true); if (pattern instanceof MMOPattern.Phrase) { if (((MMOPattern.Phrase) pattern).quoted) return mmo2_match(((MMOPattern.Phrase) pattern), s2) ? (Integer) 0 : null; String p = ((MMOPattern.Phrase) pattern).phrase; if (startsWith(p, "#")) return null; if (endsWith(p, "!")) return find3(p, s) ? 0 : null; else return find3_levenWithSwapsDistance(p, s2); } if (pattern instanceof MMOPattern.And) { int score = 0; for (MMOPattern pat : ((MMOPattern.And) pattern).l) { Integer score2 = mmo2_levenWithSwapsScore(pat, s2, startOfLine, endOfLine); if (score2 == null) return null; score += score2; } return score; } if (pattern instanceof MMOPattern.Or) { Integer min = null; for (MMOPattern pat : ((MMOPattern.Or) pattern).l) min = min_withNull(min, mmo2_levenWithSwapsScore(pat, s2, startOfLine, endOfLine)); return min; } if (pattern instanceof MMOPattern.Not) return mmo2_match(pattern, s2) ? 0 : null; throw fail("what. " + pattern); } static public Integer mmo2_levenWithSwapsScore(String pattern, String s) { return mmo2_levenWithSwapsScore(mmo2_parsePattern(pattern), s, false, false); } static public ArrayList asList(A[] a) { return a == null ? new ArrayList() : new ArrayList(Arrays.asList(a)); } static public ArrayList asList(int[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (int i : a) l.add(i); return l; } static public ArrayList asList(long[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (long i : a) l.add(i); return l; } static public ArrayList asList(float[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (float i : a) l.add(i); return l; } static public ArrayList asList(double[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (double i : a) l.add(i); return l; } static public ArrayList asList(short[] a) { if (a == null) return null; ArrayList l = emptyList(a.length); for (short i : a) l.add(i); return l; } static public ArrayList asList(Iterator it) { ArrayList l = new ArrayList(); if (it != null) while (it.hasNext()) l.add(it.next()); return l; } static public ArrayList asList(IterableIterator s) { return asList((Iterator) s); } static public 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 public ArrayList asList(Producer p) { ArrayList l = new ArrayList(); A a; if (p != null) while ((a = p.next()) != null) l.add(a); return l; } static public ArrayList asList(Enumeration e) { ArrayList l = new ArrayList(); if (e != null) while (e.hasMoreElements()) l.add(e.nextElement()); return l; } static public ArrayList asList(ReverseChain c) { return c == null ? emptyList() : c.toList(); } static public List asList(Pair p) { return p == null ? null : ll(p.a, p.b); } static public List tlft(String s) { return toLinesFullTrim(s); } static public List tlft(File f) { return toLinesFullTrim(f); } static public String quote(Object o) { if (o == null) return "null"; return quote(str(o)); } static public String quote(String s) { if (s == null) return "null"; StringBuilder out = new StringBuilder((int) (l(s) * 1.5 + 2)); quote_impl(s, out); return out.toString(); } static public void quote_impl(String s, StringBuilder out) { out.append('"'); int l = s.length(); for (int i = 0; i < l; i++) { char c = s.charAt(i); if (c == '\\' || c == '"') out.append('\\').append(c); else if (c == '\r') out.append("\\r"); else if (c == '\n') out.append("\\n"); else if (c == '\t') out.append("\\t"); else if (c == '\0') out.append("\\0"); else out.append(c); } out.append('"'); } static public A shallowCloneToUnlistedConcept(Class c, Object o) { if (o == null) return null; A cc = unlisted(c); copyFields(o, cc, conceptFields(c)); return cc; } static public A shallowCloneToUnlistedConcept(A o) { return o == null ? null : (A) shallowCloneToUnlistedConcept(getClass(o), o); } static public Object[] allConceptFieldsAsParams(Concept c) { Collection l = conceptFields(c); Object[] params = new Object[l(l) * 2]; int i = 0; for (String field : unnullForIteration(l)) { params[i++] = field; params[i++] = cget(c, field); } return params; } static public String joinWithVBar(Iterable l) { return join(" | ", l); } static public String joinWithVBar(String... l) { return joinWithVBar(asList(l)); } static public String targetBlank(String link, Object contents, Object... params) { return hrefBlank(link, contents, params); } static public String relativeRawBotLink() { return relativeRawBotLink(programID()); } static public String relativeRawBotLink(long botID) { return "/" + botID + "/raw"; } static public String relativeRawBotLink(String botID) { return relativeRawBotLink(parseSnippetID(botID)); } static public String relativeRawBotLink(long botID, String uri) { return "/" + botID + "/raw" + addPrefix("/", uri); } static public String relativeRawBotLink(String botID, String uri) { return relativeRawBotLink(parseSnippetID(botID), uri); } static public String ahrefWithConfirm(String msg, String url, Object contents, Object... params) { return ahref(url, contents, paramsPlus(params, "onClick", "return confirm(" + jsQuote(msg) + ");")); } static public Object getBot(String botID) { return callOpt(getMainBot(), "getBot", botID); } static public AutoCloseable tempInterceptPrintIfNotIntercepted(F1 f) { return print_byThread().get() == null ? tempInterceptPrint(f) : null; } static public String tok_deRoundBracket(String s) { return tok_isRoundBracketed(s) ? join(dropFirstThreeAndLastThree(javaTok(s))) : s; } static public List javaTokWithBrackets(String s) { return javaTokPlusBrackets(s); } static public List tok_splitAtComma(String s) { return tok_splitAtComma(javaTok(s)); } static public List tok_splitAtComma(List tok) { List out = new ArrayList(); for (int i = 0; i < l(tok); i++) { int j = smartIndexOf(tok, ",", i); out.add(joinSubList(tok, i + 1, j - 1)); i = j; } return out; } static public int l(Object[] a) { return a == null ? 0 : a.length; } static public int l(boolean[] a) { return a == null ? 0 : a.length; } static public int l(byte[] a) { return a == null ? 0 : a.length; } static public int l(short[] a) { return a == null ? 0 : a.length; } static public int l(long[] a) { return a == null ? 0 : a.length; } static public int l(int[] a) { return a == null ? 0 : a.length; } static public int l(float[] a) { return a == null ? 0 : a.length; } static public int l(double[] a) { return a == null ? 0 : a.length; } static public int l(char[] a) { return a == null ? 0 : a.length; } static public int l(Collection c) { return c == null ? 0 : c.size(); } static public int l(Iterator i) { return iteratorCount_int_close(i); } static public int l(Map m) { return m == null ? 0 : m.size(); } static public int l(CharSequence s) { return s == null ? 0 : s.length(); } static public long l(File f) { return f == null ? 0 : f.length(); } static public int l(MultiSet ms) { return ms == null ? 0 : ms.size(); } static public int l(IMultiMap mm) { return mm == null ? 0 : mm.size(); } static public int l(IntRange r) { return r == null ? 0 : r.length(); } static public int l(AppendableChain a) { return a == null ? 0 : a.size; } static public List lambdaMap(IF1 f, Iterable l) { return map(l, f); } static public List lambdaMap(IF1 f, A[] l) { return map(l, f); } static public List tok_splitAtPlus(String s) { return tok_splitAtPlus(javaTokWithAllBrackets_cached(s)); } static public List tok_splitAtPlus(List tok) { return splitAtTokens(tok, "+"); } static public boolean startsWith(String a, String b) { return a != null && a.startsWith(unnull(b)); } static public boolean startsWith(String a, char c) { return nemptyString(a) && a.charAt(0) == c; } static public boolean startsWith(String a, String b, Matches m) { if (!startsWith(a, b)) return false; if (m != null) m.m = new String[] { substring(a, strL(b)) }; return true; } static public boolean startsWith(List a, List b) { if (a == null || listL(b) > listL(a)) return false; for (int i = 0; i < listL(b); i++) if (neq(a.get(i), b.get(i))) return false; return true; } static public String[] dropFirst(int n, String[] a) { return drop(n, a); } static public String[] dropFirst(String[] a) { return drop(1, a); } static public Object[] dropFirst(Object[] a) { return drop(1, a); } static public List dropFirst(List l) { return dropFirst(1, l); } static public List dropFirst(int n, Iterable i) { return dropFirst(n, toList(i)); } static public List dropFirst(Iterable i) { return dropFirst(toList(i)); } static public List dropFirst(int n, List l) { return n <= 0 ? l : new ArrayList(l.subList(Math.min(n, l.size()), l.size())); } static public List dropFirst(List l, int n) { return dropFirst(n, l); } static public String dropFirst(int n, String s) { return substring(s, n); } static public String dropFirst(String s, int n) { return substring(s, n); } static public String dropFirst(String s) { return substring(s, 1); } static public Chain dropFirst(Chain c) { return c == null ? null : c.next; } static public boolean endsWith(String a, String b) { return a != null && a.endsWith(b); } static public boolean endsWith(String a, char c) { return nempty(a) && lastChar(a) == c; } static public boolean endsWith(String a, String b, Matches m) { if (!endsWith(a, b)) return false; m.m = new String[] { dropLast(l(b), a) }; return true; } static public A[] dropLast(A[] a) { return dropLast(a, 1); } static public A[] dropLast(A[] a, int n) { if (a == null) return null; n = Math.min(n, a.length); A[] b = arrayOfSameType(a, a.length - n); System.arraycopy(a, 0, b, 0, b.length); return b; } static public List dropLast(List l) { return subList(l, 0, l(l) - 1); } static public List dropLast(int n, List l) { return subList(l, 0, l(l) - n); } static public List dropLast(Iterable l) { return dropLast(asList(l)); } static public String dropLast(String s) { return substring(s, 0, l(s) - 1); } static public String dropLast(String s, int n) { return substring(s, 0, l(s) - n); } static public String dropLast(int n, String s) { return dropLast(s, n); } static public List tok_splitAtAsterisk(String s) { return tok_splitAtAsterisk(javaTokWithAllBrackets_cached(s)); } static public List tok_splitAtAsterisk(List tok) { return splitAtTokens(tok, "*"); } static public double parseDouble(String s) { return empty(s) ? 0.0 : Double.parseDouble(s); } static public A second(List l) { return get(l, 1); } static public A second(Iterable l) { if (l == null) return null; Iterator it = iterator(l); if (!it.hasNext()) return null; it.next(); return it.hasNext() ? it.next() : null; } static public A second(A[] bla) { return bla == null || bla.length <= 1 ? null : bla[1]; } static public B second(Pair p) { return p == null ? null : p.b; } static public B second(T3 t) { return t == null ? null : t.b; } static public A second(Producer p) { if (p == null) return null; if (p.next() == null) return null; return p.next(); } static public char second(String s) { return charAt(s, 1); } static public Object first(Object list) { return first((Iterable) list); } static public A first(List list) { return empty(list) ? null : list.get(0); } static public A first(A[] bla) { return bla == null || bla.length == 0 ? null : bla[0]; } static public Pair first(Map map) { return mapEntryToPair(first(entrySet(map))); } static public Pair first(MultiMap mm) { if (mm == null) return null; var e = first(mm.data.entrySet()); if (e == null) return null; return pair(e.getKey(), first(e.getValue())); } static public A first(IterableIterator i) { return first((Iterator) i); } static public A first(Iterator i) { return i == null || !i.hasNext() ? null : i.next(); } static public A first(Iterable i) { if (i == null) return null; Iterator it = i.iterator(); return it.hasNext() ? it.next() : null; } static public Character first(String s) { return empty(s) ? null : s.charAt(0); } static public Character first(CharSequence s) { return empty(s) ? null : s.charAt(0); } static public A first(Pair p) { return p == null ? null : p.a; } static public A first(T3 t) { return t == null ? null : t.a; } static public Byte first(byte[] l) { return empty(l) ? null : l[0]; } static public A first(A[] l, IF1 pred) { return firstThat(l, pred); } static public A first(Iterable l, IF1 pred) { return firstThat(l, pred); } static public A first(IF1 pred, Iterable l) { return firstThat(pred, l); } static public A first(AppendableChain a) { return a == null ? null : a.element; } static public String unquote(String s) { if (s == null) return null; if (startsWith(s, '[')) { int i = 1; while (i < s.length() && s.charAt(i) == '=') ++i; if (i < s.length() && s.charAt(i) == '[') { String m = s.substring(1, i); if (s.endsWith("]" + m + "]")) return s.substring(i + 1, s.length() - i - 1); } } if (s.length() > 1) { char c = s.charAt(0); if (c == '\"' || c == '\'') { int l = endsWith(s, c) ? s.length() - 1 : s.length(); StringBuilder sb = new StringBuilder(l - 1); for (int i = 1; i < l; i++) { char ch = s.charAt(i); if (ch == '\\') { char nextChar = (i == l - 1) ? '\\' : s.charAt(i + 1); if (nextChar >= '0' && nextChar <= '7') { String code = "" + nextChar; i++; if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') { code += s.charAt(i + 1); i++; if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') { code += s.charAt(i + 1); i++; } } sb.append((char) Integer.parseInt(code, 8)); continue; } switch(nextChar) { case '\"': ch = '\"'; break; case '\\': ch = '\\'; break; case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case '\'': ch = '\''; break; case 'u': if (i >= l - 5) { ch = 'u'; break; } int code = Integer.parseInt("" + s.charAt(i + 2) + s.charAt(i + 3) + s.charAt(i + 4) + s.charAt(i + 5), 16); sb.append(Character.toChars(code)); i += 5; continue; default: ch = nextChar; } i++; } sb.append(ch); } return sb.toString(); } } return s; } static public boolean isQuoted(String s) { if (isNormalQuoted(s)) return true; return isMultilineQuoted(s); } static public String combinePrintParameters(String s, Object o) { return (endsWithLetterOrDigit(s) ? s + ": " : s) + o; } static public void ping_okInCleanUp() { if (ping_pauseAll || ping_anyActions) ping_impl(true); } static public Object getThreadLocal(Object o, String name) { ThreadLocal t = (ThreadLocal) (getOpt(o, name)); return t != null ? t.get() : null; } static public A getThreadLocal(ThreadLocal tl) { return tl == null ? null : tl.get(); } static public A getThreadLocal(ThreadLocal tl, A defaultValue) { return or(getThreadLocal(tl), defaultValue); } static public ThreadLocal print_byThread_dontCreate() { return print_byThread; } static public boolean isFalse(Object o) { return eq(false, o); } static public Map> callF_cache = newDangerousWeakHashMap(); static public A callF(F0 f) { return f == null ? null : f.get(); } static public B callF(F1 f, A a) { return f == null ? null : f.get(a); } static public A callF(IF0 f) { return f == null ? null : f.get(); } static public B callF(IF1 f, A a) { return f == null ? null : f.get(a); } static public B callF(A a, IF1 f) { return f == null ? null : f.get(a); } static public C callF(IF2 f, A a, B b) { return f == null ? null : f.get(a, b); } static public void callF(VF1 f, A a) { if (f != null) f.get(a); } static public void callF(A a, IVF1 f) { if (f != null) f.get(a); } static public void callF(IVF1 f, A a) { if (f != null) f.get(a); } static public Object callF(Runnable r) { { if (r != null) r.run(); } return null; } static public Object callF(Object f, Object... args) { return safeCallF(f, args); } static public Object safeCallF(Object f, Object... args) { if (f instanceof Runnable) { ((Runnable) f).run(); return null; } if (f == null) return null; Class c = f.getClass(); ArrayList methods; synchronized (callF_cache) { methods = callF_cache.get(c); if (methods == null) methods = callF_makeCache(c); } int n = l(methods); if (n == 0) { if (f instanceof String) throw fail("Legacy call: " + f); throw fail("No get method in " + getClassName(c)); } if (n == 1) return invokeMethod(methods.get(0), f, args); for (int i = 0; i < n; i++) { Method m = methods.get(i); if (call_checkArgs(m, args, false)) return invokeMethod(m, f, args); } throw fail("No matching get method in " + getClassName(c)); } static public ArrayList callF_makeCache(Class c) { ArrayList l = new ArrayList(); Class _c = c; do { for (Method m : _c.getDeclaredMethods()) if (m.getName().equals("get")) { makeAccessible(m); l.add(m); } if (!l.isEmpty()) break; _c = _c.getSuperclass(); } while (_c != null); callF_cache.put(c, l); return l; } static public String getStackTrace(Throwable throwable) { lastException(throwable); return getStackTrace_noRecord(throwable); } static public String getStackTrace_noRecord(Throwable throwable) { StringWriter writer = new StringWriter(); throwable.printStackTrace(new PrintWriter(writer)); return hideCredentials(writer.toString()); } static public String getStackTrace() { return getStackTrace_noRecord(new Throwable()); } static public String getStackTrace(String msg) { return getStackTrace_noRecord(new Throwable(msg)); } static public String fixNewLines(String s) { int i = indexOf(s, '\r'); if (i < 0) return s; int l = s.length(); StringBuilder out = new StringBuilder(l); out.append(s, 0, i); for (; i < l; i++) { char c = s.charAt(i); if (c != '\r') out.append(c); else { out.append('\n'); if (i + 1 < l && s.charAt(i + 1) == '\n') ++i; } } return out.toString(); } static public void print_append(Appendable buf, String s, int max) { try { synchronized (buf) { buf.append(s); if (buf instanceof StringBuffer) rotateStringBuffer(((StringBuffer) buf), max); else if (buf instanceof StringBuilder) rotateStringBuilder(((StringBuilder) buf), max); } } catch (Exception __e) { throw rethrow(__e); } } static public void vmBus_send(String msg, Object... args) { Object arg = vmBus_wrapArgs(args); pcallFAll_minimalExceptionHandling(vm_busListeners_live(), msg, arg); pcallFAll_minimalExceptionHandling(vm_busListenersByMessage_live().get(msg), msg, arg); } static public void vmBus_send(String msg) { vmBus_send(msg, (Object) null); } static public Class mc() { return main.class; } static public Map weakMap() { return newWeakHashMap(); } static public Class _getClass(String name) { try { return Class.forName(name); } catch (ClassNotFoundException e) { return null; } } static public Class _getClass(Object o) { return o == null ? null : o instanceof Class ? (Class) o : o.getClass(); } static public Class _getClass(Object realm, String name) { try { return classLoaderForObject(realm).loadClass(classNameToVM(name)); } catch (ClassNotFoundException e) { return null; } } static public B getOrCreate(Map map, A key, Class c) { try { B b = map.get(key); if (b == null) map.put(key, b = c.newInstance()); return b; } catch (Exception __e) { throw rethrow(__e); } } static public B getOrCreate(Map map, A key, Object f) { try { B b = map.get(key); if (b == null) map.put(key, b = (B) callF(f)); return b; } catch (Exception __e) { throw rethrow(__e); } } static public B getOrCreate(IF0 f, Map map, A key) { return getOrCreate(map, key, f); } static public B getOrCreate(Map map, A key, IF0 f) { B b = map.get(key); if (b == null) map.put(key, b = f.get()); return b; } static public B getOrCreate(Class c, Map map, A key) { return getOrCreate(map, key, c); } static public List splitAtSpace(String s) { return empty(s) ? emptyList() : asList(s.split("\\s+")); } static public String toStringOpt(Object o) { return o instanceof String ? ((String) o) : null; } static public Object getOpt(Object o, String field) { return getOpt_cached(o, field); } static public Object getOpt(String field, Object o) { return getOpt_cached(o, field); } static public Object getOpt_raw(Object o, String field) { try { Field f = getOpt_findField(o.getClass(), field); if (f == null) return null; makeAccessible(f); return f.get(o); } catch (Exception __e) { throw rethrow(__e); } } static public Object getOpt(Class c, String field) { try { if (c == null) return null; Field f = getOpt_findStaticField(c, field); if (f == null) return null; makeAccessible(f); return f.get(null); } catch (Exception __e) { throw rethrow(__e); } } static public Field getOpt_findStaticField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) return f; _c = _c.getSuperclass(); } while (_c != null); return null; } static public void db() { conceptsAndBot(); } static public void db(Integer autoSaveInterval) { conceptsAndBot(autoSaveInterval); } static public void indexConceptFields(Object... params) { int i = 0; Concepts concepts; if (first(params) instanceof Concepts) { concepts = (Concepts) first(params); ++i; } else concepts = db_mainConcepts(); for (; i < l(params); i += 2) indexConceptField(concepts, (Class) params[i], (String) params[i + 1]); } static public void indexConceptField(Class c, String field) { indexConceptField(db_mainConcepts(), c, field); } static public void indexConceptField(Concepts concepts, Class c, String field) { if (!isConceptFieldIndexed(concepts, c, field)) new ConceptFieldIndex(concepts, c, field); } static volatile public Concepts mainConcepts; static public Concepts db_mainConcepts() { if (mainConcepts == null) mainConcepts = newConceptsWithClassFinder(getDBProgramID()); return mainConcepts; } static public void cleanMeUp_concepts() { if (db_mainConcepts() != null) db_mainConcepts().cleanMeUp(); } static public void warnIfOddCount(Object... list) { if (odd(l(list))) printStackTrace("Odd list size: " + list); } static public Object[] expandParams(Class c, Object[] params) { if (l(params) == 1) params = new Object[] { singleFieldName(c), params[0] }; else warnIfOddCount(params); return params; } static public boolean _csetField(Concept c, String field, Object value) { try { Field f = setOpt_findField(c.getClass(), field); if (value instanceof RC) value = c._concepts.getConcept((RC) value); value = deref(value); if (value instanceof String && l((String) value) >= concepts_internStringsLongerThan) value = intern((String) value); if (f == null) { assertIdentifier(field); Object oldVal = mapGet(c.fieldValues, field); if (value instanceof Concept) { if (oldVal instanceof Concept.Ref) return ((Concept.Ref) oldVal).set((Concept) value); else { dynamicObject_setRawFieldValue(c, field, c.new Ref((Concept) value)); c.change(); return true; } } else { if (oldVal instanceof Concept.Ref) ((Concept.Ref) oldVal).unindexAndDrop(); if (eq(oldVal, value)) return false; if (isConceptList(value) && nempty(((List) value))) { dynamicObject_setRawFieldValue(c, field, c.new RefL(((List) value))); c.change(); return true; } if (value == null) { dynamicObject_dropRawField(c, field); } else { if (!isPersistable(value)) throw fail("Can't persist: " + c + "." + field + " = " + value); dynamicObject_setRawFieldValue(c, field, value); } c.change(); return true; } } else if (isSubtypeOf(f.getType(), Concept.Ref.class)) { ((Concept.Ref) f.get(c)).set((Concept) derefRef(value)); c.change(); return true; } else if (isSubtypeOf(f.getType(), Concept.RefL.class)) { ((Concept.RefL) f.get(c)).replaceWithList(lmap(__34 -> derefRef(__34), (List) value)); c.change(); return true; } else { Object old = f.get(c); if (neq(value, old)) { boolean isTransient = isTransient(f); if (!isTransient && !isPersistable(value)) throw fail("Can't persist: " + c + "." + field + " = " + value); f.set(c, value); if (!isTransient) c.change(); return true; } } return false; } catch (Exception __e) { throw rethrow(__e); } } static public String unnullForIteration(String s) { return s == null ? "" : s; } static public Collection unnullForIteration(Collection l) { return l == null ? immutableEmptyList() : l; } static public List unnullForIteration(List l) { return l == null ? immutableEmptyList() : l; } static public int[] unnullForIteration(int[] l) { return l == null ? emptyIntArray() : l; } static public char[] unnullForIteration(char[] l) { return l == null ? emptyCharArray() : l; } static public double[] unnullForIteration(double[] l) { return l == null ? emptyDoubleArray() : l; } static public short[] unnullForIteration(short[] l) { return l == null ? emptyShortArray() : l; } static public Map unnullForIteration(Map l) { return l == null ? immutableEmptyMap() : l; } static public Iterable unnullForIteration(Iterable i) { return i == null ? immutableEmptyList() : i; } static public A[] unnullForIteration(A[] a) { return a == null ? (A[]) emptyObjectArray() : a; } static public BitSet unnullForIteration(BitSet b) { return b == null ? new BitSet() : b; } static public Pt unnullForIteration(Pt p) { return p == null ? new Pt() : p; } static public Symbol unnullForIteration(Symbol s) { return s == null ? emptySymbol() : s; } static public Pair unnullForIteration(Pair p) { return p != null ? p : new Pair(null, null); } static public long unnullForIteration(Long l) { return l == null ? 0L : l; } static public A getVar(IF0 v) { return v == null ? null : v.get(); } static public A getVar(Optional v) { return v == null ? null : v.orElse(null); } static public Collection findConceptsWhere(Class c, Object... params) { return findConceptsWhere(db_mainConcepts(), c, params); } static public Collection findConceptsWhere(String c, Object... params) { return findConceptsWhere(db_mainConcepts(), c, params); } static public Collection findConceptsWhere(Concepts concepts, Class c, Object... params) { ping(); params = expandParams(c, params); if (concepts.fieldIndices != null) for (int i = 0; i < l(params); i += 2) { IFieldIndex index = concepts.getFieldIndex(c, (String) params[i]); if (index != null) { Collection rawList = index.getAll(params[i + 1]); params = dropEntryFromParams(params, i); if (params == null) return rawList; List l = new ArrayList(); for (A x : rawList) if (checkConceptFields(x, params)) l.add(x); return l; } } return filterConcepts(concepts.list(c), params); } static public Collection findConceptsWhere(Concepts concepts, String c, Object... params) { return filterConcepts(concepts.list(c), params); } static public A uniqueConcept(Class c, Object... params) { return uniqueConcept(db_mainConcepts(), c, params); } static public A uniqueConcept(Concepts cc, Class c, Object... params) { AutoCloseable __1 = tempDBLock(cc); try { params = expandParams(c, params); A x = findConceptWhere(cc, c, params); if (x == null) { x = unlisted(c); csetAll(x, params); cc.register(x); } else { } return x; } finally { _close(__1); } } static public List deleteConceptsWhere(Class c, Object... params) { return deleteConcepts(c, params); } static public List deleteConceptsWhere(Concepts cc, Class c, Object... params) { return deleteConcepts(cc, c, params); } static public IConceptIndex simpleConceptIndex(final Runnable r) { return new IConceptIndex() { public void update(Concept c) { pcallF(r); } public void remove(Concept c) { pcallF(r); } }; } static public void _handleError(Error e) { } static public boolean startsWithIgnoreCase(String a, String b) { return regionMatchesIC(a, 0, b, 0, b.length()); } static public String substring(String s, int x) { return substring(s, x, strL(s)); } static public String substring(String s, int x, int y) { if (s == null) return null; if (x < 0) x = 0; int n = s.length(); if (y < x) y = x; if (y > n) y = n; if (x >= y) return ""; return s.substring(x, y); } static public String substring(String s, IntRange r) { return r == null ? null : substring(s, r.start, r.end); } static public String substring(String s, CharSequence l) { return substring(s, lCharSequence(l)); } static public AutoCloseable tempSetThreadLocal(final ThreadLocal tl, A a) { if (tl == null) return null; final A prev = setThreadLocal(tl, a); return new AutoCloseable() { public String toString() { return "tl.set(prev);"; } public void close() throws Exception { tl.set(prev); } }; } static public AutoCloseable tempSetThreadLocalIfNecessary(ThreadLocal tl, A a) { if (tl == null) return null; A prev = tl.get(); if (eq(prev, a)) return null; tl.set(a); return new AutoCloseable() { public String toString() { return "tl.set(prev);"; } public void close() throws Exception { tl.set(prev); } }; } static public AutoCloseable tempSetThreadLocalIfNecessary(BetterThreadLocal tl, A a) { if (tl == null) return null; A prev = tl.get(); if (eq(prev, a)) return null; tl.set(a); return new AutoCloseable() { public String toString() { return "tl.set(prev);"; } public void close() throws Exception { tl.set(prev); } }; } static public B mapGet(Map map, A a) { return map == null || a == null ? null : map.get(a); } static public B mapGet(A a, Map map) { return map == null || a == null ? null : map.get(a); } static public Object mainBot; static public Object getMainBot() { return mainBot; } static public NanoHTTPD.Response serveText_direct(String s) { return serveByteArray(toUtf8(s), "text/plain; charset=utf8"); } static public Object call(Object o) { return callF(o); } static public Object call(Object o, String method, String[] arg) { return call(o, method, new Object[] { arg }); } static public Object call(Object o, String method, Object... args) { return call_withVarargs(o, method, args); } static public byte[] toUtf8(String s) { try { return s.getBytes(utf8charset()); } catch (Exception __e) { throw rethrow(__e); } } static public ArrayList emptyList() { return new ArrayList(); } static public ArrayList emptyList(int capacity) { return new ArrayList(max(0, capacity)); } static public ArrayList emptyList(Iterable l) { return l instanceof Collection ? emptyList(((Collection) l).size()) : emptyList(); } static public ArrayList emptyList(Object[] l) { return emptyList(l(l)); } static public ArrayList emptyList(Class c) { return new ArrayList(); } static public int[] emptyIntArray_a = new int[0]; static public int[] emptyIntArray() { return emptyIntArray_a; } static public char[] emptyCharArray = new char[0]; static public char[] emptyCharArray() { return emptyCharArray; } static public double[] emptyDoubleArray = new double[0]; static public double[] emptyDoubleArray() { return emptyDoubleArray; } static public Map emptyMap() { return new HashMap(); } static public Object[] emptyObjectArray_a = new Object[0]; static public Object[] emptyObjectArray() { return emptyObjectArray_a; } static public Symbol emptySymbol_value; static public Symbol emptySymbol() { if (emptySymbol_value == null) emptySymbol_value = symbol(""); return emptySymbol_value; } static public Object callOpt(Object o) { return callF(o); } static public Object callOpt(Object o, String method, Object... args) { return callOpt_withVarargs(o, method, args); } static public Map cloneMap(Map map) { if (map == null) return new HashMap(); synchronized (map) { return map instanceof TreeMap ? new TreeMap((TreeMap) map) : map instanceof LinkedHashMap ? new LinkedHashMap(map) : new HashMap(map); } } static public List cloneMap(Iterable l, IF1 f) { List x = emptyList(l); if (l != null) for (A o : cloneList(l)) x.add(f.get(o)); return x; } static public HashMap litmap(Object... x) { HashMap map = new HashMap(); litmap_impl(map, x); return map; } static public void litmap_impl(Map map, Object... x) { if (x != null) for (int i = 0; i < x.length - 1; i += 2) if (x[i + 1] != null) map.put(x[i], x[i + 1]); } 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 public String programID; static public String getProgramID() { return nempty(programID) ? formatSnippetIDOpt(programID) : "?"; } static public String getProgramID(Class c) { String id = (String) getOpt(c, "programID"); if (nempty(id)) return formatSnippetID(id); return "?"; } static public String getProgramID(Object o) { return getProgramID(getMainClass(o)); } static public String addPrefix(String prefix, String s) { return s.startsWith(prefix) ? s : prefix + s; } static public RuntimeException fail() { throw new RuntimeException("fail"); } static public RuntimeException fail(Throwable e) { throw asRuntimeException(e); } static public RuntimeException fail(Object msg) { throw new RuntimeException(String.valueOf(msg)); } static public RuntimeException fail(Object... objects) { throw new Fail(objects); } static public RuntimeException fail(String msg) { throw new RuntimeException(msg == null ? "" : msg); } static public RuntimeException fail(String msg, Throwable innerException) { throw new RuntimeException(msg, innerException); } static public String getType(Object o) { return getClassName(o); } static public long getFileSize(String path) { return path == null ? 0 : new File(path).length(); } static public long getFileSize(File f) { return f == null ? 0 : f.length(); } static public String tag(String tag) { return htag(tag); } static public String tag(String tag, Object contents, Object... params) { return htag(tag, str(contents), params); } static public String tag(String tag, StringBuilder contents, Object... params) { return htag(tag, contents, params); } static public String tag(String tag, StringBuffer contents, Object... params) { return htag(tag, contents, params); } static public int iceil(double d) { return (int) Math.ceil(d); } static public boolean nempty(Collection c) { return !empty(c); } static public boolean nempty(CharSequence s) { return !empty(s); } static public boolean nempty(Object[] o) { return !empty(o); } static public boolean nempty(byte[] o) { return !empty(o); } static public boolean nempty(int[] o) { return !empty(o); } static public boolean nempty(BitSet bs) { return !empty(bs); } static public boolean nempty(Map m) { return !empty(m); } static public boolean nempty(Iterator i) { return i != null && i.hasNext(); } static public boolean nempty(IMultiMap mm) { return mm != null && mm.size() != 0; } static public boolean nempty(Object o) { return !empty(o); } static public boolean nempty(IntRange r) { return !empty(r); } static public boolean nempty(Rect r) { return r != null && r.w != 0 && r.h != 0; } static public boolean nempty(MultiSet ms) { return ms != null && !ms.isEmpty(); } static public String makePostData(Map map) { StringBuilder buf = new StringBuilder(); for (Map.Entry e : castMapToMapO(map).entrySet()) { String key = (String) (e.getKey()); Object val = e.getValue(); if (val != null) { String value = str(val); if (nempty(buf)) buf.append("&"); buf.append(urlencode(key)).append("=").append(urlencode((value))); } } return str(buf); } static public String makePostData(Object... params) { StringBuilder buf = new StringBuilder(); int n = l(params); for (int i = 0; i + 1 < n; i += 2) { String key = (String) (params[i]); Object val = params[i + 1]; if (val != null) { String value = str(val); if (nempty(buf)) buf.append("&"); buf.append(urlencode(key)).append("=").append(urlencode((value))); } } return str(buf); } static public int smartIndexOf(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 public int smartIndexOf(String s, int i, char c) { return smartIndexOf(s, c, i); } static public int smartIndexOf(String s, char c, int i) { if (s == null) return 0; i = s.indexOf(c, min(i, l(s))); return i >= 0 ? i : l(s); } static public int smartIndexOf(String s, String sub) { return smartIndexOf(s, sub, 0); } static public int smartIndexOf(String s, char c) { return smartIndexOf(s, c, 0); } static public int smartIndexOf(List l, A sub) { return smartIndexOf(l, sub, 0); } static public int smartIndexOf(List l, int start, A sub) { return smartIndexOf(l, sub, start); } static public int smartIndexOf(List l, A sub, int start) { int i = indexOf(l, sub, start); return i < 0 ? l(l) : i; } static public List takeFirst(List l, int n) { return l(l) <= n ? l : newSubListOrSame(l, 0, n); } static public List takeFirst(int n, List l) { return takeFirst(l, n); } static public String takeFirst(int n, String s) { return substring(s, 0, n); } static public String takeFirst(String s, int n) { return substring(s, 0, n); } static public CharSequence takeFirst(int n, CharSequence s) { return subCharSequence(s, 0, n); } static public List takeFirst(int n, Iterator it) { if (it == null) return null; List l = new ArrayList(); for (int _repeat_0 = 0; _repeat_0 < n; _repeat_0++) { if (it.hasNext()) l.add(it.next()); else break; } return l; } static public List takeFirst(int n, Iterable i) { if (i == null) return null; return i == null ? null : takeFirst(n, i.iterator()); } static public List takeFirst(int n, IterableIterator i) { return takeFirst(n, (Iterator) i); } static public int[] takeFirst(int n, int[] a) { return takeFirstOfIntArray(n, a); } static public short[] takeFirst(int n, short[] a) { return takeFirstOfShortArray(n, a); } static public byte[] takeFirst(int n, byte[] a) { return takeFirstOfByteArray(n, a); } static public byte[] takeFirst(byte[] a, int n) { return takeFirstOfByteArray(n, a); } static public double[] takeFirst(int n, double[] a) { return takeFirstOfDoubleArray(n, a); } static public double[] takeFirst(double[] a, int n) { return takeFirstOfDoubleArray(n, a); } static public Map paramsToMap(Object... params) { int n = l(params); if (l(params) == 1 && params[0] instanceof Map) return (Map) params[0]; LinkedHashMap map = new LinkedHashMap(); for (int i = 0; i + 1 < n; i += 2) mapPut(map, params[i], params[i + 1]); return map; } static public String programID() { return getProgramID(); } static public String programID(Object o) { return getProgramID(o); } static public String myDomain() { return or2(trim(loadTextFile(javaxDataDir("my-domain.txt"))), "botcompany.de"); } static public Object subBot_serveInputStream(InputStream in, String mimeType) { return call(mainBot(), "serveInputStream", in, mimeType); } static public Object subBot_serveFile(File file) { return call(getMainBot(), "serveFile", file); } static public Object subBot_serveFile(File file, String mimeType) { return call(getMainBot(), "serveFile", file, mimeType); } static public String hcss(Object contents) { if (contents instanceof String && isRelativeOrAbsoluteURL((String) contents)) return hstylesheetsrc((String) contents); else return htag("style", contents); } static public String htitle_noEncode(String title) { return tag("title", title); } static public String dropTags(String html) { return dropAllTags(html); } static public List dropTags(List tok) { return dropAllTags(tok); } static public String hfulltag(String tag) { return hfulltag(tag, ""); } static public String hfulltag(String tag, Object contents, Object... params) { return hopeningTag(tag, params) + str(contents) + ""; } static public String htmlencode_noQuotes(String s) { if (s == null) return ""; int n = s.length(); StringBuilder out = null; for (int i = 0; i < n; i++) { char c = s.charAt(i); if (c == '<') { if (out == null) out = new StringBuilder(Math.max(16, n)).append(takeFirst(i, s)); out.append("<"); } else if (c == '>') { if (out == null) out = new StringBuilder(Math.max(16, n)).append(takeFirst(i, s)); out.append(">"); } else if (c > 127 || c == '&') { int cp = s.codePointAt(i); if (out == null) out = new StringBuilder(Math.max(16, n)).append(takeFirst(i, s)); out.append("&#x"); out.append(intToHex_flexLength(cp)); out.append(';'); i += Character.charCount(cp) - 1; } else { if (out != null) out.append(c); } } return out == null ? s : out.toString(); } static public String strOrEmpty(Object o) { return o == null ? "" : str(o); } static public void typeWriterConsole() { if (isHeadless()) return; Font f = typeWriterFont(); consoleFont(f); consoleInputFont(f); } static public Object[] paramsPlus_inFront(Object[] a1, Object... a2) { return paramsPlus(a2, a1); } static public String dropSuffix(String suffix, String s) { return nempty(suffix) && endsWith(s, suffix) ? s.substring(0, l(s) - l(suffix)) : s; } static public boolean isInstance(Class type, Object arg) { return type.isInstance(arg); } static public String getClassName(Object o) { return o == null ? "null" : o instanceof Class ? ((Class) o).getName() : o.getClass().getName(); } static public Object unstructure(String text) { return unstructure(text, false); } static public Object unstructure(String text, boolean allDynamic) { return unstructure(text, allDynamic, null); } static public Object unstructure(String text, IF1 classFinder) { return unstructure(text, false, classFinder); } static public int structure_internStringsLongerThan = 50; static public int unstructure_unquoteBufSize = 100; static public int unstructure_tokrefs; abstract static public class unstructure_Receiver { abstract public void set(Object o); } static public Object unstructure(String text, boolean allDynamic, Object classFinder) { if (text == null) return null; return unstructure_tok(javaTokC_noMLS_iterator(text), allDynamic, classFinder); } static public Object unstructure_reader(BufferedReader reader) { return unstructure_tok(javaTokC_noMLS_onReader(reader), false, null); } public interface unstructure_Handler { public void parse(int refID, int tokIndex, unstructure_Receiver out); } static public Object unstructure_tok(final Producer tok, final boolean allDynamic, final Object _classFinder) { final boolean debug = unstructure_debug; final class X { public int i = -1; final public Object classFinder = _classFinder != null ? _classFinder : _defaultClassFinder(); public String mcDollar = actualMCDollar(); public HashMap refs = new HashMap(); public HashMap tokrefs = new HashMap(); public HashSet concepts = new HashSet(); public List stack = new ArrayList(); public Map baseClassMap = new HashMap(); public HashMap innerClassConstructors = new HashMap(); public String curT; public char[] unquoteBuf = new char[unstructure_unquoteBufSize]; final public HashMap handlers = new HashMap(); public X() { try { Class mc = (Class) (callF(_classFinder, "
")); if (mc != null) mcDollar = mc.getName() + "$"; } catch (Throwable __e) { printStackTrace(__e); } makeHandlers(); } public void makeHandlers() { unstructure_Handler h; handlers.put("bigint", (unstructure_Handler) (refID, tokIndex, out) -> out.set(parseBigInt())); handlers.put("d", (unstructure_Handler) (refID, tokIndex, out) -> out.set(parseDouble())); handlers.put("fl", (unstructure_Handler) (refID, tokIndex, out) -> out.set(parseFloat())); handlers.put("sh", (unstructure_Handler) (refID, tokIndex, out) -> { consume(); String t = tpp(); if (t.equals("-")) { t = tpp(); out.set((short) (-parseInt(t))); return; } out.set((short) parseInt(t)); }); handlers.put("enum", (unstructure_Handler) (refID, tokIndex, out) -> { consume(); String t = tpp(); assertTrue(isJavaIdentifier(t)); String fullClassName = mcDollar + t; Class _c = findAClass(fullClassName); if (_c == null) throw fail("Enum class not found: " + fullClassName); int ordinal = parseInt(tpp()); out.set(_c.getEnumConstants()[ordinal]); }); handlers.put("false", h = (unstructure_Handler) (refID, tokIndex, out) -> { consume(); out.set(false); }); handlers.put("f", h); handlers.put("true", h = (unstructure_Handler) (refID, tokIndex, out) -> { consume(); out.set(true); }); handlers.put("t", h); handlers.put("{", (unstructure_Handler) (refID, tokIndex, out) -> parseMap(out)); handlers.put("[", (unstructure_Handler) (refID, tokIndex, out) -> { ArrayList l = new ArrayList(); if (refID >= 0) refs.put(refID, l); this.parseList(l, out); }); handlers.put("bitset", (unstructure_Handler) (refID, tokIndex, out) -> parseBitSet(out)); handlers.put("array", h = (unstructure_Handler) (refID, tokIndex, out) -> parseArray(out)); handlers.put("intarray", h); handlers.put("dblarray", h); } public Class findAClass(String fullClassName) { try { return classFinder != null ? (Class) callF(classFinder, fullClassName) : findClass_fullName(fullClassName); } catch (Throwable __e) { return null; } } public String unquote(String s) { return unquoteUsingCharArray(s, unquoteBuf); } public String t() { return curT; } public String tpp() { String t = curT; consume(); return t; } public void parse(final unstructure_Receiver out) { String t = t(); int refID; if (structure_isMarker(t, 0, l(t))) { refID = parseInt(t.substring(1)); consume(); } else refID = -1; final int tokIndex = i; parse_inner(refID, tokIndex, new unstructure_Receiver() { public void set(Object o) { if (refID >= 0) refs.put(refID, o); if (o != null) tokrefs.put(tokIndex, o); out.set(o); } }); } public void parse_inner(int refID, int tokIndex, unstructure_Receiver out) { String t = t(); Object handler = handlers.get(t); if (handler instanceof unstructure_Handler) { ((unstructure_Handler) handler).parse(refID, tokIndex, out); return; } Class c = (Class) handler; if (c == null) { if (t.startsWith("\"")) { String s = internIfLongerThan(unquote(tpp()), structure_internStringsLongerThan); out.set(s); return; } if (t.startsWith("'")) { out.set(unquoteCharacter(tpp())); return; } if (t.equals("-")) { consume(); t = tpp(); out.set(isLongConstant(t) ? (Object) (-parseLong(t)) : (Object) (-parseInt(t))); return; } if (isInteger(t) || isLongConstant(t)) { consume(); if (isLongConstant(t)) { out.set(parseLong(t)); return; } long l = parseLong(t); boolean isInt = l == (int) l; out.set(isInt ? (Object) Integer.valueOf((int) l) : (Object) Long.valueOf(l)); return; } if (t.equals("-")) { consume(); t = tpp(); out.set(isLongConstant(t) ? (Object) (-parseLong(t)) : (Object) (-parseInt(t))); return; } if (isInteger(t) || isLongConstant(t)) { consume(); if (isLongConstant(t)) { out.set(parseLong(t)); return; } long l = parseLong(t); boolean isInt = l == (int) l; out.set(isInt ? (Object) Integer.valueOf((int) l) : (Object) Long.valueOf(l)); return; } if (t.equals("File")) { consume(); File f = new File(unquote(tpp())); out.set(f); return; } if (t.startsWith("r") && isInteger(t.substring(1))) { consume(); int ref = Integer.parseInt(t.substring(1)); Object o = refs.get(ref); if (o == null) warn("unsatisfied back reference " + ref); out.set(o); return; } if (t.startsWith("t") && isInteger(t.substring(1))) { consume(); int ref = Integer.parseInt(t.substring(1)); Object o = tokrefs.get(ref); if (o == null) warn("unsatisfied token reference " + ref + " at " + tokIndex); out.set(o); return; } if (t.equals("hashset")) { parseHashSet(out); return; } if (t.equals("lhs")) { parseLinkedHashSet(out); return; } if (t.equals("treeset")) { parseTreeSet(out); return; } if (t.equals("ciset")) { parseCISet(out); return; } if (eqOneOf(t, "hashmap", "hm")) { consume(); parseMap(new HashMap(), out); return; } if (t.equals("lhm")) { consume(); parseMap(new LinkedHashMap(), out); return; } if (t.equals("tm")) { consume(); parseMap(new TreeMap(), out); return; } if (t.equals("cimap")) { consume(); parseMap(ciMap(), out); return; } if (t.equals("ll")) { consume(); LinkedList l = new LinkedList(); if (refID >= 0) refs.put(refID, l); { parseList(l, out); return; } } if (t.equals("syncLL")) { consume(); { parseList(synchroLinkedList(), out); return; } } if (t.equals("sync")) { consume(); { parse(new unstructure_Receiver() { public void set(Object value) { if (value instanceof Map) { if (value instanceof NavigableMap) { out.set(synchroNavigableMap((NavigableMap) value)); return; } if (value instanceof SortedMap) { out.set(synchroSortedMap((SortedMap) value)); return; } { out.set(synchroMap((Map) value)); return; } } else { out.set(synchroList((List) value)); return; } } }); return; } } if (t.equals("ba")) { consume(); String hex = unquote(tpp()); out.set(hexToBytes(hex)); return; } if (t.equals("boolarray")) { consume(); int n = parseInt(tpp()); String hex = unquote(tpp()); out.set(boolArrayFromBytes(hexToBytes(hex), n)); return; } if (t.equals("class")) { out.set(parseClass()); return; } if (t.equals("l")) { parseLisp(out); return; } if (t.equals("null")) { consume(); out.set(null); return; } if (eq(t, "c")) { consume(); t = t(); assertTrue(isJavaIdentifier(t)); concepts.add(t); } if (eq(t, "cu")) { consume(); t = tpp(); assertTrue(isJavaIdentifier(t)); String fullClassName = mcDollar + t; Class _c = findAClass(fullClassName); if (_c == null) throw fail("Class not found: " + fullClassName); parse(new unstructure_Receiver() { public void set(Object value) { out.set(call(_c, "_deserialize", value)); } }); return; } } if (eq(t, "j")) { consume(); out.set(parseJava()); return; } if (eq(t, "bc")) { consume(); String c1 = tpp(); String c2 = tpp(); baseClassMap.put(c1, c2); { parse_inner(refID, i, out); return; } } if (c == null && !isJavaIdentifier(t)) throw new RuntimeException("Unknown token " + (i + 1) + ": " + quote(t)); consume(); String className, fullClassName; if (eq(t(), ".")) { consume(); className = fullClassName = t + "." + assertIdentifier(tpp()); } else { className = t; fullClassName = mcDollar + t; } if (c == null && !allDynamic) { c = findAClass(fullClassName); handlers.put(className, c); } if (c == null && !allDynamic) { Set seen = new HashSet(); String parent = className; while (true) { String baseName = baseClassMap.get(parent); if (baseName == null) break; if (!seen.add(baseName)) throw fail("Cyclic superclass info: " + baseName); c = findAClass(mcDollar + baseName); if (c == null) print("Base class " + baseName + " of " + parent + " doesn't exist either"); else if (isAbstract(c)) print("Can't instantiate abstract base class: " + c); else { printVars_str("Reverting to base class", "className", className, "baseName", baseName, "c", c); handlers.put(className, c); break; } parent = baseName; } } boolean hasBracket = eq(t(), "("); if (hasBracket) consume(); boolean hasOuter = hasBracket && startsWith(t(), "this$"); DynamicObject dO = null; Object o = null; final String thingName = t; try { if (c != null) { if (hasOuter) try { Constructor ctor = innerClassConstructors.get(c); if (ctor == null) innerClassConstructors.put(c, ctor = nuStubInnerObject_findConstructor(c, classFinder)); o = ctor.newInstance(new Object[] { null }); } catch (Exception e) { print("Error deserializing " + c + ": " + e); o = nuEmptyObject(c); } else o = nuEmptyObject(c); if (o instanceof DynamicObject) dO = (DynamicObject) o; } else { if (concepts.contains(t) && (c = findAClass(mcDollar + "Concept")) != null) o = dO = (DynamicObject) nuEmptyObject(c); else dO = new DynamicObject(); dO.className = className; } } catch (Throwable __e) { printStackTrace(__e); } if (o == null && dO == null) dO = new DynamicObject(); if (refID >= 0) refs.put(refID, o != null ? o : dO); tokrefs.put(tokIndex, o != null ? o : dO); HashMap fields = new HashMap(); Object _o = o; DynamicObject _dO = dO; if (hasBracket) { stack.add(new Runnable() { public void run() { try { if (eq(t(), ",")) consume(); if (eq(t(), ")")) { consume(")"); objRead(_o, _dO, fields, hasOuter); out.set(_o != null ? _o : _dO); } else { final String key = unquote(tpp()); String t = tpp(); if (!eq(t, "=")) throw fail("= expected, got " + t + " after " + quote(key) + " in object " + thingName); stack.add(this); parse(new unstructure_Receiver() { public void set(Object value) { fields.put(key, value); } }); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "ifdef unstructure_debug\r\n print(\"in object values, token: \" + t())..."; } }); } else { objRead(o, dO, fields, hasOuter); out.set(o != null ? o : dO); } } public void objRead(Object o, DynamicObject dO, Map fields, boolean hasOuter) { Object outer = fields.get("this$0"); if (outer != null) fields.put("this$1", outer); else { outer = fields.get("this$1"); if (outer != null) fields.put("this$0", outer); } if (o != null) { if (dO != null) { setOptAllDyn_pcall(dO, fields); } else { setOptAll_pcall(o, fields); } if (hasOuter) fixOuterRefs(o); } else for (Map.Entry e : fields.entrySet()) setDynObjectValue(dO, intern(e.getKey()), e.getValue()); if (o != null) pcallOpt_noArgs(o, "_doneLoading"); } public void parseSet(final Set set, final unstructure_Receiver out) { this.parseList(new ArrayList(), new unstructure_Receiver() { public void set(Object o) { set.addAll((List) o); out.set(set); } }); } public void parseLisp(final unstructure_Receiver out) { throw fail("class Lisp not included"); } public void parseBitSet(final unstructure_Receiver out) { consume("bitset"); consume("{"); final BitSet bs = new BitSet(); stack.add(new Runnable() { public void run() { try { if (eq(t(), "}")) { consume("}"); out.set(bs); } else { stack.add(this); parse(new unstructure_Receiver() { public void set(Object o) { bs.set((Integer) o); if (eq(t(), ",")) consume(); } }); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (eq(t(), \"}\")) {\r\n consume(\"}\");\r\n out.set(bs);\r\n ..."; } }); } public void parseList(final List list, final unstructure_Receiver out) { tokrefs.put(i, list); consume("["); stack.add(new Runnable() { public void run() { try { if (eq(t(), "]")) { consume(); out.set(list); } else { stack.add(this); parse(new unstructure_Receiver() { public void set(Object o) { list.add(o); if (eq(t(), ",")) consume(); } }); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (eq(t(), \"]\")) {\r\n consume();\r\n ifdef unstructure_debug\r..."; } }); } public void parseArray(unstructure_Receiver out) { String _type = tpp(); int dims; if (eq(t(), "S")) { _type = "S"; consume(); } if (eq(t(), "/")) { consume(); dims = parseInt(tpp()); } else dims = 1; consume("{"); List list = new ArrayList(); String type = _type; stack.add(new Runnable() { public void run() { try { if (eq(t(), "}")) { consume("}"); if (dims > 1) { Class atype; if (type.equals("intarray")) atype = int.class; else if (type.equals("S")) atype = String.class; else throw todo("multi-dimensional arrays of other types"); out.set(list.toArray((Object[]) newMultiDimensionalOuterArray(atype, dims, l(list)))); } else out.set(type.equals("intarray") ? toIntArray(list) : type.equals("dblarray") ? toDoubleArray(list) : type.equals("S") ? toStringArray(list) : list.toArray()); } else { stack.add(this); parse(new unstructure_Receiver() { public void set(Object o) { list.add(o); if (eq(t(), ",")) consume(); } }); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (eq(t(), \"}\")) {\r\n consume(\"}\");\r\n if (dims > 1) {\r\n ..."; } }); } public Object parseClass() { consume("class"); consume("("); String name = unquote(tpp()); consume(")"); Class c = allDynamic ? null : findAClass(name); if (c != null) return c; DynamicObject dO = new DynamicObject(); dO.className = "java.lang.Class"; name = dropPrefix(mcDollar, name); dO.fieldValues.put("name", name); return dO; } public Object parseBigInt() { consume("bigint"); consume("("); String val = tpp(); if (eq(val, "-")) val = "-" + tpp(); consume(")"); return new BigInteger(val); } public Object parseDouble() { consume("d"); consume("("); String val = unquote(tpp()); consume(")"); return Double.parseDouble(val); } public Object parseFloat() { consume("fl"); String val; if (eq(t(), "(")) { consume("("); val = unquote(tpp()); consume(")"); } else { val = unquote(tpp()); } return Float.parseFloat(val); } public void parseHashSet(unstructure_Receiver out) { consume("hashset"); parseSet(new HashSet(), out); } public void parseLinkedHashSet(unstructure_Receiver out) { consume("lhs"); parseSet(new LinkedHashSet(), out); } public void parseTreeSet(unstructure_Receiver out) { consume("treeset"); parseSet(new TreeSet(), out); } public void parseCISet(unstructure_Receiver out) { consume("ciset"); parseSet(ciSet(), out); } public void parseMap(unstructure_Receiver out) { parseMap(new TreeMap(), out); } public Object parseJava() { String j = unquote(tpp()); Matches m = new Matches(); if (jmatch("java.awt.Color[r=*,g=*,b=*]", j, m)) return nuObject("java.awt.Color", parseInt(m.unq(0)), parseInt(m.unq(1)), parseInt(m.unq(2))); else { warn("Unknown Java object: " + j); return null; } } public void parseMap(final Map map, final unstructure_Receiver out) { consume("{"); stack.add(new Runnable() { public boolean v = false; public Object key; public void run() { if (v) { v = false; stack.add(this); if (!eq(tpp(), "=")) throw fail("= expected, got " + t() + " in map of size " + l(map)); parse(new unstructure_Receiver() { public void set(Object value) { map.put(key, value); if (eq(t(), ",")) consume(); } }); } else { if (eq(t(), "}")) { consume("}"); out.set(map); } else { v = true; stack.add(this); parse(new unstructure_Receiver() { public void set(Object o) { key = o; } }); } } } }); } public void consume() { curT = tok.next(); ++i; } public void consume(String s) { if (!eq(t(), s)) { throw fail(quote(s) + " expected, got " + quote(t())); } consume(); } public void parse_initial(unstructure_Receiver out) { consume(); parse(out); while (nempty(stack)) popLast(stack).run(); } } ThreadLocal tlLoading = dynamicObjectIsLoading_threadLocal(); Boolean b = tlLoading.get(); tlLoading.set(true); try { final Var v = new Var(); X x = new X(); x.parse_initial(new unstructure_Receiver() { public void set(Object o) { v.set(o); } }); unstructure_tokrefs = x.tokrefs.size(); return v.get(); } finally { tlLoading.set(b); } } static public boolean unstructure_debug = false; static public Object safeUnstructureGZFile(File f) { try { if (!fileExists(f)) return null; BufferedReader reader = utf8BufferedReader(gzInputStream(f)); return unstructure_tok(javaTokC_noMLS_onReader(reader), true, null); } catch (Exception __e) { throw rethrow(__e); } } static public TreeMap ciMap() { return caseInsensitiveMap(); } static public A get(List l, int idx) { return l != null && idx >= 0 && idx < l(l) ? l.get(idx) : null; } static public A get(A[] l, int idx) { return idx >= 0 && idx < l(l) ? l[idx] : null; } static public boolean get(boolean[] l, int idx) { return idx >= 0 && idx < l(l) ? l[idx] : false; } static public Object get(Object o, String field) { try { if (o == null) return null; 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) { makeAccessible(f); return f.get(o); } if (o instanceof DynamicObject) return getOptDynOnly(((DynamicObject) o), field); } catch (Exception e) { throw asRuntimeException(e); } throw new RuntimeException("Field '" + field + "' not found in " + o.getClass().getName()); } static public Object get_raw(String field, Object o) { return get_raw(o, field); } static public Object get_raw(Object o, String field) { try { if (o == null) return null; Field f = get_findField(o.getClass(), field); makeAccessible(f); return f.get(o); } catch (Exception __e) { throw rethrow(__e); } } static public Object get(Class c, String field) { try { Field f = get_findStaticField(c, field); makeAccessible(f); return f.get(null); } catch (Exception e) { throw new RuntimeException(e); } } static public Field get_findStaticField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) return f; _c = _c.getSuperclass(); } while (_c != null); throw new RuntimeException("Static field '" + field + "' not found in " + c.getName()); } static public 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 public Object get(String field, Object o) { return get(o, field); } static public boolean get(BitSet bs, int idx) { return bs != null && bs.get(idx); } static public HashMap findClass_cache = new HashMap(); static public Class findClass(String name) { synchronized (findClass_cache) { if (findClass_cache.containsKey(name)) return findClass_cache.get(name); if (!isJavaIdentifier(name)) return null; Class c; try { c = Class.forName("main$" + name); } catch (ClassNotFoundException e) { c = null; } findClass_cache.put(name, c); return c; } } static public Object nuObject(String className, Object... args) { try { return nuObject(classForName(className), args); } catch (Exception __e) { throw rethrow(__e); } } static public A nuObject(Class c, Object... args) { try { if (args == null || args.length == 0) return nuObjectWithoutArguments(c); Constructor m = nuObject_findConstructor(c, args); makeAccessible(m); return (A) m.newInstance(args); } catch (Exception __e) { throw rethrow(__e); } } static public Constructor nuObject_findConstructor(Class c, Object... args) { for (Constructor m : getDeclaredConstructors_cached(c)) { if (!nuObject_checkArgs(m.getParameterTypes(), args, false)) continue; return m; } throw fail("Constructor " + c.getName() + getClasses(args) + " not found" + (args.length == 0 && (c.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0 ? " - hint: it's a non-static class!" : "")); } static public boolean nuObject_checkArgs(Class[] types, Object[] args, boolean debug) { 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 public int csetAll(Concept c, Object... values) { return cset(c, values); } static public int csetAll(Iterable l, Object... values) { int n = 0; for (Concept c : unnullForIteration(l)) n += cset(c, values); return n; } static public int csetAll(Concept c, Map values) { int n = 0; for (Map.Entry __0 : _entrySet(values)) { String field = __0.getKey(); Object value = __0.getValue(); n += cset(c, field, value); } return n; } static public Map objectToMap(Object o) { try { if (o instanceof Map) return (Map) o; TreeMap map = new TreeMap(); Class c = o.getClass(); while (c != Object.class) { Field[] fields = c.getDeclaredFields(); for (final Field field : fields) { if ((field.getModifiers() & Modifier.STATIC) != 0) continue; field.setAccessible(true); final Object value = field.get(o); if (value != null) map.put(field.getName(), value); } c = c.getSuperclass(); } if (o instanceof DynamicObject) putAll(map, ((DynamicObject) o).fieldValues); return map; } catch (Exception __e) { throw rethrow(__e); } } static public List> objectToMap(Iterable l) { if (l == null) return null; List x = new ArrayList(); for (Object o : l) x.add(objectToMap(o)); return x; } static public Field setOpt_findField(Class c, String field) { HashMap map; synchronized (getOpt_cache) { map = getOpt_cache.get(c); if (map == null) map = getOpt_makeCache(c); } return map.get(field); } static public void setOpt(Object o, String field, Object value) { try { if (o == null) return; Class c = o.getClass(); HashMap map; if (getOpt_cache == null) map = getOpt_makeCache(c); else synchronized (getOpt_cache) { map = getOpt_cache.get(c); if (map == null) map = getOpt_makeCache(c); } if (map == getOpt_special) { if (o instanceof Class) { setOpt((Class) o, field, value); return; } setOpt_raw(o, field, value); return; } Field f = map.get(field); if (f != null) { smartSet(f, o, value); return; } if (o instanceof DynamicObject) { setDyn(((DynamicObject) o), field, value); return; } if (o instanceof IMeta) setDyn(((IMeta) o), field, value); } catch (Exception __e) { throw rethrow(__e); } } static public void setOpt(Class c, String field, Object value) { if (c == null) return; try { Field f = setOpt_findStaticField(c, field); if (f != null) smartSet(f, null, value); } catch (Exception e) { throw new RuntimeException(e); } } static public Field setOpt_findStaticField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) { makeAccessible(f); return f; } _c = _c.getSuperclass(); } while (_c != null); return null; } static public String[] asStringArray(Collection c) { return toStringArray(c); } static public String[] asStringArray(Object o) { return toStringArray(o); } static public String htmlEncode_nlToBr(String s) { return nlToBr(htmlEncode2(s)); } static public String fromLines(Iterable lines) { StringBuilder buf = new StringBuilder(); if (lines != null) for (Object line : lines) buf.append(str(line)).append('\n'); return buf.toString(); } static public String fromLines(String... lines) { return fromLines(asList(lines)); } static public IterableIterator toLines(File f) { return linesFromFile(f); } static public 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; } static public int toLines_nextLineBreak(String s, int start) { int n = s.length(); for (int i = start; i < n; i++) { char c = s.charAt(i); if (c == '\r' || c == '\n') return i; } return -1; } static public List mapToLines(Map map) { List l = new ArrayList(); for (Object key : keys(map)) l.add(str(key) + " = " + str(map.get(key))); return l; } static public String mapToLines(Map map, Object f) { return lines(map(map, f)); } static public String mapToLines(Object f, Map map) { return lines(map(map, f)); } static public String mapToLines(Object f, Iterable l) { return lines(map(f, l)); } static public String mapToLines(Iterable l, IF1 f) { return mapToLines((Object) f, l); } static public String mapToLines(IF1 f, Iterable l) { return mapToLines((Object) f, l); } static public String mapToLines(Map map, IF2 f) { return lines(map(map, f)); } static public String mapToLines(IF1 f, A data1, A... moreData) { return lines(map(f, data1, moreData)); } static public Map similarEmptyMap(Map m) { if (m instanceof TreeMap) return new TreeMap(((TreeMap) m).comparator()); if (m instanceof LinkedHashMap) return new LinkedHashMap(); return new HashMap(); } static public Map similarEmptyMap(Iterable m) { if (m instanceof TreeSet) return new TreeMap(((TreeSet) m).comparator()); if (m instanceof LinkedHashSet) return new LinkedHashMap(); return new HashMap(); } static public String dynShortName(Object o) { return shortDynamicClassName(o); } static public void sort(T[] a, Comparator c) { if (a != null) Arrays.sort(a, c); } static public void sort(T[] a) { if (a != null) Arrays.sort(a); } static public void sort(int[] a) { if (a != null) Arrays.sort(a); } static public void sort(List a, Comparator c) { if (a != null) Collections.sort(a, c); } static public void sort(List a) { if (a != null) Collections.sort(a); } static public int cmp(Number a, Number b) { return a == null ? b == null ? 0 : -1 : cmp(a.doubleValue(), b.doubleValue()); } static public int cmp(double a, double b) { return a < b ? -1 : a == b ? 0 : 1; } static public int cmp(int a, int b) { return a < b ? -1 : a == b ? 0 : 1; } static public int cmp(long a, long b) { return a < b ? -1 : a == b ? 0 : 1; } static public int cmp(Object a, Object b) { if (a == null) return b == null ? 0 : -1; if (b == null) return 1; return ((Comparable) a).compareTo(b); } static public Object[] paramsPlus(Object[] a1, Object... a2) { if (a2 == null) return a1; if (a1 == null) return a2; if (l(a1) == 1 && a1[0] instanceof Map) return new Object[] { mapPlus((Map) a1[0], a2) }; assertEvenLength(a1); assertEvenLength(a2); Map map = paramsToOrderedMap(a1); int n = l(a2); for (int i = 0; i < n; i += 2) { Object key = a2[i]; if (key != null) map.put(key, a2[i + 1]); } return mapToParams(map); } static public Object[] paramsPlus(Map a1, Object... a2) { return paramsPlus(new Object[] { a1 }, a2); } static public String hcheckboxWithText(String name, String text, boolean checked, Object... params) { String id = randomID(); return hcheckbox(name, checked, paramsPlus(params, "id", id)) + " " + hlabelFor(id, htmlEncode2(text)); } static public String hcheckboxWithText(String name, String text) { return hcheckboxWithText(name, text, false); } static public String asString(Object o) { return o == null ? null : o.toString(); } static public Object[] concatArrays(Object[]... arrays) { int l = 0; for (Object[] a : arrays) l += l(a); Object[] x = new Object[l]; int i = 0; for (Object[] a : arrays) if (a != null) { System.arraycopy(a, 0, x, i, l(a)); i += l(a); } return x; } static public String hiddenFields(Map map, Collection keys) { StringBuilder buf = new StringBuilder(); for (String key : keys) { String value = map.get(key); if (!empty(value)) buf.append(htag("input", "", "type", "hidden", "name", key, "value", value) + "\n"); } return str(buf); } static public String hiddenFields(Map map, String... keys) { return hiddenFields(map, asList(keys)); } static public ThreadLocal htmlTable2_cellEncoder = new ThreadLocal(); static public String htmlTable2(Object data, Object... __) { boolean htmlEncode = optPar("htmlEncode", __, true); boolean useBr = boolPar("useBr", __); Map paramsByColName = (Map) (optPar("paramsByColName", __)); Object[] tableParams = (Object[]) (optPar("tableParams", __)); Object[] trParams = (Object[]) (optPar("trParams", __)); Object[] tdParams = (Object[]) (optPar("tdParams", __)); Map replaceHeaders = (Map) (optPar("replaceHeaders", __)); boolean noHeader = boolPar("noHeader", __); List> rows = new ArrayList(); List cols = new ContentsIndexedList(); if (data instanceof List) { for (Object x : (List) data) { try { rows.add(dataToTable_makeRow(x, cols)); } catch (Throwable __e) { printStackTrace(__e); } } } else if (data instanceof Map) { Map map = (Map) data; for (Object key : map.keySet()) { Object value = map.get(key); rows.add(litlist(structureOrText(key), structureOrText(value))); } } else print("Unknown data type: " + data); int w = 0; for (List row : rows) w = max(w, l(row)); StringBuilder buf = new StringBuilder(); buf.append(hopeningtag("table", paramsPlus(tableParams, "border", html_valueLessParam())) + "\n"); if (!noHeader) { buf.append("\n"); for (String cell : padList(cols, w, "")) buf.append(" " + htmlTable2_encodeCell(getOrKeep(replaceHeaders, cell), htmlEncode, useBr) + "\n"); buf.append("\n"); } for (List row : rows) { buf.append(hopeningtag("tr", trParams)); int i = 0; for (String cell : padList(row, w, "")) { String col = get(cols, i++); Object[] params = paramsPlus(tdParams, mapGet(paramsByColName, col)); buf.append(" " + tag("td", htmlTable2_encodeCell(cell, htmlEncode, useBr), params) + "\n"); } buf.append("\n"); } buf.append("\n"); return buf.toString(); } static public String htmlTable2_encodeCell(String cell, boolean useHtmlEncode, boolean useBr) { if (htmlTable2_cellEncoder.get() != null) return (String) callF(htmlTable2_cellEncoder.get(), cell); if (useHtmlEncode) cell = htmlEncode2(cell); if (useBr) cell = nlToBr(cell); return cell; } static public String containerTag(String tag) { return containerTag(tag, ""); } static public String containerTag(String tag, Object contents, Object... params) { String openingTag = hopeningTag(tag, params); String s = str(contents); return openingTag + s + ""; } static public String hhead_title(String title) { return hhead(htitle(title)); } static public String htmldecode_dropAllTags(String html) { return htmldecode(dropAllTags(html)); } static public String href(String link, Object contents, Object... params) { if (link == null) return str(contents); return hfulltag("a", contents, arrayPlus(params, "href", link)); } static public String joinNempties(String sep, Object... strings) { return joinStrings(sep, strings); } static public String joinNempties(String sep, Iterable strings) { return joinStrings(sep, strings); } static public List collectField(Iterable c, String field) { List l = new ArrayList(); if (c != null) for (Object a : c) l.add(getOpt(a, field)); return l; } static public List collectField(String field, Iterable c) { return collectField(c, field); } static public List reverseInPlace(List l) { return reverseList(l); } static public List sortedByField(Collection c, final String field) { List l = new ArrayList(c); sort(l, new Comparator() { public int compare(A a, A b) { return cmp(getOpt(a, field), getOpt(b, field)); } }); return l; } static public List sortedByField(String field, Collection c) { return sortedByField(c, field); } static public List sortedByFieldDesc(Collection c, String field) { List l = new ArrayList(c); sort(l, descFieldComparator(field)); return l; } static public List sortedByFieldDesc(String field, Collection c) { return sortedByFieldDesc(c, field); } static public String n2(long l) { return formatWithThousands(l); } static public String n2(AtomicLong l) { return n2(l.get()); } static public String n2(Collection l) { return n2(l(l)); } static public String n2(Map map) { return n2(l(map)); } static public String n2(double l, String singular) { return empty(singular) ? str(l) : n2(l, singular, singular + "s"); } static public String n2(double l, String singular, String plural) { if (fraction(l) == 0) return n2((long) l, singular, plural); else return l + " " + plural; } static public String n2(long l, String singular, String plural) { return n_fancy2(l, singular, plural); } static public String n2(long l, String singular) { return empty(singular) ? n2(l) : n_fancy2(l, singular, singular + "s"); } static public String n2(Collection l, String singular) { return n2(l(l), singular); } static public String n2(Collection l, String singular, String plural) { return n_fancy2(l, singular, plural); } static public String n2(Map m, String singular, String plural) { return n_fancy2(m, singular, plural); } static public String n2(Map m, String singular) { return n2(l(m), singular); } static public String n2(long[] a, String singular) { return n2(l(a), singular); } static public String n2(Object[] a, String singular) { return n2(l(a), singular); } static public String n2(Object[] a, String singular, String plural) { return n_fancy2(a, singular, plural); } static public String n2(MultiSet ms, String singular) { return n2(ms, singular, singular + "s"); } static public String n2(MultiSet ms, String singular, String plural) { return n_fancy2(ms, singular, plural); } static public String n2(IMultiMap mm, String singular) { return n2(mm, singular, singular + "s"); } static public String n2(IMultiMap mm, String singular, String plural) { return n_fancy2(l(mm), singular, plural); } public static String join(String glue, Iterable strings) { if (strings == null) return ""; if (strings instanceof Collection) { if (((Collection) strings).size() == 1) return str(first((Collection) 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(String glue, Object... strings) { return join(glue, Arrays.asList(strings)); } static public String join(Iterable strings) { return join("", strings); } static public String join(Iterable strings, String glue) { return join(glue, strings); } public static String join(String[] strings) { return join("", strings); } static public String join(String glue, Pair p) { return p == null ? "" : str(p.a) + glue + str(p.b); } static public List map(Iterable l, Object f) { return map(f, l); } static public List map(Object f, Iterable l) { List x = emptyList(l); if (l != null) for (Object o : l) { ping(); x.add(callF(f, o)); } return x; } static public List map(Map map, Object f) { List x = new ArrayList(); if (map != null) for (Object _e : map.entrySet()) { ping(); Map.Entry e = (Map.Entry) _e; x.add(callF(f, e.getKey(), e.getValue())); } return x; } static public List map(Object f, Object[] l) { return map(f, asList(l)); } static public List map(Object[] l, Object f) { return map(f, l); } static public List map(Object f, Map map) { return map(map, f); } static public List map(Iterable l, F1 f) { return map(f, l); } static public List map(F1 f, Iterable l) { List x = emptyList(l); if (l != null) for (A o : l) { ping(); x.add(callF(f, o)); } return x; } static public List map(IF1 f, Iterable l) { return map(l, f); } static public List map(Iterable l, IF1 f) { List x = emptyList(l); if (l != null) for (A o : l) { ping(); x.add(f.get(o)); } return x; } static public List map(IF1 f, A[] l) { return map(l, f); } static public List map(A[] l, IF1 f) { List x = emptyList(l); if (l != null) for (A o : l) { ping(); x.add(f.get(o)); } return x; } static public List map(Map map, IF2 f) { List x = new ArrayList(); if (map != null) for (Map.Entry e : map.entrySet()) { ping(); x.add(f.get(e.getKey(), e.getValue())); } return x; } static public List map(IF1 f, A data1, A... moreData) { List x = emptyList(l(moreData) + 1); x.add(f.get(data1)); if (moreData != null) for (A o : moreData) { ping(); x.add(f.get(o)); } return x; } static public boolean emptyString(String s) { return s == null || s.length() == 0; } static public List javaTokWithCurlyBrackets(String s) { return tok_combineCurlyBrackets_keep(javaTok(s)); } static public int countCodeTokens(String s) { return countTokens(s); } static public int countCodeTokens(List tok) { return countTokens(tok); } static public String firstCodeToken(String s) { return firstJavaToken(s); } static public String firstCodeToken(List tok) { return get(tok, 1); } static public boolean tok_isRoundOrCurlyBracketed(String s) { return isCurlyBraced(s) || tok_isRoundBracketed(s); } static public String secondCodeToken(List tok) { return get(tok, 3); } static public String tok_deRoundOrCurlyBracket_keepSpaces(String s) { return isCurlyBraced(s) || tok_isRoundBracketed(s) ? join(dropFirstTwoAndLastTwo(javaTok(s))) : s; } static public Random defaultRandomGenerator() { { Random r = customRandomizerForThisThread(); if (r != null) return r; } return ThreadLocalRandom.current(); } static public Random getRandomizer(Random r) { return r != null ? r : defaultRandomGenerator(); } static public A oneOf(List l) { if (empty(l)) return null; int n = l.size(); return n == 1 ? first(l) : l.get(defaultRandomizer().nextInt(n)); } static public char oneOf(String s) { return empty(s) ? '?' : s.charAt(random(l(s))); } static public A oneOf(A... l) { return oneOf(asList(l)); } static public A collectionGet(Collection c, int idx) { if (c == null || idx < 0 || idx >= l(c)) return null; if (c instanceof List) return listGet((List) c, idx); Iterator it = c.iterator(); for (int i = 0; i < idx; i++) if (it.hasNext()) it.next(); else return null; return it.hasNext() ? it.next() : null; } static public Pair entryToPair(Map.Entry e) { return mapEntryToPair(e); } static public Set> entries(Map map) { return _entrySet(map); } static volatile public boolean ping_pauseAll = false; static public int ping_sleep = 100; static volatile public boolean ping_anyActions = false; static public Map ping_actions = newWeakHashMap(); static public ThreadLocal ping_isCleanUpThread = new ThreadLocal(); static public boolean ping(PingSource pingSource) { return ping(); } static public boolean ping() { newPing(); if (ping_pauseAll || ping_anyActions) ping_impl(true); return true; } static public boolean ping_impl(boolean okInCleanUp) { try { if (ping_pauseAll && !isAWTThread()) { do Thread.sleep(ping_sleep); while (ping_pauseAll); return true; } if (ping_anyActions) { if (!okInCleanUp && !isTrue(ping_isCleanUpThread.get())) failIfUnlicensed(); Object action = null; synchronized (ping_actions) { if (!ping_actions.isEmpty()) { 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; } catch (Exception __e) { throw rethrow(__e); } } static public boolean emptyAfterTrim(String s) { return empty(trim(s)); } static public List subList(List l, int startIndex) { return subList(l, startIndex, l(l)); } static public List subList(int startIndex, List l) { return subList(l, startIndex); } static public List subList(int startIndex, int endIndex, List l) { return subList(l, startIndex, endIndex); } static public List subList(List l, int startIndex, int endIndex) { if (l == null) return null; int n = l(l); startIndex = Math.max(0, startIndex); endIndex = Math.min(n, endIndex); if (startIndex > endIndex) return ll(); if (startIndex == 0 && endIndex == n) return l; return l.subList(startIndex, endIndex); } static public List subList(List l, IntRange r) { return subList(l, r.start, r.end); } static public ThreadLocal saveTiming_last = new ThreadLocal(); static public void saveTiming(long ms) { print(ms + " ms"); saveTiming_noPrint(ms); } static public void saveTiming_noPrint(long ms) { saveTiming_last.set(ms); } static public ThreadLocal saveTiming_tl() { return saveTiming_last; } static public HashMap pairsToMap(Collection> l) { HashMap map = new HashMap(); if (l != null) for (Pair p : l) map.put(p.a, p.b); return map; } static public List> collectTwoFieldsAsPair(final String fieldA, final String fieldB, Iterable l) { return map(l, new F1>() { public Pair get(Object c) { try { return pair(getOpt(c, fieldA), getOpt(c, fieldB)); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "pair(getOpt(c, fieldA), getOpt(c, fieldB))"; } }); } static public List sortByCalculatedField(Iterable c, final Object f) { List l = cloneList(c); sort(l, new Comparator() { public int compare(A a, A b) { return stdcompare(callF(f, a), callF(f, b)); } }); return l; } static public ArrayList cloneList(Iterable l) { return l instanceof Collection ? cloneList((Collection) l) : asList(l); } static public ArrayList cloneList(Collection l) { if (l == null) return new ArrayList(); synchronized (collectionMutex(l)) { return new ArrayList(l); } } static public int stdcompare(Number a, Number b) { return cmp(a, b); } static public int stdcompare(String a, String b) { return cmp(a, b); } static public int stdcompare(long a, long b) { return a < b ? -1 : a > b ? 1 : 0; } static public int stdcompare(Object a, Object b) { return cmp(a, b); } static public boolean cicWithSmartWordBoundary(String a, String b) { return containsRegexpIC(a, phraseToRegExp(b)); } static public boolean match3_startOrEndOfLine(String pat, String s, boolean startOfLine, boolean endOfLine) { if (startOfLine) return endOfLine ? match3(pat, s) : matchStart(pat, s); else return endOfLine ? matchEnd(pat, s) : find3(pat, s); } static public boolean all(Object pred, Iterable l) { if (l != null) for (Object o : l) if (!isTrue(callF(pred, o))) return false; return true; } static public boolean all(Iterable l, IF1 f) { if (l != null) for (A a : l) if (!f.get(a)) return false; return true; } static public boolean all(IF1 f, Iterable l) { return all(l, f); } static public boolean all(int[] l, IIntPred f) { if (l != null) for (int i : l) if (!f.get(i)) return false; return true; } static public boolean any(Object pred, Iterable l) { if (l != null) for (A a : l) if (isTrue(callF(pred, a))) return true; return false; } static public boolean any(IF1 pred, Iterable l) { if (l != null) for (A a : l) if (pred.get(a)) return true; return false; } static public boolean any(Iterable l, IF1 pred) { return any(pred, l); } static public boolean any(A[] l, IF1 pred) { if (l != null) for (A a : l) if (pred.get(a)) return true; return false; } static public boolean any(Iterable l) { if (l != null) for (Boolean a : l) if (isTrue(a)) return true; return false; } static public boolean find3(String pat, String s) { return find3(pat, s, null); } static public boolean find3(String pat, String s, Matches matches) { return find3(pat, parse3_cachedInput(s), matches); } static public boolean find3(String pat, List toks, Matches matches) { List tokpat = parse3_cachedPattern(pat); String[] m = find2(tokpat, toks); if (m == null) return false; if (matches != null) matches.m = m; return true; } static public Integer find3_levenWithSwapsDistance(String pat, String input) { List tokPat = parse3_cachedPattern(pat); List tok = parse3_cachedInput(input); int end = tok.size() - tokPat.size() + 1; Integer min = null; for (int idx = 0; idx < end; idx += 2) { int score = 0; for (int i = 1; i < tokPat.size(); i += 2) { String p = tokPat.get(i), t = tok.get(idx + i); score += levenWithSwapsIC(p, t); } min = min_withNull(min, score); } return min; } static public Integer min_withNull(Integer a, Integer b) { return a == null ? b : b == null ? a : (Integer) min(a, b); } static public List toLinesFullTrim(String s) { List l = new ArrayList(); for (String line : toLines(s)) if (nempty(line = trim(line))) l.add(line); return l; } static public List toLinesFullTrim(File f) { List l = new ArrayList(); for (String line : linesFromFile(f)) if (nempty(line = trim(line))) l.add(line); return l; } static public A unlisted(Class c, Object... args) { concepts_unlisted.set(true); try { return nuObject(c, args); } finally { concepts_unlisted.set(null); } } static public Concept unlisted(String name, Object... args) { Class cc = findClass(name); concepts_unlisted.set(true); try { return cc != null ? nuObject(cc) : new Concept(name); } finally { concepts_unlisted.set(null); } } static public String[] conceptFields_drop = { "className", "fieldValues", "id", "created", "_modified", "refs", "backRefs", "_concepts" }; static public Set conceptFields(Concept c) { return setMinus(mergeSets(allNonStaticNonTransientFields(c), keys(c.fieldValues)), conceptFields_drop); } static public Set conceptFields(Class c) { return setMinus(allNonStaticNonTransientFields(c), conceptFields_drop); } static public Class getClass(String name) { return _getClass(name); } static public Class getClass(Object o) { return _getClass(o); } static public Class getClass(Object realm, String name) { return _getClass(realm, name); } static public Object cget(Object c, String field) { c = derefRef(c); Object o = getOpt(c, field); return derefRef(o); } static public Object cget(String field, Object c) { return cget(c, field); } static public String hrefBlank(String link, Object contents, Object... params) { return empty(link) ? strOrEmpty(contents) : tag("a", contents, concatArrays(new Object[] { "href", link, "target", "_blank" }, params)); } static public String jsQuote(String s) { return javascriptQuote(s); } static public class getOpt_Map extends WeakHashMap { public getOpt_Map() { if (getOpt_special == null) getOpt_special = new HashMap(); clear(); } public void clear() { super.clear(); put(Class.class, getOpt_special); put(String.class, getOpt_special); } } static final public Map> getOpt_cache = _registerDangerousWeakMap(synchroMap(new getOpt_Map())); static public HashMap getOpt_special; static public Map getOpt_getFieldMap(Object o) { Class c = _getClass(o); HashMap map = getOpt_cache.get(c); if (map == null) map = getOpt_makeCache(c); return map; } static public Object getOpt_cached(Object o, String field) { try { if (o == null) return null; Map map = getOpt_getFieldMap(o); if (map == getOpt_special) { if (o instanceof Class) return getOpt((Class) o, field); if (o instanceof Map) return ((Map) o).get(field); } Field f = map.get(field); if (f != null) return f.get(o); if (o instanceof DynamicObject) return syncMapGet2(((DynamicObject) o).fieldValues, field); return null; } catch (Exception __e) { throw rethrow(__e); } } static public HashMap getOpt_makeCache(Class c) { HashMap map; if (isSubtypeOf(c, Map.class)) map = getOpt_special; else { map = new HashMap(); if (!reflection_classesNotToScan().contains(c.getName())) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) { makeAccessible(f); String name = f.getName(); if (!map.containsKey(name)) map.put(name, f); } _c = _c.getSuperclass(); } while (_c != null); } } if (getOpt_cache != null) getOpt_cache.put(c, map); return map; } static public ThreadLocal print_byThread() { synchronized (print_byThread_lock) { if (print_byThread == null) print_byThread = new ThreadLocal(); } return print_byThread; } static public AutoCloseable tempInterceptPrint(F1 f) { return tempSetThreadLocal(print_byThread(), f); } static public boolean tok_isRoundBracketed(String s) { List tok = tok_combineRoundBrackets_keep(javaTok(s)); return l(tok) == 3 && startsWithAndEndsWith(tok.get(1), "(", ")"); } static public List dropFirstThreeAndLastThree(List l) { return dropFirstAndLast(3, l); } static public int javaTok_n, javaTok_elements; static public boolean javaTok_opt = false; static public List javaTok(String s) { ++javaTok_n; ArrayList tok = new ArrayList(); int l = s == null ? 0 : s.length(); int i = 0; while (i < l) { int j = i; char c, d; while (j < l) { c = s.charAt(j); d = j + 1 >= l ? '\0' : s.charAt(j + 1); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (c == '/' && d == '*') { do ++j; while (j < l && !regionMatches(s, j, "*/")); j = Math.min(j + 2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } tok.add(javaTok_substringN(s, i, j)); i = j; if (i >= l) break; c = s.charAt(i); d = i + 1 >= l ? '\0' : s.charAt(i + 1); if (c == '\'' && Character.isJavaIdentifierStart(d) && i + 2 < l && "'\\".indexOf(s.charAt(i + 2)) < 0) { j += 2; while (j < l && Character.isJavaIdentifierPart(s.charAt(j))) ++j; } else if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { int c2 = s.charAt(j); if (c2 == opener || c2 == '\n' && opener == '\'') { ++j; break; } else if (c2 == '\\' && j + 1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || s.charAt(j) == '\'')); else if (Character.isDigit(c)) { do ++j; while (j < l && Character.isDigit(s.charAt(j))); if (j < l && s.charAt(j) == 'L') ++j; } else if (c == '[' && d == '[') { do ++j; while (j < l && !regionMatches(s, j, "]]")); j = Math.min(j + 2, l); } else if (c == '[' && d == '=' && i + 2 < l && s.charAt(i + 2) == '[') { do ++j; while (j + 2 < l && !regionMatches(s, j, "]=]")); j = Math.min(j + 3, l); } else ++j; tok.add(javaTok_substringC(s, i, j)); i = j; } if ((tok.size() % 2) == 0) tok.add(""); javaTok_elements += tok.size(); return tok; } static public List javaTok(List tok) { return javaTokWithExisting(join(tok), tok); } static public List javaTokPlusBrackets(String s) { return tok_combineRoundOrCurlyBrackets_keep(javaTok(s)); } static public String joinSubList(List l, int i, int j) { return join(subList(l, i, j)); } static public String joinSubList(List l, int i) { return join(subList(l, i)); } static public String joinSubList(List l, IntRange r) { return r == null ? null : joinSubList(l, r.start, r.end); } static public int iteratorCount_int_close(Iterator i) { try { int n = 0; if (i != null) while (i.hasNext()) { i.next(); ++n; } if (i instanceof AutoCloseable) ((AutoCloseable) i).close(); return n; } catch (Exception __e) { throw rethrow(__e); } } static public Map> javaTokWithAllBrackets_cached_cache = synchronizedMRUCache(defaultTokenizerCacheSize()); static public List javaTokWithAllBrackets_cached(String s) { List tok = javaTokWithAllBrackets_cached_cache.get(s); if (tok == null) javaTokWithAllBrackets_cached_cache.put(s, tok = javaTokWithAllBrackets(s)); return tok; } static public List splitAtTokens(String s, List tokens) { return splitAtTokens(javaTok(s), tokens); } static public List splitAtTokens(List tok, List tokens) { List l = new ArrayList(); int i = 0; while (i < l(tok)) { int j = indexOfSubList(tok, tokens, i); if (i >= l(tok)) break; if (j < 0) j = l(tok); l.add(trimJoin(tok.subList(i, j))); i = j + l(tokens); } return l; } static public List splitAtTokens(List tok, String... tokens) { List l = new ArrayList(); int i = 0; while (i < l(tok)) { int j = indexOfSubList(tok, tokens, i); if (i >= l(tok)) break; if (j < 0) j = l(tok); l.add(trimJoin(tok.subList(i, j))); i = j + l(tokens); } return l; } static public boolean nemptyString(String s) { return s != null && s.length() > 0; } static public int strL(String s) { return s == null ? 0 : s.length(); } static public int listL(Collection l) { return l == null ? 0 : l.size(); } static public 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 public 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 public ArrayList toList(A[] a) { return asList(a); } static public ArrayList toList(int[] a) { return asList(a); } static public ArrayList toList(Set s) { return asList(s); } static public ArrayList toList(Iterable s) { return asList(s); } static public char lastChar(String s) { return empty(s) ? '\0' : s.charAt(l(s) - 1); } static public A[] arrayOfSameType(A[] a, int n) { return newObjectArrayOfSameType(a, n); } static public Iterator iterator(Iterable c) { return c == null ? emptyIterator() : c.iterator(); } static public char charAt(String s, int i) { return s != null && i >= 0 && i < s.length() ? s.charAt(i) : '\0'; } static public Pair mapEntryToPair(Map.Entry e) { return e == null ? null : pair(e.getKey(), e.getValue()); } static public Set> entrySet(Map map) { return _entrySet(map); } static public A firstThat(Iterable l, IF1 pred) { for (A a : unnullForIteration(l)) if (pred.get(a)) return a; return null; } static public A firstThat(A[] l, IF1 pred) { for (A a : unnullForIteration(l)) if (pred.get(a)) return a; return null; } static public A firstThat(IF1 pred, Iterable l) { return firstThat(l, pred); } static public A firstThat(IF1 pred, A[] l) { return firstThat(l, pred); } static public boolean isNormalQuoted(String s) { int l = l(s); if (!(l >= 2 && s.charAt(0) == '"' && lastChar(s) == '"')) return false; int j = 1; while (j < l) if (s.charAt(j) == '"') return j == l - 1; else if (s.charAt(j) == '\\' && j + 1 < l) j += 2; else ++j; return false; } static public boolean isMultilineQuoted(String s) { if (!startsWith(s, "[")) return false; int i = 1; while (i < s.length() && s.charAt(i) == '=') ++i; return i < s.length() && s.charAt(i) == '['; } static public boolean endsWithLetterOrDigit(String s) { return s != null && s.length() > 0 && Character.isLetterOrDigit(s.charAt(s.length() - 1)); } static public A or(A a, A b) { return a != null ? a : b; } static public Map newDangerousWeakHashMap() { return _registerDangerousWeakMap(synchroMap(new WeakHashMap())); } static public Map newDangerousWeakHashMap(Object initFunction) { return _registerDangerousWeakMap(synchroMap(new WeakHashMap()), initFunction); } static public Object invokeMethod(Method m, Object o, Object... args) { try { try { return m.invoke(o, args); } catch (InvocationTargetException e) { throw rethrow(getExceptionCause(e)); } catch (IllegalArgumentException e) { throw new IllegalArgumentException(e.getMessage() + " - was calling: " + m + ", args: " + joinWithSpace(classNames(args))); } } catch (Exception __e) { throw rethrow(__e); } } static public boolean call_checkArgs(Method m, Object[] args, boolean debug) { Class[] types = m.getParameterTypes(); if (types.length != l(args)) { if (debug) print("Bad parameter length: " + args.length + " vs " + types.length); return false; } for (int i = 0; i < types.length; i++) { Object arg = args[i]; if (!(arg == null ? !types[i].isPrimitive() : isInstanceX(types[i], arg))) { if (debug) print("Bad parameter " + i + ": " + arg + " vs " + types[i]); return false; } } return true; } static public Field makeAccessible(Field f) { try { f.setAccessible(true); } catch (Throwable e) { vmBus_send("makeAccessible_error", e, f); } return f; } static public Method makeAccessible(Method m) { try { m.setAccessible(true); } catch (Throwable e) { vmBus_send("makeAccessible_error", e, m); } return m; } static public Constructor makeAccessible(Constructor c) { try { c.setAccessible(true); } catch (Throwable e) { vmBus_send("makeAccessible_error", e, c); } return c; } static volatile public PersistableThrowable lastException_lastException; static public PersistableThrowable lastException() { return lastException_lastException; } static public void lastException(Throwable e) { lastException_lastException = persistableThrowable(e); } static public String hideCredentials(URL url) { return url == null ? null : hideCredentials(str(url)); } static public String hideCredentials(String url) { try { if (startsWithOneOf(url, "http://", "https://") && isAGIBlueDomain(hostNameFromURL(url))) return url; } catch (Throwable e) { print("HideCredentials", e); } return url.replaceAll("([&?])(_pass|key|cookie)=[^&\\s\"]*", "$1$2="); } static public String hideCredentials(Object o) { return hideCredentials(str(o)); } static public int indexOf(List l, A a, int startIndex) { if (l == null) return -1; int n = l(l); for (int i = startIndex; i < n; i++) if (eq(l.get(i), a)) return i; return -1; } static public int indexOf(List l, int startIndex, A a) { return indexOf(l, a, startIndex); } static public int indexOf(List l, A a) { if (l == null) return -1; return l.indexOf(a); } static public int indexOf(String a, String b) { return a == null || b == null ? -1 : a.indexOf(b); } static public int indexOf(String a, String b, int i) { return a == null || b == null ? -1 : a.indexOf(b, i); } static public int indexOf(String a, char b) { return a == null ? -1 : a.indexOf(b); } static public int indexOf(String a, int i, char b) { return indexOf(a, b, i); } static public int indexOf(String a, char b, int i) { return a == null ? -1 : a.indexOf(b, i); } static public int indexOf(String a, int i, String b) { return a == null || b == null ? -1 : a.indexOf(b, i); } static public int indexOf(A[] x, A a) { int n = l(x); for (int i = 0; i < n; i++) if (eq(x[i], a)) return i; return -1; } static public int indexOf(Iterable l, A a) { if (l == null) return -1; int i = 0; for (A x : l) { if (eq(x, a)) return i; i++; } return -1; } static public void rotateStringBuffer(StringBuffer buf, int max) { try { if (buf == null) return; synchronized (buf) { if (buf.length() <= max) return; 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); } buf.trimToSize(); } } catch (Exception __e) { throw rethrow(__e); } } static public void rotateStringBuilder(StringBuilder buf, int max) { try { if (buf == null) return; synchronized (buf) { if (buf.length() <= max) return; 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); } buf.trimToSize(); } } catch (Exception __e) { throw rethrow(__e); } } static public Object vmBus_wrapArgs(Object... args) { return empty(args) ? null : l(args) == 1 ? args[0] : args; } static public void pcallFAll_minimalExceptionHandling(Collection l, Object... args) { if (l != null) for (Object f : cloneList(l)) { ping(); pcallF_minimalExceptionHandling(f, args); } } static public void pcallFAll_minimalExceptionHandling(Iterator it, Object... args) { while (it.hasNext()) { ping(); pcallF_minimalExceptionHandling(it.next(), args); } } static public Set vm_busListeners_live_cache; static public Set vm_busListeners_live() { if (vm_busListeners_live_cache == null) vm_busListeners_live_cache = vm_busListeners_live_load(); return vm_busListeners_live_cache; } static public Set vm_busListeners_live_load() { return vm_generalIdentityHashSet("busListeners"); } static public Map vm_busListenersByMessage_live_cache; static public Map vm_busListenersByMessage_live() { if (vm_busListenersByMessage_live_cache == null) vm_busListenersByMessage_live_cache = vm_busListenersByMessage_live_load(); return vm_busListenersByMessage_live_cache; } static public Map vm_busListenersByMessage_live_load() { return vm_generalHashMap("busListenersByMessage"); } static public Map newWeakHashMap() { return _registerWeakMap(synchroMap(new WeakHashMap())); } static public ClassLoader classLoaderForObject(Object o) { if (o instanceof ClassLoader) return ((ClassLoader) o); if (o == null) return null; return _getClass(o).getClassLoader(); } static public String classNameToVM(String name) { return name.replace(".", "$"); } static public 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; } volatile static public boolean conceptsAndBot_running = false; static public boolean conceptsAndBot_thinOnStart = true; static public void conceptsAndBot() { conceptsAndBot(null); } static public void conceptsAndBot(Integer autoSaveInterval) { if (conceptsAndBot_running) return; conceptsAndBot_running = true; Concepts cc = db_mainConcepts(); cc.programID = getDBProgramID(); try { if (cc.useFileLock) { if (!cc.fileLock().tryToLock()) { ensureDBNotRunning(dbBotStandardName()); cc.fileLock().forceLock(); } } else ensureDBNotRunning(dbBotStandardName()); } catch (Throwable e) { printStackTrace(e); cc.dontSave = true; throw rethrow(e); } cc.persist(autoSaveInterval); dbBot(false); if (conceptsAndBot_thinOnStart) { try { thinAProgramsBackups(getDBProgramID(), true); } catch (Throwable __e) { printStackTrace(__e); } } } static public boolean isConceptFieldIndexed(Class c, String field) { return isConceptFieldIndexed(db_mainConcepts(), c, field); } static public boolean isConceptFieldIndexed(Concepts concepts, Class c, String field) { return concepts.getFieldIndex(c, field) != null; } static public Concepts newConceptsWithClassFinder(String progID) { Concepts cc = new Concepts(progID); cc.classFinder = _defaultClassFinder(); return cc; } static public Concepts newConceptsWithClassFinder(File conceptsFile) { Concepts cc = new Concepts(assertNotNull(conceptsFile)); cc.classFinder = _defaultClassFinder(); return cc; } static public Concepts newConceptsWithClassFinder(File conceptsFile, IF1 classFinder) { Concepts cc = new Concepts(assertNotNull(conceptsFile)); cc.classFinder = classFinder; return cc; } static public String getDBProgramID_id; static public String getDBProgramID() { return nempty(getDBProgramID_id) ? getDBProgramID_id : programIDWithCase(); } static public boolean odd(int i) { return (i & 1) != 0; } static public boolean odd(long i) { return (i & 1) != 0; } static public boolean odd(BigInteger i) { return odd(toInt(i)); } static public String singleFieldName(Class c) { Set l = listFields(c); if (l(l) != 1) throw fail("No single field found in " + c + " (have " + n(l(l), "fields") + ")"); return first(l); } static public Object deref(Object o) { if (o instanceof IRef) return ((IRef) o).get(); return o; } static public String intern(String s) { return fastIntern(s); } static public String assertIdentifier(String s) { return assertIsIdentifier(s); } static public String assertIdentifier(String msg, String s) { return assertIsIdentifier(msg, s); } static public void dynamicObject_setRawFieldValue(DynamicObject o, Object key, Object value) { if (o == null) return; synchronized (o) { o.fieldValues = syncMapPut2_createLinkedHashMap((LinkedHashMap) o.fieldValues, key, value); } } static public boolean isConceptList(Object o) { if (!(o instanceof List)) return false; List l = (List) o; for (Object x : l) if (!(x instanceof Concept)) return false; return true; } static public void dynamicObject_dropRawField(DynamicObject o, Object key) { if (o == null) return; synchronized (o) { o.fieldValues = (LinkedHashMap) syncMapRemove_deleteMapIfEmpty((Map) o.fieldValues, key); } } static public boolean isPersistable(Object o) { return !isInAnonymousClass(o); } static public boolean isSubtypeOf(Class a, Class b) { return a != null && b != null && b.isAssignableFrom(a); } static public Object derefRef(Object o) { if (o instanceof Concept.Ref) o = ((Concept.Ref) o).get(); return o; } static public A derefRef(Concept.Ref r) { return r == null ? null : r.get(); } static public List lmap(IF1 f, Iterable l) { return lambdaMap(f, l); } static public List lmap(IF1 f, A[] l) { return lambdaMap(f, l); } static public boolean isTransient(Field f) { return (f.getModifiers() & java.lang.reflect.Modifier.TRANSIENT) != 0; } static public List immutableEmptyList() { return Collections.emptyList(); } static public short[] emptyShortArray = new short[0]; static public short[] emptyShortArray() { return emptyShortArray; } static public Map immutableEmptyMap() { return Collections.emptyMap(); } static public Object[] dropEntryFromParams(Object[] params, int i) { int n = l(params); if (i < 0 || i >= n) return params; if (n == 2) return null; Object[] p = new Object[n - 2]; System.arraycopy(params, 0, p, 0, i); System.arraycopy(params, i + 2, p, i, n - i - 2); return p; } static public boolean checkConceptFields(Concept x, Object... data) { for (int i = 0; i < l(data); i += 2) if (neq(cget(x, (String) data[i]), deref(data[i + 1]))) return false; return true; } static public List filterConcepts(List list, Object... params) { if (empty(params)) return list; List l = new ArrayList(); for (A x : list) if (checkConceptFields(x, params)) l.add(x); return l; } static public AutoCloseable tempDBLock(Concepts concepts) { return tempLock(concepts.lock); } static public AutoCloseable tempDBLock() { return tempDBLock(db_mainConcepts()); } static public A findConceptWhere(Class c, Object... params) { return findConceptWhere(db_mainConcepts(), c, params); } static public A findConceptWhere(Concepts concepts, Class c, Object... params) { ping(); params = expandParams(c, params); if (concepts.fieldIndices != null) for (int i = 0; i < l(params); i += 2) { IFieldIndex index = concepts.getFieldIndex(c, (String) params[i]); if (index != null) { for (A x : index.getAll(params[i + 1])) if (checkConceptFields(x, params)) return x; return null; } } for (A x : concepts.list(c)) if (checkConceptFields(x, params)) return x; return null; } static public Concept findConceptWhere(Concepts concepts, String c, Object... params) { for (Concept x : concepts.list(c)) if (checkConceptFields(x, params)) return x; return null; } static public void deleteConcepts(Collection conceptsOrIDs) { db_mainConcepts().deleteConcepts(asList(conceptsOrIDs)); } static public List deleteConcepts(Class c, Object... params) { return deleteConcepts(db_mainConcepts(), c, params); } static public List deleteConcepts(Concepts cc, Class c, Object... params) { List l = asList(findConceptsWhere(cc, c, params)); deleteConcepts(l); return l; } static public List deleteConcepts(Class c, IF1 pred) { return deleteConcepts(db_mainConcepts(), c, pred); } static public List deleteConcepts(Concepts cc, Class c, IF1 pred) { var l = filter(list(cc, c), pred); deleteConcepts(l); return l; } static public List deleteConcepts(Concepts cc) { return deleteConcepts(cc, Concept.class); } static public Object pcallF(Object f, Object... args) { return pcallFunction(f, args); } static public A pcallF(F0 f) { try { return f == null ? null : f.get(); } catch (Throwable __e) { printStackTrace(__e); } return null; } static public B pcallF(F1 f, A a) { try { return f == null ? null : f.get(a); } catch (Throwable __e) { printStackTrace(__e); } return null; } static public void pcallF(VF1 f, A a) { try { { if (f != null) f.get(a); } } catch (Throwable __e) { printStackTrace(__e); } } static public Object pcallF(Runnable r) { try { { if (r != null) r.run(); } } catch (Throwable __e) { printStackTrace(__e); } return null; } static public A pcallF(IF0 f) { try { return f == null ? null : f.get(); } catch (Throwable __e) { printStackTrace(__e); } return null; } static public B pcallF(IF1 f, A a) { try { return f == null ? null : f.get(a); } catch (Throwable __e) { printStackTrace(__e); } return null; } static public boolean regionMatchesIC(String a, int offsetA, String b, int offsetB, int len) { return a != null && a.regionMatches(true, offsetA, b, offsetB, len); } static public int lCharSequence(CharSequence s) { return s == null ? 0 : s.length(); } static public A setThreadLocal(ThreadLocal tl, A value) { if (tl == null) return null; A old = tl.get(); tl.set(value); return old; } static public NanoHTTPD.Response serveByteArray(byte[] data, String mimeType) { try { return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Status.OK, mimeType, new ByteArrayInputStream(data), l(data)); } catch (Exception __e) { throw rethrow(__e); } } static public Object call_withVarargs(Object o, String methodName, Object... args) { try { if (o == null) return null; if (o instanceof Class) { Class c = (Class) o; _MethodCache cache = callOpt_getCache(c); Method me = cache.findStaticMethod(methodName, args); if (me != null) return invokeMethod(me, null, args); List methods = cache.cache.get(methodName); if (methods != null) methodSearch: for (Method m : methods) { { if (!(m.isVarArgs())) continue; } { if (!(isStaticMethod(m))) continue; } Object[] newArgs = massageArgsForVarArgsCall(m, args); if (newArgs != null) return invokeMethod(m, null, newArgs); } throw fail("Method " + c.getName() + "." + methodName + "(" + joinWithComma(classNames(args)) + ") not found"); } else { Class c = o.getClass(); _MethodCache cache = callOpt_getCache(c); Method me = cache.findMethod(methodName, args); if (me != null) return invokeMethod(me, o, args); List methods = cache.cache.get(methodName); if (methods != null) methodSearch: for (Method m : methods) { { if (!(m.isVarArgs())) continue; } Object[] newArgs = massageArgsForVarArgsCall(m, args); if (newArgs != null) return invokeMethod(m, o, newArgs); } throw fail("Method " + c.getName() + "." + methodName + "(" + joinWithComma(classNames(args)) + ") not found"); } } catch (Exception __e) { throw rethrow(__e); } } static public Charset utf8charset_cache; static public Charset utf8charset() { if (utf8charset_cache == null) utf8charset_cache = utf8charset_load(); return utf8charset_cache; } static public Charset utf8charset_load() { return Charset.forName("UTF-8"); } static public int max(int a, int b) { return Math.max(a, b); } static public int max(int a, int b, int c) { return max(max(a, b), c); } static public long max(int a, long b) { return Math.max((long) a, b); } static public long max(long a, long b) { return Math.max(a, b); } static public double max(int a, double b) { return Math.max((double) a, b); } static public float max(float a, float b) { return Math.max(a, b); } static public double max(double a, double b) { return Math.max(a, b); } static public > A max(Iterable l) { A max = null; var it = iterator(l); if (it.hasNext()) { max = it.next(); while (it.hasNext()) { A a = it.next(); if (cmp(a, max) > 0) max = a; } } return max; } static public 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 public float max(float[] c) { if (c.length == 0) return Float.MAX_VALUE; float x = c[0]; for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]); return x; } static public byte max(byte[] c) { byte x = -128; for (byte d : c) if (d > x) x = d; return x; } static public short max(short[] c) { short x = -0x8000; for (short d : c) if (d > x) x = d; return x; } static public int max(int[] c) { int x = Integer.MIN_VALUE; for (int d : c) if (d > x) x = d; return x; } static public > A max(A a, A b) { return cmp(a, b) >= 0 ? a : b; } static public WeakHasherMap symbol_map = new WeakHasherMap(new Hasher() { public int hashCode(Symbol symbol) { return symbol.text.hashCode(); } public boolean equals(Symbol a, Symbol b) { if (a == null) return b == null; return b != null && eq(a.text, b.text); } }); static public Symbol symbol(String s) { if (s == null) return null; synchronized (symbol_map) { Symbol symbol = new Symbol(s, true); Symbol existingSymbol = symbol_map.findKey(symbol); if (existingSymbol == null) symbol_map.put(existingSymbol = symbol, true); return existingSymbol; } } static public Symbol symbol(CharSequence s) { if (s == null) return null; if (s instanceof Symbol) return (Symbol) s; if (s instanceof String) return symbol((String) s); return symbol(str(s)); } static public Symbol symbol(Object o) { return symbol((CharSequence) o); } static public Object callOpt_withVarargs(Object o, String method, Object... args) { try { if (o == null) return null; if (o instanceof Class) { Class c = (Class) o; _MethodCache cache = callOpt_getCache(c); Method me = cache.findMethod(method, args); if (me == null) { return null; } if ((me.getModifiers() & Modifier.STATIC) == 0) return null; return invokeMethod(me, null, args); } else { Class c = o.getClass(); _MethodCache cache = callOpt_getCache(c); Method me = cache.findMethod(method, args); if (me != null) return invokeMethod(me, o, args); List methods = cache.cache.get(method); if (methods != null) methodSearch: for (Method m : methods) { { if (!(m.isVarArgs())) continue; } Object[] newArgs = massageArgsForVarArgsCall(m, args); if (newArgs != null) return invokeMethod(m, o, newArgs); } return null; } } catch (Exception __e) { throw rethrow(__e); } } static public 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 public String formatSnippetIDOpt(String s) { return isSnippetID(s) ? formatSnippetID(s) : s; } static public String formatSnippetID(String id) { return "#" + parseSnippetID(id); } static public String formatSnippetID(long id) { return "#" + id; } static public Class getMainClass() { return mc(); } static public Class getMainClass(Object o) { try { if (o == null) return null; if (o instanceof Class && eq(((Class) o).getName(), "x30")) return (Class) o; ClassLoader cl = (o instanceof Class ? (Class) o : o.getClass()).getClassLoader(); if (cl == null) return null; String name = mainClassNameForClassLoader(cl); return loadClassFromClassLoader_orNull(cl, name); } catch (Exception __e) { throw rethrow(__e); } } static public RuntimeException asRuntimeException(Throwable t) { if (t instanceof Error) _handleError((Error) t); return t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t); } static public String htag(String tag) { return htag(tag, ""); } static public String htag(String tag, Object contents, Object... params) { String openingTag = hopeningTag(tag, params); String s = str(contents); if (empty(s) && neqic(tag, "script")) return dropLast(openingTag) + "/>"; return openingTag + s + ""; } static public Map castMapToMapO(Map map) { return map; } static public int min(int a, int b) { return Math.min(a, b); } static public long min(long a, long b) { return Math.min(a, b); } static public float min(float a, float b) { return Math.min(a, b); } static public float min(float a, float b, float c) { return min(min(a, b), c); } static public double min(double a, double b) { return Math.min(a, b); } static public double min(double[] c) { double x = Double.MAX_VALUE; for (double d : c) x = Math.min(x, d); return x; } static public float min(float[] c) { float x = Float.MAX_VALUE; for (float d : c) x = Math.min(x, d); return x; } static public byte min(byte[] c) { byte x = 127; for (byte d : c) if (d < x) x = d; return x; } static public short min(short[] c) { short x = 0x7FFF; for (short d : c) if (d < x) x = d; return x; } static public int min(int[] c) { int x = Integer.MAX_VALUE; for (int d : c) if (d < x) x = d; return x; } static public List newSubListOrSame(List l, int startIndex) { return newSubListOrSame(l, startIndex, l(l)); } static public List newSubListOrSame(List l, int startIndex, int endIndex) { if (l == null) return null; int n = l(l); startIndex = max(0, startIndex); endIndex = min(n, endIndex); if (startIndex >= endIndex) return ll(); if (startIndex == 0 && endIndex == n) return l; return cloneList(l.subList(startIndex, endIndex)); } static public List newSubListOrSame(List l, IntRange r) { return newSubListOrSame(l, r.start, r.end); } static public CharSequence subCharSequence(CharSequence s, int x) { return subCharSequence(s, x, s == null ? 0 : s.length()); } static public CharSequence subCharSequence(CharSequence 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.subSequence(x, y); } static public int[] takeFirstOfIntArray(int[] b, int n) { return subIntArray(b, 0, n); } static public int[] takeFirstOfIntArray(int n, int[] b) { return takeFirstOfIntArray(b, n); } static public short[] takeFirstOfShortArray(short[] b, int n) { return subShortArray(b, 0, n); } static public short[] takeFirstOfShortArray(int n, short[] b) { return takeFirstOfShortArray(b, n); } static public byte[] takeFirstOfByteArray(byte[] b, int n) { return subByteArray(b, 0, n); } static public byte[] takeFirstOfByteArray(int n, byte[] b) { return takeFirstOfByteArray(b, n); } static public double[] takeFirstOfDoubleArray(double[] b, int n) { return subDoubleArray(b, 0, n); } static public double[] takeFirstOfDoubleArray(int n, double[] b) { return takeFirstOfDoubleArray(b, n); } static public void mapPut(Map map, A key, B value) { if (map != null && key != null && value != null) map.put(key, value); } static public void mapPut(Map map, Pair p) { if (map != null && p != null) map.put(p.a, p.b); } static public String loadTextFile(String fileName) { return loadTextFile(fileName, null); } static public String loadTextFile(File f, String defaultContents) { return loadTextFile(f, defaultContents, "UTF-8"); } static public String loadTextFile(File f, String defaultContents, String encoding) { try { checkFileNotTooBigToRead(f); if (f == null || !f.exists()) return defaultContents; FileInputStream fileInputStream = new FileInputStream(f); InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, encoding); return loadTextFile(inputStreamReader); } catch (Exception __e) { throw rethrow(__e); } } public static String loadTextFile(File fileName) { return loadTextFile(fileName, null); } static public String loadTextFile(String fileName, String defaultContents) { return fileName == null ? defaultContents : loadTextFile(newFile(fileName), defaultContents); } static public 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 str(builder); } static public File javaxDataDir_dir; static public File javaxDataDir() { return javaxDataDir_dir != null ? javaxDataDir_dir : new File(userHome(), "JavaX-Data"); } static public File javaxDataDir(String... subs) { return newFile(javaxDataDir(), subs); } static public boolean isRelativeOrAbsoluteURL(String s) { return isAbsoluteURL(s) || isRelativeURL(s); } static public String hstylesheetsrc(String src) { return tag("link", "", "rel", "stylesheet", "href", src); } static public List dropAllTags(List tok) { List list = new ArrayList(); for (int i = 0; i < l(tok); i++) { String t = tok.get(i); if (odd(i) && t.startsWith("<")) { list.set(list.size() - 1, list.get(list.size() - 1) + tok.get(i + 1)); ++i; } else list.add(t); } return list; } static public String dropAllTags(String html) { if (!contains(html, '<')) return html; return join(dropAllTags(htmlcoarsetok(html))); } static public String hopeningTag(String tag, Map params) { return hopeningTag(tag, mapToParams(params)); } static public String hopeningTag(String tag, Object... params) { StringBuilder buf = new StringBuilder(); buf.append("<" + tag); params = unrollParams(params); for (int i = 0; i < l(params); i += 2) { String name = (String) get(params, i); Object val = get(params, i + 1); if (nempty(name) && val != null) { if (eqOneOf(val, html_valueLessParam(), true)) buf.append(" " + name); else { String s = str(val); if (!empty(s)) buf.append(" " + name + "=" + htmlQuote(s)); } } } buf.append(">"); return str(buf); } static public String intToHex_flexLength(int i) { return Integer.toHexString(i); } static public Boolean isHeadless_cache; static public boolean isHeadless() { if (isHeadless_cache != null) return isHeadless_cache; if (isAndroid()) return isHeadless_cache = true; if (GraphicsEnvironment.isHeadless()) return isHeadless_cache = true; try { SwingUtilities.isEventDispatchThread(); return isHeadless_cache = false; } catch (Throwable e) { return isHeadless_cache = true; } } static public Font typeWriterFont() { return typeWriterFont(iround(14 * getSwingFontScale())); } static public Font typeWriterFont(int size) { return new Font("Courier", Font.PLAIN, size); } static public void consoleFont(Font font) { callOpt(getConsoleTextArea_gen(), "setFont", font); } static public void consoleInputFont(final Font f) { { swing(() -> { JTextField input = consoleInputField(); if (input != null) { input.setFont(f); revalidateFrame(input); } }); } } static public Producer javaTokC_noMLS_iterator(final String s) { return javaTokC_noMLS_iterator(s, 0); } static public Producer javaTokC_noMLS_iterator(final String s, final int startIndex) { return new Producer() { final public int l = s.length(); public int i = startIndex; public String next() { if (i >= l) return null; int j = i; char c, d; while (j < l) { c = s.charAt(j); d = j + 1 >= l ? '\0' : s.charAt(j + 1); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (c == '/' && d == '*') { do ++j; while (j < l && !s.substring(j, Math.min(j + 2, l)).equals("*/")); j = Math.min(j + 2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } i = j; if (i >= l) return null; c = s.charAt(i); d = i + 1 >= l ? '\0' : s.charAt(i + 1); if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { if (s.charAt(j) == opener || s.charAt(j) == '\n') { ++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))); else if (Character.isDigit(c)) { do ++j; while (j < l && Character.isDigit(s.charAt(j))); if (j < l && s.charAt(j) == 'L') ++j; } else ++j; String t = quickSubstring(s, i, j); i = j; return t; } }; } static public Producer javaTokC_noMLS_onReader(final BufferedReader r) { final class X implements Producer { public StringBuilder buf = new StringBuilder(); public char c, d, e = 'x'; public X() { nc(); nc(); nc(); } public void nc() { try { c = d; d = e; if (e == '\0') return; int i = r.read(); e = i < 0 ? '\0' : i == '\0' ? '_' : (char) i; } catch (Exception __e) { throw rethrow(__e); } } public void ncSave() { if (c != '\0') { buf.append(c); nc(); } } public String next() { while (c != '\0') { if (c == ' ' || c == '\t' || c == '\r' || c == '\n') nc(); else if (c == '/' && d == '*') { do nc(); while (c != '\0' && !(c == '*' && d == '/')); nc(); nc(); } else if (c == '/' && d == '/') { do nc(); while (c != '\0' && "\r\n".indexOf(c) < 0); } else break; } if (c == '\0') return null; if (c == '\'' || c == '"') { char opener = c; ncSave(); while (c != '\0') { if (c == opener || c == '\n') { ncSave(); break; } else if (c == '\\') { ncSave(); ncSave(); } else ncSave(); } } else if (Character.isJavaIdentifierStart(c)) do ncSave(); while (Character.isJavaIdentifierPart(c) || c == '\''); else if (Character.isDigit(c)) { do ncSave(); while (Character.isDigit(c)); if (c == 'L') ncSave(); } else ncSave(); String t = buf.toString(); buf.setLength(0); return t; } } return new X(); } static public Object _defaultClassFinder_value = defaultDefaultClassFinder(); static public Object _defaultClassFinder() { return _defaultClassFinder_value; } static public String actualMCDollar() { return actualMC().getName() + "$"; } static public BigInteger parseBigInt(String s) { return new BigInteger(s); } static public float parseFloat(String s) { return Float.parseFloat(s); } static public void assertTrue(Object o) { if (!(eq(o, true))) throw fail(str(o)); } static public boolean assertTrue(String msg, boolean b) { if (!b) throw fail(msg); return b; } static public boolean assertTrue(boolean b) { if (!b) throw fail("oops"); return b; } static public boolean isJavaIdentifier(String s) { if (empty(s) || !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 public HashMap findClass_fullName_cache = new HashMap(); static public Class findClass_fullName(String name) { synchronized (findClass_fullName_cache) { if (findClass_fullName_cache.containsKey(name)) return findClass_fullName_cache.get(name); Class c; try { c = Class.forName(name); } catch (ClassNotFoundException e) { c = null; } findClass_fullName_cache.put(name, c); return c; } } static public String unquoteUsingCharArray(String s, char[] buf) { if (s == null) return null; if (startsWith(s, '[')) { int i = 1; while (i < s.length() && s.charAt(i) == '=') ++i; if (i < s.length() && s.charAt(i) == '[') { String m = s.substring(1, i); if (s.endsWith("]" + m + "]")) return s.substring(i + 1, s.length() - i - 1); } } if (s.length() > 1) { char c = s.charAt(0); if (c == '\"' || c == '\'') { int l = endsWith(s, c) ? s.length() - 1 : s.length(); if (l > buf.length) return unquote(s); int n = 0; for (int i = 1; i < l; i++) { char ch = s.charAt(i); if (ch == '\\') { char nextChar = (i == l - 1) ? '\\' : s.charAt(i + 1); if (nextChar >= '0' && nextChar <= '7') { String code = "" + nextChar; i++; if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') { code += s.charAt(i + 1); i++; if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') { code += s.charAt(i + 1); i++; } } buf[n++] = (char) Integer.parseInt(code, 8); continue; } switch(nextChar) { case '\"': ch = '\"'; break; case '\\': ch = '\\'; break; case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case '\'': ch = '\''; break; case 'u': if (i >= l - 5) { ch = 'u'; break; } int code = Integer.parseInt("" + s.charAt(i + 2) + s.charAt(i + 3) + s.charAt(i + 4) + s.charAt(i + 5), 16); char[] x = Character.toChars(code); int lx = x.length; for (int j = 0; j < lx; j++) buf[n++] = x[j]; i += 5; continue; default: ch = nextChar; } i++; } buf[n++] = ch; } return new String(buf, 0, n); } } return s; } static public boolean structure_isMarker(String s, int i, int j) { if (i >= j) return false; if (s.charAt(i) != 'm') return false; ++i; while (i < j) { char c = s.charAt(i); if (c < '0' || c > '9') return false; ++i; } return true; } static public String internIfLongerThan(String s, int l) { return s == null ? null : l(s) >= l ? intern(s) : s; } static public char unquoteCharacter(String s) { assertTrue(s.startsWith("'") && s.length() > 1); return unquote("\"" + s.substring(1, s.endsWith("'") ? s.length() - 1 : s.length()) + "\"").charAt(0); } static public boolean isLongConstant(String s) { if (!s.endsWith("L")) return false; s = s.substring(0, l(s) - 1); return isInteger(s); } static public boolean isInteger(String s) { int n = l(s); if (n == 0) return false; int i = 0; if (s.charAt(0) == '-') if (++i >= n) return false; while (i < n) { char c = s.charAt(i); if (c < '0' || c > '9') return false; ++i; } return true; } static public boolean warn_on = true; static public ThreadLocal> warn_warnings = new ThreadLocal(); static public void warn(String s) { if (warn_on) print("Warning: " + s); } static public void warn(String s, List warnings) { warn(s); if (warnings != null) warnings.add(s); addToCollection(warn_warnings.get(), s); } static public List parseList(String s) { return (List) safeUnstructure(s); } static public List synchroLinkedList() { return synchroList(new LinkedList()); } static public NavigableMap synchroNavigableMap(NavigableMap map) { return new SynchronizedNavigableMap(map); } static public SortedMap synchroSortedMap(SortedMap map) { return new SynchronizedSortedMap(map); } static public Map synchroMap() { return synchroHashMap(); } static public Map synchroMap(Map map) { return new SynchronizedMap(map); } static public List synchroList() { return synchroList(new ArrayList()); } static public List synchroList(List l) { return new SynchronizedList(l); } static public byte[] hexToBytes(String s) { if (odd(l(s))) throw fail("Hex string has odd length: " + quote(shorten(10, s))); int n = l(s) / 2; byte[] bytes = new byte[n]; for (int i = 0; i < n; i++) { int a = parseHexChar(s.charAt(i * 2)); int b = parseHexChar(s.charAt(i * 2 + 1)); if (a < 0 || b < 0) throw fail("Bad hex byte: " + quote(substring(s, i * 2, i * 2 + 2)) + " at " + i * 2 + "/" + l(s)); bytes[i] = (byte) ((a << 4) | b); } return bytes; } static public boolean[] boolArrayFromBytes(byte[] a, int n) { boolean[] b = new boolean[n]; int m = min(n, l(a) * 8); for (int i = 0; i < m; i++) b[i] = (a[i / 8] & 1 << (i & 7)) != 0; return b; } static public boolean isAbstract(Class c) { return (c.getModifiers() & Modifier.ABSTRACT) != 0; } static public boolean isAbstract(Method m) { return (m.getModifiers() & Modifier.ABSTRACT) != 0; } static public void printVars_str(Object... params) { print(renderVars_str(params)); } static public Constructor nuStubInnerObject_findConstructor(Class c) { return nuStubInnerObject_findConstructor(c, null); } static public Constructor nuStubInnerObject_findConstructor(Class c, Object classFinder) { try { Class outerType = getOuterClass(c, classFinder); Constructor m = c.getDeclaredConstructor(outerType); makeAccessible(m); return m; } catch (Exception __e) { throw rethrow(__e); } } static public Map nuEmptyObject_cache = newDangerousWeakHashMap(); static public A nuEmptyObject(Class c) { try { Constructor ctr; synchronized (nuEmptyObject_cache) { ctr = nuEmptyObject_cache.get(c); if (ctr == null) { nuEmptyObject_cache.put(c, ctr = nuEmptyObject_findConstructor(c)); makeAccessible(ctr); } } try { return (A) ctr.newInstance(); } catch (InstantiationException e) { if (empty(e.getMessage())) if ((c.getModifiers() & Modifier.ABSTRACT) != 0) throw fail("Can't instantiate abstract class " + className(c), e); else throw fail("Can't instantiate " + className(c), e); else throw rethrow(e); } } catch (Exception __e) { throw rethrow(__e); } } static public Constructor nuEmptyObject_findConstructor(Class c) { for (Constructor m : getDeclaredConstructors_cached(c)) if (m.getParameterTypes().length == 0) return m; throw fail("No default constructor declared in " + c.getName()); } static public void setOptAllDyn_pcall(DynamicObject o, Map fields) { if (fields == null || o == null) return; HashMap fieldMap = instanceFieldsMap(o); for (Map.Entry e : fields.entrySet()) { try { String field = e.getKey(); Object val = e.getValue(); Field f = fieldMap.get(field); if (f != null) smartSet(f, o, val); else { dynamicObject_setRawFieldValue(o, intern(field), val); } } catch (Throwable __e) { printStackTrace(__e); } } } static public void setOptAll_pcall(Object o, Map fields) { if (fields == null) return; for (String field : keys(fields)) try { setOpt(o, field, fields.get(field)); } catch (Throwable __e) { print(exceptionToStringShort(__e)); } } static public void setOptAll_pcall(Object o, Object... values) { warnIfOddCount(values); for (int i = 0; i + 1 < l(values); i += 2) { String field = (String) values[i]; Object value = values[i + 1]; try { setOpt(o, field, value); } catch (Throwable __e) { print(exceptionToStringShort(__e)); } } } static public void fixOuterRefs(Object o) { try { if (o == null) return; Field[] l = thisDollarOneFields(o.getClass()); if (l.length <= 1) return; Object father = null; for (Field f : l) { father = f.get(o); if (father != null) break; } if (father == null) return; for (Field f : l) f.set(o, father); } catch (Exception __e) { throw rethrow(__e); } } static public void setDynObjectValue(DynamicObject o, String field, Object value) { dynamicObject_setRawFieldValue(o, field, value); } static public void pcallOpt_noArgs(Object o, String method) { try { callOpt_noArgs(o, method); } catch (Throwable __e) { printStackTrace(__e); } } static public RuntimeException todo() { throw new RuntimeException("TODO"); } static public RuntimeException todo(Object msg) { throw new RuntimeException("TODO: " + msg); } static public Object newMultiDimensionalOuterArray(Class elementType, int dimensions, int length) { int[] dims = new int[dimensions]; dims[0] = length; return Array.newInstance(elementType, dims); } static public int[] toIntArray(Collection l) { int[] a = new int[l(l)]; int i = 0; if (a.length != 0) for (int x : l) a[i++] = x; return a; } static public double[] toDoubleArray(Collection l) { double[] a = new double[l(l)]; int i = 0; if (a.length != 0) for (double x : l) a[i++] = x; return a; } static public String[] toStringArray(Collection c) { String[] a = new String[l(c)]; Iterator it = c.iterator(); for (int i = 0; i < l(a); i++) a[i] = it.next(); return a; } static public String[] toStringArray(Object o) { if (o instanceof String[]) return (String[]) o; else if (o instanceof Collection) return toStringArray((Collection) o); else throw fail("Not a collection or array: " + getClassName(o)); } static public String dropPrefix(String prefix, String s) { return s == null ? null : s.startsWith(prefix) ? s.substring(l(prefix)) : s; } static public TreeSet ciSet() { return caseInsensitiveSet(); } static public boolean jmatch(String pat, String s) { return jmatch(pat, s, null); } static public boolean jmatch(String pat, String s, Matches matches) { if (s == null) return false; return jmatch(pat, javaTok(s), matches); } static public boolean jmatch(String pat, List toks) { return jmatch(pat, toks, null); } static public boolean jmatch(String pat, List toks, Matches matches) { List tokpat = javaTok(pat); String[] m = match2(tokpat, toks); if (m == null) return false; else { if (matches != null) matches.m = m; return true; } } static public A popLast(List l) { return liftLast(l); } static public List popLast(int n, List l) { return liftLast(n, l); } static public ThreadLocal DynamicObject_loading = or((ThreadLocal) get(getClass("x30_pkg.x30_util"), "DynamicObject_loading"), new ThreadLocal()); static public ThreadLocal dynamicObjectIsLoading_threadLocal() { return DynamicObject_loading; } static public boolean fileExists(String path) { return path != null && new File(path).exists(); } static public boolean fileExists(File f) { return f != null && f.exists(); } static public BufferedReader utf8BufferedReader(InputStream in) { return utf8bufferedReader(in); } static public BufferedReader utf8BufferedReader(File f) { return utf8bufferedReader(f); } static public int gzInputStream_defaultBufferSize = 65536; static public GZIPInputStream gzInputStream(File f) { try { return gzInputStream(new FileInputStream(f)); } catch (Exception __e) { throw rethrow(__e); } } static public GZIPInputStream gzInputStream(File f, int bufferSize) { try { return gzInputStream(new FileInputStream(f), bufferSize); } catch (Exception __e) { throw rethrow(__e); } } static public GZIPInputStream gzInputStream(InputStream in) { return gzInputStream(in, gzInputStream_defaultBufferSize); } static public GZIPInputStream gzInputStream(InputStream in, int bufferSize) { try { return _registerIOWrap(new GZIPInputStream(in, gzInputStream_defaultBufferSize), in); } catch (Exception __e) { throw rethrow(__e); } } static public TreeMap caseInsensitiveMap() { return new TreeMap(caseInsensitiveComparator()); } static public Object getOptDynOnly(DynamicObject o, String field) { if (o == null || o.fieldValues == null) return null; return o.fieldValues.get(field); } static public Map classForName_cache = synchroHashMap(); static public Class classForName(String name) { return classForName(name, null); } static public Class classForName(String name, Object classFinder) { if (classForName_cache == null || classFinder != null) return classForName_uncached(name, classFinder); Class c = classForName_cache.get(name); if (c == null) classForName_cache.put(name, c = classForName_uncached(name, null)); return c; } static public Class classForName_uncached(String name, Object classFinder) { try { if (classFinder != null) return (Class) callF(classFinder, name); return Class.forName(name); } catch (Exception __e) { throw rethrow(__e); } } static public Map nuObjectWithoutArguments_cache = newDangerousWeakHashMap(); static public Object nuObjectWithoutArguments(String className) { try { return nuObjectWithoutArguments(classForName(className)); } catch (Exception __e) { throw rethrow(__e); } } static public A nuObjectWithoutArguments(Class c) { try { if (nuObjectWithoutArguments_cache == null) return (A) nuObjectWithoutArguments_findConstructor(c).newInstance(); Constructor m = nuObjectWithoutArguments_cache.get(c); if (m == null) nuObjectWithoutArguments_cache.put(c, m = nuObjectWithoutArguments_findConstructor(c)); return (A) m.newInstance(); } catch (Exception __e) { throw rethrow(__e); } } static public Constructor nuObjectWithoutArguments_findConstructor(Class c) { for (Constructor m : getDeclaredConstructors_cached(c)) if (empty(m.getParameterTypes())) { makeAccessible(m); return m; } throw fail("No default constructor found in " + c.getName()); } static public Map getDeclaredConstructors_cached_cache = newDangerousWeakHashMap(); static public Constructor[] getDeclaredConstructors_cached(Class c) { Constructor[] ctors; synchronized (getDeclaredConstructors_cached_cache) { ctors = getDeclaredConstructors_cached_cache.get(c); if (ctors == null) { getDeclaredConstructors_cached_cache.put(c, ctors = c.getDeclaredConstructors()); for (var ctor : ctors) makeAccessible(ctor); } } return ctors; } static public List getClasses(Object[] array) { List l = emptyList(l(array)); for (Object o : array) l.add(_getClass(o)); return l; } static public 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 public Map putAll(Map a, Map b) { if (a != null && b != null) a.putAll(b); return a; } static public MultiMap putAll(MultiMap a, Map b) { if (a != null) a.putAll((Map) b); return a; } static public Map putAll(Map a, Object... b) { if (a != null) litmap_impl(a, b); return a; } static public void setOpt_raw(Object o, String field, Object value) { try { if (o == null) return; if (o instanceof Class) setOpt_raw((Class) o, field, value); else { Field f = setOpt_raw_findField(o.getClass(), field); if (f != null) { makeAccessible(f); smartSet(f, o, value); } } } catch (Exception __e) { throw rethrow(__e); } } static public void setOpt_raw(Class c, String field, Object value) { try { if (c == null) return; Field f = setOpt_raw_findStaticField(c, field); if (f != null) { makeAccessible(f); smartSet(f, null, value); } } catch (Exception __e) { throw rethrow(__e); } } static public Field setOpt_raw_findStaticField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) return f; _c = _c.getSuperclass(); } while (_c != null); return null; } static public Field setOpt_raw_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 public void smartSet(Field f, Object o, Object value) throws Exception { try { f.set(o, value); } catch (Exception e) { Class type = f.getType(); if (type == int.class && value instanceof Long) { f.set(o, ((Long) value).intValue()); return; } if (type == boolean.class && value instanceof String) { f.set(o, isTrueOrYes(((String) value))); return; } if (type == LinkedHashMap.class && value instanceof Map) { f.set(o, asLinkedHashMap((Map) value)); return; } try { if (f.getType() == Concept.Ref.class) { f.set(o, ((Concept) o).new Ref((Concept) value)); return; } if (o instanceof Concept.Ref) { f.set(o, ((Concept.Ref) o).get()); return; } } catch (Throwable _e) { } throw e; } } static public A setDyn(A o, String key, Object value) { setDynObjectValue(o, key, value); return o; } static public void setDyn(IMeta o, String key, Object value) { metaMapPut(o, key, value); } static public String nlToBr(String s) { return s.replace("\n", "
\n"); } static public CloseableIterableIterator linesFromFile(File f) { return linesFromFile(f, null); } static public CloseableIterableIterator linesFromFile(File f, IResourceHolder resourceHolder) { try { if (!f.exists()) return emptyCloseableIterableIterator(); if (ewic(f.getName(), ".gz")) return linesFromReader(utf8bufferedReader(newGZIPInputStream(f)), resourceHolder); return linesFromReader(utf8bufferedReader(f), resourceHolder); } catch (Exception __e) { throw rethrow(__e); } } static public CloseableIterableIterator linesFromFile(String path) { return linesFromFile(path, null); } static public CloseableIterableIterator linesFromFile(String path, IResourceHolder resourceHolder) { return linesFromFile(newFile(path), resourceHolder); } static public String shortDynamicClassName(Object o) { if (o instanceof DynamicObject && ((DynamicObject) o).className != null) return ((DynamicObject) o).className; return shortClassName(o); } static public Object[] assertEvenLength(Object[] a) { assertTrue(even(l(a))); return a; } static public LinkedHashMap paramsToOrderedMap(Object... params) { return asLinkedHashMap(paramsToMap(params)); } static public Object[] mapToParams(Map map) { return mapToObjectArray(map); } static public int randomID_defaultLength = 12; static public String randomID(int length) { return makeRandomID(length); } static public String randomID(Random r, int length) { return makeRandomID(r, length); } static public String randomID() { return randomID(randomID_defaultLength); } static public String randomID(Random r) { return randomID(r, randomID_defaultLength); } static public String hlabelFor(String id, Object contents) { String s = strOrEmpty(contents); return empty(s) ? "" : htag("label", s, "for", id); } static public
A optPar(ThreadLocal tl, A defaultValue) { A a = tl.get(); if (a != null) { tl.set(null); return a; } return defaultValue; } static public A optPar(ThreadLocal tl) { return optPar(tl, null); } static public Object optPar(Object[] params, String name) { return optParam(params, name); } static public Object optPar(String name, Object[] params) { return optParam(params, name); } static public Object optPar(String name, Map params) { return optParam(name, params); } static public A optPar(Object[] params, String name, A defaultValue) { return optParam(params, name, defaultValue); } static public A optPar(String name, Object[] params, A defaultValue) { return optParam(params, name, defaultValue); } static public String htmlEncode(String s) { return htmlencode(s); } static public boolean boolPar(ThreadLocal tl) { return boolOptParam(tl); } static public boolean boolPar(Object[] __, String name) { return boolOptParam(__, name); } static public boolean boolPar(String name, Object[] __) { return boolOptParam(__, name); } static public boolean boolPar(String name, Map __) { return boolOptParam(name, __); } static public boolean boolPar(String name, Object[] params, boolean defaultValue) { return optParam(params, name, defaultValue); } static public ThreadLocal dataToTable_useStruct = threadLocalWithDefault(true); static public void dataToTable_dynSet(List l, int i, Object s) { while (i >= l.size()) l.add(""); l.set(i, s); } static public List dataToTable_makeRow(Object x, List cols) { if (instanceOf(x, "DynamicObject")) x = get_raw(x, "fieldValues"); if (x instanceof Map) { Map m = (Map) x; List row = new ArrayList(); for (Object _field : keysWithoutHidden(m)) { String field = (String) _field; Object value = m.get(field); int col = cols.indexOf(field); if (col < 0) { cols.add(field); col = cols.size() - 1; } dataToTable_dynSet(row, col, dataToTable_wrapValue(value)); } return row; } if (x instanceof List) return allToString((List) x); return litlist(structureOrText(x)); } static public Object dataToTable_wrapValue(Object o) { if (o instanceof BufferedImage) return o; if (o instanceof MakesBufferedImage) return ((MakesBufferedImage) o).getBufferedImage(); if (o instanceof Boolean) return o; return dataToTable_useStruct.get() ? structureOrTextForUser(o) : strOrNull(o); } static public ArrayList litlist(A... a) { ArrayList l = new ArrayList(a.length); for (A x : a) l.add(x); return l; } static public String structureOrText(Object o) { return o instanceof String ? (String) o : structure(o); } static public String hopeningtag(String tag, Map params) { return hopeningTag(tag, params); } static public String hopeningtag(String tag, Object... params) { return hopeningTag(tag, params); } static public List padList(List l, int w) { return padList(l, w, null); } static public List padList(List l, int w, A a) { if (l(l) >= w) return l; List x = cloneList(l); while (l(x) < w) x.add(a); return x; } static public A getOrKeep(Map map, A a) { if (map == null) return a; A v = map.get(a); return v != null ? v : a; } static public String tr(Object contents) { return tag("tr", contents); } static public String hhead(Object contents) { return tag("head", contents); } static public String htitle(String title) { return hfulltag("title", htmlencode_noQuotes(title)); } static public String htmldecode(final String input) { if (input == null) return null; final int MIN_ESCAPE = 2; final int MAX_ESCAPE = 6; StringWriter writer = null; int len = input.length(); int i = 1; int st = 0; while (true) { while (i < len && input.charAt(i - 1) != '&') i++; if (i >= len) break; int j = i; while (j < len && j < i + MAX_ESCAPE + 1 && input.charAt(j) != ';') j++; if (j == len || j < i + MIN_ESCAPE || j == i + MAX_ESCAPE + 1) { i++; continue; } if (input.charAt(i) == '#') { int k = i + 1; int radix = 10; final char firstChar = input.charAt(k); if (firstChar == 'x' || firstChar == 'X') { k++; radix = 16; } try { int entityValue = Integer.parseInt(input.substring(k, j), radix); if (writer == null) writer = new StringWriter(input.length()); writer.append(input.substring(st, i - 1)); if (entityValue > 0xFFFF) { final char[] chrs = Character.toChars(entityValue); writer.write(chrs[0]); writer.write(chrs[1]); } else { writer.write(entityValue); } } catch (NumberFormatException ex) { i++; continue; } } else { CharSequence value = htmldecode_lookupMap().get(input.substring(i, j)); if (value == null) { i++; continue; } if (writer == null) writer = new StringWriter(input.length()); writer.append(input.substring(st, i - 1)); writer.append(value); } st = j + 1; i = st; } if (writer != null) { writer.append(input.substring(st, len)); return writer.toString(); } return input; } static public HashMap htmldecode_lookupMap_cache; static public HashMap htmldecode_lookupMap() { if (htmldecode_lookupMap_cache == null) htmldecode_lookupMap_cache = htmldecode_lookupMap_load(); return htmldecode_lookupMap_cache; } static public HashMap htmldecode_lookupMap_load() { var map = new HashMap(); for (CharSequence[] seq : htmldecode_escapes()) map.put(seq[1].toString(), seq[0]); return map; } static public String a(String noun) { if (eq(noun, "")) return "?"; return ("aeiou".indexOf(noun.charAt(0)) >= 0 ? "an " : "a ") + noun; } static public String a(String contents, Object... params) { return hfulltag("a", contents, params); } static public Object[] arrayPlus(Object[] a1, Object... a2) { return concatArrays(a1, a2); } static public String joinStrings(String sep, Object... strings) { return joinStrings(sep, Arrays.asList(strings)); } static public String joinStrings(String sep, Iterable strings) { StringBuilder buf = new StringBuilder(); for (Object o : unnull(strings)) { String s = strOrNull(o); if (nempty(s)) { if (nempty(buf)) buf.append(sep); buf.append(s); } } return str(buf); } static public List reverseList(List l) { Collections.reverse(l); return l; } static public Comparator descFieldComparator(final String field) { return new Comparator() { public int compare(A a, A b) { return cmp(getOpt(b, field), getOpt(a, field)); } }; } static public String formatWithThousands(long l) { return formatWithThousandsSeparator(l); } static public double fraction(double d) { return d % 1; } static public String n_fancy2(long l, String singular, String plural) { return formatWithThousandsSeparator(l) + " " + trim(l == 1 ? singular : plural); } static public String n_fancy2(Collection l, String singular, String plural) { return n_fancy2(l(l), singular, plural); } static public String n_fancy2(Map m, String singular, String plural) { return n_fancy2(l(m), singular, plural); } static public String n_fancy2(Object[] a, String singular, String plural) { return n_fancy2(l(a), singular, plural); } static public String n_fancy2(MultiSet ms, String singular, String plural) { return n_fancy2(l(ms), singular, plural); } static public List tok_combineCurlyBrackets_keep(List tok) { List l = new ArrayList(); for (int i = 0; i < l(tok); i++) { String t = tok.get(i); if (odd(i) && eq(t, "{")) { int j = findEndOfCurlyBracketPart(tok, i); l.add(joinSubList(tok, i, j)); i = j - 1; } else l.add(t); } return l; } static public int countTokens(String s) { return l(javaTokC(s)); } static public int countTokens(List tok) { return l(tok) / 2; } static public int countTokens(IntRange r) { return r == null ? 0 : cncCorrect(r).length() / 2; } static public String firstJavaToken(String s) { if (s == null) return null; int l = s.length(); int j = 0; char c, d; while (j < l) { c = s.charAt(j); d = j + 1 >= l ? '\0' : s.charAt(j + 1); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (c == '/' && d == '*') { do ++j; while (j < l && !s.substring(j, Math.min(j + 2, l)).equals("*/")); j = Math.min(j + 2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } if (j >= l) return null; int i = j; c = s.charAt(i); d = i + 1 >= l ? '\0' : s.charAt(i + 1); if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { if (s.charAt(j) == opener || s.charAt(j) == '\n') { ++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)); else if (Character.isDigit(c)) { do ++j; while (j < l && Character.isDigit(s.charAt(j))); if (j < l && s.charAt(j) == 'L') ++j; } else if (c == '[' && d == '[') { do ++j; while (j + 1 < l && !s.substring(j, j + 2).equals("]]")); j = Math.min(j + 2, l); } else if (c == '[' && d == '=' && 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; return quickSubstring(s, i, j); } static public boolean isCurlyBraced(String s) { List tok = tok_combineCurlyBrackets_keep(javaTok(s)); return l(tok) == 3 && startsWithAndEndsWith(tok.get(1), "{", "}"); } static public List dropFirstTwoAndLastTwo(List l) { return dropFirstAndLast(2, l); } static public Random customRandomizerForThisThread() { return customRandomizerForThisThread_tl().get(); } static public Random defaultRandomizer() { return defaultRandomGenerator(); } static public A listGet(List l, int idx) { return l != null && idx >= 0 && idx < l(l) ? l.get(idx) : null; } static public void newPing() { var tl = newPing_actionTL(); Runnable action = tl == null ? null : tl.get(); { if (action != null) action.run(); } } static public boolean isAWTThread() { if (isAndroid()) return false; if (isHeadless()) return false; return isAWTThread_awt(); } static public boolean isAWTThread_awt() { return SwingUtilities.isEventDispatchThread(); } static public void failIfUnlicensed() { assertTrue("license off", licensed()); } static public Thread currentThread() { return Thread.currentThread(); } static public Object collectionMutex(List l) { return l; } static public Object collectionMutex(Object o) { if (o instanceof List) return o; String c = className(o); return o; } static public boolean containsRegexpIC(String s, String pat) { return compileRegexpIC(pat).matcher(s).find(); } static public String phraseToRegExp(String b) { return (startsWithLetterOrDigit(b) ? "\\b" : "") + regexpQuote(b) + (endsWithLetterOrDigit(b) ? "\\b" : ""); } static public boolean match3(String pat, String s) { return match3(pat, s, null); } static public boolean match3(String pat, String s, Matches matches) { if (pat == null || s == null) return false; return match3(pat, parse3_cachedInput(s), matches); } static public boolean match3(String pat, List toks, Matches matches) { List tokpat = parse3_cachedPattern(pat); return match3(tokpat, toks, matches); } static public boolean match3(List tokpat, List toks, Matches matches) { String[] m = match2(tokpat, toks); if (m == null) return false; if (matches != null) matches.m = m; return true; } static public boolean matchStart(String pat, String s) { return matchStart(pat, s, null); } static public boolean matchStart(String pat, String s, Matches matches) { if (s == null) return false; return matchStart(pat, parse3_cachedInput(s), matches); } static public boolean matchStart(String pat, List toks, Matches matches) { if (toks == null) return false; List tokpat = parse3_cachedPattern(pat); if (toks.size() < tokpat.size()) return false; String[] m = match2(tokpat, toks.subList(0, tokpat.size())); if (m == null) return false; if (matches != null) { matches.m = new String[m.length + 1]; arraycopy(m, matches.m); matches.m[m.length] = joinSubList(toks, tokpat.size(), toks.size()); } return true; } static public boolean matchEnd(String pat, String s) { return matchEnd(pat, s, null); } static public boolean matchEnd(String pat, String s, Matches matches) { if (s == null) return false; List tokpat = parse3(pat), toks = parse3(s); if (toks.size() < tokpat.size()) return false; String[] m = match2(tokpat, takeLast(l(tokpat), toks)); if (m == null) return false; if (matches != null) { matches.m = new String[m.length + 1]; arraycopy(m, matches.m); matches.m[m.length] = join(dropLast(l(tokpat), toks)); } return true; } static public Map> parse3_cachedInput_cache = synchronizedMRUCache(1000); static public List parse3_cachedInput(String s) { List tok = parse3_cachedInput_cache.get(s); if (tok == null) parse3_cachedInput_cache.put(s, tok = parse3(s)); return tok; } static public Map> parse3_cachedPattern_cache = synchronizedMRUCache(1000); static synchronized public List parse3_cachedPattern(String s) { List tok = parse3_cachedPattern_cache.get(s); if (tok == null) parse3_cachedPattern_cache.put(s, tok = parse3(s)); return tok; } static public String[] find2(List pat, List tok) { for (int idx = 0; idx < tok.size(); idx += 2) { String[] result = find2(pat, tok, idx); if (result != null) return result; } return null; } static public String[] find2(List pat, List tok, int idx) { if (idx + pat.size() > tok.size()) return null; List result = new ArrayList(); for (int i = 1; i < pat.size(); i += 2) { String p = pat.get(i), t = tok.get(idx + i); if (eq(p, "*")) result.add(t); else if (!p.equalsIgnoreCase(t)) return null; } return toStringArray(result); } static public int levenWithSwapsIC(String s, String t) { if (s.equals(t)) return 0; int ls = s.length(), lt = t.length(); if (ls == 0) return lt; if (lt == 0) return ls; int[] vx = new int[lt + 1]; int[] v0 = new int[lt + 1]; int[] v1 = new int[lt + 1]; for (int i = 0; i < v0.length; i++) v0[i] = i; for (int i = 0; i < ls; i++) { v1[0] = i + 1; for (int j = 0; j < lt; j++) { int cost = equalsIgnoreCase(s.charAt(i), t.charAt(j)) ? 0 : 1; int d = min3(v1[j] + 1, v0[j + 1] + 1, v0[j] + cost); if (i > 0 && j > 0 && equalsIgnoreCase(s.charAt(i), t.charAt(j - 1)) && equalsIgnoreCase(s.charAt(i - 1), t.charAt(j))) d = min(d, vx[j - 1] + 1); v1[j + 1] = d; } int[] v = vx; vx = v0; v0 = v1; v1 = v; } return v0[lt]; } static public Set setMinus(Set set, Object... stuff) { Set s2 = cloneSet(set); for (Object o : stuff) s2.remove(o); return s2; } static public Set mergeSets(Collection... l) { return joinSets(l); } static public Set allNonStaticNonTransientFields(Object o) { TreeSet fields = new TreeSet(); Class _c = _getClass(o); do { for (Field f : _c.getDeclaredFields()) if ((f.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) == 0) fields.add(f.getName()); _c = _c.getSuperclass(); } while (_c != null); return fields; } static public String javascriptQuote(String s) { return quote(s); } static public void clear(Collection c) { if (c != null) c.clear(); } static public void clear(Map map) { if (map != null) map.clear(); } static public void put(Map map, A a, B b) { if (map != null) map.put(a, b); } static public void put(List l, int i, A a) { if (l != null && i >= 0 && i < l(l)) l.set(i, a); } static public List _registerDangerousWeakMap_preList; static public A _registerDangerousWeakMap(A map) { return _registerDangerousWeakMap(map, null); } static public A _registerDangerousWeakMap(A map, Object init) { callF(init, map); if (init instanceof String) { final String f = (String) init; init = new VF1() { public void get(Map map) { try { callMC(f, map); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "callMC(f, map)"; } }; } if (javax() == null) { if (_registerDangerousWeakMap_preList == null) _registerDangerousWeakMap_preList = synchroList(); _registerDangerousWeakMap_preList.add(pair(map, init)); return map; } call(javax(), "_registerDangerousWeakMap", map, init); return map; } static public void _onLoad_registerDangerousWeakMap() { assertNotNull(javax()); if (_registerDangerousWeakMap_preList == null) return; for (Pair p : _registerDangerousWeakMap_preList) _registerDangerousWeakMap(p.a, p.b); _registerDangerousWeakMap_preList = null; } static public B syncMapGet2(Map map, A a) { if (map == null) return null; synchronized (collectionMutex(map)) { return map.get(a); } } static public B syncMapGet2(A a, Map map) { return syncMapGet2(map, a); } static public Set reflection_classesNotToScan_value = litset("jdk.internal.loader.URLClassPath"); static public Set reflection_classesNotToScan() { return reflection_classesNotToScan_value; } static public List tok_combineRoundBrackets_keep(List tok) { List l = new ArrayList(); for (int i = 0; i < l(tok); i++) { String t = tok.get(i); if (odd(i) && eq(t, "(")) { int j = findEndOfBracketPart(tok, i); l.add(joinSubList(tok, i, j)); i = j - 1; } else l.add(t); } return l; } static public boolean startsWithAndEndsWith(String s, String prefix, String suffix) { return startsWith(s, prefix) && endsWith(s, suffix); } static public List dropFirstAndLast(int n, List l) { return cloneSubList(l, n, l(l) - n); } static public List dropFirstAndLast(int m, int n, List l) { return cloneSubList(l, m, l(l) - n); } static public List dropFirstAndLast(List l) { return dropFirstAndLast(1, l); } static public String dropFirstAndLast(String s) { return substring(s, 1, l(s) - 1); } static public boolean regionMatches(String a, int offsetA, String b, int offsetB, int len) { return a != null && b != null && a.regionMatches(offsetA, b, offsetB, len); } static public boolean regionMatches(String a, int offsetA, String b) { return regionMatches(a, offsetA, b, 0, l(b)); } static public String javaTok_substringN(String s, int i, int j) { if (i == j) return ""; if (j == i + 1 && s.charAt(i) == ' ') return " "; return s.substring(i, j); } static public String javaTok_substringC(String s, int i, int j) { return s.substring(i, j); } static public List javaTokWithExisting(String s, List existing) { ++javaTok_n; int nExisting = javaTok_opt && existing != null ? existing.size() : 0; ArrayList 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, d; while (j < l) { c = s.charAt(j); d = j + 1 >= l ? '\0' : s.charAt(j + 1); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (c == '/' && d == '*') { do ++j; while (j < l && !s.substring(j, Math.min(j + 2, l)).equals("*/")); j = Math.min(j + 2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } if (n < nExisting && javaTokWithExisting_isCopyable(existing.get(n), s, i, j)) tok.add(existing.get(n)); else tok.add(javaTok_substringN(s, i, j)); ++n; i = j; if (i >= l) break; c = s.charAt(i); d = i + 1 >= l ? '\0' : s.charAt(i + 1); if (c == '\'' && Character.isJavaIdentifierStart(d) && i + 2 < l && "'\\".indexOf(s.charAt(i + 2)) < 0) { j += 2; while (j < l && Character.isJavaIdentifierPart(s.charAt(j))) ++j; } else if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { if (s.charAt(j) == opener) { ++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)); else if (Character.isDigit(c)) { do ++j; while (j < l && Character.isDigit(s.charAt(j))); if (j < l && s.charAt(j) == 'L') ++j; } else if (c == '[' && d == '[') { do ++j; while (j + 1 < l && !s.substring(j, j + 2).equals("]]")); j = Math.min(j + 2, l); } else if (c == '[' && d == '=' && 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 && javaTokWithExisting_isCopyable(existing.get(n), s, i, j)) tok.add(existing.get(n)); else tok.add(javaTok_substringC(s, i, j)); ++n; i = j; } if ((tok.size() % 2) == 0) tok.add(""); javaTok_elements += tok.size(); return tok; } static public boolean javaTokWithExisting_isCopyable(String t, String s, int i, int j) { return t.length() == j - i && s.regionMatches(i, t, 0, j - i); } static public List tok_combineRoundOrCurlyBrackets_keep(List tok) { List l = new ArrayList(); for (int i = 0; i < l(tok); i++) { String t = tok.get(i); if (odd(i) && eqOneOf(t, "{", "(")) { int j = findEndOfBracketPart(tok, i); l.add(joinSubList(tok, i, j)); i = j - 1; } else l.add(t); } return l; } static public Map synchronizedMRUCache(int maxSize) { return synchroMap(new MRUCache(maxSize)); } static public int defaultTokenizerCacheSize() { return 1000; } static public List javaTokWithAllBrackets(String s) { return javaTokPlusBrackets2(s); } static public int indexOfSubList(List x, List y) { return indexOfSubList(x, y, 0); } static public 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 public int indexOfSubList(List x, A[] 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[j])) continue outer; return i; } return -1; } static public String trimJoin(List s) { return trim(join(s)); } static public A[] newObjectArrayOfSameType(A[] a) { return newObjectArrayOfSameType(a, a.length); } static public A[] newObjectArrayOfSameType(A[] a, int n) { return (A[]) Array.newInstance(a.getClass().getComponentType(), n); } static public Iterator emptyIterator() { return Collections.emptyIterator(); } static public Throwable getExceptionCause(Throwable e) { Throwable c = e.getCause(); return c != null ? c : e; } static public String joinWithSpace(Iterable c) { return join(" ", c); } static public String joinWithSpace(String... c) { return join(" ", c); } static public List classNames(Collection l) { return getClassNames(l); } static public List classNames(Object[] l) { return getClassNames(asList(l)); } static public PersistableThrowable persistableThrowable(Throwable e) { return e == null ? null : new PersistableThrowable(e); } static public boolean startsWithOneOf(String s, String... l) { for (String x : l) if (startsWith(s, x)) return true; return false; } static public boolean startsWithOneOf(String s, Matches m, String... l) { for (String x : l) if (startsWith(s, x, m)) return true; return false; } static public boolean isAGIBlueDomain(String domain) { return domainIsUnder(domain, theAGIBlueDomain()); } static public String hostNameFromURL(String url) { try { return empty(url) ? null : new URL(url).getHost(); } catch (Exception __e) { throw rethrow(__e); } } static public Object pcallF_minimalExceptionHandling(Object f, Object... args) { try { return callFunction(f, args); } catch (Throwable e) { System.out.println(getStackTrace(e)); _storeException(e); } return null; } static public Set vm_generalIdentityHashSet(Object name) { synchronized (vm_generalMap()) { Set set = (Set) (vm_generalMap_get(name)); if (set == null) vm_generalMap_put(name, set = syncIdentityHashSet()); return set; } } static public Map vm_generalHashMap(Object name) { synchronized (vm_generalMap()) { Map m = (Map) (vm_generalMap_get(name)); if (m == null) vm_generalMap_put(name, m = syncHashMap()); return m; } } static public List _registerWeakMap_preList; static public A _registerWeakMap(A map) { if (javax() == null) { if (_registerWeakMap_preList == null) _registerWeakMap_preList = synchroList(); _registerWeakMap_preList.add(map); return map; } try { call(javax(), "_registerWeakMap", map); } catch (Throwable e) { printException(e); print("Upgrade JavaX!!"); } return map; } static public void _onLoad_registerWeakMap() { assertNotNull(javax()); if (_registerWeakMap_preList == null) return; for (Object o : _registerWeakMap_preList) _registerWeakMap(o); _registerWeakMap_preList = null; } static public void ensureDBNotRunning(String name) { if (hasBot(name)) { try { String framesBot = dropSuffix(".", name) + " Frames"; print("Trying to activate frames of running DB: " + framesBot); if (isOK(sendOpt(framesBot, "activate frames")) && isMainProgram()) cleanKill(); } catch (Throwable __e) { printStackTrace(__e); } throw fail("Already running: " + name); } } static public void ensureDBNotRunning() { ensureDBNotRunning(dbBotStandardName()); } static public String dbBotStandardName() { String home = userHome(); String name = dbBotName(getDBProgramID()); if (neq(home, actualUserHome())) name += " " + quote(home); return name + "."; } static volatile public Android3 dbBot_instance; static public Android3 dbBot() { return dbBot(true); } static public Android3 dbBot(boolean ensureNotRunning) { return dbBot(dbBotStandardName(), ensureNotRunning); } static public Android3 dbBot(String name) { return dbBot(name, true); } static public Android3 dbBot(String name, boolean ensureNotRunning) { if (ensureNotRunning) ensureDBNotRunning(name); return dbBot_instance = methodsBot2(name, assertNotNull(db_mainConcepts()), db_standardExposedMethods(), db_mainConcepts().lock); } static public void thinAProgramsBackups(String progID, boolean doIt) { File dir = programDir(progID); thinAProgramsBackups(dir, doIt); } static public void thinAProgramsBackups(File dir, boolean doIt) { List files = new ArrayList(); Map ageMap = new HashMap(); java.util.regex.Pattern pat = regexp("^(.*)\\.backup(20\\d\\d)(\\d\\d)(\\d\\d)-(\\d\\d)(\\d*)$"); print("Processing backups in " + dir); for (File f : listFilesNotDirs(dir, newFile(dir, "backups"))) { String s = f.getName(); java.util.regex.Matcher matcher = pat.matcher(s); { if (!(matcher.find())) continue; } String originalName = matcher.group(1); { if (!(eq(originalName, "concepts.structure.gz"))) continue; } int year = matcherInt(matcher, 2); int month = matcherInt(matcher, 3); int day = matcherInt(matcher, 4); int hour = matcherInt(matcher, 5); int minute = matcherInt(matcher, 6); long time = timestampFromYMDHM(year, month, day, hour, minute); double age = ((now() - time) / 1000.0 / 60 / 60 / 24); ageMap.put(f, age); files.add(f); } int numDeleted = 0; sortByMap_inPlace(files, ageMap); double lastAge = -1; for (File f : files) { double age = ageMap.get(f); if (!thinAProgramsBackups_shouldKeep(age, lastAge)) { ++numDeleted; if (doIt) { print("Deleting: " + f); f.delete(); } } else { lastAge = age; } } if (numDeleted != 0) print((doIt ? "Deleted: " : "Would delete: ") + n(numDeleted, "file")); } static public boolean thinAProgramsBackups_shouldKeep(double age, double lastAge) { return defaultAgeBasedBackupRetentionStrategy_shouldKeep(age, lastAge); } static public A assertNotNull(A a) { assertTrue(a != null); return a; } static public A assertNotNull(String msg, A a) { assertTrue(msg, a != null); return a; } static public A assertNotNull(Scorer scorer, String msg, A a) { if (scorer == null) return assertNotNull(msg, a); if (a == null) { print("BAD - " + msg + " is null: " + a); scorer.add(false); } else { print("OK, " + msg + " not null: " + a); scorer.add(true); } return a; } static public String programIDWithCase() { return nempty(caseID()) ? programID() + "/" + quoteUnlessIdentifierOrInteger(caseID()) : programID(); } static public int toInt(Object o) { if (o == null) return 0; if (o instanceof Number) return ((Number) o).intValue(); if (o instanceof String) return parseInt((String) o); if (o instanceof Boolean) return boolToInt((Boolean) o); throw fail("woot not int: " + getClassName(o)); } static public int toInt(long l) { if (l != (int) l) throw fail("Too large for int: " + l); return (int) l; } static public Set listFields(Object c) { TreeSet fields = new TreeSet(); for (Field f : _getClass(c).getDeclaredFields()) fields.add(f.getName()); return fields; } static public String n(long l, String name) { return l + " " + trim(l == 1 ? singular(name) : getPlural(name)); } static public String n(Collection l, String name) { return n(l(l), name); } static public String n(Map m, String name) { return n(l(m), name); } static public String n(Object[] a, String name) { return n(l(a), name); } static public String n(MultiSet ms, String name) { return n(l(ms), name); } static public Method fastIntern_method; static public String fastIntern(String s) { try { if (s == null) return null; if (fastIntern_method == null) { fastIntern_method = findMethodNamed(javax(), "internPerProgram"); if (fastIntern_method == null) upgradeJavaXAndRestart(); } return (String) fastIntern_method.invoke(null, s); } catch (Exception __e) { throw rethrow(__e); } } static public String assertIsIdentifier(String s) { if (!isIdentifier(s)) throw fail("Not an identifier: " + quote(s)); return s; } static public String assertIsIdentifier(String msg, String s) { if (!isIdentifier(s)) throw fail(msg + " - Not an identifier: " + quote(s)); return s; } static public LinkedHashMap syncMapPut2_createLinkedHashMap(LinkedHashMap map, A key, B value) { if (key != null) if (value != null) { if (map == null) map = new LinkedHashMap(); synchronized (collectionMutex(map)) { map.put(key, value); } } else if (map != null) synchronized (collectionMutex(map)) { map.remove(key); } return map; } static public > C syncMapRemove_deleteMapIfEmpty(C map, A key) { if (map != null && key != null) synchronized (collectionMutex(map)) { map.remove(key); if (map.isEmpty()) return null; } return map; } static public boolean isInAnonymousClass(Object o) { if (o == null) return false; return isAnonymousClassName(className(o)); } static public AutoCloseable tempLock(Lock lock) { return tempLock("", lock); } static public AutoCloseable tempLock(String purpose, Lock lock) { if (lock == null) return null; lock(lock); return new AutoCloseable() { public String toString() { return "unlock(lock);"; } public void close() throws Exception { unlock(lock); } }; } static public Object pcallFunction(Object f, Object... args) { try { return callFunction(f, args); } catch (Throwable __e) { printStackTrace(__e); } return null; } static final public Map callOpt_cache = newDangerousWeakHashMap(); static public Object callOpt_cached(Object o, String methodName, Object... args) { try { if (o == null) return null; if (o instanceof Class) { Class c = (Class) o; _MethodCache cache = callOpt_getCache(c); Method me = cache.findMethod(methodName, args); if (me == null || (me.getModifiers() & Modifier.STATIC) == 0) return null; return invokeMethod(me, null, args); } else { Class c = o.getClass(); _MethodCache cache = callOpt_getCache(c); Method me = cache.findMethod(methodName, args); if (me == null) return null; return invokeMethod(me, o, args); } } catch (Exception __e) { throw rethrow(__e); } } static public _MethodCache callOpt_getCache(Class c) { _MethodCache cache = callOpt_cache.get(c); if (cache == null) callOpt_cache.put(c, cache = new _MethodCache(c)); return cache; } static public boolean isStaticMethod(Method m) { return methodIsStatic(m); } static public Object[] massageArgsForVarArgsCall(Executable m, Object[] args) { Class[] types = m.getParameterTypes(); int n = types.length - 1, nArgs = l(args); if (nArgs < n) return null; for (int i = 0; i < n; i++) if (!argumentCompatibleWithType(args[i], types[i])) return null; Class varArgType = types[n].getComponentType(); for (int i = n; i < nArgs; i++) if (!argumentCompatibleWithType(args[i], varArgType)) return null; Object[] newArgs = new Object[n + 1]; arraycopy(args, 0, newArgs, 0, n); int nVarArgs = nArgs - n; Object varArgs = Array.newInstance(varArgType, nVarArgs); for (int i = 0; i < nVarArgs; i++) Array.set(varArgs, i, args[n + i]); newArgs[n] = varArgs; return newArgs; } static public String joinWithComma(Collection c) { return join(", ", c); } static public String joinWithComma(Object... c) { return join(", ", c); } static public String joinWithComma(String... c) { return join(", ", c); } static public String joinWithComma(Pair p) { return p == null ? "" : joinWithComma(str(p.a), str(p.b)); } public static boolean isSnippetID(String s) { try { parseSnippetID(s); return true; } catch (RuntimeException e) { return false; } } static public String mainClassNameForClassLoader(ClassLoader cl) { return or((String) callOpt(cl, "mainClassName"), "main"); } static public Class loadClassFromClassLoader_orNull(ClassLoader cl, String name) { try { return cl == null ? null : cl.loadClass(name); } catch (ClassNotFoundException e) { return null; } } static public int[] subIntArray(int[] b, int start) { return subIntArray(b, start, l(b)); } static public int[] subIntArray(int[] b, int start, int end) { start = max(start, 0); end = min(end, l(b)); if (start == 0 && end == l(b)) return b; if (start >= end) return new int[0]; int[] x = new int[end - start]; System.arraycopy(b, start, x, 0, end - start); return x; } static public int[] subIntArray(int[] a, IntRange r) { return r == null ? null : subIntArray(a, r.start, r.end); } static public short[] subShortArray(short[] b, int start, int end) { start = max(start, 0); end = min(end, l(b)); if (start == 0 && end == l(b)) return b; if (start >= end) return new short[0]; short[] x = new short[end - start]; System.arraycopy(b, start, x, 0, end - start); return x; } static public byte[] subByteArray(byte[] b, int start) { return subByteArray(b, start, l(b)); } static public byte[] subByteArray(byte[] b, int start, int end) { start = max(start, 0); end = min(end, l(b)); if (start == 0 && end == l(b)) return b; if (start >= end) return new byte[0]; byte[] x = new byte[end - start]; System.arraycopy(b, start, x, 0, end - start); return x; } static public byte[] subByteArray(byte[] b, IntRange r) { return r == null ? null : subByteArray(b, r.start, r.end); } static public double[] subDoubleArray(double[] b, int start) { return subDoubleArray(b, start, l(b)); } static public double[] subDoubleArray(double[] b, int start, int end) { start = max(start, 0); end = min(end, l(b)); if (start == 0 && end == l(b)) return b; if (start >= end) return new double[0]; double[] x = new double[end - start]; System.arraycopy(b, start, x, 0, end - start); return x; } static public ThreadLocal> checkFileNotTooBigToRead_tl = new ThreadLocal(); static public void checkFileNotTooBigToRead(File f) { callF(checkFileNotTooBigToRead_tl.get(), f); } static public File newFile(File base, String... names) { for (String name : names) base = new File(base, name); return base; } static public File newFile(String name) { return name == null ? null : new File(name); } static public File newFile(String base, String... names) { return newFile(newFile(base), names); } static public String _userHome; static public String userHome() { if (_userHome == null) return actualUserHome(); return _userHome; } static public File userHome(String path) { return new File(userDir(), path); } static public boolean isAbsoluteURL(String s) { return isURL(s); } static public boolean isRelativeURL(String s) { return startsWithOneOf(s, "/", "./", "../"); } static public boolean contains(Collection c, Object o) { return c != null && c.contains(o); } static public boolean contains(Iterable it, Object a) { if (it != null) for (Object o : it) if (eq(a, o)) return true; return false; } static public boolean contains(Object[] x, Object o) { if (x != null) for (Object a : x) if (eq(a, o)) return true; return false; } static public boolean contains(String s, char c) { return s != null && s.indexOf(c) >= 0; } static public boolean contains(String s, String b) { return s != null && s.indexOf(b) >= 0; } static public boolean contains(BitSet bs, int i) { return bs != null && bs.get(i); } static public boolean contains(Producer p, A a) { if (p != null && a != null) while (true) { A x = p.next(); if (x == null) break; if (eq(x, a)) return true; } return false; } static public boolean contains(Rect r, Pt p) { return rectContains(r, p); } static public List htmlcoarsetok(String s) { List tok = new ArrayList(); int l = s == null ? 0 : s.length(); int i = 0; while (i < l) { int j = i; char c; while (j < l) { if (s.charAt(j) != '<') ++j; else if (s.substring(j, Math.min(j + 4, l)).equals("")); j = Math.min(j + 3, l); } else { char d = charAt(s, j + 1); if (d == '/' || isLetter(d)) break; else ++j; } } tok.add(s.substring(i, j)); i = j; if (i >= l) break; c = s.charAt(i); if (c == '<') { ++j; while (j < l && s.charAt(j) != '>') ++j; if (j < l) ++j; } tok.add(s.substring(i, j)); i = j; } if ((tok.size() & 1) == 0) tok.add(""); return tok; } static public Object[] unrollParams(Object[] params) { if (l(params) == 1 && params[0] instanceof Map) return mapToParams((Map) params[0]); return params; } static public String htmlQuote(String s) { return "\"" + htmlencode_forParams(s) + "\""; } static public int isAndroid_flag; static public boolean isAndroid() { if (isAndroid_flag == 0) isAndroid_flag = System.getProperty("java.vendor").toLowerCase().indexOf("android") >= 0 ? 1 : -1; return isAndroid_flag > 0; } static public int iround(double d) { return (int) Math.round(d); } static public int iround(Number n) { return iround(toDouble(n)); } static public float getSwingFontScale() { return or((Float) vm_generalMap_get("swingFontScale_value"), 1f); } static public Object getConsoleTextArea_gen() { return getOpt(get(getJavaX(), "console"), "textArea"); } static public Object swing(Object f) { return swingAndWait(f); } static public void swing(Runnable f) { swingAndWait(f); } static public A swing(F0 f) { return (A) swingAndWait(f); } static public A swing(IF0 f) { return (A) swingAndWait(f); } static public JTextField consoleInputField() { Object console = get(getJavaX(), "console"); return (JTextField) getOpt(console, "tfInput"); } static public void revalidateFrame(Component c) { revalidate(getFrame(c)); } static public String quickSubstring(String s, int i, int j) { if (i >= j) return ""; return s.substring(i, j); } static public Object defaultDefaultClassFinder() { return new F1() { public Class get(String name) { name = replacePrefix("main$main$", "main$", name); Class c = get2(name); return c; } public Class get2(String name) { if (eq(name, "
")) return mc(); { Class c = findClass_fullName(name); if (c != null) return c; } if (startsWithAny(name, "loadableUtils.utils$", "main$", mcDollar())) for (String pkg : ll("loadableUtils.utils$", mcDollar())) { String newName = pkg + afterDollar(name); { Class c = findClass_fullName(newName); if (c != null) return c; } } return null; } }; } static public Class actualMC() { return or((Class) realMC(), mc()); } static public boolean addToCollection(Collection c, A a) { return c != null && c.add(a); } static public Map synchroHashMap() { return synchronizedMap(new HashMap()); } static public int shorten_default = 100; static public String shorten(CharSequence s) { return shorten(s, shorten_default); } static public String shorten(CharSequence s, int max) { return shorten(s, max, "..."); } static public String shorten(CharSequence s, int max, String shortener) { if (s == null) return ""; if (max < 0) return str(s); return s.length() <= max ? str(s) : subCharSequence(s, 0, min(s.length(), max - l(shortener))) + shortener; } static public String shorten(int max, CharSequence s) { return shorten(s, max); } static public int parseHexChar(char c) { if (c >= '0' && c <= '9') return charDiff(c, '0'); if (c >= 'a' && c <= 'f') return charDiff(c, 'a') + 10; if (c >= 'A' && c <= 'F') return charDiff(c, 'A') + 10; return -1; } static public String renderVars_str(Object... params) { List l = new ArrayList(); int i = 0; if (odd(l(params))) { l.add(strOrNull(first(params))); ++i; } for (; i + 1 < l(params); i += 2) l.add(params[i] + "=" + params[i + 1]); return trim(joinWithComma(l)); } static public Class getOuterClass(Class c) { return getOuterClass(c, null); } static public Class getOuterClass(Class c, Object classFinder) { try { String s = c.getName(); int i = s.lastIndexOf('$'); String name = substring(s, 0, i); return classForName(name, classFinder); } catch (Exception __e) { throw rethrow(__e); } } static public Class getOuterClass(Object o) { return getOuterClass(o, null); } static public Class getOuterClass(Object o, Object classFinder) { return getOuterClass(_getClass(o), classFinder); } static public String className(Object o) { return getClassName(o); } static public HashMap instanceFieldsMap(Object o) { return (HashMap) getOpt_getFieldMap(o); } static public String exceptionToStringShort(Throwable e) { lastException(e); e = getInnerException(e); String msg = hideCredentials(unnull(e.getMessage())); if (msg.indexOf("Error") < 0 && msg.indexOf("Exception") < 0) return baseClassName(e) + prependIfNempty(": ", msg); else return msg; } static public Map thisDollarOneFields_cache = newDangerousWeakHashMap(); static public Field[] thisDollarOneFields(Class c) { synchronized (thisDollarOneFields_cache) { Field[] l = thisDollarOneFields_cache.get(c); if (l == null) thisDollarOneFields_cache.put(c, l = thisDollarOneFields_uncached(c)); return l; } } static public Field[] thisDollarOneFields_uncached(Class c) { List fields = new ArrayList(); do { for (Field f : c.getDeclaredFields()) if (f.getName().startsWith("this$")) fields.add(makeAccessible(f)); c = c.getSuperclass(); } while (c != null); return toArray(new Field[l(fields)], fields); } static public Map> callOpt_noArgs_cache = newDangerousWeakHashMap(); static public Object callOpt_noArgs(Object o, String method) { try { if (o == null) return null; if (o instanceof Class) return callOpt(o, method); Class c = o.getClass(); HashMap map; synchronized (callOpt_noArgs_cache) { map = callOpt_noArgs_cache.get(c); if (map == null) map = callOpt_noArgs_makeCache(c); } Method m = map.get(method); return m != null ? m.invoke(o) : null; } catch (Exception __e) { throw rethrow(__e); } } static public HashMap callOpt_noArgs_makeCache(Class c) { HashMap map = new HashMap(); Class _c = c; do { for (Method m : c.getDeclaredMethods()) if (m.getParameterTypes().length == 0 && !reflection_isForbiddenMethod(m)) { makeAccessible(m); String name = m.getName(); if (!map.containsKey(name)) map.put(name, m); } _c = _c.getSuperclass(); } while (_c != null); callOpt_noArgs_cache.put(c, map); return map; } static public TreeSet caseInsensitiveSet() { return caseInsensitiveSet_treeSet(); } static public TreeSet caseInsensitiveSet(Collection c) { return caseInsensitiveSet_treeSet(c); } static public String[] match2(List pat, List tok) { int i = pat.indexOf("..."); if (i < 0) return match2_match(pat, tok); pat = new ArrayList(pat); pat.set(i, "*"); while (pat.size() < tok.size()) { pat.add(i, "*"); pat.add(i + 1, ""); } return match2_match(pat, tok); } static public String[] match2_match(List pat, List tok) { List result = new ArrayList(); if (pat.size() != tok.size()) { return null; } for (int i = 1; i < pat.size(); i += 2) { String p = pat.get(i), t = tok.get(i); if (eq(p, "*")) result.add(t); else if (!equalsIgnoreCase(unquote(p), unquote(t))) return null; } return result.toArray(new String[result.size()]); } static public A liftLast(List l) { if (empty(l)) return null; int i = l(l) - 1; A a = l.get(i); l.remove(i); return a; } static public List liftLast(int n, List l) { int i = l(l) - n; List part = cloneSubList(l, i); removeSubList(l, i); return part; } static public BufferedReader utf8bufferedReader(InputStream in) { try { return in == null ? null : bufferedReader(_registerIOWrap(new InputStreamReader(in, "UTF-8"), in)); } catch (Exception __e) { throw rethrow(__e); } } static public BufferedReader utf8bufferedReader(File f) { try { return utf8bufferedReader(newFileInputStream(f)); } catch (Exception __e) { throw rethrow(__e); } } static public A _registerIOWrap(A wrapper, Object wrapped) { return wrapper; } static public Comparator caseInsensitiveComparator() { return betterCIComparator(); } static public boolean isTrueOrYes(Object o) { return isTrueOpt(o) || o instanceof String && (eqicOneOf(((String) o), "1", "t", "true") || isYes(((String) o))); } static public LinkedHashMap asLinkedHashMap(Map map) { if (map instanceof LinkedHashMap) return (LinkedHashMap) map; LinkedHashMap m = new LinkedHashMap(); if (map != null) synchronized (collectionMutex(map)) { m.putAll(map); } return m; } static public void metaMapPut(IMeta o, Object key, Object value) { { if (o != null) o.metaPut(key, value); } } static public void metaMapPut(Object o, Object key, Object value) { var meta = initIMeta(o); { if (meta != null) meta.metaPut(key, value); } } static public CloseableIterableIterator emptyCloseableIterableIterator_instance = new CloseableIterableIterator() { public Object next() { throw fail(); } public boolean hasNext() { return false; } }; static public CloseableIterableIterator emptyCloseableIterableIterator() { return emptyCloseableIterableIterator_instance; } static public boolean ewic(String a, String b) { return endsWithIgnoreCase(a, b); } static public boolean ewic(String a, String b, Matches m) { return endsWithIgnoreCase(a, b, m); } static public CloseableIterableIterator linesFromReader(Reader r) { return linesFromReader(r, null); } static public CloseableIterableIterator linesFromReader(Reader r, IResourceHolder resourceHolder) { final BufferedReader br = bufferedReader(r); return holdResource(resourceHolder, iteratorFromFunction_f0_autoCloseable(new F0() { public String get() { try { return readLineFromReaderWithClose(br); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "return readLineFromReaderWithClose(br);"; } }, _wrapIOCloseable(r))); } static public GZIPInputStream newGZIPInputStream(File f) { return gzInputStream(f); } static public GZIPInputStream newGZIPInputStream(InputStream in) { return gzInputStream(in); } static public String shortClassName(Object o) { if (o == null) return null; Class c = o instanceof Class ? (Class) o : o.getClass(); String name = c.getName(); return shortenClassName(name); } static public boolean even(int i) { return (i & 1) == 0; } static public boolean even(long i) { return (i & 1) == 0; } static public boolean even(BigInteger n) { return even(n.intValue()); } static public Object[] mapToObjectArray(Map map) { List l = new ArrayList(); for (Object o : keys(map)) { l.add(o); l.add(map.get(o)); } return toObjectArray(l); } static public Object[] mapToObjectArray(Object f, Collection l) { int n = l(l); Object[] array = new Object[n]; if (n != 0) { Iterator it = iterator(l); for (int i = 0; i < n; i++) array[i] = callF(f, it.next()); } return array; } static public Object[] mapToObjectArray(Object f, Object[] l) { int n = l(l); Object[] array = new Object[n]; for (int i = 0; i < n; i++) array[i] = callF(f, l[i]); return array; } static public Object[] mapToObjectArray(Collection l, IF1 f) { return mapToObjectArray(f, l); } static public Object[] mapToObjectArray(A[] l, IF1 f) { return mapToObjectArray(f, l); } static public Object[] mapToObjectArray(IF1 f, A[] l) { int n = l(l); Object[] array = new Object[n]; for (int i = 0; i < n; i++) array[i] = f.get(l[i]); return array; } static public Object[] mapToObjectArray(IF1 f, Collection l) { int n = l(l); Object[] array = new Object[n]; if (n != 0) { Iterator it = iterator(l); for (int i = 0; i < n; i++) array[i] = callF(f, it.next()); } return array; } static public String makeRandomID(int length) { return makeRandomID(length, defaultRandomGenerator()); } static public String makeRandomID(int length, Random 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 public String makeRandomID(Random r, int length) { return makeRandomID(length, r); } static public A optParam(ThreadLocal tl, A defaultValue) { return optPar(tl, defaultValue); } static public A optParam(ThreadLocal tl) { return optPar(tl); } static public Object optParam(String name, Map params) { return mapGet(params, name); } static public A optParam(Object[] opt, String name, A defaultValue) { int n = l(opt); if (n == 1 && opt[0] instanceof Map) { Map map = (Map) (opt[0]); return map.containsKey(name) ? (A) map.get(name) : defaultValue; } if (!even(l(opt))) throw fail("Odd parameter length"); for (int i = 0; i < l(opt); i += 2) if (eq(opt[i], name)) return (A) opt[i + 1]; return defaultValue; } static public Object optParam(Object[] opt, String name) { return optParam(opt, name, null); } static public Object optParam(String name, Object[] params) { return optParam(params, name); } static public String htmlencode(Object o) { return htmlencode(str(o)); } static public String htmlencode(String s) { if (s == null) return ""; StringBuilder out = new StringBuilder(Math.max(16, s.length())); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c > 127 || c == '"' || c == '<' || c == '>' || c == '&') { int cp = s.codePointAt(i); out.append("&#x"); out.append(intToHex_flexLength(cp)); out.append(';'); i += Character.charCount(cp) - 1; } else out.append(c); } return out.toString(); } static public boolean boolOptParam(ThreadLocal tl) { return isTrue(optPar(tl)); } static public boolean boolOptParam(Object[] __, String name) { return isTrue(optParam(__, name)); } static public boolean boolOptParam(String name, Object[] __) { return boolOptParam(__, name); } static public boolean boolOptParam(String name, Map __) { return isTrue(optPar(name, __)); } static public ThreadLocal threadLocalWithDefault(A defaultValue) { return new ThreadLocal() { public A initialValue() { return defaultValue; } }; } static public boolean instanceOf(Object o, String className) { if (o == null) return false; String c = o.getClass().getName(); return eq(c, className) || eq(c, "main$" + className); } static public boolean instanceOf(Object o, Class c) { if (c == null) return false; return c.isInstance(o); } static public boolean instanceOf(Class c, Object o) { return instanceOf(o, c); } static public List keysWithoutHidden(Map map) { return filter(keys(map), new F1() { public Boolean get(Object o) { try { return !eq(o, "[hidden]") && !isStringStartingWith(o, "[hidden] "); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "!eq(o, \"[hidden]\") && !isStringStartingWith(o, \"[hidden] \")"; } }); } static public List allToString(Iterable c) { List l = new ArrayList(); for (Object o : unnull(c)) l.add(str(o)); return l; } static public List allToString(Object[] c) { List l = new ArrayList(); for (Object o : unnull(c)) l.add(str(o)); return l; } static public String structureOrTextForUser(Object o) { return o == null ? "" : o instanceof String ? (String) o : structureForUser(o); } static public String strOrNull(Object o) { return o == null ? null : str(o); } static public boolean structure_showTiming, structure_checkTokenCount; static public String structure(Object o) { return structure(o, new structure_Data()); } static public String structure(Object o, structure_Data d) { StringWriter sw = new StringWriter(); d.out = new PrintWriter(sw); structure_go(o, d); String s = str(sw); if (structure_checkTokenCount) { print("token count=" + d.n); assertEquals("token count", l(javaTokC(s)), d.n); } return s; } static public void structure_go(Object o, structure_Data d) { structure_1(o, d); while (nempty(d.stack)) popLast(d.stack).run(); } static public void structureToPrintWriter(Object o, PrintWriter out) { structureToPrintWriter(o, out, new structure_Data()); } static public void structureToPrintWriter(Object o, PrintWriter out, structure_Data d) { d.out = out; structure_go(o, d); } static public boolean structure_allowShortening = false; static public class structure_ClassInfo { public Class c; public String shortName; public List fields; public Method customSerializer; public IVF1 serializeObject; public boolean special = false; public boolean nullInstances = false; public boolean javafy = false; public Object emptyInstance; public void nullInstances(boolean b) { this.nullInstances = b; if (b) special = true; } public void javafy(boolean b) { this.javafy = b; if (b) special = true; } } static public class structure_Data { public PrintWriter out; public int stringSizeLimit; public int shareStringsLongerThan = 20; public boolean noStringSharing = false; public boolean storeBaseClasses = false; public boolean honorFieldOrder = true; public String mcDollar = actualMCDollar(); final public structure_Data setWarnIfUnpersistable(boolean warnIfUnpersistable) { return warnIfUnpersistable(warnIfUnpersistable); } public structure_Data warnIfUnpersistable(boolean warnIfUnpersistable) { this.warnIfUnpersistable = warnIfUnpersistable; return this; } final public boolean getWarnIfUnpersistable() { return warnIfUnpersistable(); } public boolean warnIfUnpersistable() { return warnIfUnpersistable; } public boolean warnIfUnpersistable = true; final public structure_Data setStackTraceIfUnpersistable(boolean stackTraceIfUnpersistable) { return stackTraceIfUnpersistable(stackTraceIfUnpersistable); } public structure_Data stackTraceIfUnpersistable(boolean stackTraceIfUnpersistable) { this.stackTraceIfUnpersistable = stackTraceIfUnpersistable; return this; } final public boolean getStackTraceIfUnpersistable() { return stackTraceIfUnpersistable(); } public boolean stackTraceIfUnpersistable() { return stackTraceIfUnpersistable; } public boolean stackTraceIfUnpersistable = true; final public structure_Data setSkipDefaultValues(boolean skipDefaultValues) { return skipDefaultValues(skipDefaultValues); } public structure_Data skipDefaultValues(boolean skipDefaultValues) { this.skipDefaultValues = skipDefaultValues; return this; } final public boolean getSkipDefaultValues() { return skipDefaultValues(); } public boolean skipDefaultValues() { return skipDefaultValues; } public boolean skipDefaultValues = false; transient public IF1 shouldIncludeField; public boolean shouldIncludeField(Field f) { return shouldIncludeField != null ? shouldIncludeField.get(f) : shouldIncludeField_base(f); } final public boolean shouldIncludeField_fallback(IF1 _f, Field f) { return _f != null ? _f.get(f) : shouldIncludeField_base(f); } public boolean shouldIncludeField_base(Field f) { return true; } public IdentityHashMap seen = new IdentityHashMap(); public HashMap strings = new HashMap(); public HashSet concepts = new HashSet(); public HashMap infoByClass = new HashMap(); public HashMap> persistenceInfo = new HashMap(); public int n; public List stack = new ArrayList(); public structure_Data append(String token) { out.print(token); ++n; return this; } public structure_Data append(int i) { out.print(i); ++n; return this; } public structure_Data append(String token, int tokCount) { out.print(token); n += tokCount; return this; } public structure_Data app(String token) { out.print(token); return this; } public structure_Data app(int i) { out.print(i); return this; } public structure_ClassInfo infoForClass(Class c) { structure_ClassInfo info = infoByClass.get(c); if (info == null) info = newClass(c); return info; } public structure_ClassInfo newClass(Class c) { structure_ClassInfo info = new structure_ClassInfo(); info.c = c; infoByClass.put(c, info); String name = c.getName(); String shortName = dropPrefix("main$", dropPrefix("loadableUtils.utils$", dropPrefix(mcDollar, name))); if (startsWithDigit(shortName)) shortName = name; info.shortName = shortName; try { if (isSyntheticOrAnonymous(c)) { info.nullInstances(true); return info; } if (c.isEnum()) { info.special = true; return info; } if (c.isArray()) { return info; } if ((info.customSerializer = findMethodNamed(c, "_serialize")) != null) info.special = true; if (storeBaseClasses) { Class sup = c.getSuperclass(); if (sup != Object.class) { append("bc "); append(shortDynClassNameForStructure(c)); out.print(" "); append(shortDynClassNameForStructure(sup)); out.print(" "); infoForClass(sup); } } if (eqOneOf(name, "java.awt.Color", "java.lang.ThreadLocal")) info.javafy(true); else if (name.startsWith("sun") || !isPersistableClass(c)) { info.javafy(true); if (warnIfUnpersistable) { String msg = "Class not persistable: " + c + " (anonymous or no default constructor), referenced from " + last(stack); if (stackTraceIfUnpersistable) printStackTrace(new Throwable(msg)); else print(msg); } } else if (skipDefaultValues) { var ctor = getDefaultConstructor(c); if (ctor != null) info.emptyInstance = invokeConstructor(ctor); } } catch (Throwable e) { printStackTrace(e); info.nullInstances(true); } return info; } public void setFields(structure_ClassInfo info, List fields) { info.fields = fields; } public void writeObject(Object o, String shortName, Map fv) { String singleField = fv.size() == 1 ? first(fv.keySet()) : null; append(shortName); n += countDots(shortName) * 2; int l = n; Iterator it = fv.entrySet().iterator(); class WritingObject implements Runnable { public String lastFieldWritten; public void run() { try { if (!it.hasNext()) { if (n != l) append(")"); } else { Map.Entry e = (Map.Entry) (it.next()); append(n == l ? "(" : ", "); append(lastFieldWritten = (String) e.getKey()).append("="); stack.add(this); structure_1(e.getValue(), structure_Data.this); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return shortName + "." + lastFieldWritten; } } stack.add(new WritingObject()); } } static public void structure_1(final Object o, final structure_Data d) { try { if (o == null) { d.append("null"); return; } Class c = o.getClass(); boolean concept = false; concept = o instanceof Concept; structure_ClassInfo info = d.infoForClass(c); List lFields = info.fields; if (lFields == null) { if (o instanceof Number) { PrintWriter out = d.out; if (o instanceof Integer) { int i = ((Integer) o).intValue(); out.print(i); d.n += i < 0 ? 2 : 1; return; } if (o instanceof Long) { long l = ((Long) o).longValue(); out.print(l); out.print("L"); d.n += l < 0 ? 2 : 1; return; } if (o instanceof Short) { short s = ((Short) o).shortValue(); d.append("sh "); out.print(s); d.n += s < 0 ? 2 : 1; return; } if (o instanceof Float) { d.append("fl ", 2); quoteToPrintWriter(str(o), out); return; } if (o instanceof Double) { d.append("d(", 3); quoteToPrintWriter(str(o), out); d.append(")"); return; } if (o instanceof BigInteger) { out.print("bigint("); out.print(o); out.print(")"); d.n += ((BigInteger) o).signum() < 0 ? 5 : 4; return; } } if (o instanceof Boolean) { d.append(((Boolean) o).booleanValue() ? "t" : "f"); return; } if (o instanceof Character) { d.append(quoteCharacter((Character) o)); return; } if (o instanceof File) { d.append("File ").append(quote(((File) o).getPath())); return; } Integer ref = d.seen.get(o); if (o instanceof String && ref == null) ref = d.strings.get((String) o); if (ref != null) { d.append("t").app(ref); return; } if (!(o instanceof String)) d.seen.put(o, d.n); else { String s = d.stringSizeLimit != 0 ? shorten((String) o, d.stringSizeLimit) : (String) o; if (!d.noStringSharing) { if (d.shareStringsLongerThan == Integer.MAX_VALUE) d.seen.put(o, d.n); if (l(s) >= d.shareStringsLongerThan) d.strings.put(s, d.n); } quoteToPrintWriter(s, d.out); d.n++; return; } if (o instanceof Set) { if (((Set) o) instanceof TreeSet) { d.append(isCISet_gen((Set) o) ? "ciset" : "treeset"); structure_1(new ArrayList((Set) o), d); return; } d.append(((Set) o) instanceof LinkedHashSet ? "lhs" : "hashset"); structure_1(new ArrayList((Set) o), d); return; } String name = c.getName(); if (o instanceof Collection && !isJavaXClassName(name)) { if (name.equals("java.util.Collections$SynchronizedList") || name.equals("java.util.Collections$SynchronizedRandomAccessList")) { d.append("sync "); { structure_1(unwrapSynchronizedList(((List) o)), d); return; } } else if (name.equals("java.util.LinkedList")) d.append("ll"); d.append("["); final int l = d.n; final Iterator it = cloneList((Collection) o).iterator(); d.stack.add(new Runnable() { public void run() { try { if (!it.hasNext()) d.append("]"); else { d.stack.add(this); if (d.n != l) d.append(", "); structure_1(it.next(), d); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (!it.hasNext())\r\n d.append(\"]\");\r\n else {\r\n d.sta..."; } }); return; } if (o instanceof SynchronizedMap) { d.append("sync "); { structure_1(((SynchronizedMap) o).m, d); return; } } if (o instanceof Map && !startsWith(name, d.mcDollar)) { if (o instanceof LinkedHashMap) d.append("lhm"); else if (o instanceof HashMap) d.append("hm"); else if (o instanceof TreeMap) d.append(isCIMap_gen((TreeMap) o) ? "cimap" : "tm"); else if (name.equals("java.util.Collections$SynchronizedMap") || name.equals("java.util.Collections$SynchronizedSortedMap") || name.equals("java.util.Collections$SynchronizedNavigableMap")) { d.append("sync "); { structure_1(unwrapSynchronizedMap(((Map) o)), d); return; } } d.append("{"); final int l = d.n; final Iterator it = cloneMap((Map) o).entrySet().iterator(); d.stack.add(new Runnable() { public boolean v = false; public Map.Entry e; public void run() { if (v) { d.append("="); v = false; d.stack.add(this); structure_1(e.getValue(), d); } else { if (!it.hasNext()) d.append("}"); else { e = (Map.Entry) it.next(); v = true; d.stack.add(this); if (d.n != l) d.append(", "); structure_1(e.getKey(), d); } } } }); return; } if (c.isArray()) { if (o instanceof byte[]) { d.append("ba ").append(quote(bytesToHex((byte[]) o))); return; } final 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; d.append("boolarray ").append(n).app(" ").append(quote(substring(hex, 0, i))); return; } String atype = "array"; if (o instanceof int[]) { atype = "intarray"; } else if (o instanceof double[]) { atype = "dblarray"; } else { Pair p = arrayTypeAndDimensions(c); if (p.a == int.class) atype = "intarray"; else if (p.a == byte.class) atype = "bytearray"; else if (p.a == boolean.class) atype = "boolarray"; else if (p.a == double.class) atype = "dblarray"; else if (p.a == String.class) { atype = "array S"; d.n++; } else atype = "array"; if (p.b > 1) { atype += "/" + p.b; d.n += 2; } } d.append(atype).append("{"); d.stack.add(new Runnable() { public int i; public void run() { if (i >= n) d.append("}"); else { d.stack.add(this); if (i > 0) d.append(", "); structure_1(Array.get(o, i++), d); } } }); return; } if (o instanceof Class) { d.append("class(", 2).append(quote(((Class) o).getName())).append(")"); return; } if (o instanceof Throwable) { d.append("exception(", 2).append(quote(((Throwable) o).getMessage())).append(")"); return; } if (o instanceof BitSet) { BitSet bs = (BitSet) o; d.append("bitset{", 2); int l = d.n; for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { if (d.n != l) d.append(", "); d.append(i); } d.append("}"); return; } if (info.javafy) { d.append("j ").append(quote(str(o))); return; } if (info.special) { if (c.isEnum()) { d.append("enum "); d.append(info.shortName); d.out.append(' '); d.append(((Enum) o).ordinal()); return; } if (info.customSerializer != null) { Object o2 = invokeMethod(info.customSerializer, o); if (o2 == o) { } else { d.append("cu "); String shortName = dropPrefix(d.mcDollar, name); d.append(shortName); d.out.append(' '); structure_1(o2, d); return; } } else if (info.nullInstances) { d.append("null"); return; } else if (info.serializeObject != null) { info.serializeObject.get(o); return; } else throw fail("unknown special type"); } String dynName = shortDynClassNameForStructure(o); if (concept && !d.concepts.contains(dynName)) { d.concepts.add(dynName); d.append("c "); } TreeSet fields = new TreeSet(new Comparator() { public int compare(Field a, Field b) { return stdcompare(a.getName(), b.getName()); } }); Class cc = c; while (cc != Object.class) { for (Field field : getDeclaredFields_cached(cc)) { if (!d.shouldIncludeField(field)) continue; String fieldName = field.getName(); if (fieldName.equals("_persistenceInfo")) d.persistenceInfo.put(c, obj -> (Map) fieldGet(field, obj)); if ((field.getModifiers() & (java.lang.reflect.Modifier.STATIC | java.lang.reflect.Modifier.TRANSIENT)) != 0) continue; fields.add(field); } cc = cc.getSuperclass(); } Method persistenceInfoMethod = findInstanceMethod(c, "_persistenceInfo"); if (persistenceInfoMethod != null) d.persistenceInfo.put(c, obj -> (Map) invokeMethod(persistenceInfoMethod, obj)); lFields = asList(d.honorFieldOrder ? fieldObjectsInFieldOrder(c, fields) : fields); int n = l(lFields); for (int i = 0; i < n; i++) { Field f = lFields.get(i); if (f.getName().startsWith("this$")) { lFields.remove(i); lFields.add(0, f); break; } } d.setFields(info, lFields); } else { Integer ref = d.seen.get(o); if (ref != null) { d.append("t").app(ref); return; } d.seen.put(o, d.n); } IF1 piGetter = d.persistenceInfo.get(c); Map persistenceInfo = piGetter == null ? null : piGetter.get(o); if (piGetter == null && o instanceof DynamicObject) persistenceInfo = (Map) getOptDynOnly(((DynamicObject) o), "_persistenceInfo"); LinkedHashMap fv = new LinkedHashMap(); Object defaultInstance = info.emptyInstance; for (Field f : lFields) { Object value, defaultValue = null; try { value = f.get(o); defaultValue = defaultInstance == null ? null : f.get(defaultInstance); } catch (Exception e) { value = "?"; } if (!eq(defaultValue, value) && (persistenceInfo == null || !Boolean.FALSE.equals(persistenceInfo.get(f.getName())))) fv.put(f.getName(), value); } String shortName = info.shortName; if (concept && eq(fv.get("className"), shortName)) fv.remove("className"); if (o instanceof DynamicObject) { putAll(fv, (Map) fv.get("fieldValues")); fv.remove("fieldValues"); if (((DynamicObject) o).className != null) { shortName = shortDynClassNameForStructure((DynamicObject) o); fv.remove("className"); } } d.writeObject(o, shortName, fv); } catch (Exception __e) { throw rethrow(__e); } } static public String[][] htmldecode_escapes() { return htmldecode_ESCAPES; } static final public String[][] htmldecode_ESCAPES = { { "\"", "quot" }, { "&", "amp" }, { "<", "lt" }, { ">", "gt" }, { "\u00A0", "nbsp" }, { "\u00A1", "iexcl" }, { "\u00A2", "cent" }, { "\u00A3", "pound" }, { "\u00A4", "curren" }, { "\u00A5", "yen" }, { "\u00A6", "brvbar" }, { "\u00A7", "sect" }, { "\u00A8", "uml" }, { "\u00A9", "copy" }, { "\u00AA", "ordf" }, { "\u00AB", "laquo" }, { "\u00AC", "not" }, { "\u00AD", "shy" }, { "\u00AE", "reg" }, { "\u00AF", "macr" }, { "\u00B0", "deg" }, { "\u00B1", "plusmn" }, { "\u00B2", "sup2" }, { "\u00B3", "sup3" }, { "\u00B4", "acute" }, { "\u00B5", "micro" }, { "\u00B6", "para" }, { "\u00B7", "middot" }, { "\u00B8", "cedil" }, { "\u00B9", "sup1" }, { "\u00BA", "ordm" }, { "\u00BB", "raquo" }, { "\u00BC", "frac14" }, { "\u00BD", "frac12" }, { "\u00BE", "frac34" }, { "\u00BF", "iquest" }, { "\u00C0", "Agrave" }, { "\u00C1", "Aacute" }, { "\u00C2", "Acirc" }, { "\u00C3", "Atilde" }, { "\u00C4", "Auml" }, { "\u00C5", "Aring" }, { "\u00C6", "AElig" }, { "\u00C7", "Ccedil" }, { "\u00C8", "Egrave" }, { "\u00C9", "Eacute" }, { "\u00CA", "Ecirc" }, { "\u00CB", "Euml" }, { "\u00CC", "Igrave" }, { "\u00CD", "Iacute" }, { "\u00CE", "Icirc" }, { "\u00CF", "Iuml" }, { "\u00D0", "ETH" }, { "\u00D1", "Ntilde" }, { "\u00D2", "Ograve" }, { "\u00D3", "Oacute" }, { "\u00D4", "Ocirc" }, { "\u00D5", "Otilde" }, { "\u00D6", "Ouml" }, { "\u00D7", "times" }, { "\u00D8", "Oslash" }, { "\u00D9", "Ugrave" }, { "\u00DA", "Uacute" }, { "\u00DB", "Ucirc" }, { "\u00DC", "Uuml" }, { "\u00DD", "Yacute" }, { "\u00DE", "THORN" }, { "\u00DF", "szlig" }, { "\u00E0", "agrave" }, { "\u00E1", "aacute" }, { "\u00E2", "acirc" }, { "\u00E3", "atilde" }, { "\u00E4", "auml" }, { "\u00E5", "aring" }, { "\u00E6", "aelig" }, { "\u00E7", "ccedil" }, { "\u00E8", "egrave" }, { "\u00E9", "eacute" }, { "\u00EA", "ecirc" }, { "\u00EB", "euml" }, { "\u00EC", "igrave" }, { "\u00ED", "iacute" }, { "\u00EE", "icirc" }, { "\u00EF", "iuml" }, { "\u00F0", "eth" }, { "\u00F1", "ntilde" }, { "\u00F2", "ograve" }, { "\u00F3", "oacute" }, { "\u00F4", "ocirc" }, { "\u00F5", "otilde" }, { "\u00F6", "ouml" }, { "\u00F7", "divide" }, { "\u00F8", "oslash" }, { "\u00F9", "ugrave" }, { "\u00FA", "uacute" }, { "\u00FB", "ucirc" }, { "\u00FC", "uuml" }, { "\u00FD", "yacute" }, { "\u00FE", "thorn" }, { "\u00FF", "yuml" }, { "\u2013", "ndash" }, { "\u2018", "lsquo" }, { "\u2019", "rsquo" }, { "\u201D", "rdquo" }, { "\u201C", "ldquo" }, { "\u2014", "mdash" }, { "'", "apos" } }; static public String formatWithThousandsSeparator(long l) { return NumberFormat.getInstance(new Locale("en_US")).format(l); } static public int findEndOfCurlyBracketPart(List cnc, int i) { int j = i + 2, level = 1; while (j < cnc.size()) { if (eq(cnc.get(j), "{")) ++level; else if (eq(cnc.get(j), "}")) --level; if (level == 0) return j + 1; ++j; } return cnc.size(); } static public List javaTokC(String s) { if (s == null) return null; int l = s.length(); ArrayList tok = new ArrayList(); int i = 0; while (i < l) { int j = i; char c, d; while (j < l) { c = s.charAt(j); d = j + 1 >= l ? '\0' : s.charAt(j + 1); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (c == '/' && d == '*') { do ++j; while (j < l && !s.substring(j, Math.min(j + 2, l)).equals("*/")); j = Math.min(j + 2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } i = j; if (i >= l) break; c = s.charAt(i); d = i + 1 >= l ? '\0' : s.charAt(i + 1); if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { if (s.charAt(j) == opener || s.charAt(j) == '\n') { ++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)); else if (Character.isDigit(c)) { do ++j; while (j < l && Character.isDigit(s.charAt(j))); if (j < l && s.charAt(j) == 'L') ++j; } else if (c == '[' && d == '[') { do ++j; while (j + 1 < l && !s.substring(j, j + 2).equals("]]")); j = Math.min(j + 2, l); } else if (c == '[' && d == '=' && 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(javaTok_substringC(s, i, j)); i = j; } return tok; } static public IntRange cncCorrect(IntRange r) { return r == null ? null : new IntRange(r.start & ~1, r.end | 1); } static public ThreadLocal customRandomizerForThisThread_tl = new ThreadLocal(); static public ThreadLocal customRandomizerForThisThread_tl() { return customRandomizerForThisThread_tl; } static public x30_pkg.x30_util.BetterThreadLocal newPing_actionTL; static public x30_pkg.x30_util.BetterThreadLocal newPing_actionTL() { if (newPing_actionTL == null) newPing_actionTL = vm_generalMap_getOrCreate("newPing_actionTL", () -> { Runnable value = (Runnable) (callF_gen(vm_generalMap_get("newPing_valueForNewThread"))); var tl = new x30_pkg.x30_util.BetterThreadLocal(); tl.set(value); return tl; }); return newPing_actionTL; } static volatile public boolean licensed_yes = true; static public boolean licensed() { if (!licensed_yes) return false; ping_okInCleanUp(); return true; } static public void licensed_off() { licensed_yes = false; } static public Map compileRegexpIC_cache = syncMRUCache(10); static public java.util.regex.Pattern compileRegexpIC(String pat) { java.util.regex.Pattern p = compileRegexpIC_cache.get(pat); if (p == null) { try { compileRegexpIC_cache.put(pat, p = java.util.regex.Pattern.compile(pat, Pattern.CASE_INSENSITIVE)); } catch (PatternSyntaxException e) { throw rethrow(wrapPatternSyntaxException(e)); } } return p; } static public boolean startsWithLetterOrDigit(String s) { return nempty(s) && Character.isLetterOrDigit(s.charAt(0)); } static public String regexpQuote(String s) { return s.length() == 0 ? "" : Pattern.quote(s); } static public void arraycopy(Object[] a, Object[] b) { if (a != null && b != null) arraycopy(a, 0, b, 0, Math.min(a.length, b.length)); } static public void arraycopy(Object src, int srcPos, int destPos, int n) { arraycopy(src, srcPos, src, destPos, n); } static public void arraycopy(Object src, int srcPos, Object dest, int destPos, int n) { if (n != 0) System.arraycopy(src, srcPos, dest, destPos, n); } static public List parse3(String s) { return dropPunctuation(javaTokPlusPeriod(s)); } static public List takeLast(List l, int n) { return newSubList(l, l(l) - n); } static public List takeLast(int n, List l) { return takeLast(l, n); } static public String takeLast(int n, String s) { return substring(s, l(s) - n); } static public String takeLast(String s, int n) { return substring(s, l(s) - n); } static public boolean equalsIgnoreCase(String a, String b) { return eqic(a, b); } static public boolean equalsIgnoreCase(char a, char b) { return eqic(a, b); } static public int min3(int a, int b, int c) { return min(min(a, b), c); } static public double min3(double a, double b, double c) { return min(min(a, b), c); } static public Set cloneSet(Collection set) { if (set == null) return new HashSet(); synchronized (collectionMutex(set)) { Set s = similarEmptySet(set); s.addAll(set); return s; } } static public Set joinSets(Collection... l) { Set set = similarEmptySet(first(l)); for (Collection o : l) if (o != null) set.addAll(o); return set; } static public HashMap> callMC_cache = new HashMap(); static public String callMC_key; static public Method callMC_value; static public Object callMC(String method, String[] arg) { return callMC(method, new Object[] { arg }); } static public Object callMC(String method, Object... args) { try { Method me; if (callMC_cache == null) callMC_cache = new HashMap(); synchronized (callMC_cache) { me = method == callMC_key ? callMC_value : null; } if (me != null) try { return invokeMethod(me, null, args); } catch (IllegalArgumentException e) { throw new RuntimeException("Can't call " + me + " with arguments " + classNames(args), e); } List m; synchronized (callMC_cache) { m = callMC_cache.get(method); } if (m == null) { if (callMC_cache.isEmpty()) { callMC_makeCache(); m = callMC_cache.get(method); } if (m == null) throw fail("Method named " + method + " not found in main"); } int n = m.size(); if (n == 1) { me = m.get(0); synchronized (callMC_cache) { callMC_key = method; callMC_value = me; } try { return invokeMethod(me, null, args); } catch (IllegalArgumentException e) { throw new RuntimeException("Can't call " + me + " with arguments " + classNames(args), e); } } for (int i = 0; i < n; i++) { me = m.get(i); if (call_checkArgs(me, args, false)) return invokeMethod(me, null, args); } throw fail("No method called " + method + " with arguments (" + joinWithComma(getClasses(args)) + ") found in main"); } catch (Exception __e) { throw rethrow(__e); } } static public void callMC_makeCache() { synchronized (callMC_cache) { callMC_cache.clear(); Class _c = (Class) mc(), c = _c; while (c != null) { for (Method m : c.getDeclaredMethods()) if ((m.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) { makeAccessible(m); multiMapPut(callMC_cache, m.getName(), m); } c = c.getSuperclass(); } } } static public Class javax() { return getJavaX(); } static public HashSet litset(A... items) { return lithashset(items); } static public int findEndOfBracketPart(List cnc, int i) { int j = i + 2, level = 1; while (j < cnc.size()) { if (eqOneOf(cnc.get(j), "{", "(")) ++level; else if (eqOneOf(cnc.get(j), "}", ")")) --level; if (level == 0) return j + 1; ++j; } return cnc.size(); } static public List cloneSubList(List l, int startIndex, int endIndex) { return newSubList(l, startIndex, endIndex); } static public List cloneSubList(List l, int startIndex) { return newSubList(l, startIndex); } static public List javaTokPlusBrackets2(String s) { return tok_combineRoundCurlySquareBrackets_keep(javaTok(s)); } static public List getClassNames(Collection l) { List out = new ArrayList(); if (l != null) for (Object o : l) out.add(o == null ? null : getClassName(o)); return out; } static public boolean domainIsUnder(String domain, String mainDomain) { return eqic(domain, mainDomain) || ewic(domain, "." + mainDomain); } static public String theAGIBlueDomain() { return "agi.blue"; } static public Object callFunction(Object f, Object... args) { return callF(f, args); } static public Throwable _storeException_value; static public void _storeException(Throwable e) { _storeException_value = e; } static public Map vm_generalMap_map; static public Map vm_generalMap() { if (vm_generalMap_map == null) vm_generalMap_map = (Map) get(javax(), "generalMap"); return vm_generalMap_map; } static public Object vm_generalMap_get(Object key) { return vm_generalMap().get(key); } static public Object vm_generalMap_put(Object key, Object value) { return mapPutOrRemove(vm_generalMap(), key, value); } static public Set syncIdentityHashSet() { return (Set) synchronizedSet(identityHashSet()); } static public Map syncHashMap() { return synchroHashMap(); } static public A printException(A e) { printStackTrace(e); return e; } static public boolean hasBot(String searchPattern) { try { DialogIO io = findBot(searchPattern); if (io != null) { io.close(); return true; } else return false; } catch (Exception __e) { throw rethrow(__e); } } static public boolean isOK(String s) { s = trim(s); return swic(s, "ok ") || eqic(s, "ok") || matchStart("ok", s); } static public String sendOpt(String bot, String text, Object... args) { return sendToLocalBotOpt(bot, text, args); } static public boolean isMainProgram() { return creator() == null; } static public void cleanKill() { cleanKillVM(); } static public String dbBotName(String progIDWithCase) { return fsI_flex(progIDWithCase) + " Concepts"; } static public String actualUserHome_value; static public String actualUserHome() { if (actualUserHome_value == null) { if (isAndroid()) actualUserHome_value = "/storage/emulated/0/"; else actualUserHome_value = System.getProperty("user.home"); } return actualUserHome_value; } static public File actualUserHome(String sub) { return newFile(new File(actualUserHome()), sub); } static public Android3 methodsBot2(String name, final Object receiver, final List exposedMethods) { return methodsBot2(name, receiver, exposedMethods, null); } static public Android3 methodsBot2(String name, final Object receiver, final List exposedMethods, final Lock lock) { Android3 android = new Android3(); android.greeting = name; android.console = false; android.responder = new Responder() { public String answer(String s, List history) { return exposeMethods2(receiver, s, exposedMethods, lock); } }; return makeBot(android); } static public List db_standardExposedMethods_list = ll("xlist", "xnew", "xset", "xdelete", "xget", "xclass", "xfullgrab", "xshutdown", "xchangeCount", "xcount"); static public List db_standardExposedMethods() { return db_standardExposedMethods_list; } static public File programDir_mine; static public File programDir() { return programDir(getProgramID()); } static public File programDir(String snippetID) { boolean me = sameSnippetID(snippetID, programID()); if (programDir_mine != null && me) return programDir_mine; File dir = new File(javaxDataDir(), formatSnippetIDOpt(snippetID)); if (me) { String c = caseID(); if (nempty(c)) dir = newFile(dir, c); } return dir; } static public File programDir(String snippetID, String subPath) { return new File(programDir(snippetID), subPath); } static public Matcher regexp(String pat, String s) { return regexp(compileRegexp(pat), unnull(s)); } static public Matcher regexp(java.util.regex.Pattern pat, String s) { return pat.matcher(unnull(s)); } static public java.util.regex.Pattern regexp(String pat) { return compileRegexp(pat); } static public List listFilesNotDirs(String dir) { return listFilesOnly(dir); } static public List listFilesNotDirs(File... dirs) { return listFilesOnly(dirs); } static public int matcherInt(Matcher m, int i) { return parseInt(m.group(i)); } static public long timestampFromYMDHM(int y, int m, int d, int h, int minutes) { return new GregorianCalendar(y, m - 1, d, h, minutes).getTimeInMillis(); } static public long now_virtualTime; static public long now() { return now_virtualTime != 0 ? now_virtualTime : System.currentTimeMillis(); } static public List sortByMap_inPlace(List l, Map map) { sort(l, mapComparator(map)); return l; } static public boolean defaultAgeBasedBackupRetentionStrategy_shouldKeep(double age, double lastAge) { if (age <= 1 / 12.0) return true; if (age <= 0.5 && age >= lastAge + 1 / 12.0) return true; if (age <= 7 && age >= lastAge + 1) return true; if (age <= 28 && age >= lastAge + 7) return true; if (age >= lastAge + 365.0 / 12) return true; return false; } static volatile public String caseID_caseID; static public String caseID() { return caseID_caseID; } static public void caseID(String id) { caseID_caseID = id; } static public String quoteUnlessIdentifierOrInteger(String s) { return quoteIfNotIdentifierOrInteger(s); } static public int boolToInt(boolean b) { return b ? 1 : 0; } static public Map singular_specials = litmap("children", "child", "images", "image", "chess", "chess"); static public Set singular_specials2 = litciset("time", "machine", "line", "rule"); static public String singular(String s) { if (s == null) return null; { String __1 = singular_specials.get(s); if (!empty(__1)) return __1; } if (singular_specials2.contains(dropSuffix("s", afterLastSpace(s)))) return dropSuffix("s", s); if (s.endsWith("ness")) return s; if (s.endsWith("ges")) return dropSuffix("s", s); if (endsWith(s, "bases")) return dropLast(s); s = dropSuffix("es", s); s = dropSuffix("s", s); return s; } static public Set getPlural_specials = litciset("sheep", "fish"); static public String getPlural(String s) { if (contains(getPlural_specials, s)) return s; if (ewic(s, "y")) return dropSuffixIgnoreCase("y", s) + "ies"; if (ewicOneOf(s, "ss", "ch")) return s + "es"; if (ewic(s, "s")) return s; return s + "s"; } static public Method findMethodNamed(Object obj, String method) { if (obj == null) return null; if (obj instanceof Class) return findMethodNamed((Class) obj, method); return findMethodNamed(obj.getClass(), method); } static public Method findMethodNamed(Class c, String method) { while (c != null) { for (Method m : c.getDeclaredMethods()) if (m.getName().equals(method)) { makeAccessible(m); return m; } c = c.getSuperclass(); } return null; } static public void upgradeJavaXAndRestart() { run("#1001639"); restart(); sleep(); } static public boolean isIdentifier(String s) { return isJavaIdentifier(s); } static public boolean isAnonymousClassName(String s) { for (int i = 0; i < l(s); i++) if (s.charAt(i) == '$' && Character.isDigit(s.charAt(i + 1))) return true; return false; } static public void lock(Lock lock) { try { ping(); if (lock == null) return; try { vmBus_send("locking", lock, "thread", currentThread()); lock.lockInterruptibly(); vmBus_send("locked", lock, "thread", currentThread()); } catch (InterruptedException e) { Object reason = vm_threadInterruptionReasonsMap().get(currentThread()); print("Locking interrupted! Reason: " + strOr(reason, "Unknown")); printStackTrace(e); rethrow(e); } } catch (Exception __e) { throw rethrow(__e); } } static public void lock(Lock lock, String msg) { print("Locking: " + msg); lock(lock); } static public void lock(Lock lock, String msg, long timeout) { print("Locking: " + msg); lockOrFail(lock, timeout); } static public ReentrantLock lock() { return fairLock(); } static public void unlock(Lock lock, String msg) { if (lock == null) return; lock.unlock(); vmBus_send("unlocked", lock, "thread", currentThread()); print("Unlocked: " + msg); } static public void unlock(Lock lock) { if (lock == null) return; lock.unlock(); vmBus_send("unlocked", lock, "thread", currentThread()); } static public boolean methodIsStatic(Method m) { return (m.getModifiers() & Modifier.STATIC) != 0; } static public boolean argumentCompatibleWithType(Object arg, Class type) { return arg == null ? !type.isPrimitive() : isInstanceX(type, arg); } static public File userDir() { return new File(userHome()); } static public File userDir(String path) { return new File(userHome(), path); } static public boolean isURL(String s) { return startsWithOneOf(s, "http://", "https://", "file:"); } static public boolean rectContains(int x1, int y1, int w, int h, Pt p) { return p.x >= x1 && p.y >= y1 && p.x < x1 + w && p.y < y1 + h; } static public boolean rectContains(Rect a, Rect b) { return b.x >= a.x && b.y >= a.y && b.x2() <= a.x2() && b.y2() <= a.y2(); } static public boolean rectContains(Rect a, Rectangle b) { return rectContains(a, toRect(b)); } static public boolean rectContains(Rect a, int x, int y) { return a != null && a.contains(x, y); } static public boolean rectContains(Rect a, Pt p) { return a != null && p != null && a.contains(p); } static public boolean isLetter(char c) { return Character.isLetter(c); } static public ThreadLocal htmlencode_forParams_useV2 = new ThreadLocal(); static public String htmlencode_forParams(String s) { if (s == null) return ""; if (isTrue(htmlencode_forParams_useV2.get())) return htmlencode_forParams_v2(s); StringBuilder out = new StringBuilder(Math.max(16, s.length())); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c > 127 || c == '"' || c == '<' || c == '>') { out.append("&#"); out.append((int) c); out.append(';'); } else out.append(c); } return out.toString(); } static public double toDouble(Object o) { if (o instanceof Number) return ((Number) o).doubleValue(); if (o instanceof BigInteger) return ((BigInteger) o).doubleValue(); if (o instanceof String) return parseDouble((String) o); if (o == null) return 0.0; throw fail(o); } static public Class __javax; static public Class getJavaX() { try { return __javax; } catch (Exception __e) { throw rethrow(__e); } } static public void __setJavaX(Class j) { __javax = j; _onJavaXSet(); } static public void swingAndWait(Runnable r) { try { if (isAWTThread()) r.run(); else EventQueue.invokeAndWait(addThreadInfoToRunnable(r)); } catch (Exception __e) { throw rethrow(__e); } } static public Object swingAndWait(final Object f) { if (isAWTThread()) return callF(f); else { final Var result = new Var(); swingAndWait(new Runnable() { public void run() { try { result.set(callF(f)); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "result.set(callF(f));"; } }); return result.get(); } } static public A revalidate(final A c) { if (c == null || !c.isShowing()) return c; { swing(() -> { c.revalidate(); c.repaint(); }); } return c; } static public void revalidate(JFrame f) { revalidate((Component) f); } static public void revalidate(JInternalFrame f) { revalidate((Component) f); } static public JFrame getFrame(final Object _o) { return swing(new F0() { public JFrame get() { try { Object o = _o; if (o instanceof ButtonGroup) o = first(buttonsInGroup((ButtonGroup) 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; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "O o = _o;\r\n if (o instanceof ButtonGroup) o = first(buttonsInGroup((Button..."; } }); } static public String replacePrefix(String prefix, String replacement, String s) { if (!startsWith(s, prefix)) return s; return replacement + substring(s, l(prefix)); } static public Object get2(Object o, String field1, String field2) { return get(get(o, field1), field2); } static public boolean startsWithAny(String a, Collection b) { for (String prefix : unnullForIteration(b)) if (startsWith(a, prefix)) return true; return false; } static public boolean startsWithAny(String a, String... b) { if (b != null) for (String prefix : unnullForIteration(b)) if (startsWith(a, prefix)) return true; return false; } static public boolean startsWithAny(String a, Collection b, Matches m) { for (String prefix : unnullForIteration(b)) if (startsWith(a, prefix, m)) return true; return false; } static public String mcDollar() { return mcName() + "$"; } static public String afterDollar(String s) { return substring(s, smartIndexOf(s, '$') + 1); } static public Object realMC() { return getThreadLocal(realMC_tl()); } static public Map synchronizedMap() { return synchroMap(); } static public Map synchronizedMap(Map map) { return synchroMap(map); } static public int charDiff(char a, char b) { return (int) a - (int) b; } static public int charDiff(String a, char b) { return charDiff(stringToChar(a), b); } static public Throwable getInnerException(Throwable e) { if (e == null) return null; while (e.getCause() != null) e = e.getCause(); return e; } static public Throwable getInnerException(Runnable r) { return getInnerException(getException(r)); } static public String baseClassName(String className) { return substring(className, className.lastIndexOf('.') + 1); } static public String baseClassName(Object o) { return baseClassName(getClassName(o)); } static public String prependIfNempty(String prefix, String s) { return empty(s) ? unnull(s) : prefix + s; } static public Object[] toArray(Collection c) { return toObjectArray(c); } static public A[] toArray(Class type, Iterable c) { return toArray(c, type); } static public A[] toArray(Class type, Collection c) { return toArray(c, type); } static public A[] toArray(Collection c, Class type) { A[] a = arrayOfType(l(c), type); if (a.length == 0) return a; asList(c).toArray(a); return a; } static public A[] toArray(Iterable c, Class type) { var c2 = asList(c); A[] a = arrayOfType(l(c2), type); if (a.length == 0) return a; c2.toArray(a); return a; } static public A[] toArray(A[] array, Collection c) { if (array == null || c == null) return null; asList(c).toArray(array); return array; } static public boolean reflection_isForbiddenMethod(Method m) { return m.getDeclaringClass() == Object.class && eqOneOf(m.getName(), "finalize", "clone", "registerNatives"); } static public TreeSet caseInsensitiveSet_treeSet() { return new TreeSet(caseInsensitiveComparator()); } static public TreeSet caseInsensitiveSet_treeSet(Collection c) { return toCaseInsensitiveSet_treeSet(c); } static public void removeSubList(List l, int from, int to) { if (l != null) subList(l, from, to).clear(); } static public void removeSubList(List l, int from) { if (l != null) subList(l, from).clear(); } static public BufferedReader bufferedReader(Reader r) { return bufferedReader(r, 8192); } static public BufferedReader bufferedReader(Reader r, int bufSize) { if (r == null) return null; return r instanceof BufferedReader ? (BufferedReader) r : _registerIOWrap(new BufferedReader(r, bufSize), r); } static public FileInputStream newFileInputStream(File path) throws IOException { return newFileInputStream(path.getPath()); } static public FileInputStream newFileInputStream(String path) throws IOException { FileInputStream f = new FileInputStream(path); _registerIO(f, path, true); return f; } static public betterCIComparator_C betterCIComparator_instance; static public betterCIComparator_C betterCIComparator() { if (betterCIComparator_instance == null) betterCIComparator_instance = new betterCIComparator_C(); return betterCIComparator_instance; } final static public class betterCIComparator_C implements Comparator { public int compare(String s1, String s2) { if (s1 == null) return s2 == null ? 0 : -1; if (s2 == null) return 1; int n1 = s1.length(); int n2 = s2.length(); int min = Math.min(n1, n2); for (int i = 0; i < min; i++) { char c1 = s1.charAt(i); char c2 = s2.charAt(i); if (c1 != c2) { c1 = Character.toUpperCase(c1); c2 = Character.toUpperCase(c2); if (c1 != c2) { c1 = Character.toLowerCase(c1); c2 = Character.toLowerCase(c2); if (c1 != c2) { return c1 - c2; } } } } return n1 - n2; } } static public boolean isTrueOpt(Object o) { if (o instanceof Boolean) return ((Boolean) o).booleanValue(); return false; } static public boolean isTrueOpt(String field, Object o) { return isTrueOpt(getOpt(field, o)); } static public boolean eqicOneOf(String s, String... l) { for (String x : l) if (eqic(s, x)) return true; return false; } static public List isYes_yesses = litlist("y", "yes", "yeah", "y", "yup", "yo", "corect", "sure", "ok", "afirmative"); static public boolean isYes(String s) { return isYes_yesses.contains(collapseWord(toLowerCase(firstWord2(s)))); } static public IMeta initIMeta(Object o) { if (o == null) return null; if (o instanceof IMeta) return ((IMeta) o); if (o instanceof JComponent) return initMetaOfJComponent((JComponent) o); if (o instanceof BufferedImage) return optCast(IMeta.class, ((BufferedImage) o).getProperty("meta")); return null; } static public boolean endsWithIgnoreCase(String a, String b) { int la = l(a), lb = l(b); return la >= lb && regionMatchesIC(a, la - lb, b, 0, lb); } static public boolean endsWithIgnoreCase(String a, String b, Matches m) { if (!endsWithIgnoreCase(a, b)) return false; if (m != null) m.m = new String[] { substring(a, 0, l(a) - l(b)) }; return true; } static public A holdResource(IResourceHolder holder, A a) { { if (holder != null) holder.add(a); } return a; } static public CloseableIterableIterator iteratorFromFunction_f0_autoCloseable(final F0 f, final AutoCloseable closeable) { class IFF2 extends CloseableIterableIterator { public A a; public boolean done = false; public boolean hasNext() { getNext(); return !done; } public A next() { getNext(); if (done) throw fail(); A _a = a; a = null; return _a; } public void getNext() { if (done || a != null) return; a = f.get(); done = a == null; } public void close() throws Exception { if (closeable != null) closeable.close(); } } ; return new IFF2(); } static public String readLineFromReaderWithClose(BufferedReader r) { try { String s = r.readLine(); if (s == null) r.close(); return s; } catch (Exception __e) { throw rethrow(__e); } } static public AutoCloseable _wrapIOCloseable(final AutoCloseable c) { return c == null ? null : new AutoCloseable() { public String toString() { return "c.close();\r\n _registerIO(c, null, false);"; } public void close() throws Exception { c.close(); _registerIO(c, null, false); } }; } static public String shortenClassName(String name) { if (name == null) return null; int i = lastIndexOf(name, "$"); if (i < 0) i = lastIndexOf(name, "."); return i < 0 ? name : substring(name, i + 1); } static public Object[] toObjectArray(Collection c) { return toObjectArray((Iterable) c); } static public Object[] toObjectArray(Iterable c) { List l = asList(c); return l.toArray(new Object[l.size()]); } static public boolean isStringStartingWith(Object o, String prefix) { return o instanceof String && ((String) o).startsWith(prefix); } static public String structureForUser(Object o) { return structureForUser(o, new structure_Data()); } static public String structureForUser(Object o, structure_Data d) { d.noStringSharing = true; d.warnIfUnpersistable(false); return beautifyStructure(structure(o, d)); } static public A assertEquals(Object x, A y) { return assertEquals("", x, y); } static public A assertEquals(String msg, Object x, A y) { if (assertVerbose()) return assertEqualsVerbose(msg, x, y); if (!(x == null ? y == null : x.equals(y))) throw fail((msg != null ? msg + ": " : "") + y + " != " + x); return y; } static public void assertEquals(Scorer scorer, Object x, Object y) { assertEquals(scorer, "", x, y); } static public void assertEquals(Scorer scorer, String msg, Object x, Object y) { if (scorer == null) { assertEquals(msg, x, y); return; } scorer.add(eq(x, y), nullIfEmpty(msg)); } static public boolean startsWithDigit(String s) { return nempty(s) && isDigit(s.charAt(0)); } static public boolean isSyntheticOrAnonymous(Class c) { return c != null && (c.isSynthetic() || isAnonymousClassName(c.getName())); } static public String shortDynClassNameForStructure(Object o) { if (o instanceof DynamicObject && ((DynamicObject) o).className != null) return ((DynamicObject) o).className; if (o == null) return null; Class c = o instanceof Class ? (Class) o : o.getClass(); String name = c.getName(); return name.startsWith("dyn.") ? classNameToVM(name) : shortenClassName(name); } static public boolean isPersistableClass(Class c) { String name = c.getName(); if (isSubtypeOf(c, TransientObject.class)) return false; if (isAnonymousClassName(name)) return false; if (isBoxedType(c)) return true; if (isArrayType(c)) return true; if (c == Class.class || c == String.class || c == File.class || c == Color.class) return true; if (name.startsWith("java.util.Collections$Synchronized")) return true; if (hasThisDollarFields(c)) return hasSingleArgumentConstructor(c); else return getDefaultConstructor(c) != null; } static public A last(List l) { return empty(l) ? null : l.get(l.size() - 1); } static public char last(String s) { return empty(s) ? '#' : s.charAt(l(s) - 1); } static public byte last(byte[] a) { return l(a) != 0 ? a[l(a) - 1] : 0; } static public int last(int[] a) { return l(a) != 0 ? a[l(a) - 1] : 0; } static public double last(double[] a) { return l(a) != 0 ? a[l(a) - 1] : 0; } static public A last(A[] a) { return l(a) != 0 ? a[l(a) - 1] : null; } static public A last(Iterator it) { A a = null; while (it.hasNext()) { ping(); a = it.next(); } return a; } static public A last(Collection l) { if (l == null) return null; if (l instanceof List) return (A) last((List) l); if (l instanceof SortedSet) return (A) last((SortedSet) l); Iterator it = iterator(l); A a = null; while (it.hasNext()) { ping(); a = it.next(); } return a; } static public A last(SortedSet l) { return l == null ? null : l.last(); } static public A last(ReverseChain l) { return l == null ? null : l.element; } static public A last(CompactLinkedHashSet set) { return set == null ? null : set.last(); } static public Constructor getDefaultConstructor(Class c) { if (c != null) for (Constructor m : getDeclaredConstructors_cached(c)) if (empty(m.getParameterTypes())) return m; return null; } static public Object invokeConstructor(Constructor m, Object... args) { try { makeAccessible(m); return m.newInstance(args); } catch (Exception __e) { throw rethrow(__e); } } static public int countDots(String s) { int n = l(s), count = 0; for (int i = 0; i < n; i++) if (s.charAt(i) == '.') ++count; return count; } static public void quoteToPrintWriter(String s, PrintWriter out) { if (s == null) { out.print("null"); return; } out.print('"'); int l = s.length(); for (int i = 0; i < l; i++) { char c = s.charAt(i); if (c == '\\' || c == '"') { out.print('\\'); out.print(c); } else if (c == '\r') out.print("\\r"); else if (c == '\n') out.print("\\n"); else if (c == '\0') out.print("\\0"); else out.print(c); } out.print('"'); } static public String quoteCharacter(char c) { if (c == '\'') return "'\\''"; if (c == '\\') return "'\\\\'"; if (c == '\r') return "'\\r'"; if (c == '\n') return "'\\n'"; if (c == '\t') return "'\\t'"; return "'" + c + "'"; } static public boolean isCISet_gen(Iterable l) { return l instanceof TreeSet && className(((TreeSet) l).comparator()).contains("CIComp"); } static public boolean isJavaXClassName(String s) { return startsWithOneOf(s, "main$", "loadableUtils."); } static public List unwrapSynchronizedList(List l) { if (l instanceof SynchronizedList) return ((SynchronizedList) l).list; if (eqOneOf(className(l), "java.util.Collections$SynchronizedList", "java.util.Collections$SynchronizedRandomAccessList")) return (List) get_raw(l, "list"); return l; } static public boolean isCIMap_gen(Map map) { return map instanceof TreeMap && className(((TreeMap) map).comparator()).contains("CIComp"); } static public Map unwrapSynchronizedMap(Map map) { if (eqOneOf(shortClassName(map), "SynchronizedMap", "SynchronizedSortedMap", "SynchronizedNavigableMap")) return (Map) get_raw(map, "m"); return map; } 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 public String boolArrayToHex(boolean[] a) { return bytesToHex(boolArrayToBytes(a)); } static public Pair arrayTypeAndDimensions(Object o) { return arrayTypeAndDimensions(_getClass(o)); } static public Pair arrayTypeAndDimensions(Class c) { if (c == null || !c.isArray()) return null; Class elem = c.getComponentType(); if (elem.isArray()) return mapPairB(arrayTypeAndDimensions(elem), dim -> dim + 1); return pair(elem, 1); } static public Map getDeclaredFields_cache = newDangerousWeakHashMap(); static public Field[] getDeclaredFields_cached(Class c) { Field[] fields; synchronized (getDeclaredFields_cache) { fields = getDeclaredFields_cache.get(c); if (fields == null) { getDeclaredFields_cache.put(c, fields = c.getDeclaredFields()); for (Field f : fields) makeAccessible(f); } } return fields; } static public Object fieldGet(Field f, Object o) { try { return f == null ? null : f.get(o); } catch (Exception __e) { throw rethrow(__e); } } static public Method findInstanceMethod(Class c, String method, Object... args) { while (c != null) { for (Method m : c.getDeclaredMethods()) if (m.getName().equals(method) && findMethod_checkArgs(m, args, false)) return m; c = c.getSuperclass(); } return null; } static public Set fieldObjectsInFieldOrder(Class c, Set fields) { try { var byName = mapToKey(f -> f.getName(), fields); LinkedHashSet out = new LinkedHashSet(); for (String name : unnullForIteration(getFieldOrder(c))) { Field f = byName.get(name); if (f != null) { byName.remove(name); out.add(f); } } addAll(out, fields); return out; } catch (Throwable __0) { printStackTrace(__0); return fields; } } static public A vm_generalMap_getOrCreate(Object key, F0 create) { return vm_generalMap_getOrCreate(key, f0ToIF0(create)); } static public A vm_generalMap_getOrCreate(Object key, IF0 create) { Map generalMap = vm_generalMap(); if (generalMap == null) return null; synchronized (generalMap) { A a = (A) (vm_generalMap_get(key)); if (a == null) vm_generalMap_put(key, a = create == null ? null : create.get()); return a; } } static public A callF_gen(F0 f) { return f == null ? null : f.get(); } static public B callF_gen(F1 f, A a) { return f == null ? null : f.get(a); } static public A callF_gen(IF0 f) { return f == null ? null : f.get(); } static public B callF_gen(IF1 f, A a) { return f == null ? null : f.get(a); } static public B callF_gen(A a, IF1 f) { return f == null ? null : f.get(a); } static public C callF_gen(IF2 f, A a, B b) { return f == null ? null : f.get(a, b); } static public void callF_gen(VF1 f, A a) { { if (f != null) f.get(a); } } static public void callF_gen(A a, IVF1 f) { { if (f != null) f.get(a); } } static public void callF_gen(IVF1 f, A a) { { if (f != null) f.get(a); } } static public Object callF_gen(Runnable r) { { if (r != null) r.run(); } return null; } static public Object callF_gen(Object f, Object... args) { return callF(f, args); } static public Map syncMRUCache(int size) { return synchroMap(new MRUCache(size)); } static public RuntimeException wrapPatternSyntaxException(PatternSyntaxException e) { if (e == null) return null; String pat = e.getPattern(); int i = e.getIndex(); return new RuntimeException("Regular expression error between " + multiLineQuoteWithSpaces(substring(pat, 0, i)) + " and " + multiLineQuoteWithSpaces(substring(pat, i)) + " - " + e.getMessage()); } static public List dropPunctuation_keep = ll("*", "<", ">"); static public List dropPunctuation(List tok) { tok = new ArrayList(tok); for (int i = 1; i < tok.size(); i += 2) { String t = tok.get(i); if (t.length() == 1 && !Character.isLetter(t.charAt(0)) && !Character.isDigit(t.charAt(0)) && !dropPunctuation_keep.contains(t)) { tok.set(i - 1, tok.get(i - 1) + tok.get(i + 1)); tok.remove(i); tok.remove(i); i -= 2; } } return tok; } static public String dropPunctuation(String s) { return join(dropPunctuation(nlTok(s))); } static public List javaTokPlusPeriod(String s) { List tok = new ArrayList(); if (s == null) return tok; int l = s.length(); int i = 0; while (i < l) { int j = i; char c; String cc; 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)); if (c == (char) 0x201C || c == (char) 0x201D) c = '"'; if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { char _c = s.charAt(j); if (_c == (char) 0x201C || _c == (char) 0x201D) _c = '"'; 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) == '\'')); 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 public List newSubList(List l, int startIndex, int endIndex) { return cloneList(subList(l, startIndex, endIndex)); } static public List newSubList(List l, int startIndex) { return cloneList(subList(l, startIndex)); } static public Set similarEmptySet(Iterable m) { if (m instanceof TreeSet) return new TreeSet(((TreeSet) m).comparator()); if (m instanceof LinkedHashSet) return new LinkedHashSet(); return new HashSet(); } static public Set similarEmptySet(Map m) { if (m instanceof TreeMap) return new TreeSet(((TreeMap) m).comparator()); if (m instanceof LinkedHashMap) return new LinkedHashSet(); return new HashSet(); } static public void multiMapPut(Map> map, A a, B b) { List l = map.get(a); if (l == null) map.put(a, l = new ArrayList()); l.add(b); } static public void multiMapPut(MultiMap mm, A key, B value) { if (mm != null && key != null && value != null) mm.put(key, value); } static public HashSet lithashset(A... items) { HashSet set = new HashSet(); for (A a : items) set.add(a); return set; } static public List tok_combineRoundCurlySquareBrackets_keep(List tok) { List l = new ArrayList(); for (int i = 0; i < l(tok); i++) { String t = tok.get(i); if (odd(i) && eqOneOf(t, "{", "(", "[")) { int j = findEndOfBracketPart2(tok, i); l.add(joinSubList(tok, i, j)); i = j - 1; } else l.add(t); } return l; } static public B mapPutOrRemove(Map map, A key, B value) { if (map != null && key != null) if (value != null) return map.put(key, value); else return map.remove(key); return null; } static public Set synchronizedSet() { return synchroHashSet(); } static public Set synchronizedSet(Set set) { return new SynchronizedSet(set); } static public Set identityHashSet() { return Collections.newSetFromMap(new IdentityHashMap()); } static public Map findBot_cache = synchroHashMap(); static public int findBot_timeout = 5000; static public DialogIO findBot(String searchPattern) { String subBot = null; int i = searchPattern.indexOf('/'); if (i >= 0 && (isJavaIdentifier(searchPattern.substring(0, i)) || isInteger(searchPattern.substring(0, i)))) { subBot = searchPattern.substring(i + 1); searchPattern = searchPattern.substring(0, i); if (!isInteger(searchPattern)) searchPattern = "Multi-Port at " + searchPattern + "."; } if (isInteger(searchPattern)) return talkToSubBot(subBot, talkTo(parseInt(searchPattern))); if (eq(searchPattern, "remote")) return talkToSubBot(subBot, talkTo("second.tinybrain.de", 4999)); Integer port = findBot_cache.get(searchPattern); if (port != null) try { DialogIO io = talkTo("localhost", port); io.waitForLine(); String line = io.readLineNoBlock(); if (indexOfIgnoreCase(line, searchPattern) == 0) { call(io, "pushback", line); return talkToSubBot(subBot, io); } } catch (Exception e) { e.printStackTrace(); } List bots = quickBotScan(); for (ProgramScan.Program p : bots) { if (indexOfIgnoreCase(p.helloString, searchPattern) == 0) { findBot_cache.put(searchPattern, p.port); return talkToSubBot(subBot, talkTo("localhost", p.port)); } } for (ProgramScan.Program p : bots) { String botName = firstPartOfHelloString(p.helloString); boolean isVM = startsWithIgnoreCase(p.helloString, "This is a JavaX VM."); boolean shouldRecurse = startsWithIgnoreCase(botName, "Multi-Port") || isVM; if (shouldRecurse) try { Map subBots = (Map) unstructure(sendToLocalBotQuietly(p.port, "list bots")); for (Number vport : subBots.keySet()) { String name = subBots.get(vport); if (startsWithIgnoreCase(name, searchPattern)) return talkToSubBot(vport.longValue(), talkTo("localhost", p.port)); } } catch (Throwable __e) { print(exceptionToStringShort(__e)); } } return null; } static public String sendToLocalBotOpt(String bot, String text, Object... args) { if (bot == null) return null; text = format(text, args); DialogIO channel = findBot(bot); try { if (channel == null) { print(quote(bot) + " not found, skipping send: " + quote(text)); return null; } try { channel.readLine(); print(shorten(bot + "> " + text, 200)); channel.sendLine(text); String s = channel.readLine(); print(shorten(bot + "< " + s, 200)); return s; } catch (Throwable e) { e.printStackTrace(); return null; } } finally { _close(channel); } } static public WeakReference creator_class; static public Object creator() { return creator_class == null ? null : creator_class.get(); } static public void cleanKillVM() { try { ping(); assertNotOnAWTThread(); cleanKillVM_noSleep(); Object o = new Object(); synchronized (o) { o.wait(); } } catch (Exception __e) { throw rethrow(__e); } } static public void cleanKillVM_noSleep() { call(getJavaX(), "cleanKill"); } static public String fsI_flex(String s) { return startsWithDigit(s) ? "#" + s : s; } static public boolean exposeMethods2_debug = false; static public String exposeMethods2(Object receiver, String s, List methodNames) { return exposeMethods2(receiver, s, methodNames, null); } static public String exposeMethods2(Object receiver, String s, List methodNames, Lock lock) { Matches m = new Matches(); if (exposeMethods2_debug) print("Received: " + s); if (match("call *", s, m)) { List l; if (isIdentifier(m.unq(0))) l = ll(m.unq(0)); else l = (List) unstructure(m.unq(0)); String method = getString(l, 0); if (!contains(methodNames, method)) throw fail("Method not allowed: " + method); if (lock != null) lock.lock(); try { if (exposeMethods2_debug) print("Calling: " + method); Object o = call(receiver, method, asObjectArray(subList(l, 1))); if (exposeMethods2_debug) print("Got: " + getClassName(o)); return ok2(structure(o)); } finally { if (lock != null) lock.unlock(); } } if (match("list methods", s)) return ok2(structure(methodNames)); return null; } static public int makeBot(String greeting) { return makeAndroid3(greeting).port; } static public Android3 makeBot(Android3 a) { makeAndroid3(a); return a; } static public Android3 makeBot(String greeting, Object responder) { Android3 a = new Android3(greeting); a.responder = makeResponder(responder); makeBot(a); return a; } static public Android3 makeBot() { return makeAndroid3(defaultBotName()); } static public boolean sameSnippetID(String a, String b) { if (!isSnippetID(a) || !isSnippetID(b)) return false; return parseSnippetID(a) == parseSnippetID(b); } static public Map compileRegexp_cache = syncMRUCache(10); static public java.util.regex.Pattern compileRegexp(String pat) { java.util.regex.Pattern p = compileRegexp_cache.get(pat); if (p == null) { compileRegexp_cache.put(pat, p = java.util.regex.Pattern.compile(pat)); } return p; } static public List listFilesOnly(String dir) { return listFilesOnly(new File(dir)); } static public List listFilesOnly(File... dirs) { return concatMap(dir -> listFilesWithSuffix("", dir), dirs); } static public Comparator mapComparator(final Map map) { return new Comparator() { public int compare(A a, A b) { return cmp(map.get(a), map.get(b)); } }; } static public String quoteIfNotIdentifierOrInteger(String s) { if (s == null) return null; return isJavaIdentifier(s) || isInteger(s) ? s : quote(s); } static public TreeSet litciset(String... items) { TreeSet set = caseInsensitiveSet(); for (String a : items) set.add(a); return set; } static public TreeSet litciset(Symbol... items) { TreeSet set = treeSet(); for (Symbol a : items) set.add(a); return set; } static public String afterLastSpace(String s) { return s == null ? null : substring(s, s.lastIndexOf(' ') + 1); } static public String dropSuffixIgnoreCase(String suffix, String s) { return ewic(s, suffix) ? s.substring(0, l(s) - l(suffix)) : s; } static public boolean ewicOneOf(String s, String... l) { if (s != null) for (String x : l) if (ewic(s, x)) return true; return false; } static public Class run(String progID, String... args) { Class main = hotwire(progID); callMain(main, args); return main; } static public void restart() { Object j = getJavaX(); call(j, "cleanRestart", get(j, "fullArgs")); } static volatile public boolean sleep_noSleep = false; static public void sleep(long ms) { ping(); if (ms < 0) return; if (isAWTThread() && ms > 100) throw fail("Should not sleep on AWT thread"); try { Thread.sleep(ms); } catch (Exception e) { throw new RuntimeException(e); } } static public void sleep() { try { if (sleep_noSleep) throw fail("nosleep"); print("Sleeping."); sleepQuietly(); } catch (Exception __e) { throw rethrow(__e); } } static public Map vm_threadInterruptionReasonsMap() { return vm_generalWeakSubMap("Thread interruption reasons"); } static public String strOr(Object o, String ifNull) { return o == null ? ifNull : str(o); } static public void lockOrFail(Lock lock, long timeout) { try { ping(); vmBus_send("locking", lock, "thread", currentThread()); if (!lock.tryLock(timeout, TimeUnit.MILLISECONDS)) { String s = "Couldn't acquire lock after " + timeout + " ms."; if (lock instanceof ReentrantLock) { ReentrantLock l = (ReentrantLock) lock; s += " Hold count: " + l.getHoldCount() + ", owner: " + call(l, "getOwner"); } throw fail(s); } vmBus_send("locked", lock, "thread", currentThread()); ping(); } catch (Exception __e) { throw rethrow(__e); } } static public ReentrantLock fairLock() { return new ReentrantLock(true); } static public Rect toRect(Rectangle r) { return r == null ? null : new Rect(r); } static public Rect toRect(RectangularShape r) { return r == null ? null : toRect(r.getBounds()); } static public Rect toRect(Rect r) { return r; } static public String htmlencode_forParams_v2(String s) { if (s == null) return ""; StringBuilder out = new StringBuilder(Math.max(16, s.length())); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c > 127 || c == '"' || c == '<' || c == '>' || c == '&') { out.append("&#"); out.append((int) c); out.append(';'); } else out.append(c); } return out.toString(); } static public void _onJavaXSet() { } static public Runnable addThreadInfoToRunnable(final Object r) { final Object info = _threadInfo(); return info == null ? asRunnable(r) : new Runnable() { public void run() { try { _inheritThreadInfo(info); callF(r); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "_inheritThreadInfo(info); callF(r);"; } }; } static public List buttonsInGroup(ButtonGroup g) { if (g == null) return ll(); return asList(g.getElements()); } static public String mcName() { return mc().getName(); } static public ThreadLocal realMC_tl_tl = new ThreadLocal(); static public ThreadLocal realMC_tl() { return realMC_tl_tl; } static public char stringToChar(String s) { if (l(s) != 1) throw fail("bad stringToChar: " + s); return firstChar(s); } static public Throwable getException(Runnable r) { try { callF(r); return null; } catch (Throwable e) { return e; } } static public A[] arrayOfType(Class type, int n) { return makeArray(type, n); } static public A[] arrayOfType(int n, Class type) { return arrayOfType(type, n); } static public TreeSet toCaseInsensitiveSet_treeSet(Iterable c) { if (isCISet(c)) return (TreeSet) c; TreeSet set = caseInsensitiveSet_treeSet(); addAll(set, c); return set; } static public TreeSet toCaseInsensitiveSet_treeSet(String... x) { TreeSet set = caseInsensitiveSet_treeSet(); addAll(set, x); return set; } static public void _registerIO(Object object, String path, boolean opened) { } static public String collapseWord(String s) { if (s == null) return ""; StringBuilder buf = new StringBuilder(); for (int i = 0; i < l(s); i++) if (i == 0 || !charactersEqualIC(s.charAt(i), s.charAt(i - 1))) buf.append(s.charAt(i)); return buf.toString(); } static public List toLowerCase(List strings) { List x = new ArrayList(); for (String s : strings) x.add(s.toLowerCase()); return x; } static public String[] toLowerCase(String[] strings) { String[] x = new String[l(strings)]; for (int i = 0; i < l(strings); i++) x[i] = strings[i].toLowerCase(); return x; } static public String toLowerCase(String s) { return s == null ? "" : s.toLowerCase(); } static public String firstWord2(String s) { s = xltrim(s); if (empty(s)) return ""; if (isLetterOrDigit(first(s))) return takeCharsWhile(__35 -> isLetterOrDigit(__35), s); else return "" + first(s); } static public IMeta initMetaOfJComponent(JComponent c) { if (c == null) return null; IMeta meta = (IMeta) (c.getClientProperty(IMeta.class)); if (meta == null) c.putClientProperty(IMeta.class, meta = new Meta()); return meta; } static public A optCast(Class c, Object o) { return isInstance(c, o) ? (A) o : null; } static public int lastIndexOf(String a, String b) { return a == null || b == null ? -1 : a.lastIndexOf(b); } static public int lastIndexOf(String a, char b) { return a == null ? -1 : a.lastIndexOf(b); } static public int lastIndexOf(List l, int i, A a) { if (l == null) return -1; for (i = min(l(l), i) - 1; i >= 0; i--) if (eq(l.get(i), a)) return i; return -1; } static public int lastIndexOf(List l, A a) { if (l == null) return -1; for (int i = l(l) - 1; i >= 0; i--) if (eq(l.get(i), a)) return i; return -1; } static public String beautifyStructure(String s) { List tok = javaTokForStructure(s); structure_addTokenMarkers(tok); jreplace(tok, "lhm", ""); return join(tok); } static public ThreadLocal assertVerbose_value = new ThreadLocal(); static public void assertVerbose(boolean b) { assertVerbose_value.set(b); } static public boolean assertVerbose() { return isTrue(assertVerbose_value.get()); } static public A assertEqualsVerbose(Object x, A y) { assertEqualsVerbose((String) null, x, y); return y; } static public A assertEqualsVerbose(String msg, Object x, A y) { if (!eq(x, y)) { throw fail((nempty(msg) ? msg + ": " : "") + "expected: " + x + ", got: " + y); } else print("OK" + (empty(msg) ? "" : " " + msg) + ": " + (x)); return y; } static public void assertEqualsVerbose(Scorer scorer, Object x, Object y) { assertEqualsVerbose(scorer, "", x, y); } static public void assertEqualsVerbose(Scorer scorer, String msg, Object x, Object y) { if (scorer == null) { assertEqualsVerbose(x, y); return; } if (!eq(x, y)) { print(appendColonIfNempty(msg) + y + " != " + x); scorer.add(false); } else { print("OK: " + appendColonIfNempty(msg) + x); scorer.add(true); } } static public String nullIfEmpty(String s) { return isEmpty(s) ? null : s; } static public Map nullIfEmpty(Map map) { return isEmpty(map) ? null : map; } static public List nullIfEmpty(List l) { return isEmpty(l) ? null : l; } static public boolean isDigit(char c) { return Character.isDigit(c); } static public boolean isBoxedType(Class type) { return type == Boolean.class || type == Integer.class || type == Long.class || type == Float.class || type == Short.class || type == Character.class || type == Byte.class || type == Double.class; } static public boolean isArrayType(Class type) { return type != null && type.isArray(); } static public boolean hasThisDollarFields(Object o) { Matches m = new Matches(); for (var f : allFieldObjects_dontMakeAccessible(o)) if (startsWith(f.getName(), "this$", m) && isInteger(m.rest())) return true; return false; } static public boolean hasSingleArgumentConstructor(Class c) { if (c != null) for (Constructor m : getDeclaredConstructors_cached(c)) if (l(m.getParameterTypes()) == 1) return true; return false; } static public 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 public List> mapPairB(final Object f, Iterable> l) { return map(l, new F1, Pair>() { public Pair get(Pair p) { try { return p == null ? null : pair(p.a, (C) callF(f, p.b)); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "p == null ? null : pair(p.a, (C) callF(f, p.b))"; } }); } static public List> mapPairB(final F1 f, Iterable> l) { return mapPairB((Object) f, l); } static public List> mapPairB(final IF1 f, Iterable> l) { return mapPairB((Object) f, l); } static public List> mapPairB(Iterable> l, IF1 f) { return mapPairB((Object) f, l); } static public Pair mapPairB(IF1 f, Pair p) { return pairMapB(f, p); } static public Pair mapPairB(Pair p, IF1 f) { return pairMapB(f, p); } static public Method findMethod(Object o, String method, Object... args) { return findMethod_cached(o, method, args); } static public boolean findMethod_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 public Map mapToKey(Iterable l, IF1 f) { return mapToKeys(l, f); } static public Map mapToKey(IF1 f, Iterable l) { return mapToKeys(f, l); } static public void addAll(Collection c, Iterable b) { if (c != null && b != null) for (A a : b) c.add(a); } static public boolean addAll(Collection c, Collection b) { return c != null && b != null && c.addAll(b); } static public boolean addAll(Collection c, B... b) { return c != null && b != null && c.addAll(Arrays.asList(b)); } static public Map addAll(Map a, Map b) { if (a != null && b != null) a.putAll(b); return a; } static public A addAll(A c, Collection components) { return addComponents(c, components); } static public A addAll(A c, Component... components) { return addComponents(c, components); } static public IF0 f0ToIF0(F0 f) { return f == null ? null : () -> f.get(); } static public String multiLineQuoteWithSpaces(String s) { return multiLineQuote(" " + s + " "); } static public List nlTok(String s) { return javaTokPlusPeriod(s); } static public int findEndOfBracketPart2(List cnc, int i) { int j = i + 2, level = 1; while (j < cnc.size()) { if (eqOneOf(cnc.get(j), "{", "(", "[")) ++level; else if (eqOneOf(cnc.get(j), "}", ")", "]")) --level; if (level == 0) return j + 1; ++j; } return cnc.size(); } static public Set synchroHashSet() { return synchronizedSet(new HashSet()); } static public DialogIO talkToSubBot(final long vport, final DialogIO io) { return talkToSubBot(String.valueOf(vport), io); } static public DialogIO talkToSubBot(final String subBot, final DialogIO io) { if (subBot == null) return io; return new talkToSubBot_IO(subBot, io); } static public class talkToSubBot_IO extends DialogIO { public String subBot; public DialogIO io; public talkToSubBot_IO(String subBot, DialogIO io) { this.io = io; this.subBot = subBot; } public boolean isStillConnected() { return io.isStillConnected(); } public String readLineImpl() { return io.readLineImpl(); } public boolean isLocalConnection() { return io.isLocalConnection(); } public Socket getSocket() { return io.getSocket(); } public void close() { try { io.close(); } catch (Exception __e) { throw rethrow(__e); } } public void sendLine(String line) { io.sendLine(format3("please forward to bot *: *", subBot, line)); } } static public DialogIO talkTo(int port) { return talkTo("localhost", port); } static public int talkTo_defaultTimeout = 10000; static public int talkTo_timeoutForReads = 0; static public ThreadLocal> talkTo_byThread = new ThreadLocal(); static public DialogIO talkTo(String ip, int port) { try { String full = ip + ":" + port; Map map = talkTo_byThread.get(); if (map != null && map.containsKey(full)) return map.get(full); if (isLocalhost(ip) && port == vmPort()) return talkToThisVM(); return new talkTo_IO(ip, port); } catch (Exception __e) { throw rethrow(__e); } } static public class talkTo_IO extends DialogIO { public String ip; public int port; public Socket s; public Writer w; public BufferedReader in; public talkTo_IO(String ip, int port) { this.port = port; this.ip = ip; try { s = new Socket(); try { if (talkTo_timeoutForReads != 0) s.setSoTimeout(talkTo_timeoutForReads); s.connect(new InetSocketAddress(ip, port), talkTo_defaultTimeout); } catch (Throwable e) { throw fail("Tried talking to " + ip + ":" + port, e); } w = new OutputStreamWriter(s.getOutputStream(), "UTF-8"); in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8")); } catch (Exception __e) { throw rethrow(__e); } } public boolean isLocalConnection() { return s.getInetAddress().isLoopbackAddress(); } public boolean isStillConnected() { return !(eos || s.isClosed()); } public void sendLine(String line) { try { Lock __0 = lock; lock(__0); try { w.write(line + "\n"); w.flush(); } finally { unlock(__0); } } catch (Exception __e) { throw rethrow(__e); } } public String readLineImpl() { try { return in.readLine(); } catch (Exception __e) { throw rethrow(__e); } } public void close() { try { if (!noClose) s.close(); } catch (IOException e) { } } public Socket getSocket() { return s; } } static public int indexOfIgnoreCase(List a, String b) { return indexOfIgnoreCase(a, b, 0); } static public int indexOfIgnoreCase(List a, String b, int i) { int n = a == null ? 0 : a.size(); for (; i < n; i++) if (eqic(a.get(i), b)) return i; return -1; } static public int indexOfIgnoreCase(String[] a, String b) { return indexOfIgnoreCase(a, b, 0); } static public int indexOfIgnoreCase(String[] a, String b, int i) { int n = a == null ? 0 : a.length; for (; i < n; i++) if (eqic(a[i], b)) return i; return -1; } static public int indexOfIgnoreCase(String a, String b) { return indexOfIgnoreCase_manual(a, b); } static public int indexOfIgnoreCase(String a, String b, int i) { return indexOfIgnoreCase_manual(a, b, i); } static public List quickBotScan() { return ProgramScan.quickBotScan(); } static public List quickBotScan(int[] preferredPorts) { return ProgramScan.quickBotScan(preferredPorts); } static public List quickBotScan(String searchPattern) { List l = new ArrayList(); for (ProgramScan.Program p : ProgramScan.quickBotScan()) if (indexOfIgnoreCase(p.helloString, searchPattern) == 0) l.add(p); return l; } static public String firstPartOfHelloString(String s) { int i = s.lastIndexOf('/'); return i < 0 ? s : rtrim(s.substring(0, i)); } static public String sendToLocalBotQuietly(String bot, String text, Object... args) { text = format3(text, args); DialogIO channel = newFindBot2(bot); try { if (channel == null) throw fail(quote(bot) + " not found"); try { channel.readLine(); channel.sendLine(text); String s = channel.readLine(); return s; } catch (Throwable e) { e.printStackTrace(); return null; } } finally { _close(channel); } } static public String sendToLocalBotQuietly(int port, String text, Object... args) { text = format3(text, args); DialogIO channel = talkTo(port); try { try { channel.readLine(); channel.sendLine(text); String s = channel.readLine(); return s; } catch (Throwable e) { e.printStackTrace(); return null; } } finally { _close(channel); } } static public String format(String pat, Object... args) { return format3(pat, args); } static public void assertNotOnAWTThread() { assertFalse("Can't do this in AWT thread", isAWTThread()); } static public boolean match(String pat, String s) { return match3(pat, s); } static public boolean match(String pat, String s, Matches matches) { return match3(pat, s, matches); } static public boolean match(String pat, List toks, Matches matches) { return match3(pat, toks, matches); } static public Object[] asObjectArray(Collection l) { return toObjectArray(l); } static public String ok2(String s) { return "ok " + s; } static public boolean makeAndroid3_disable = false; static public class Android3 implements AutoCloseable { public String greeting; public boolean publicOverride = false; public int startPort = 5000; public Responder responder; public boolean console = true; public boolean quiet = false; public boolean daemon = false; public boolean incomingSilent = false; public int incomingPrintLimit = 200; public boolean useMultiPort = true; public boolean recordHistory = false; public boolean verbose = false; public int answerPrintLimit = 500; public boolean newLineAboveAnswer, newLineBelowAnswer; public int port; public long vport; public DialogHandler handler; public ServerSocket server; public Android3(String greeting) { this.greeting = greeting; } public Android3() { } public void close() { dispose(); } synchronized public void dispose() { if (server != null) { try { server.close(); } catch (IOException e) { print("[internal] " + e); } server = null; } if (vport != 0) { try { print("Disposing " + this); removeFromMultiPort(vport); vport = 0; } catch (Throwable __e) { printStackTrace(__e); } } } public String toString() { return "Bot: " + greeting + " [vport " + vport + "]"; } } static abstract public class Responder { abstract public String answer(String s, List history); } static public Android3 makeAndroid3(final String greeting) { return makeAndroid3(new Android3(greeting)); } static public Android3 makeAndroid3(final String greeting, Responder responder) { Android3 android = new Android3(greeting); android.responder = responder; return makeAndroid3(android); } static public Android3 makeAndroid3(final Android3 a) { if (makeAndroid3_disable) return a; if (a.responder == null) a.responder = new Responder() { public String answer(String s, List history) { return callStaticAnswerMethod(s, history); } }; if (!a.quiet) print("[bot] " + a.greeting); if (a.console && (readLine_noReadLine || makeAndroid3_consoleInUse())) a.console = false; record(a); if (a.useMultiPort) a.vport = addToMultiPort(a.greeting, makeAndroid3_verboseResponder(a)); if (a.console) makeAndroid3_handleConsole(a); if (a.useMultiPort) return a; a.handler = makeAndroid3_makeDialogHandler(a); if (a.quiet) startDialogServer_quiet.set(true); try { a.port = a.daemon ? startDialogServerOnPortAboveDaemon(a.startPort, a.handler) : startDialogServerOnPortAbove(a.startPort, a.handler); } finally { startDialogServer_quiet.set(null); } a.server = startDialogServer_serverSocket; return a; } static public void makeAndroid3_handleConsole(final Android3 a) { if (!a.quiet) print("You may also type on this console."); { startThread(new Runnable() { public void run() { try { List history = new ArrayList(); while (licensed()) { String line; try { line = readLine(); } catch (Throwable e) { print(getInnerMessage(e)); break; } if (line == null) break; { history.add(line); history.add(makeAndroid3_getAnswer(line, history, a)); } } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "List history = new ArrayList();\r\n while (licensed()) {\r\n Stri..."; } }); } } static public DialogHandler makeAndroid3_makeDialogHandler(final Android3 a) { return new DialogHandler() { public void run(final DialogIO io) { if (!a.publicOverride && !(publicCommOn() || io.isLocalConnection())) { io.sendLine("Sorry, not allowed"); return; } String dialogID = randomID(8); io.sendLine(a.greeting + " / Your ID: " + dialogID); List history = new ArrayList(); while (io.isStillConnected()) { if (io.waitForLine()) { final String line = io.readLineNoBlock(); String s = dialogID + " at " + now() + ": " + quote(line); if (!a.incomingSilent) print(shorten(s, a.incomingPrintLimit)); if (eq(line, "bye")) { io.sendLine("bye stranger"); return; } Matches m = new Matches(); if (a.recordHistory) history.add(line); String answer; if (match3("this is a continuation of talk *", s, m) || match3("hello bot! this is a continuation of talk *", s, m)) { dialogID = unquote(m.m[0]); answer = "ok"; } else try { makeAndroid3_io.set(io); answer = makeAndroid3_getAnswer(line, history, a); } finally { makeAndroid3_io.set(null); } if (a.recordHistory) history.add(answer); io.sendLine(answer); } } } }; } static public String makeAndroid3_getAnswer(String line, List history, Android3 a) { String answer, originalAnswer; try { originalAnswer = a.responder.answer(line, history); answer = makeAndroid3_fallback(line, history, originalAnswer); } catch (Throwable e) { e = getInnerException(e); printStackTrace(e); originalAnswer = answer = e.toString(); } if (!a.incomingSilent) { if (originalAnswer == null) originalAnswer = "?"; if (a.newLineAboveAnswer) print(); print(">" + dropFirst(indentx(2, shorten(rtrim(originalAnswer), a.answerPrintLimit)))); if (a.newLineBelowAnswer) print(); } return answer; } static public String makeAndroid3_fallback(String s, List history, String answer) { if (answer == null && match3("what is your pid", s)) return getPID(); if (answer == null && match3("what is your program id", s)) return getProgramID(); if (match3("get injection id", s)) return getInjectionID(); if (answer == null) answer = "?"; if (answer.indexOf('\n') >= 0 || answer.indexOf('\r') >= 0) answer = quote(answer); return answer; } static public boolean makeAndroid3_consoleInUse() { if (isTrue(vm_generalMap_get("consoleInUse"))) return true; for (Object o : record_list) if (o instanceof Android3 && ((Android3) o).console) return true; return false; } static public Responder makeAndroid3_verboseResponder(final Android3 a) { return new Responder() { public String answer(String s, List history) { if (a.verbose) print("> " + shorten(s, a.incomingPrintLimit)); String answer = a.responder.answer(s, history); if (a.verbose) print("< " + shorten(answer, a.incomingPrintLimit)); return answer; } }; } static public ThreadLocal makeAndroid3_io = new ThreadLocal(); static public Android3 makeAndroid3() { return makeAndroid3(getProgramTitle() + "."); } static public String makeResponder_callAnswerMethod(Object bot, String s, List history) { String answer = (String) callOpt(bot, "answer", s, history); if (answer == null) answer = (String) callOpt(bot, "answer", s); return answer; } static public Responder makeResponder(final Object bot) { if (bot instanceof Responder) return (Responder) bot; if (bot instanceof String) { String f = (String) bot; return new Responder() { public String answer(String s, List history) { String answer = (String) callOptMC((String) bot, s, history); if (answer == null) answer = (String) callOptMC((String) bot, s); return answer; } }; } return new Responder() { public String answer(String s, List history) { return makeResponder_callAnswerMethod(bot, s, history); } }; } static public String defaultBotName() { return getProgramTitle() + "."; } static public List concatMap(Object f, Iterable l) { return concatLists(map(f, l)); } static public List concatMap(Iterable l, Object f) { return concatMap(f, l); } static public List concatMap(Object f, Object[] l) { return concatLists(map(f, l)); } static public List concatMap(Object[] l, Object f) { return concatMap(f, l); } static public > List concatMap(Iterable l, IF1 f) { return concatMap(l, (Object) f); } static public > List concatMap(IF1 f, Iterable l) { return concatMap(l, f); } static public > List concatMap(IF1 f, A[] l) { return concatMap((Object) f, l); } static public List listFilesWithSuffix(File dir, String suffix) { List l = new ArrayList(); for (File f : listFiles(dir)) if (!f.isDirectory() && (empty(suffix) || endsWithIgnoreCase(f.getName(), suffix))) l.add(f); return l; } static public List listFilesWithSuffix(String suffix, File dir) { return listFilesWithSuffix(dir, suffix); } static public TreeSet treeSet() { return new TreeSet(); } static public Class hotwire(String src) { return hotwire(src, __1 -> mainClassNameForClassLoader(__1)); } static public Class hotwire(String src, IF1 calculateMainClass) { assertFalse(_inCore()); Class j = getJavaX(); if (isAndroid()) { synchronized (j) { List libraries = new ArrayList(); File srcDir = (File) call(j, "transpileMain", src, libraries); if (srcDir == null) throw fail("transpileMain returned null (src=" + quote(src) + ")"); Object androidContext = get(j, "androidContext"); return (Class) call(j, "loadx2android", srcDir, src); } } else { Class c = (Class) (call(j, "hotwire", src)); hotwire_copyOver(c); return c; } } static public A callMain(A c, String... args) { callOpt(c, "main", new Object[] { args }); return c; } static public void callMain() { callMain(mc()); } static public Object sleepQuietly_monitor = new Object(); static public void sleepQuietly() { try { assertFalse(isAWTThread()); synchronized (sleepQuietly_monitor) { sleepQuietly_monitor.wait(); } } catch (Exception __e) { throw rethrow(__e); } } static public Map vm_generalWeakSubMap(Object name) { synchronized (vm_generalMap()) { Map map = (Map) (vm_generalMap_get(name)); if (map == null) vm_generalMap_put(name, map = newWeakMap()); return map; } } static public List> _threadInfo_makers = synchroList(); static public Object _threadInfo() { if (empty(_threadInfo_makers)) return null; HashMap map = new HashMap(); pcallFAll(_threadInfo_makers, map); return map; } static public Runnable asRunnable(Object o) { return toRunnable(o); } static public void _inheritThreadInfo(Object info) { _threadInheritInfo(info); } static public char firstChar(String s) { return s.charAt(0); } static public A[] makeArray(Class type, int n) { return (A[]) Array.newInstance(type, n); } static public boolean isCISet(Iterable l) { return l instanceof TreeSet && ((TreeSet) l).comparator() == caseInsensitiveComparator(); } static public boolean charactersEqualIC(char c1, char c2) { if (c1 == c2) return true; char u1 = Character.toUpperCase(c1); char u2 = Character.toUpperCase(c2); if (u1 == u2) return true; return Character.toLowerCase(u1) == Character.toLowerCase(u2); } static public String xltrim(String s) { int i = 0, n = l(s); while (i < n && contains(" \t\r\n", s.charAt(i))) ++i; return substr(s, i); } static public boolean isLetterOrDigit(char c) { return Character.isLetterOrDigit(c); } static public String takeCharsWhile(String s, Object pred) { int i = 0; while (i < l(s) && isTrue(callF(pred, s.charAt(i)))) ++i; return substring(s, 0, i); } static public String takeCharsWhile(IF1 f, String s) { return takeCharsWhile(s, f); } static public List javaTokForStructure(String s) { return javaTok_noMLS(s); } static public String structure_addTokenMarkers(String s) { return join(structure_addTokenMarkers(javaTokForStructure(s))); } static public List structure_addTokenMarkers(List tok) { TreeSet refs = new TreeSet(); for (int i = 1; i < l(tok); i += 2) { String t = tok.get(i); if (t.startsWith("t") && isInteger(t.substring(1))) refs.add(parseInt(t.substring(1))); } if (empty(refs)) return tok; for (int i : refs) { int idx = i * 2 + 1; if (idx >= l(tok)) continue; String t = ""; if (endsWithLetterOrDigit(tok.get(idx - 1))) t = " "; tok.set(idx, t + "m" + i + " " + tok.get(idx)); } return tok; } static public String jreplace(String s, String in, String out) { return jreplace(s, in, out, null); } static public String jreplace(String s, String in, String out, Object condition) { List tok = javaTok(s); return jreplace(tok, in, out, condition) ? join(tok) : s; } static public boolean jreplace(List tok, String in, String out) { return jreplace(tok, in, out, false, true, null); } static public boolean jreplace(List tok, String in, String out, Object condition) { return jreplace(tok, in, out, false, true, condition); } static public boolean jreplace(List tok, String in, String out, IF2, Integer, Boolean> condition) { return jreplace(tok, in, out, (Object) condition); } static public boolean jreplace(List tok, String in, String out, boolean ignoreCase, boolean reTok, Object condition) { String[] toks = javaTokForJFind_array(in); int lTokin = toks.length * 2 + 1; boolean anyChange = false; int i = -1; for (int n = 0; n < 10000; n++) { i = findCodeTokens(tok, i + 1, ignoreCase, toks, condition); if (i < 0) return anyChange; List subList = tok.subList(i - 1, i + lTokin - 1); String expansion = jreplaceExpandRefs(out, subList); int end = i + lTokin - 2; clearAllTokens(tok, i, end); tok.set(i, expansion); if (reTok) reTok(tok, i, end); i = end; anyChange = true; } throw fail("woot? 10000! " + quote(in) + " => " + quote(out)); } static public boolean jreplace_debug = false; static public String appendColonIfNempty(String s) { return empty(s) ? "" : s + ": "; } static public boolean isEmpty(Collection c) { return c == null || c.isEmpty(); } static public boolean isEmpty(CharSequence s) { return s == null || s.length() == 0; } static public boolean isEmpty(Object[] a) { return a == null || a.length == 0; } static public boolean isEmpty(byte[] a) { return a == null || a.length == 0; } static public boolean isEmpty(Map map) { return map == null || map.isEmpty(); } static public boolean isEmpty(AppendableChain c) { return c == null; } static public List allFieldObjects_dontMakeAccessible(Object o) { List fields = new ArrayList(); Class _c = _getClass(o); do { addAll(fields, _c.getDeclaredFields()); _c = _c.getSuperclass(); } while (_c != null); return fields; } static public Pair pairMapB(Object f, Pair p) { return p == null ? null : pair(p.a, callF(f, p.b)); } static public Pair pairMapB(IF1 f, Pair p) { return p == null ? null : pair(p.a, f.get(p.b)); } static public Pair pairMapB(Pair p, Object f) { return pairMap(f, p); } static public Method findMethod_cached(Object o, String method, Object... args) { try { if (o == null) return null; if (o instanceof Class) { _MethodCache cache = callOpt_getCache((Class) o); List methods = cache.cache.get(method); if (methods != null) for (Method m : methods) if (isStaticMethod(m) && findMethod_checkArgs(m, args, false)) return m; return null; } else { _MethodCache cache = callOpt_getCache(o.getClass()); List methods = cache.cache.get(method); if (methods != null) for (Method m : methods) if (findMethod_checkArgs(m, args, false)) return m; return null; } } catch (Exception __e) { throw rethrow(__e); } } static public Map mapToKeys(Iterable l, IF1 f) { if (l == null) return null; HashMap map = new HashMap(); for (A a : l) map.put(f.get(a), a); return map; } static public Map mapToKeys(IF1 f, A[] l) { return mapToKeys(f, asList(l)); } static public Map mapToKeys(IF1 f, Iterable l) { return mapToKeys(l, f); } static public A addComponents(A c, Collection components) { if (nempty(components)) { swing(() -> { for (Component comp : components) if (comp != null) c.add(comp); revalidate(c); }); } return c; } static public A addComponents(A c, Component... components) { return addComponents(c, asList(components)); } static public String multiLineQuote(String s) { for (int i = 0; ; i++) { String closer = "]" + rep('=', i) + "]"; if (!contains(s, closer)) return "[" + rep('=', i) + "[" + s + closer; } } static public 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 public 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 public boolean isLocalhost(String ip) { return isLoopbackIP(ip) || eqic(ip, "localhost"); } static public int vmPort() { return myVMPort(); } static public DialogIO talkToThisVM() { return new talkToThisVM_IO(); } static public class talkToThisVM_IO extends DialogIO { public List answers = ll(thisVMGreeting()); public boolean isLocalConnection() { return true; } public boolean isStillConnected() { return true; } public int getPort() { return vmPort(); } public void sendLine(String line) { answers.add(or2(sendToThisVM_newThread(line), "?")); } public String readLineImpl() { try { return popFirst(answers); } catch (Exception __e) { throw rethrow(__e); } } public void close() { } public Socket getSocket() { return null; } } static public int indexOfIgnoreCase_manual(String a, String b) { return indexOfIgnoreCase_manual(a, b, 0); } static public int indexOfIgnoreCase_manual(String a, String b, int i) { int la = strL(a), lb = strL(b); if (la < lb) return -1; int n = la - lb; loop: for (; i <= n; i++) { for (int j = 0; j < lb; j++) { char c1 = a.charAt(i + j), c2 = b.charAt(j); if (!eqic(c1, c2)) continue loop; } return i; } return -1; } public static String rtrim(String s) { if (s == null) return null; 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 public Map newFindBot2_cache = synchroHashMap(); static public boolean newFindBot2_verbose = false; static public DialogIO newFindBot2(String name) { Integer port = newFindBot2_cache.get(name); if (port != null) { if (newFindBot2_verbose) print("newFindBot2: testing " + name + " => " + port); DialogIO io = talkTo(port); String q = format("has bot *", name); String s = io.ask(q); if (match("yes", s)) { io = talkToSubBot(name, io); call(io, "pushback", "?"); return io; } newFindBot2_cache.remove(name); if (newFindBot2_verbose) print("newFindBot2: dropping " + name + " => " + port); } DialogIO io = findBot(name); if (io != null) { newFindBot2_cache.put(name, io.getPort()); if (newFindBot2_verbose) print("newFindBot2: remembering " + name + " => " + port); } return io; } static public void assertFalse(Object o) { if (!(eq(o, false))) throw fail(str(o)); } static public boolean assertFalse(boolean b) { if (b) throw fail("oops"); return b; } static public boolean assertFalse(String msg, boolean b) { if (b) throw fail(msg); return b; } static public void removeFromMultiPort(long vport) { if (vport == 0) return; for (Object port : getMultiPorts()) call(port, "removePort", vport); } static public String callStaticAnswerMethod(List bots, String s) { for (Object c : bots) try { String answer = callStaticAnswerMethod(c, s); if (!empty(answer)) return answer; } catch (Throwable e) { print("Error calling " + getProgramID(c)); e.printStackTrace(); } return null; } static public String callStaticAnswerMethod(Object c, String s) { String answer = (String) callOpt(c, "answer", s, litlist(s)); if (answer == null) answer = (String) callOpt(c, "answer", s); return emptyToNull(answer); } static public String callStaticAnswerMethod(String s) { return callStaticAnswerMethod(mc(), s); } static public String callStaticAnswerMethod(String s, List history) { return callStaticAnswerMethod(mc(), s, history); } static public String callStaticAnswerMethod(Object c, String s, List history) { String answer = (String) callOpt(c, "answer", s, history); if (answer == null) answer = (String) callOpt(c, "answer", s); return emptyToNull(answer); } static public List record_list = synchroList(); static public void record(Object o) { record_list.add(o); } static public Object addToMultiPort_responder; static public long addToMultiPort(final String botName) { return addToMultiPort(botName, new Object() { public String answer(String s, List history) { String answer = (String) (callOpt(getMainClass(), "answer", s, history)); if (answer != null) return answer; answer = (String) callOpt(getMainClass(), "answer", s); if (answer != null) return answer; if (match3("get injection id", s)) return getInjectionID(); return null; } }); } static public long addToMultiPort(final String botName, final Object responder) { addToMultiPort_responder = responder; startMultiPort(); List ports = getMultiPorts(); if (ports == null) return 0; if (ports.isEmpty()) throw fail("No multiports!"); if (ports.size() > 1) print("Multiple multi-ports. Using last one."); Object port = last(ports); Object responder2 = new Object() { public String answer(String s, List history) { if (match3("get injection id", s)) return getInjectionID(); if (match3("your name", s)) return botName; return (String) call(responder, "answer", s, history); } }; record(responder2); return (Long) call(port, "addResponder", botName, responder2); } static public AtomicInteger dialogServer_clients = new AtomicInteger(); static public boolean dialogServer_printConnects = false; static public ThreadLocal startDialogServer_quiet = new ThreadLocal(); static public Set dialogServer_knownClients = synchroTreeSet(); static public int startDialogServerOnPortAbove(int port, DialogHandler handler) { while (!forbiddenPort(port) && !startDialogServerIfPortAvailable(port, handler)) ++port; return port; } static public int startDialogServerOnPortAboveDaemon(int port, DialogHandler handler) { while (!forbiddenPort(port) && !startDialogServerIfPortAvailable(port, handler, true)) ++port; return port; } static public void startDialogServer(int port, DialogHandler handler) { if (!startDialogServerIfPortAvailable(port, handler)) throw fail("Can't start dialog server on port " + port); } static public boolean startDialogServerIfPortAvailable(int port, final DialogHandler handler) { return startDialogServerIfPortAvailable(port, handler, false); } static public ServerSocket startDialogServer_serverSocket; static public boolean startDialogServerIfPortAvailable(int port, final DialogHandler handler, boolean daemon) { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(port); } catch (IOException e) { return false; } final ServerSocket _serverSocket = serverSocket; startDialogServer_serverSocket = serverSocket; Thread thread = new Thread("Socket accept port " + port) { public void run() { try { while (true) { try { final Socket s = _serverSocket.accept(); String client = s.getInetAddress().toString(); if (!dialogServer_knownClients.contains(client) && neq(client, "/127.0.0.1")) { print("connect from " + client + " - clients: " + dialogServer_clients.incrementAndGet()); dialogServer_knownClients.add(client); } String threadName = "Handling client " + s.getInetAddress(); Thread t2 = new Thread(threadName) { public void run() { try { final Writer w = new OutputStreamWriter(s.getOutputStream(), "UTF-8"); final BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8")); DialogIO io = new DialogIO() { public boolean isLocalConnection() { return s.getInetAddress().isLoopbackAddress(); } public boolean isStillConnected() { return !(eos || s.isClosed()); } public void sendLine(String line) { try { w.write(line + "\n"); w.flush(); } catch (Exception __e) { throw rethrow(__e); } } public String readLineImpl() { try { return in.readLine(); } catch (Exception __e) { throw rethrow(__e); } } public void close() { try { s.close(); } catch (IOException e) { } } public Socket getSocket() { return s; } }; try { handler.run(io); } finally { if (!io.noClose) s.close(); } } catch (IOException e) { print("[internal] " + e); } finally { } } }; t2.setDaemon(true); t2.start(); } catch (SocketTimeoutException e) { } } } catch (IOException e) { print("[internal] " + e); } } }; if (daemon) thread.setDaemon(true); thread.start(); if (!isTrue(getAndClearThreadLocal(startDialogServer_quiet))) print("Dialog server on port " + port + " started."); return true; } static public Thread startThread(Object runnable) { return startThread(defaultThreadName(), runnable); } static public Thread startThread(String name, Runnable runnable) { runnable = wrapAsActivity(runnable); return startThread(newThread(runnable, name)); } static public Thread startThread(String name, Object runnable) { runnable = wrapAsActivity(runnable); return startThread(newThread(toRunnable(runnable), name)); } static public Thread startThread(Thread t) { _registerThread(t); t.start(); return t; } static volatile public boolean readLine_noReadLine = false; static public String readLine_lastInput; static public String readLine_prefix = "[] "; static public String readLine() { if (readLine_noReadLine) return null; String s = readLineHidden(); if (s != null) { readLine_lastInput = s; print(readLine_prefix + s); } return s; } static public String getInnerMessage(Throwable e) { if (e == null) return null; return getInnerException(e).getMessage(); } static public boolean publicCommOn() { return "1".equals(loadTextFile(new File(userHome(), ".javax/public-communication"))); } static public String indentx(Object s) { return indentx(strOrEmpty(s)); } static public String indentx(String s) { return indentx(indent_default, s); } static public String indentx(int n, String s) { return dropSuffix(repeat(' ', n), indent(n, s)); } static public String indentx(String indent, String s) { return dropSuffix(indent, indent(indent, s)); } static public String processID_cached; static public String getPID() { if (processID_cached == null) { String name = ManagementFactory.getRuntimeMXBean().getName(); processID_cached = name.replaceAll("@.*", ""); } return processID_cached; } static public String getInjectionID() { return (String) call(getJavaX(), "getInjectionID", getMainClass()); } static public String getProgramTitle() { return getProgramName(); } static public Object callOptMC(String method, Object... args) { return callOpt(mc(), method, args); } static public List concatLists(Iterable... lists) { List l = new ArrayList(); if (lists != null) for (Iterable list : lists) addAll(l, list); return l; } static public List concatLists(Collection> lists) { List l = new ArrayList(); if (lists != null) for (Iterable list : lists) addAll(l, list); return l; } static public File[] listFiles(File dir) { File[] files = dir.listFiles(); return files == null ? new File[0] : files; } static public File[] listFiles(String dir) { return listFiles(new File(dir)); } static public boolean _inCore() { return false; } static public List hotwire_copyOver_after = synchroList(); static public void hotwire_copyOver(Class c) { for (String field : ll("print_log", "print_silent", "androidContext", "_userHome")) setOptIfNotNull(c, field, getOpt(mc(), field)); setOptIfNotNull(c, "mainBot", getMainBot()); setOpt(c, "creator_class", new WeakReference(mc())); pcallFAll(hotwire_copyOver_after, c); } static public Map newWeakMap() { return newWeakHashMap(); } static public void pcallFAll(Collection l, Object... args) { if (l != null) for (Object f : cloneList(l)) pcallF(f, args); } static public void pcallFAll(Iterator it, Object... args) { while (it.hasNext()) pcallF(it.next(), args); } static public Runnable toRunnable(final Object o) { if (o == null) return null; if (o instanceof Runnable) return (Runnable) o; if (o instanceof String) throw fail("callF_legacy"); return new Runnable() { public void run() { try { callF(o); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "callF(o)"; } }; } static public List> _threadInheritInfo_retrievers = synchroList(); static public void _threadInheritInfo(Object info) { if (info == null) return; pcallFAll(_threadInheritInfo_retrievers, (Map) info); } static public String substr(String s, int x) { return substring(s, x); } static public String substr(String s, int x, int y) { return substring(s, x, y); } static public List javaTok_noMLS(String s) { ArrayList tok = new ArrayList(); int l = s == null ? 0 : s.length(); int i = 0, n = 0; while (i < l) { int j = i; char c, d; while (j < l) { c = s.charAt(j); d = j + 1 >= l ? '\0' : s.charAt(j + 1); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (c == '/' && d == '*') { do ++j; while (j < l && !s.substring(j, Math.min(j + 2, l)).equals("*/")); j = Math.min(j + 2, l); } else if (c == '/' && d == '/') { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } tok.add(javaTok_substringN(s, i, j)); ++n; i = j; if (i >= l) break; c = s.charAt(i); d = i + 1 >= l ? '\0' : s.charAt(i + 1); if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { int c2 = s.charAt(j); if (c2 == opener || c2 == '\n' && opener == '\'') { ++j; break; } else if (c2 == '\\' && j + 1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && Character.isJavaIdentifierPart(s.charAt(j))); else if (Character.isDigit(c)) { do ++j; while (j < l && Character.isDigit(s.charAt(j))); if (j < l && s.charAt(j) == 'L') ++j; } else ++j; tok.add(javaTok_substringC(s, i, j)); ++n; i = j; } if ((tok.size() % 2) == 0) tok.add(""); return tok; } static public Map javaTokForJFind_array_cache = synchronizedMRUCache(1000); static public String[] javaTokForJFind_array(String s) { String[] tok = javaTokForJFind_array_cache.get(s); if (tok == null) javaTokForJFind_array_cache.put(s, tok = codeTokensAsStringArray(jfind_preprocess(javaTok(s)))); return tok; } static public int findCodeTokens(List tok, String... tokens) { return findCodeTokens(tok, 1, false, tokens); } static public int findCodeTokens(List tok, boolean ignoreCase, String... tokens) { return findCodeTokens(tok, 1, ignoreCase, tokens); } static public int findCodeTokens(List tok, int startIdx, boolean ignoreCase, String... tokens) { return findCodeTokens(tok, startIdx, ignoreCase, tokens, null); } static public HashSet findCodeTokens_specials = lithashset("*", "", "", "", "\\*"); static public int findCodeTokens_bails, findCodeTokens_nonbails; static public interface findCodeTokens_Matcher { public boolean get(String token); } static public int findCodeTokens(List tok, int startIdx, boolean ignoreCase, String[] tokens, Object condition) { int end = tok.size() - tokens.length * 2 + 2, nTokens = tokens.length; int i = startIdx | 1; if (i >= end) return -1; String firstToken = tokens[0]; if (!ignoreCase && !findCodeTokens_specials.contains(firstToken)) { while (i < end && !firstToken.equals(tok.get(i))) i += 2; } findCodeTokens_Matcher[] matchers = new findCodeTokens_Matcher[nTokens]; for (int j = 0; j < nTokens; j++) { String p = tokens[j]; findCodeTokens_Matcher matcher; if (p.equals("*")) matcher = t -> true; else if (p.equals("")) matcher = t -> isQuoted(t); else if (p.equals("")) matcher = t -> isIdentifier(t); else if (p.equals("")) matcher = t -> isInteger(t); else if (p.equals("\\*")) matcher = t -> t.equals("*"); else if (ignoreCase) matcher = t -> eqic(p, t); else matcher = t -> t.equals(p); matchers[j] = matcher; } outer: for (; i < end; i += 2) { for (int j = 0; j < nTokens; j++) if (!matchers[j].get(tok.get(i + j * 2))) continue outer; if (condition == null || checkTokCondition(condition, tok, i - 1)) return i; } return -1; } static public String jreplaceExpandRefs(String s, List tokref) { if (!contains(s, '$')) return s; List tok = javaTok(s); for (int i = 1; i < l(tok); i += 2) { String t = tok.get(i); if (t.startsWith("$") && isInteger(t.substring(1))) { String x = tokref.get(-1 + parseInt(t.substring(1)) * 2); tok.set(i, x); } else if (t.equals("\\")) { tok.set(i, ""); i += 2; } } return join(tok); } static public void clearAllTokens(List tok) { for (int i = 0; i < tok.size(); i++) tok.set(i, ""); } static public void clearAllTokens(List tok, int i, int j) { for (; i < j; i++) tok.set(i, ""); } static public List reTok(List tok) { replaceCollection(tok, javaTok(tok)); return tok; } static public List reTok(List tok, int i) { return reTok(tok, i, i + 1); } static public List reTok(List tok, int i, int j) { i = max(i & ~1, 0); j = min(l(tok), j | 1); if (i >= j) return tok; List t = javaTok(joinSubList(tok, i, j)); replaceListPart(tok, i, j, t); return tok; } static public List reTok(List tok, IntRange r) { if (r != null) reTok(tok, r.start, r.end); return tok; } static public Pair pairMap(Object f, Pair p) { return p == null ? null : pair(callF(f, p.a), callF(f, p.b)); } static public Pair pairMap(IF1 f, Pair p) { return p == null ? null : pair(callF(f, p.a), callF(f, p.b)); } static public Pair pairMap(Pair p, Object f) { return pairMap(f, p); } static public String rep(int n, char c) { return repeat(c, n); } static public String rep(char c, int n) { return repeat(c, n); } static public List rep(A a, int n) { return repeat(a, n); } static public List rep(int n, A a) { return repeat(n, a); } static public boolean isNonNegativeInteger(String s) { int n = l(s); if (n == 0) return false; int i = 0; while (i < n) { char c = s.charAt(i); if (c < '0' || c > '9') return false; ++i; } return true; } static public boolean isLoopbackIP(String ip) { return eq(ip, "127.0.0.1"); } static public int myVMPort() { List records = (List) (get(getJavaX(), "record_list")); Object android = last(records); return or0((Integer) get(android, "port")); } static public String thisVMGreeting() { List record_list = (List) (get(getJavaX(), "record_list")); Object android = first(record_list); return getString(android, "greeting"); } static public String sendToThisVM_newThread(String s, Object... args) { final String _s = format(s, args); try { return (String) evalInNewThread(new F0() { public Object get() { try { return callStaticAnswerMethod(getJavaX(), _s); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "return callStaticAnswerMethod(getJavaX(), _s);"; } }); } catch (Throwable e) { e = getInnerException(e); printStackTrace(e); return str(e); } } static public A popFirst(List l) { if (empty(l)) return null; A a = first(l); l.remove(0); return a; } static public A popFirst(Collection l) { if (empty(l)) return null; A a = first(l); l.remove(a); return a; } static public Pair popFirst(Map map) { if (map == null) return null; var it = map.entrySet().iterator(); if (!it.hasNext()) return null; var p = mapEntryToPair(it.next()); it.remove(); return p; } static public List popFirst(int n, List l) { List part = cloneSubList(l, 0, n); removeSubList(l, 0, n); return part; } static public AppendableChain popFirst(AppendableChain a) { return a == null ? null : a.popFirst(); } static public List getMultiPorts() { return (List) callOpt(getJavaX(), "getMultiPorts"); } static public String emptyToNull(String s) { return eq(s, "") ? null : s; } static public Map emptyToNull(Map map) { return empty(map) ? null : map; } static public void startMultiPort() { List mp = getMultiPorts(); if (mp != null && mp.isEmpty()) { nohupJavax("#1001639"); throw fail("Upgrading JavaX, please restart this program afterwards."); } } static public Set synchroTreeSet() { return Collections.synchronizedSet(new TreeSet()); } static public Set synchroTreeSet(TreeSet set) { return Collections.synchronizedSet(set); } static public boolean forbiddenPort(int port) { return port == 5037; } static public A getAndClearThreadLocal(ThreadLocal tl) { A a = tl.get(); tl.set(null); return a; } static public String defaultThreadName_name; static public String defaultThreadName() { if (defaultThreadName_name == null) defaultThreadName_name = "A thread by " + programID(); return defaultThreadName_name; } static public Runnable wrapAsActivity(Object r) { if (r == null) return null; Runnable r2 = toRunnable(r); Object mod = dm_current_generic(); if (mod == null) return r2; return new Runnable() { public void run() { try { AutoCloseable c = (AutoCloseable) (rcall("enter", mod)); AutoCloseable __1 = c; try { r2.run(); } finally { _close(__1); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "AutoCloseable c = (AutoCloseable) (rcall enter(mod));\r\n temp c;\r\n r2.r..."; } }; } static public Thread newThread(Object runnable) { return new BetterThread(_topLevelErrorHandling(toRunnable(runnable))); } static public Thread newThread(Object runnable, String name) { if (name == null) name = defaultThreadName(); return new BetterThread(_topLevelErrorHandling(toRunnable(runnable)), name); } static public Thread newThread(String name, Object runnable) { return newThread(runnable, name); } static public Map _registerThread_threads; static public Object _onRegisterThread; static public Thread _registerThread(Thread t) { if (_registerThread_threads == null) _registerThread_threads = newWeakHashMap(); _registerThread_threads.put(t, true); vm_generalWeakSubMap("thread2mc").put(t, weakRef(mc())); callF(_onRegisterThread, t); return t; } static public void _registerThread() { _registerThread(Thread.currentThread()); } static public String readLineHidden() { try { if (get(javax(), "readLine_reader") == null) set(javax(), "readLine_reader", new BufferedReader(new InputStreamReader(System.in, "UTF-8"))); try { return ((BufferedReader) get(javax(), "readLine_reader")).readLine(); } finally { consoleClearInput(); } } catch (Exception __e) { throw rethrow(__e); } } static public String repeat(char c, int n) { n = Math.max(n, 0); char[] chars = new char[n]; for (int i = 0; i < n; i++) chars[i] = c; return new String(chars); } static public List repeat(A a, int n) { n = Math.max(n, 0); List l = new ArrayList(n); for (int i = 0; i < n; i++) l.add(a); return l; } static public List repeat(int n, A a) { return repeat(a, n); } static public int indent_default = 2; static public String indent(int indent) { return repeat(' ', indent); } static public String indent(int indent, String s) { return indent(repeat(' ', indent), s); } static public String indent(String indent, String s) { return indent + replace(unnull(s), "\n", "\n" + indent); } static public String indent(String s) { return indent(indent_default, s); } static public List indent(String indent, List lines) { List l = new ArrayList(); if (lines != null) for (String s : lines) l.add(indent + s); return l; } static public String getProgramName_cache; static public String getProgramName() { Lock __0 = downloadLock(); lock(__0); try { if (getProgramName_cache == null) getProgramName_cache = getSnippetTitleOpt(programID()); return getProgramName_cache; } finally { unlock(__0); } } static public void _onLoad_getProgramName() { { startThread(new Runnable() { public void run() { try { getProgramName(); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "getProgramName();"; } }); } } static public void setOptIfNotNull(Object o, String field, Object value) { if (value != null) setOpt(o, field, value); } static public String[] codeTokensAsStringArray(List tok) { int n = max(0, (l(tok) - 1) / 2); String[] out = new String[n]; for (int i = 0; i < n; i++) out[i] = tok.get(i * 2 + 1); return out; } static public int jfind(String s, String in) { return jfind(javaTok(s), in); } static public int jfind(List tok, String in) { return jfind(tok, 1, in); } static public int jfind(List tok, int startIdx, String in) { return jfind(tok, startIdx, in, (ITokCondition) null); } static public int jfind(List tok, String in, Object condition) { return jfind(tok, 1, in, condition); } static public int jfind(List tok, String in, IIntPred condition) { return jfind(tok, 1, in, condition); } static public int jfind(List tok, int startIndex, String in, IIntPred condition) { return jfind(tok, startIndex, in, tokCondition(condition)); } static public int jfind(List tok, String in, ITokCondition condition) { return jfind(tok, 1, in, condition); } static public int jfind(List tok, int startIndex, String in, ITokCondition condition) { return jfind(tok, startIndex, in, (Object) condition); } static public int jfind(List tok, int startIdx, String in, Object condition) { return jfind(tok, startIdx, javaTokForJFind_array(in), condition); } static public int jfind(List tok, List tokin) { return jfind(tok, 1, tokin); } static public int jfind(List tok, int startIdx, List tokin) { return jfind(tok, startIdx, tokin, null); } static public int jfind(List tok, int startIdx, String[] tokinC, Object condition) { return findCodeTokens(tok, startIdx, false, tokinC, condition); } static public int jfind(List tok, int startIdx, List tokin, Object condition) { return jfind(tok, startIdx, codeTokensAsStringArray(tokin), condition); } static public List jfind_preprocess(List tok) { for (String type : litlist("quoted", "id", "int")) replaceSublist(tok, ll("<", "", type, "", ">"), ll("<" + type + ">")); replaceSublist(tok, ll("\\", "", "*"), ll("\\*")); return tok; } static public boolean checkTokCondition(Object condition, List tok, int i) { if (condition instanceof TokCondition) return ((TokCondition) condition).get(tok, i); return checkCondition(condition, tok, i); } static public void replaceCollection(Collection dest, Collection src) { if (dest == src) return; dest.clear(); if (src != null) dest.addAll(src); } static public void replaceListPart(List l, int i, int j, List l2) { replaceSublist(l, i, j, l2); } static public int or0(Integer i) { return i == null ? 0 : i; } static public long or0(Long l) { return l == null ? 0L : l; } static public double or0(Double d) { return d == null ? 0.0 : d; } static public Object evalInNewThread(final Object f) { final Flag flag = new Flag(); final Var var = new Var(); final Var exception = new Var(); { startThread(new Runnable() { public void run() { try { try { var.set(callF(f)); } catch (Throwable e) { exception.set(e); } flag.raise(); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "try {\r\n var.set(callF(f));\r\n } catch (Throwable e) {\r\n exception..."; } }); } flag.waitUntilUp(); if (exception.has()) throw rethrow(exception.get()); return var.get(); } static public void nohupJavax(final String javaxargs) { { startThread(new Runnable() { public void run() { try { call(hotwireOnce("#1008562"), "nohupJavax", javaxargs); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "call(hotwireOnce(\"#1008562\"), \"nohupJavax\", javaxargs);"; } }); } } static public void nohupJavax(final String javaxargs, final String vmArgs) { { startThread(new Runnable() { public void run() { try { call(hotwireOnce("#1008562"), "nohupJavax", javaxargs, vmArgs); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "call(hotwireOnce(\"#1008562\"), \"nohupJavax\", javaxargs, vmArgs);"; } }); } } static public Object dm_current_generic() { return getWeakRef(dm_current_generic_tl().get()); } static public Object rcall(String method, Object o, Object... args) { return call_withVarargs(o, method, args); } static public Runnable _topLevelErrorHandling(Runnable r) { if (r == null) return null; Object info = _threadInfo(); Object mod = dm_current_generic(); Runnable r2 = r; if (info != null || mod == null) r2 = new Runnable() { public void run() { try { AutoCloseable __1 = (AutoCloseable) (rcall("enter", mod)); try { _threadInheritInfo(info); r.run(); } finally { _close(__1); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "temp (AutoCloseable) rcall enter(mod);\r\n _threadInheritInfo(info);\r\n ..."; } }; r2 = rPcall(r2); return r2; } static public WeakReference weakRef(A a) { return newWeakReference(a); } static public A set(A o, String field, Object value) { if (o == null) return null; if (o instanceof Class) set((Class) o, field, value); else try { Field f = set_findField(o.getClass(), field); makeAccessible(f); smartSet(f, o, value); } catch (Exception e) { throw new RuntimeException(e); } return o; } static public void set(Class c, String field, Object value) { if (c == null) return; try { Field f = set_findStaticField(c, field); makeAccessible(f); smartSet(f, null, value); } catch (Exception e) { throw new RuntimeException(e); } } static public Field set_findStaticField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) return f; _c = _c.getSuperclass(); } while (_c != null); throw new RuntimeException("Static field '" + field + "' not found in " + c.getName()); } static public Field set_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 public void set(BitSet bs, int idx) { { if (bs != null) bs.set(idx); } } static public void consoleClearInput() { consoleSetInput(""); } static public List replace(List l, A a, A b) { for (int i = 0; i < l(l); i++) if (eq(l.get(i), a)) l.set(i, b); return l; } static public List replace(A a, A b, List l) { return replace(l, a, b); } static public String replace(String s, String a, String b) { return s == null ? null : a == null || b == null ? s : s.replace(a, b); } static public String replace(String s, char a, char b) { return s == null ? null : s.replace(a, b); } static public Lock downloadLock_lock = fairLock(); static public Lock downloadLock() { return downloadLock_lock; } static public String getSnippetTitleOpt(String s) { try { return isSnippetID(s) ? getSnippetTitle(s) : s; } catch (Throwable __e) { printStackTrace(__e); } return s; } static public ITokCondition tokCondition(IIntPred condition) { return condition == null ? null : (tok, nIdx) -> condition.get(nIdx); } static public List replaceSublist(List l, List x, List y) { if (x == null) return l; int i = 0; while (true) { i = indexOfSubList(l, x, i); if (i < 0) break; replaceSublist(l, i, i + l(x), y); i += l(y); } return l; } static public List replaceSublist(List l, int fromIndex, int toIndex, List y) { int n = y.size(), toIndex_new = fromIndex + n; if (toIndex_new < toIndex) { removeSubList(l, toIndex_new, toIndex); copyListPart(y, 0, l, fromIndex, n); } else { copyListPart(y, 0, l, fromIndex, toIndex - fromIndex); if (toIndex_new > toIndex) l.addAll(toIndex, subList(y, toIndex - fromIndex)); } return l; } static public List replaceSublist(List l, IntRange r, List y) { return replaceSublist(l, r.start, r.end, y); } static public boolean checkCondition(Object condition, Object... args) { return isTrue(callF(condition, args)); } static public boolean checkCondition(IF1 condition, A arg) { return isTrue(callF(condition, arg)); } static public Class hotwireOnce(String programID) { return hotwireCached(programID, false); } static public A getWeakRef(Reference ref) { return ref == null ? null : ref.get(); } static public x30_pkg.x30_util.BetterThreadLocal dm_current_generic_tl; static public x30_pkg.x30_util.BetterThreadLocal dm_current_generic_tl() { if (dm_current_generic_tl == null) dm_current_generic_tl = vm_generalMap_getOrCreate("currentModule", () -> new x30_pkg.x30_util.BetterThreadLocal()); return dm_current_generic_tl; } static public Runnable rPcall(Runnable r) { return r == null ? null : () -> { try { r.run(); } catch (Throwable __e) { printStackTrace(__e); } }; } static public WeakReference newWeakReference(A a) { return a == null ? null : new WeakReference(a); } static public void consoleSetInput(final String text) { if (headless()) return; setTextAndSelectAll(consoleInputField(), text); focusConsole(); } static public String getSnippetTitle(String id) { if (id == null) return null; if (!isSnippetID(id)) return "?"; IResourceLoader rl = vm_getResourceLoader(); if (rl != null) return rl.getSnippetTitle(id); return getSnippetTitle_noResourceLoader(id); } static public String getSnippetTitle_noResourceLoader(String id) { try { if (isLocalSnippetID(id)) return localSnippetTitle(id); long parsedID = parseSnippetID(id); String url; if (isImageServerSnippet(parsedID)) url = imageServerURL() + "title/" + parsedID + muricaCredentialsQuery(); else if (isGeneralFileServerSnippet(parsedID)) url = "http://butter.botcompany.de:8080/files/name/" + parsedID; else url = tb_mainServer() + "/tb-int/getfield.php?id=" + parsedID + "&field=title" + standardCredentials_noCookies(); String title = trim(loadPageSilently(url)); if (title != null) try { saveTextFileIfChanged(snippetTitle_cacheFile(id), title); } catch (Throwable __e) { print(exceptionToStringShort(__e)); } return or(title, "?"); } catch (Exception __e) { throw rethrow(__e); } } static public String getSnippetTitle(long id) { return getSnippetTitle(fsI(id)); } static public void copyListPart(List a, int i1, List b, int i2, int n) { if (a == null || b == null) return; for (int i = 0; i < n; i++) b.set(i2 + i, a.get(i1 + i)); } static public TreeMap hotwireCached_cache = new TreeMap(); static public Lock hotwireCached_lock = lock(); static public Class hotwireCached(String programID) { return hotwireCached(programID, true); } static public Class hotwireCached(String programID, boolean runMain) { return hotwireCached(programID, runMain, false); } static public Class hotwireCached(String programID, boolean runMain, boolean dependent) { Lock __0 = hotwireCached_lock; lock(__0); try { programID = formatSnippetID(programID); Class c = hotwireCached_cache.get(programID); if (c == null) { c = hotwire(programID); if (dependent) makeDependent(c); if (runMain) callMain(c); hotwireCached_cache.put(programID, c); } return c; } finally { unlock(__0); } } static public boolean headless() { return isHeadless(); } static public JTextField setTextAndSelectAll(final JTextField tf, final String text) { if (tf != null) { swing(() -> { tf.setText(text); tf.selectAll(); }); } return tf; } static public void focusConsole(String s) { setConsoleInput(s); focusConsole(); } static public void focusConsole() { JComponent tf = consoleInputFieldOrComboBox(); if (tf != null) { tf.requestFocus(); } } static public IResourceLoader vm_getResourceLoader() { return proxy(IResourceLoader.class, vm_generalMap_get("_officialResourceLoader")); } static public boolean isLocalSnippetID(String snippetID) { return isSnippetID(snippetID) && isLocalSnippetID(psI(snippetID)); } static public boolean isLocalSnippetID(long snippetID) { return snippetID >= 1000 && snippetID <= 9999; } static public String localSnippetTitle(String snippetID) { if (!isLocalSnippetID(snippetID)) return null; File f = localSnippetFile(snippetID); if (!f.exists()) return null; return or2(getFileInfoField(dropExtension(f), "Title"), "Unnamed"); } static public boolean isImageServerSnippet(long id) { return id >= 1100000 && id < 1200000; } static public String imageServerURL() { return or2(trim(loadTextFile(javaxDataDir("image-server-url.txt"))), "http://botcompany.de/images/raw/"); } static public String muricaCredentialsQuery() { return htmlQuery(muricaCredentials()); } static public boolean isGeneralFileServerSnippet(long id) { return id >= 1400000 && id < 1500000; } static public String tb_mainServer_default = "https://code.botcompany.de:9898"; static public Object tb_mainServer_override; static public String tb_mainServer() { if (tb_mainServer_override != null) return (String) callF(tb_mainServer_override); return trim(loadTextFile(tb_mainServer_file(), tb_mainServer_default)); } static public File tb_mainServer_file() { return getProgramFile("#1001638", "mainserver.txt"); } static public boolean tb_mainServer_isDefault() { return eq(tb_mainServer(), tb_mainServer_default); } static public String standardCredentials_noCookies() { return standardCredentials() + "&noCookies=1"; } static public int loadPage_defaultTimeout = 60000; static public ThreadLocal loadPage_charset = new ThreadLocal(); static public boolean loadPage_allowGzip = true, loadPage_debug; static public boolean loadPage_anonymous = false; static public int loadPage_verboseness = 100000; static public int loadPage_retries = 1; static public ThreadLocal loadPage_silent = new ThreadLocal(); static volatile public int loadPage_forcedTimeout; static public ThreadLocal loadPage_forcedTimeout_byThread = new ThreadLocal(); static public ThreadLocal>> loadPage_responseHeaders = new ThreadLocal(); static public ThreadLocal> loadPage_extraHeaders = new ThreadLocal(); static public ThreadLocal loadPage_sizeLimit = new ThreadLocal(); public static String loadPageSilently(String url) { try { return loadPageSilently(new URL(loadPage_preprocess(url))); } catch (Exception __e) { throw rethrow(__e); } } public static String loadPageSilently(URL url) { try { if (!networkAllowanceTest(str(url))) throw fail("Not allowed: " + url); IOException e = null; for (int tries = 0; tries < loadPage_retries; tries++) try { URLConnection con = loadPage_openConnection(url); return loadPage(con, url); } catch (IOException _e) { e = _e; if (loadPage_debug) print(exceptionToStringShort(e)); if (tries < loadPage_retries - 1) sleepSeconds(1); } throw e; } catch (Exception __e) { throw rethrow(__e); } } static public String loadPage_preprocess(String url) { if (url.startsWith("tb/")) url = tb_mainServer() + "/" + url; if (url.indexOf("://") < 0) url = "http://" + url; return url; } static public String loadPage(String url) { try { url = loadPage_preprocess(url); if (!isTrue(loadPage_silent.get())) printWithTime("Loading: " + hideCredentials(url)); return loadPageSilently(new URL(url)); } catch (Exception __e) { throw rethrow(__e); } } static public String loadPage(URL url) { return loadPage(url.toExternalForm()); } static public String loadPage(URLConnection con, URL url) throws IOException { return loadPage(con, url, true); } static public String loadPage(URLConnection con, URL url, boolean addHeaders) throws IOException { Map extraHeaders = getAndClearThreadLocal(loadPage_extraHeaders); Long limit = optPar(loadPage_sizeLimit); if (addHeaders) try { if (!loadPage_anonymous) setHeaders(con); if (loadPage_allowGzip) con.setRequestProperty("Accept-Encoding", "gzip"); con.setRequestProperty("X-No-Cookies", "1"); for (String key : keys(extraHeaders)) con.setRequestProperty(key, extraHeaders.get(key)); } catch (Throwable e) { } vm_generalSubMap("URLConnection per thread").put(currentThread(), con); loadPage_responseHeaders.set(con.getHeaderFields()); InputStream in = null; try { in = urlConnection_getInputStream(con); if (loadPage_debug) print("Put stream in map: " + currentThread()); String contentType = con.getContentType(); if (contentType == null) { throw new IOException("Page could not be read: " + hideCredentials(url)); } String charset = loadPage_charset == null ? null : loadPage_charset.get(); if (charset == null) charset = loadPage_guessCharset(contentType); if ("gzip".equals(con.getContentEncoding())) { if (loadPage_debug) print("loadPage: Using gzip."); in = newGZIPInputStream(in); } Reader r; try { r = new InputStreamReader(in, unquote(charset)); } catch (UnsupportedEncodingException e) { print(toHex(utf8(charset))); throw e; } boolean silent = isTrue(loadPage_silent.get()); StringBuilder buf = new StringBuilder(); int n = 0; while (limit == null || n < limit) { ping(); int ch = r.read(); if (ch < 0) break; buf.append((char) ch); ++n; if (!silent && (n % loadPage_verboseness) == 0) print(" " + n + " chars read"); } return buf.toString(); } finally { if (loadPage_debug) print("loadPage done"); vm_generalSubMap("URLConnection per thread").remove(currentThread()); if (in != null) in.close(); } } static public String loadPage_guessCharset(String contentType) { Matcher m = regexpMatcher("text/[a-z]+;\\s*charset=([^\\s]+)\\s*", contentType); String match = m.matches() ? m.group(1) : null; if (loadPage_debug) print("loadPage: contentType=" + contentType + ", match: " + match); return or(match, "UTF-8"); } static public URLConnection loadPage_openConnection(URL url) { URLConnection con = openConnection(url); int timeout = toInt(loadPage_forcedTimeout_byThread.get()); if (timeout == 0) timeout = loadPage_forcedTimeout; if (timeout != 0) setURLConnectionTimeouts(con, loadPage_forcedTimeout); else setURLConnectionDefaultTimeouts(con, loadPage_defaultTimeout); return con; } static public boolean saveTextFileIfChanged(File f, String contents) { return saveTextFileIfDifferent(f, contents); } static public File snippetTitle_cacheFile(String snippetID) { return javaxCachesDir("Snippet Titles/" + psI(snippetID)); } static public String fsI(String id) { return formatSnippetID(id); } static public String fsI(long id) { return formatSnippetID(id); } static public Object makeDependent_postProcess; static public void makeDependent(Object c) { if (c == null) return; assertTrue("Not a class", c instanceof Class); dependentClasses(); hotwire_classes.add(new WeakReference(c)); Object local_log = getOpt(mc(), "local_log"); if (local_log != null) setOpt(c, "local_log", local_log); Object print_byThread = getOpt(mc(), "print_byThread"); if (print_byThread != null) setOpt(c, "print_byThread", print_byThread); callF(makeDependent_postProcess, c); } static public void setConsoleInput(String text) { consoleSetInput(text); } static public JComponent consoleInputFieldOrComboBox() { Object console = get(getJavaX(), "console"); JComboBox cb = (JComboBox) (getOpt(console, "cbInput")); if (cb != null) return cb; return (JTextField) getOpt(console, "tfInput"); } static public A proxy(Class intrface, final Object target) { if (target == null) return null; if (isInstance(intrface, target)) return (A) target; return (A) java.lang.reflect.Proxy.newProxyInstance(intrface.getClassLoader(), new Class[] { intrface }, new proxy_InvocationHandler(target)); } static public A proxy(Object target, Class intrface) { return proxy(intrface, target); } static public long psI(String snippetID) { return parseSnippetID(snippetID); } static public File localSnippetFile(long snippetID) { return localSnippetsDir(snippetID + ".text"); } static public File localSnippetFile(String snippetID) { return localSnippetFile(parseSnippetID(snippetID)); } static public String getFileInfoField(File f, String field) { return getOneLineFileInfoField(f, field); } static public File dropExtension(File f) { return f == null ? null : fileInSameDir(f, dropExtension(f.getName())); } static public String dropExtension(String s) { return takeFirst(s, smartLastIndexOf(s, '.')); } static public String htmlQuery(Map params) { return empty(params) ? "" : "?" + makePostData(params); } static public String htmlQuery(Object... data) { return empty(data) ? "" : "?" + makePostData(data); } static public Object[] muricaCredentials() { String pass = muricaPassword(); return nempty(pass) ? new Object[] { "_pass", pass } : new Object[0]; } static public File getProgramFile(String progID, String fileName) { if (new File(fileName).isAbsolute()) return new File(fileName); return new File(getProgramDir(progID), fileName); } static public File getProgramFile(String fileName) { return getProgramFile(getProgramID(), fileName); } static public String standardCredentials() { String user = standardCredentialsUser(); String pass = standardCredentialsPass(); if (nempty(user) && nempty(pass)) return "&_user=" + urlencode(user) + "&_pass=" + urlencode(pass); return ""; } static public boolean networkAllowanceTest(String url) { return isAllowed("networkAllowanceTest", url); } static public void sleepSeconds(double s) { if (s > 0) sleep(round(s * 1000)); } static public A printWithTime(A a) { return printWithTime("", a); } static public A printWithTime(String s, A a) { print(hmsWithColons() + ": " + s, a); return a; } static public void setHeaders(URLConnection con) throws IOException { String computerID = getComputerID_quick(); if (computerID != null) try { con.setRequestProperty("X-ComputerID", computerID); con.setRequestProperty("X-OS", System.getProperty("os.name") + " " + System.getProperty("os.version")); } catch (Throwable e) { } } static public Map vm_generalSubMap(Object name) { synchronized (vm_generalMap()) { Map map = (Map) (vm_generalMap_get(name)); if (map == null) vm_generalMap_put(name, map = synchroMap()); return map; } } static public InputStream urlConnection_getInputStream(URLConnection con) throws IOException { return con.getInputStream(); } static public String toHex(byte[] bytes) { return bytesToHex(bytes); } static public String toHex(byte[] bytes, int ofs, int len) { return bytesToHex(bytes, ofs, len); } static public byte[] utf8(String s) { return toUtf8(s); } static public Matcher regexpMatcher(String pat, String s) { return compileRegexp(pat).matcher(unnull(s)); } static public Matcher regexpMatcher(java.util.regex.Pattern pat, String s) { return pat.matcher(unnull(s)); } static public URLConnection openConnection(String url) { try { return openConnection(new URL(url)); } catch (Exception __e) { throw rethrow(__e); } } static public URLConnection openConnection(URL url) { try { ping(); callOpt(javax(), "recordOpenURLConnection", str(url)); return url.openConnection(); } catch (Exception __e) { throw rethrow(__e); } } static public URLConnection setURLConnectionTimeouts(URLConnection con, long timeout) { con.setConnectTimeout(toInt(timeout)); con.setReadTimeout(toInt(timeout)); if (con.getConnectTimeout() != timeout || con.getReadTimeout() != timeout) print("Warning: Timeouts not set by JDK."); return con; } static public URLConnection setURLConnectionDefaultTimeouts(URLConnection con, long timeout) { if (con.getConnectTimeout() == 0) { con.setConnectTimeout(toInt(timeout)); if (con.getConnectTimeout() != timeout) print("Warning: URL connect timeout not set by JDK."); } if (con.getReadTimeout() == 0) { con.setReadTimeout(toInt(timeout)); if (con.getReadTimeout() != timeout) print("Warning: URL read timeout not set by JDK."); } return con; } static public boolean saveTextFileIfDifferent(File f, String contents) { if (eq(loadTextFile(f), contents)) return false; { saveTextFile(f, contents); return true; } } static public File javaxCachesDir_dir; static public File javaxCachesDir() { return javaxCachesDir_dir != null ? javaxCachesDir_dir : new File(userHome(), "JavaX-Caches"); } static public File javaxCachesDir(String sub) { return newFile(javaxCachesDir(), sub); } static public List dependentClasses() { return cleanUpAndGetWeakReferencesList(hotwire_classes); } static public File localSnippetsDir() { return javaxDataDir("Personal Programs"); } static public File localSnippetsDir(String sub) { return newFile(localSnippetsDir(), sub); } static public String getOneLineFileInfoField(File f, String field) { File infoFile = associatedInfosFile(f); List lines = lines(loadTextFile(infoFile)); return firstStartingWithIC_drop(lines, field + ": "); } static public File fileInSameDir(File f, String newName) { return newFile(parentFile(f), newName); } static public int smartLastIndexOf(String s, char c) { if (s == null) return 0; int i = s.lastIndexOf(c); return i >= 0 ? i : l(s); } static public int smartLastIndexOf(List l, A sub) { int i = lastIndexOf(l, sub); return i < 0 ? l(l) : i; } static volatile public boolean muricaPassword_pretendNotAuthed = false; static public String muricaPassword() { if (muricaPassword_pretendNotAuthed) return null; return trim(loadTextFile(muricaPasswordFile())); } static public File getProgramDir() { return programDir(); } static public File getProgramDir(String snippetID) { return programDir(snippetID); } static public String standardCredentialsUser() { return trim(loadTextFile(oneOfTheFiles(javaxSecretDir("tinybrain-username"), userDir(".tinybrain/username")))); } static public String standardCredentialsPass() { return trim(loadTextFile(oneOfTheFiles(javaxSecretDir("tinybrain-userpass"), userDir(".tinybrain/userpass")))); } static volatile public Object isAllowed_function; static volatile public boolean isAllowed_all = true; static public boolean isAllowed(String askingMethod, Object... args) { Object f = vm_generalMap_get("isAllowed_function"); if (f != null && !isTrue(callF(f, askingMethod, args))) return false; return isAllowed_all || isTrue(callF(isAllowed_function, askingMethod, args)); } static public long round(double d) { return Math.round(d); } static public String round(String s) { return roundBracket(s); } static public Complex round(Complex c) { return new Complex(round(c.re), round(c.im)); } static public String hmsWithColons() { return hmsWithColons(now()); } static public String hmsWithColons(long time) { return new SimpleDateFormat("HH:mm:ss").format(time); } static public String getComputerID_quick() { return computerID(); } static public File saveTextFile(String fileName, String contents) throws IOException { File file = new File(fileName); mkdirsForFile(file); String tempFileName = fileName + "_temp"; File tempFile = new File(tempFileName); if (contents != null) { if (tempFile.exists()) try { String saveName = tempFileName + ".saved." + now(); copyFile(tempFile, new File(saveName)); } catch (Throwable e) { printStackTrace(e); } FileOutputStream fileOutputStream = newFileOutputStream(tempFile.getPath()); try { OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "UTF-8"); PrintWriter printWriter = new PrintWriter(outputStreamWriter); printWriter.print(contents); printWriter.close(); } finally { _close(fileOutputStream); } } if (file.exists() && !file.delete()) throw new IOException("Can't delete " + fileName); if (contents != null) if (!tempFile.renameTo(file)) throw new IOException("Can't rename " + tempFile + " to " + file); vmBus_send("wroteFile", file); return file; } static public File saveTextFile(File fileName, String contents) { try { saveTextFile(fileName.getPath(), contents); return fileName; } catch (Exception __e) { throw rethrow(__e); } } static public List> hotwire_classes = synchroList(); static public Class hotwireDependent(String src) { Class c = hotwire(src); makeDependent(c); return c; } static public List cleanUpAndGetWeakReferencesList(List> l) { if (l == null) return null; synchronized (l) { List out = new ArrayList(); for (int i = 0; i < l(l); i++) { A a = l.get(i).get(); if (a == null) l.remove(i--); else out.add(a); } return out; } } static public File associatedInfosFile(File f) { return replaceExtension(f, ".infos"); } static public String firstStartingWithIC_drop(Collection l, final String prefix) { for (String s : unnull(l)) if (swic(s, prefix)) return substring(s, l(prefix)); return null; } static public String firstStartingWithIC_drop(String prefix, Collection l) { return firstStartingWithIC_drop(l, prefix); } static public File parentFile(File f) { return dirOfFile(f); } static public File muricaPasswordFile() { return new File(javaxSecretDir(), "murica/muricaPasswordFile"); } static public File oneOfTheFiles(String... paths) { if (paths != null) for (String path : paths) if (fileExists(path)) return newFile(path); return null; } static public File oneOfTheFiles(File... files) { return oneOfTheFiles(asList(files)); } static public File oneOfTheFiles(Iterable files) { if (files != null) for (File f : files) if (fileExists(f)) return f; return null; } static public File javaxSecretDir_dir; static public File javaxSecretDir() { return javaxSecretDir_dir != null ? javaxSecretDir_dir : new File(userHome(), "JavaX-Secret"); } static public File javaxSecretDir(String sub) { return newFile(javaxSecretDir(), sub); } static public String roundBracket(String s) { return "(" + s + ")"; } static public String roundBracket(Object s) { return roundBracket(str(s)); } static public String _computerID; static public Lock computerID_lock = lock(); public static String computerID() { if (_computerID == null) { Lock __0 = computerID_lock; lock(__0); try { if (_computerID != null) return _computerID; File file = computerIDFile(); _computerID = loadTextFile(file.getPath()); if (_computerID == null) { _computerID = loadTextFile(userDir(".tinybrain/computer-id")); if (_computerID == null) _computerID = makeRandomID(12, new SecureRandom()); saveTextFile(file, _computerID); } } finally { unlock(__0); } } return _computerID; } public static File mkdirsForFile(File file) { File dir = file.getParentFile(); if (dir != null) { dir.mkdirs(); if (!dir.isDirectory()) if (dir.isFile()) throw fail("Please delete the file " + f2s(dir) + " - it is supposed to be a directory!"); else throw fail("Unknown IO exception during mkdirs of " + f2s(file)); } return file; } public static String mkdirsForFile(String path) { mkdirsForFile(new File(path)); return path; } static public File copyFile(File src, File dest) { try { FileInputStream inputStream = new FileInputStream(src.getPath()); FileOutputStream outputStream = newFileOutputStream(dest.getPath()); try { copyStream(inputStream, outputStream); inputStream.close(); } finally { outputStream.close(); } return dest; } catch (Exception __e) { throw rethrow(__e); } } static public FileOutputStream newFileOutputStream(File path) throws IOException { return newFileOutputStream(path.getPath()); } static public FileOutputStream newFileOutputStream(String path) throws IOException { return newFileOutputStream(path, false); } static public FileOutputStream newFileOutputStream(File path, boolean append) throws IOException { return newFileOutputStream(path.getPath(), append); } static public FileOutputStream newFileOutputStream(String path, boolean append) throws IOException { mkdirsForFile(path); FileOutputStream f = new FileOutputStream(path, append); _registerIO(f, path, true); return f; } static public File replaceExtension(File f, String extOld, String extNew) { return newFile(replaceExtension(f2s(f), extOld, extNew)); } static public File replaceExtension(File f, String extNew) { return replaceExtension(f, fileExtension(f), extNew); } static public String replaceExtension(String s, String extOld, String extNew) { s = dropSuffixIC(addPrefixOptIfNempty(".", extOld), s); return s + addPrefixOptIfNempty(".", extNew); } static public String replaceExtension(String name, String extNew) { return replaceExtension(name, fileExtension(name), extNew); } static public File dirOfFile(File f) { return f == null ? null : f.getParentFile(); } static public File computerIDFile() { return javaxDataDir("Basic Info/computer-id.txt"); } static public String f2s(File f) { return f == null ? null : f.getAbsolutePath(); } static public String f2s(String s) { return f2s(newFile(s)); } static public String f2s(java.nio.file.Path p) { return p == null ? null : f2s(p.toFile()); } static public void copyStream(InputStream in, OutputStream out) { try { byte[] buf = new byte[65536]; while (true) { int n = in.read(buf); if (n <= 0) return; out.write(buf, 0, n); } } catch (Exception __e) { throw rethrow(__e); } } static public String fileExtension(File f) { if (f == null) return null; return fileExtension(f.getName()); } static public String fileExtension(String s) { return substring(s, smartLastIndexOf(s, '.')); } static public String dropSuffixIC(String suffix, String s) { return s == null ? null : ewic(s, suffix) ? s.substring(0, l(s) - l(suffix)) : s; } static public String addPrefixOptIfNempty(String prefix, String s) { return addPrefixIfNotEmpty2(prefix, s); } static public String addPrefixIfNotEmpty2(String prefix, String s) { return empty(s) ? "" : addPrefix(prefix, s); } static abstract public class VF1 implements IVF1 { public abstract void get(A a); } static public class Meta implements IMeta { volatile public Object meta; public void _setMeta(Object meta) { this.meta = meta; } public Object _getMeta() { return meta; } final public boolean scaffolding() { return scaffoldingEnabled(); } public boolean scaffoldingEnabled() { return main.scaffoldingEnabled(this); } public boolean scaffoldingEnabled(Object o) { return main.scaffoldingEnabled(o); } } static public class Var implements IVar, ISetter { public Var() { } public Var(A v) { this.v = v; } public A v; public synchronized void set(A a) { if (v != a) { v = a; notifyAll(); } } public synchronized A get() { return v; } public synchronized boolean has() { return v != null; } public void clear() { set(null); } public String toString() { return str(this.get()); } } static public class Scorer { public double score, total; public List successes, errors; public boolean verboseFailures, verboseAll; final public void add(double score) { addZeroToOne(score); } public void addZeroToOne(double score) { ++total; this.score += clamp(score, 0, 1); } public void addZeroToOneError(double error) { addZeroToOne(1 - error); } public void addError() { add(false); } public void addError(A info) { add(false, info); } public void error(A info) { addError(info); } public void addOK() { add(true); } public void addOK(A info) { add(true, info); } public void ok() { addOK(); } public void ok(A info) { addOK(info); } public boolean add(boolean correct) { ++total; if (correct) ++score; return correct; } public boolean add(boolean correct, A info) { main.add(correct ? successes : errors, info); if (verboseAll || verboseFailures && !correct) _print((correct ? "[GOOD] " : "[BAD] ") + info); return add(correct); } public void eq(Object a, Object b) { if (_eq(a, b)) add(true); else add(false, (A) (a + " != " + b)); } public void print() { main.print(toString()); } public String toString() { return formatDouble(ratioToPercent(score, total), 1) + "% correct (n=" + formatDouble(total, 1) + ")"; } public double get() { return ratioToPercent(score, total); } public double percentScore() { return get(); } public double score() { return get(); } public boolean allCorrect() { return score == total; } public void add(Scorer scorer) { if (scorer == null) return; total += scorer.total; score += scorer.score; addAll(successes, scorer.successes); addAll(errors, scorer.errors); } public void collectErrors() { errors = new ArrayList(); } public void collectSuccesses() { successes = new ArrayList(); } } static public interface ITokCondition { public boolean get(List tok, int i); } static abstract public class TokCondition implements ITokCondition { public abstract boolean get(List tok, int i); } static public class PingSource { final public PingSource setAction(IF0 action) { return action(action); } public PingSource action(IF0 action) { this.action = action; return this; } final public IF0 getAction() { return action(); } public IF0 action() { return action; } volatile public IF0 action; public String text; public ThreadPool threadPool; public PingSource() { } public PingSource(ThreadPool threadPool) { this.threadPool = threadPool; } public PingSource(ThreadPool threadPool, String text) { this.text = text; this.threadPool = threadPool; } public PingSource(IF0 action) { this.action = action; } final public boolean get() { var a = action; return a != null && a.get(); } final public void ping() { var a = action; if (a != null) a.get(); } public void cancel() { action = new Cancelled(); } public class Cancelled implements IF0 { public Boolean get() { throw new PingSourceCancelledException(PingSource.this); } } public class Encapsulated implements Runnable, IFieldsToList { public Runnable r; public Encapsulated() { } public Encapsulated(Runnable r) { this.r = r; } public Object[] _fieldsToList() { return new Object[] { r }; } public void run() { try { try { pingSource_tl().set(PingSource.this); ping(); r.run(); } finally { pingSource_tl().set(null); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return PingSource.this + ": " + r; } } public void dO(Runnable r) { if (r == null) return; threadPool.acquireThreadOrQueue(new Encapsulated(r)); } public String toString() { String t = text; return nempty(t) ? t : super.toString(); } public ISleeper_v2 sleeper() { return threadPool.sleeper(); } } static public int concepts_internStringsLongerThan = 10; static public ThreadLocal concepts_unlisted = new ThreadLocal(); static public boolean concepts_unlistedByDefault = true; public interface IConceptIndex { public void update(Concept c); public void remove(Concept c); } public interface IFieldIndex { public Collection getAll(Val val); public List allValues(); public MultiSet allValues_multiSet(); public IterableIterator objectIterator(); } static public class ConceptsChange { } static public class ConceptCreate extends ConceptsChange implements IFieldsToList { public Concept c; public ConceptCreate() { } public ConceptCreate(Concept c) { this.c = c; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + c + ")"; } public boolean equals(Object o) { if (!(o instanceof ConceptCreate)) return false; ConceptCreate __3 = (ConceptCreate) o; return eq(c, __3.c); } public int hashCode() { int h = -1751266972; h = boostHashCombine(h, _hashCode(c)); return h; } public Object[] _fieldsToList() { return new Object[] { c }; } } static public class ConceptChange extends ConceptsChange implements IFieldsToList { public Concept c; public ConceptChange() { } public ConceptChange(Concept c) { this.c = c; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + c + ")"; } public boolean equals(Object o) { if (!(o instanceof ConceptChange)) return false; ConceptChange __4 = (ConceptChange) o; return eq(c, __4.c); } public int hashCode() { int h = -1760609256; h = boostHashCombine(h, _hashCode(c)); return h; } public Object[] _fieldsToList() { return new Object[] { c }; } } static public class ConceptDelete extends ConceptsChange implements IFieldsToList { static final public String _fieldOrder = "id c"; public long id; public Concept c; public ConceptDelete() { } public ConceptDelete(long id, Concept c) { this.c = c; this.id = id; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + id + ", " + c + ")"; } public boolean equals(Object o) { if (!(o instanceof ConceptDelete)) return false; ConceptDelete __5 = (ConceptDelete) o; return id == __5.id && eq(c, __5.c); } public int hashCode() { int h = -1734431213; h = boostHashCombine(h, _hashCode(id)); h = boostHashCombine(h, _hashCode(c)); return h; } public Object[] _fieldsToList() { return new Object[] { id, c }; } } static public class FullChange extends ConceptsChange implements IFieldsToList { public FullChange() { } public String toString() { return shortClassName_dropNumberPrefix(this); } public boolean equals(Object o) { return o instanceof FullChange; } public int hashCode() { int h = 733452095; return h; } public Object[] _fieldsToList() { return null; } } static public class Concepts implements AutoCloseable { public SortedMap concepts = synchroTreeMap(); final public long getIdCounter() { return idCounter(); } public long idCounter() { return idCounter; } public long idCounter; transient public HashMap perClassData; transient public Map miscMap; transient public String programID; transient public File conceptsFile; transient public Concepts parent; transient volatile public long changes, changesWritten, lastChange; transient volatile public java.util.Timer autoSaver; transient volatile public boolean dontSave = false; transient volatile public boolean savingConcepts, noXFullGrab; transient public boolean vmBusSend = true; transient public boolean initialSave = false; transient public int autoSaveInterval = -1000; transient public boolean useGZIP = true, quietSave; transient public ReentrantLock lock = new ReentrantLock(true); transient public ReentrantLock saverLock = new ReentrantLock(true); transient public long lastSaveTook = -1, lastSaveWas, loadTook, uncompressedSize; transient public float maxAutoSavePercentage = 10; transient public List conceptIndices; transient public Map, Map> fieldIndices; transient public Map, Map> ciFieldIndices; transient public List preSave; transient public Object classFinder = _defaultClassFinder(); transient public List onAllChanged = synchroList(); transient public Set onChange = new HashSet(); transient public Object saveWrapper; final public Concepts setModifyOnCreate(boolean modifyOnCreate) { return modifyOnCreate(modifyOnCreate); } public Concepts modifyOnCreate(boolean modifyOnCreate) { this.modifyOnCreate = modifyOnCreate; return this; } final public boolean getModifyOnCreate() { return modifyOnCreate(); } public boolean modifyOnCreate() { return modifyOnCreate; } transient public boolean modifyOnCreate = false; transient public boolean modifyOnBackRef = false; transient public boolean useFileLock = true; transient public FileBasedLock fileLock; transient public boolean storeBaseClassesInStructure = false; transient public boolean useBackRefsForSearches = false; transient public boolean defunct = false; transient public int newBackupEveryXMinutes = 60; public Concepts() { } public Concepts(String programID) { this.programID = programID; } public Concepts(File conceptsFile) { this.conceptsFile = conceptsFile; } synchronized public long internalID() { do { ++idCounter; } while (hasConcept(idCounter)); return idCounter; } synchronized public HashMap perClassData() { if (perClassData == null) perClassData = new HashMap(); return perClassData; } public void initProgramID() { if (programID == null) programID = getDBProgramID(); } public Concepts load(String structure) { return load(structure, false); } public Concepts load(String structure, boolean allDynamic) { clearConcepts(); Map map = unstructureMap(structure, allDynamic, classFinder); concepts.putAll(map); assignConceptsToUs(); calcIdCounter(); return this; } public Concepts load() { initProgramID(); Object dbGrabber = miscMapGet("dbGrabber"); if (dbGrabber != null && !isFalse(callF(dbGrabber))) return this; try { if (tryToGrab()) return this; } catch (Throwable e) { if (!exceptionMessageContains(e, "no xfullgrab")) printShortException(e); print("xfullgrab failed - loading DB of " + programID + " from disk"); } return loadFromDisk(); } public Concepts loadFromDisk() { if (nempty(concepts)) clearConcepts(); long time = now(); Map _concepts = (Map) (unstructureGZFile(conceptsFile(), toIF1(classFinder))); putAll(concepts, _concepts); assignConceptsToUs(); loadTook = now() - time; done("Loaded " + n2(l(concepts), "concept"), time); calcIdCounter(); return this; } public Concepts loadConcepts() { return load(); } public boolean tryToGrab() { if (sameSnippetID(programID, getDBProgramID())) return false; RemoteDB db = connectToDBOpt(programID); try { if (db != null) { loadGrab(db.fullgrab()); return true; } return false; } finally { _close(db); } } public Concepts loadGrab(String grab) { clearConcepts(); DynamicObject_loading.set(true); try { Map map = (Map) unstructure(grab, false, classFinder); concepts.putAll(map); assignConceptsToUs(); for (long l : map.keySet()) idCounter = max(idCounter, l); } finally { DynamicObject_loading.set(null); } return this; } public void assignConceptsToUs() { for (Pair p : mapToPairs((Map) (Map) concepts)) if (!(p.b instanceof Concept)) { print("DROPPING non-existant concept " + p.a + ": " + dynShortName(p.b)); concepts.remove(p.a); } for (Concept c : values(concepts)) c._concepts = this; for (Concept c : values(concepts)) c._doneLoading2(); } public String progID() { return programID == null ? getDBProgramID() : programID; } public Concept getConcept(String id) { return empty(id) ? null : getConcept(parseLong(id)); } public Concept getConcept(long id) { return (Concept) concepts.get((long) id); } public Concept getConcept(RC ref) { return ref == null ? null : getConcept(ref.longID()); } public boolean hasConcept(long id) { return concepts.containsKey((long) id); } public void deleteConcept(long id) { Concept c = getConcept(id); if (c == null) print("Concept " + id + " not found"); else c.delete(); } public void calcIdCounter() { Long lastID = lastKey(concepts); idCounter = lastID == null ? 1 : lastID + 1; } public File conceptsDir() { return dirOfFile(conceptsFile()); } public Concepts conceptsFile(File conceptsFile) { this.conceptsFile = conceptsFile; return this; } public File conceptsFile() { if (conceptsFile != null) return conceptsFile; return getProgramFile(programID, useGZIP ? "concepts.structure.gz" : "concepts.structure"); } public File lockFile() { return newFile(conceptsDir(), "concepts.lock"); } public FileBasedLock fileLock() { if (fileLock == null) fileLock = new FileBasedLock(lockFile()); return fileLock; } public void saveConceptsIfDirty() { saveConcepts(); } public void save() { saveConcepts(); } public void saveConcepts() { vmBus_send("saveConceptsCalled", Concepts.this); if (dontSave) return; initProgramID(); saverLock.lock(); savingConcepts = true; long start = now(), time; try { String s = null; long _changes = changes; if (_changes == changesWritten) return; File f = conceptsFile(); lock.lock(); long fullTime = now(); try { if (useGZIP) { vmBus_send("callingSaveWrapper", Concepts.this, saveWrapper); callRunnableWithWrapper(saveWrapper, new Runnable() { public void run() { try { vmBus_send("callingPreSave", Concepts.this, preSave); callFAll(preSave); vmBus_send("writingFile", Concepts.this, f); uncompressedSize = saveGZStructureToFile(f, cloneMap(concepts), makeStructureData()); vmBus_send("gzFileSaved", Concepts.this, f, uncompressedSize); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "vmBus_send callingPreSave(Concepts.this, preSave);\r\n callFAll(preS..."; } }); newFile(conceptsDir(), "concepts.structure").delete(); } else s = fullStructure(); } finally { lock.unlock(); } changesWritten = _changes; if (!useGZIP) { time = now() - start; if (!quietSave) print("Saving " + toM(l(s)) + "M chars (" + time + " ms)"); start = now(); saveTextFile(f, javaTokWordWrap(s)); newFile(conceptsDir(), "concepts.structure.gz").delete(); } File conceptsFile = conceptsFile(); File backupFile = newFile(conceptsDir(), "backups/" + fileName(conceptsFile) + ".backup" + ymd() + "-" + formatInt(hours(), 2) + (newBackupEveryXMinutes >= 60 ? "" : formatInt(roundDownTo_rev(minutes(), newBackupEveryXMinutes), 2))); copyFile(f, backupFile); time = now() - start; if (!quietSave) print("Saved " + toK(f.length()) + " K, " + n(concepts, "concepts") + " (" + time + " ms)"); lastSaveWas = fullTime; lastSaveTook = now() - fullTime; } finally { savingConcepts = false; saverLock.unlock(); } } public void _autoSaveConcepts() { if (autoSaveInterval < 0 && maxAutoSavePercentage != 0) { long pivotTime = Math.round(lastSaveWas + lastSaveTook * 100.0 / maxAutoSavePercentage); if (now() < pivotTime) { return; } } try { saveConcepts(); } catch (Throwable e) { print("Concept save failed, will try again"); printStackTrace(e); } } public String fullStructure() { return structure(cloneMap(concepts), makeStructureData()); } transient public IF0 makeStructureData; public structure_Data makeStructureData() { return makeStructureData != null ? makeStructureData.get() : makeStructureData_base(); } final public structure_Data makeStructureData_fallback(IF0 _f) { return _f != null ? _f.get() : makeStructureData_base(); } public structure_Data makeStructureData_base() { return finishStructureData(new structure_Data()); } public structure_Data finishStructureData(structure_Data data) { if (storeBaseClassesInStructure) data.storeBaseClasses = true; return data; } public void clearConcepts() { for (Concept c : allConcepts()) c.delete(); } public void fireLegacyChangeEvent() { synchronized (this) { ++changes; lastChange = sysNow(); } if (vmBusSend) vmBus_send("conceptsChanged", this); pcallFAll(onAllChanged); } synchronized public void autoSaveConcepts() { if (autoSaver == null) { if (isTransient()) throw fail("Can't persist transient database"); autoSaver = doEvery_daemon("Concepts Saver for " + conceptsDir(), abs(autoSaveInterval), new Runnable() { public void run() { try { _autoSaveConcepts(); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "_autoSaveConcepts()"; } }); } } public void close() { cleanMeUp(); } public void cleanMeUp() { try { defunct = true; boolean shouldSave = autoSaver != null; if (autoSaver != null) { autoSaver.cancel(); autoSaver = null; } while (savingConcepts) sleepInCleanUp(10); if (shouldSave) saveConceptsIfDirty(); } catch (Throwable __e) { printStackTrace(__e); } { cleanUp(fileLock); fileLock = null; } } public Map getIDsAndNames() { Map map = new HashMap(); Map cloned = cloneMap(concepts); for (long id : keys(cloned)) map.put(id, cloned.get(id).className); return map; } public void deleteConcepts(List l) { ping(); if (l != null) for (Object o : cloneList(l)) if (o instanceof Long) { Concept c = concepts.get(o); if (c != null) c.delete(); } else if (o instanceof Concept) ((Concept) o).delete(); else warn("Can't delete " + getClassName(o)); } public A conceptOfType(Class type) { IConceptCounter counter = conceptCounterForClass(type); if (counter != null) return (A) first(counter.allConcepts()); return firstOfType(allConcepts(), type); } public List conceptsOfType(Class type) { List l = conceptsOfType_noParent(type); if (parent == null) return l; return concatLists_conservative(l, parent.conceptsOfType(type)); } public List conceptsOfType_noParent(Class type) { ping(); IConceptCounter counter = conceptCounterForClass(type); if (counter != null) return (List) cloneList(counter.allConcepts()); return filterByType(allConcepts(), type); } public List listConcepts(Class type) { return conceptsOfType(type); } public List list(Class type) { return conceptsOfType(type); } public List list_noParent(Class type) { return conceptsOfType_noParent(type); } public List list(String type) { return conceptsOfType(type); } public List conceptsOfType(String type) { return filterByDynamicType(allConcepts(), "main$" + type); } public boolean hasConceptOfType(Class type) { return hasType(allConcepts(), type); } public void persistConcepts() { loadConcepts(); autoSaveConcepts(); } public void conceptPersistence() { persistConcepts(); } public Concepts persist() { persistConcepts(); return this; } public void persist(Integer interval) { if (interval != null) autoSaveInterval = interval; persist(); } public A ensureHas(Class c, Runnable r) { A a = conceptOfType(c); if (a == null) { r.run(); a = conceptOfType(c); if (a == null) throw fail("Concept not made by " + r + ": " + shortClassName(c)); } return a; } public void ensureHas(Class c1, Class c2, Object func) { for (Concept a : conceptsOfType(c1)) { Concept b = findBackRef(a, c2); if (b == null) { callF(func, a); b = findBackRef(a, c2); if (b == null) throw fail("Concept not made by " + func + ": " + shortClassName(c2)); } } } public void forEvery(Class type, Object func) { for (Concept c : conceptsOfType(type)) callF(func, c); } public int deleteAll(Class type) { List l = (List) conceptsOfType(type); for (Concept c : l) c.delete(); return l(l); } public Collection allConcepts() { synchronized (concepts) { return new ArrayList(values(concepts)); } } public IConceptCounter conceptCounterForClass(Class c) { for (IFieldIndex idx : values(mapGet(fieldIndices, c))) if (idx instanceof IConceptCounter) return ((IConceptCounter) idx); for (IFieldIndex idx : values(mapGet(ciFieldIndices, c))) if (idx instanceof IConceptCounter) return ((IConceptCounter) idx); return null; } public int countConcepts(Class c, Object... params) { int n = countConcepts_noParent(c, params); if (parent == null) return n; return n + parent.countConcepts(c, params); } public int countConcepts_noParent(Class c, Object... params) { ping(); if (empty(params)) { IConceptCounter counter = conceptCounterForClass(c); if (counter != null) return counter.countConcepts(); return l(list_noParent(c)); } int n = 0; for (A x : list_noParent(c)) if (checkConceptFields(x, params)) ++n; return n; } public int countConcepts(String c, Object... params) { ping(); if (empty(params)) return l(list(c)); int n = 0; for (Concept x : list(c)) if (checkConceptFields(x, params)) ++n; return n; } public int countConcepts() { return l(concepts); } synchronized public List clonedConceptIndices() { return cloneList(conceptIndices); } synchronized public void addConceptIndex(IConceptIndex index) { if (conceptIndices == null) conceptIndices = new ArrayList(); conceptIndices.add(index); } synchronized public void removeConceptIndex(IConceptIndex index) { if (conceptIndices == null) return; conceptIndices.remove(index); if (empty(conceptIndices)) conceptIndices = null; } synchronized public void addFieldIndex(Class c, String field, IFieldIndex index) { if (fieldIndices == null) fieldIndices = new HashMap(); Map map = fieldIndices.get(c); if (map == null) fieldIndices.put(c, map = new HashMap()); map.put(field, index); } synchronized public void removeFieldIndex(Class c, String field, IFieldIndex index) { Map map = mapGet(fieldIndices, c); mapRemove(map, field); } synchronized public IFieldIndex getFieldIndex(Class c, String field) { if (fieldIndices == null) return null; Map map = fieldIndices.get(c); return map == null ? null : map.get(field); } synchronized public IFieldIndex getAnyIndexForClass(Class c) { return firstValue(fieldIndices == null ? null : fieldIndices.get(c)); } synchronized public void addCIFieldIndex(Class c, String field, IFieldIndex index) { if (ciFieldIndices == null) ciFieldIndices = new HashMap(); Map map = ciFieldIndices.get(c); if (map == null) ciFieldIndices.put(c, map = new HashMap()); map.put(field, index); } synchronized public void removeCIFieldIndex(Class c, String field) { Map map = mapGet(ciFieldIndices, c); mapRemove(map, field); } synchronized public IFieldIndex getCIFieldIndex(Class c, String field) { if (ciFieldIndices == null) return null; Map map = ciFieldIndices.get(c); return map == null ? null : map.get(field); } public RC xnew(String name, Object... values) { return new RC(cnew(name, values)); } public void xset(long id, String field, Object value) { xset(new RC(id), field, value); } public void xset(RC c, String field, Object value) { if (value instanceof RC) value = getConcept((RC) value); cset(getConcept(c), field, value); } public Object xget(long id, String field) { return xget(new RC(id), field); } public Object xget(RC c, String field) { return xgetPost(cget(getConcept(c), field)); } public Object xgetPost(Object o) { o = deref(o); if (o instanceof Concept) return new RC((Concept) o); return o; } public void xdelete(long id) { xdelete(new RC(id)); } public void xdelete(RC c) { getConcept(c).delete(); } public void xdelete(List l) { for (RC c : l) xdelete(c); } public List xlist() { return map("toPassRef", allConcepts()); } public List xlist(String className) { return map("toPassRef", conceptsOfType(className)); } public boolean isTransient() { return eq(programID, "-"); } public String xfullgrab() { if (noXFullGrab) throw fail("no xfullgrab (DB too large)"); Lock __1 = lock(); lock(__1); try { if (changes == changesWritten && !isTransient()) return loadConceptsStructure(programID); return fullStructure(); } finally { unlock(__1); } } public void xshutdown() { cleanKillVM(); } public long xchangeCount() { return changes; } public int xcount() { return countConcepts(); } public void register(Concept c) { ping(); if (c._concepts == this) return; if (c._concepts != null) throw fail("Can't re-register"); c.id = internalID(); c.created = now(); if (modifyOnCreate) c._setModified(c.created); register_phase2(c); vmBus_send("conceptCreated", c); fireChange(new ConceptCreate(c)); } public void register_phase2(Concept c) { c._concepts = this; concepts.put((long) c.id, c); for (Concept.Ref r : c._refs()) r.index(); c.change(); c._onRegistered(); } public void registerKeepingID(Concept c) { if (c._concepts == this) return; if (c._concepts != null) throw fail("Can't re-register"); c._concepts = this; concepts.put((long) c.id, c); c.change(); } public void conceptChanged(Concept c) { fireChange(new ConceptChange(c)); if (conceptIndices != null) for (IConceptIndex index : clonedConceptIndices()) index.update(c); } public boolean hasUnsavedData() { return changes != changesWritten || savingConcepts; } synchronized public Object miscMapGet(Object key) { return mapGet(miscMap, key); } synchronized public Object miscMapPut(Object key, Object value) { if (miscMap == null) miscMap = new HashMap(); return miscMap.put(key, value); } synchronized public void miscMapRemove(Object key) { mapRemove(miscMap, key); } synchronized public A miscMapGetOrCreate(Object key, IF0 create) { if (containsKey(miscMap, key)) return (A) miscMap.get(key); A value = create.get(); miscMapPut(key, value); return value; } public void setParent(Concepts parent) { this.parent = parent; } public void fireChange(ConceptsChange change) { if (change == null) return; pcallFAll(onChange, change); fireLegacyChangeEvent(); } final public void onChange(IVF1 l) { addChangeListener(l); } public void addChangeListener(IVF1 l) { syncAdd(onChange, l); } public void removeChangeListener(IVF1 l) { syncRemove(onChange, l); } public void addPreSave(Runnable r) { preSave = syncAddOrCreate(preSave, r); } public String toString() { return nConcepts(concepts) + " (" + conceptsDir() + ", hash: " + identityHashCode(this) + ")"; } } public interface IConcept { public long _conceptID(); public Concepts concepts(); } static public class Concept extends DynamicObject implements IConcept, ChangeTriggerable { transient public Concepts _concepts; public long id; public long created, _modified; public List backRefs; public Concept(String className) { super(className); _created(); } public Concept() { if (!_loading()) { _created(); } } public Concept(boolean unlisted) { if (!unlisted) _created(); } public boolean includeZeroIDInToString() { return false; } public String toString() { String s = shortDynamicClassName(this); long id = this.id; if (id != 0 || includeZeroIDInToString()) s += " " + id; return s; } static public boolean loading() { return _loading(); } static public boolean _loading() { return dynamicObjectIsLoading(); } public void _created() { if (!concepts_unlistedByDefault && !eq(concepts_unlisted.get(), true)) db_mainConcepts().register(this); } public class TypedRef extends Ref { public TypedRef() { } public Class bType; public TypedRef(Class bType) { this.bType = bType; } public TypedRef(Class bType, B value) { this.bType = bType; set((A) value); } public TypedRef(B value) { set((A) value); } public boolean set(A a) { return super.set(checkValue(a)); } public void check() { checkValue(get()); } public C checkValue(C a) { if (bType != null && a != null) assertIsInstance(a, bType); return a; } public B b() { return (B) value; } } public class Ref implements IRef { public A value; public Ref() { if (!dynamicObjectIsLoading()) registerRef(); } public void registerRef() { vmBus_send("registeringConceptRef", this); } public Ref(A value) { this.value = value; registerRef(); index(); } public Concept concept() { return Concept.this; } public A get() { return value; } public boolean has() { return value != null; } public boolean set(A a) { if (a == value) return false; unindex(); value = a; index(); change(); return true; } public void setIfEmpty(A a) { if (!has()) set(a); } public void set(Ref ref) { set(ref.get()); } public void clear() { set((A) null); } public boolean validRef() { return value != null && _concepts != null && _concepts == value._concepts; } public void index() { if (validRef()) { value._addBackRef(this); change(); } } public Ref unindex() { if (validRef()) { value._removeBackRef(this); change(); } return this; } public void unindexAndDrop() { unindex(); _removeRef(this); } public void change() { Concept.this.change(); } public String toString() { return str(value); } } public class RefL extends AbstractList { public List> l = new ArrayList(); public RefL() { } public RefL(List l) { replaceWithList(l); } public void clear() { while (!isEmpty()) removeLast(this); } public void replaceWithList(List l) { clear(); for (A a : unnullForIteration(l)) add(a); } public A set(int i, A o) { Ref ref = syncGet(l, i); A prev = ref.get(); ref.set(o); return prev; } public void add(int i, A o) { syncAdd(l, i, new Ref(o)); } public A get(int i) { return syncGet(l, i).get(); } public A remove(int i) { return syncRemove(l, i).get(); } public int size() { return syncL(l); } public boolean contains(Object o) { if (o instanceof Concept) for (Ref r : l) if (eq(r.get(), o)) return true; return super.contains(o); } } public void delete() { for (Ref r : unnullForIteration(_refs())) r.unindex(); for (Ref r : cloneList(backRefs)) r.set((Concept) null); backRefs = null; var _concepts = this._concepts; if (_concepts != null) { _concepts.concepts.remove(id); _concepts.fireChange(new ConceptDelete(id, this)); if (_concepts.conceptIndices != null) for (IConceptIndex index : _concepts.conceptIndices) index.remove(this); this._concepts = null; } id = 0; } public BaseXRef export() { return new BaseXRef(_concepts.progID(), id); } final public void _change() { change(); } public void change() { _setModified(now()); _change_withoutUpdatingModifiedField(); } public void _setModified(long modified) { _modified = modified; } final public void _change_withoutUpdatingModifiedField() { _onChange(); if (_concepts != null) _concepts.conceptChanged(this); } public void _onChange() { } public String _programID() { return _concepts == null ? getDBProgramID() : _concepts.progID(); } public void _addBackRef(Concept.Ref ref) { backRefs = addDyn_quickSync(backRefs, ref); _backRefsModified(); } public void _backRefsModified() { if (_concepts != null && _concepts.modifyOnBackRef) change(); } public void _removeBackRef(Concept.Ref ref) { backRefs = removeDyn_quickSync(backRefs, ref); _backRefsModified(); } public void _removeRef(Concept.Ref ref) { } public int _backRefCount() { return syncL(backRefs); } final public void setField(String field, Object value) { _setField(field, value); } public void _setField(String field, Object value) { cset(this, field, value); } public boolean setField_trueIfChanged(String field, Object value) { return cset(this, field, value) != 0; } public A setFieldAndReturn(String field, A value) { setField(field, value); return value; } final public void setFields(Object... values) { _setFields(values); } public void _setFields(Object... values) { cset(this, values); } public Concepts concepts() { return _concepts; } public boolean isDeleted() { return id == 0; } public void _doneLoading() { } public void _doneLoading2() { Map map = _fieldMigrations(); if (map != null) for (Map.Entry __0 : _entrySet(map)) { String oldField = __0.getKey(); FieldMigration m = __0.getValue(); crenameField_noOverwrite(this, oldField, m.newField); } } static public class FieldMigration implements IFieldsToList { public String newField; public FieldMigration() { } public FieldMigration(String newField) { this.newField = newField; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + newField + ")"; } public boolean equals(Object o) { if (!(o instanceof FieldMigration)) return false; FieldMigration __6 = (FieldMigration) o; return eq(newField, __6.newField); } public int hashCode() { int h = 558692372; h = boostHashCombine(h, _hashCode(newField)); return h; } public Object[] _fieldsToList() { return new Object[] { newField }; } } public Map _fieldMigrations() { return null; } public Collection _refs() { return scanConceptForRefs(this); } public Concepts _concepts() { return _concepts; } public boolean _conceptsDefunct() { return _concepts != null && _concepts.defunct; } public boolean _conceptsDefunctOrUnregistered() { return _concepts == null || _concepts.defunct; } public void _onRegistered() { } public boolean addAndChange(Collection cl, A a) { if (cl == null || !cl.add(a)) return false; change(); return true; } public void clearAndChange(Collection cl) { if (cl == null) return; cl.clear(); change(); } public File conceptsDir() { var concepts = concepts(); return concepts == null ? null : concepts.conceptsDir(); } public File fileInConceptsDir(String name) { var dir = conceptsDir(); return dir == null ? null : newFile(dir, name); } public long _conceptID() { return id; } } static public class RC { transient public Object owner; public String id; public RC() { } public RC(long id) { this.id = str(id); } public RC(Object owner, long id) { this.id = str(id); this.owner = owner; } public RC(Concept c) { this(c.id); } public long longID() { return parseLong(id); } public String toString() { return id; } transient public RemoteDB db; public String getString(String field) { return db.xS(this, field); } public Object get(String field) { return db.xget(this, field); } public void set(String field, Object value) { db.xset(this, field, value); } } static public class BaseXRef { public String programID; public long id; public BaseXRef() { } public BaseXRef(String programID, long id) { this.id = id; this.programID = programID; } public boolean equals(Object o) { if (!(o instanceof BaseXRef)) return false; BaseXRef r = (BaseXRef) o; return eq(programID, r.programID) && eq(id, r.id); } public int hashCode() { return programID.hashCode() + (int) id; } } static public class XRef extends Concept { public BaseXRef ref; public XRef() { } public XRef(BaseXRef ref) { this.ref = ref; _doneLoading2(); } public void _doneLoading2() { getIndex().put(ref, this); } public HashMap getIndex() { return getXRefIndex(_concepts); } } static synchronized public HashMap getXRefIndex(Concepts concepts) { HashMap cache = (HashMap) concepts.perClassData().get(XRef.class); if (cache == null) concepts.perClassData.put(XRef.class, cache = new HashMap()); return cache; } static public XRef lookupOrCreateXRef(BaseXRef ref) { XRef xref = getXRefIndex(db_mainConcepts()).get(ref); if (xref == null) xref = new XRef(ref); return xref; } static public void loadAndAutoSaveConcepts() { db_mainConcepts().persist(); } static public void loadAndAutoSaveConcepts(int interval) { db_mainConcepts().persist(interval); } static public RC toPassRef(Concept c) { return new RC(c); } static public void concepts_setUnlistedByDefault(boolean b) { concepts_unlistedByDefault = b; } static public class HCRUD extends HAbstractRenderable { public HCRUD_Data data; public boolean mutationRights = true; public boolean allowCreateOrDelete = true; public boolean allowCreate = true; public boolean allowEdit = true; public boolean singleton = false; public boolean cmdsLeft = false; public boolean showEntryCountInTitle = false; public boolean allowFieldRenaming = false; public int defaultTextFieldCols = 80; public int valueDisplayLength = 1000; public String tableClass; public String formTableClass; public String checkBoxClass = "crud_chkbox"; public String customTitle; public boolean showTextFieldsAsAutoExpandingTextAreas = false; public Set unshownFields; public Set uneditableFields; public Set unlistedFields; public boolean showCheckBoxes = false; public boolean cleanItemIDs = false; public boolean haveJQuery, haveSelectizeJS, haveSelectizeClickable; public boolean needsJQuery = false; public boolean paginate = false; public boolean sortable = false; public boolean buttonsOnTop, buttonsOnBottom = true; public boolean duplicateInNewTab = false; public String formID = "crudForm"; public boolean showQuickSaveButton = false; public boolean enableMultiSelect = true; public boolean cellColumnToolTips = false; public boolean showSearchField = false; public String searchQuery; public Map params; public HTMLPaginator paginator = new HTMLPaginator(); public String sortByField = "id"; public String sortParameter = "sort"; public boolean descending = false; public int flexibleLengthListLeeway = 5; public Object objectIDToHighlight; public boolean showOnlySelected = false; public String fieldPrefix = "f_"; public int entryCount; public HCRUD() { } public HCRUD(HCRUD_Data data) { this.data = data; } public HCRUD(String baseLink, HCRUD_Data data) { this.data = data; this.baseLink = baseLink; } public String newLink() { return appendQueryToURL(baseLink, "cmd", "new"); } public String deleteLink(Object id) { return appendQueryToURL(baseLink, "delete_" + id, 1); } public String editLink(Object id) { return appendQueryToURL(baseLink, "edit", id); } public String duplicateLink(Object id) { return appendQueryToURL(baseLink, "duplicate", id); } public void setParams(Map params) { this.params = params; if (objectIDToHighlight == null) objectIDToHighlight = params.get("selectObj"); if (eq("1", params.get("showOnlySelected"))) showOnlySelected = true; } public String render(boolean withCmds, Map params) { setParams(params); if (!withCmds) return renderTable(false); { String __3 = handleCommands(params); if (!empty(__3)) return __3; } return renderMsgs(params) + divUnlessEmpty(nav()) + renderTable(withCmds); } transient public IF0 nav; public String nav() { return nav != null ? nav.get() : nav_base(); } final public String nav_fallback(IF0 _f) { return _f != null ? _f.get() : nav_base(); } public String nav_base() { List l = new ArrayList(); if (actuallyAllowCreate()) l.add(ahref(newLink(), "New " + itemName())); if (showSearchField) l.add(hInlineSearchForm("search", searchQuery, "")); return joinWithVBar(l); } public String handleCommands(Map params) { List msgs = new ArrayList(); if (eqGet(params, "action", "create")) { if (!actuallyAllowCreate()) throw fail("Creating objects not allowed"); processRenames(params); Object id = data.createObject(preprocessUpdateParams(params), fieldPrefix); msgs.add(itemName() + " created (ID: " + id + ")"); objectIDToHighlight = id; } if (eqGet(params, "action", "update")) { if (!actuallyAllowEdit()) throw fail("Editing objects not allowed"); String id = params.get("id"); processRenames(params); msgs.add(data.updateObject(id, preprocessUpdateParams(params), fieldPrefix)); objectIDToHighlight = id; } List toDeleteList = keysDeprefixNemptyValue(params, "delete_"); if (eq(params.get("bulkAction"), "deleteSelected")) toDeleteList.addAll(keysDeprefixNemptyValue(params, "obj_")); for (String toDelete : toDeleteList) { if (!actuallyAllowDelete()) throw fail("Deleting objects not allowed"); msgs.add(data.deleteObject(toDelete)); } return empty(msgs) ? "" : refreshAfterCommand(params, msgs); } transient public IF2, List, String> refreshAfterCommand; public String refreshAfterCommand(Map params, List msgs) { return refreshAfterCommand != null ? refreshAfterCommand.get(params, msgs) : refreshAfterCommand_base(params, msgs); } final public String refreshAfterCommand_fallback(IF2, List, String> _f, Map params, List msgs) { return _f != null ? _f.get(params, msgs) : refreshAfterCommand_base(params, msgs); } public String refreshAfterCommand_base(Map params, List msgs) { String redirectAfterSave = mapGet(params, "redirectAfterSave"); if (nempty(redirectAfterSave)) return hrefresh(redirectAfterSave); return refreshWithMsgs(msgs, "anchor", objectIDToHighlight == null ? null : "obj" + objectIDToHighlight, "params", objectIDToHighlight == null ? null : litmap("selectObj", objectIDToHighlight)); } public String encodeField(String s) { return or(data.fieldNameToHTML(s), s); } transient public IF2 renderValue; public String renderValue(String field, Object value) { return renderValue != null ? renderValue.get(field, value) : renderValue_base(field, value); } final public String renderValue_fallback(IF2 _f, String field, Object value) { return _f != null ? _f.get(field, value) : renderValue_base(field, value); } public String renderValue_base(String field, Object value) { if (value instanceof HTML) return ((HTML) value).html; value = deref(value); if (value instanceof SecretValue) return hhiddenStuff(renderValue_inner(((SecretValue) value).get())); return renderValue_inner(value); } transient public IF1 renderValue_inner; public String renderValue_inner(Object value) { return renderValue_inner != null ? renderValue_inner.get(value) : renderValue_inner_base(value); } final public String renderValue_inner_fallback(IF1 _f, Object value) { return _f != null ? _f.get(value) : renderValue_inner_base(value); } public String renderValue_inner_base(Object value) { if (value instanceof Boolean) return yesNo_short((Boolean) value); return htmlEncode_nlToBr_withIndents(shorten(valueDisplayLength, strOrEmpty(value))); } public String renderTable(boolean withCmds) { return renderTable(withCmds, data.list()); } public String valueToSortable(Object value) { if (value instanceof HTML) return ((HTML) value).get(); return strOrNull(value); } public String renderTable(boolean withCmds, List> l) { entryCount = l(l); if (empty(l)) return p("No entries"); if (!eq(data.defaultSortField(), pair(sortByField, descending))) { if (nempty(sortByField)) { print("Sorting " + nEntries(l) + " by " + sortByField); l = sortByTransformedMapKey_alphaNum(__64 -> valueToSortable(__64), l, sortByField); } if (descending) l = reversed(l); } Map keyEncoding = new HashMap(); List> l2 = lazyMap(l, _map -> { Object id = itemID(_map); return data.new Item(id) { public Map calcFullMap() { Map map = _map; map = mapMinusKeys(map, joinSets(unshownFields, unlistedFields)); Map map2 = postProcessTableRow(map, mapToMap((key, value) -> pair(mapPut_returnValue(keyEncoding, key, encodeField(key)), renderValue(key, value)), map)); if (singleton) map2.remove(encodeField(data.idField())); if (withCmds) map2 = addCmdsToTableRow(map, map2); map2.put(firstKey(map2), aname("obj" + id, firstValue(map2))); return map2; } }; }); List out = new ArrayList(); if (paginate) { paginator.processParams(params); paginator.baseLink = addParamsToURL(baseLink, filterKeys(__65 -> keepParamInPagination(__65), params)); paginator.max = l(l2); out.add(divUnlessEmpty(paginator.renderNav())); List> l3 = subListOrFull(l2, paginator.visibleRange()); if (objectIDToHighlight != null && (showOnlySelected || !any(__36 -> isHighlighted(__36), l3))) { l3 = llNonNulls(firstThat(__37 -> isHighlighted(__37), l2)); } l2 = l3; } Map replaceHeaders = new HashMap(); if (sortable && !singleton) for (Map.Entry __1 : _entrySet(keyEncoding)) { String key = __1.getKey(); String html = __1.getValue(); boolean sortedByField = eq(sortByField, key); boolean showDescendingLink = sortedByField && !descending; String htmlOld = html; if (sortedByField) { String title = showDescendingLink ? "Click here to sort descending" : "Click here to sort ascending"; String titleSorted = "Sorted by this field (" + (descending ? "descending" : "ascending") + ")"; title = titleSorted + ". " + title; html = span_title(title, unicode_downOrUpPointingTriangle(descending)) + " " + html; } String sortLink = appendQueryToURL(baseLink, sortParameter, showDescendingLink ? "-" + key : key); replaceHeaders.put(htmlOld, ahref(sortLink, html)); } Map paramsByColName = null; if (cellColumnToolTips) { paramsByColName = new HashMap(); for (Map map : l2) for (String key : keys(map)) if (!paramsByColName.containsKey(key)) paramsByColName.put(key, litobjectarray("title", nullIfEmpty(htmldecode_dropTagsAndComments(key)))); } out.add(hpostform(htmlTable2_noHtmlEncode(l2, paramsPlus(tableParams(), "replaceHeaders", replaceHeaders, "paramsByColName", paramsByColName)) + (!withCmds || !showCheckBoxes ? "" : "\n" + divUnlessEmpty(renderBulkCmds())), "action", baseLink)); if (showCheckBoxes && haveJQuery && enableMultiSelect) out.add(hCheckBoxMultiSelect_v2()); return lines_rtrim(out); } public Object mapToID(Map item) { return item == null ? null : dropAllTags(strOrNull(item.get(encodeField(idField())))); } public boolean isHighlighted(Map item) { Object id = mapToID(item); return eq(id, objectIDToHighlight); } transient public IF0 renderBulkCmds; public String renderBulkCmds() { return renderBulkCmds != null ? renderBulkCmds.get() : renderBulkCmds_base(); } final public String renderBulkCmds_fallback(IF0 _f) { return _f != null ? _f.get() : renderBulkCmds_base(); } public String renderBulkCmds_base() { return "Bulk action: " + hselect("bulkAction", litorderedmap("", "", "deleteSelected", "Delete selected")) + " " + hsubmit("OK", "onclick", "return confirm('Are you sure?')"); } public Map addCmdsToTableRow(Map map, Map map2) { if (showCheckBoxes) { Object id = itemID(map); map2.put(checkBoxKey(), hcheckbox("obj_" + id, false, "title", "Select this object for a bulk action", "class", checkBoxClass)); map2 = putKeysFirst(map2, checkBoxKey()); } map2.put(cmdsKey(), renderCmds(map)); if (cmdsLeft) map2 = putKeysFirst(map2, cmdsKey()); return map2; } public Object[] tableParams() { return litparams("tdParams", litparams("valign", "top"), "tableParams", litparams("class", tableClass)); } public String renderForm(Map map) { AutoCloseable __5 = tempSetTL(htmlencode_forParams_useV2, true); try { map = mapMinusKeys(map, joinSets(unshownFields, uneditableFields, data.filteredFields())); Map mapWithoutID = mapWithoutKey(map, data.idField()); List> matrix = map(mapWithoutID, (field, value) -> { String help = data.fieldHelp(field); return ll(allowFieldRenaming ? hinputfield("rename_" + field, field, "class", "field-rename", "style", "border: none; text-align: right", "title", "Edit this to rename field " + quote(field) + " or clear to delete field") : encodeField(field), addHelpText(help, renderInput(field, value))); }); massageFormMatrix(map, matrix); return htableRaw_valignTop(matrix, empty(formTableClass) ? litparams("border", 1, "cellpadding", 4) : litparams("class", formTableClass)); } finally { _close(__5); } } public String renderInput(String field, Object value) { String name = fieldPrefix + field; return renderInput(name, data.getRenderer(field, value), value); } public String renderInput(String name, HCRUD_Data.Renderer r, Object value) { if (r != null) value = r.preprocessValue(value); String meta = r == null ? "" : renderMetaInfo(r.metaInfo, name); if (r instanceof HCRUD_Data.AceEditor) { HTMLAceEditor ace = new HTMLAceEditor(strOrEmpty(value)); ace.name = name; ace.divParams.put("style", "width: " + ((HCRUD_Data.AceEditor) r).cols + "ch; height: " + ((HCRUD_Data.AceEditor) r).rows + "em"); customizeACEEditor(ace); return meta + ace.headStuff() + ace.html(); } if (r instanceof HCRUD_Data.TextArea) return meta + htextarea(strOrEmpty(value), "name", name, "cols", ((HCRUD_Data.TextArea) r).cols, "rows", ((HCRUD_Data.TextArea) r).rows); if (r instanceof HCRUD_Data.TextField) return meta + renderTextField(name, strOrEmpty(value), ((HCRUD_Data.TextField) r).cols); if (r instanceof HCRUD_Data.ComboBox) return meta + renderComboBox(name, ((HCRUD_Data.ComboBox) r).valueToEntry(value), ((HCRUD_Data.ComboBox) r).entries, ((HCRUD_Data.ComboBox) r).editable); if (r instanceof HCRUD_Data.DynamicComboBox) return meta + renderDynamicComboBox(name, ((HCRUD_Data.DynamicComboBox) r).valueToEntry(value), ((HCRUD_Data.DynamicComboBox) r).info, ((HCRUD_Data.DynamicComboBox) r).editable, ((HCRUD_Data.DynamicComboBox) r).url); if (r instanceof HCRUD_Data.CheckBox) return meta + htrickcheckboxWithText(name, "", isTrue(value)); if (r instanceof HCRUD_Data.FlexibleLengthList) { List list = (List) value; List rows = new ArrayList(); int n = l(list) + flexibleLengthListLeeway; for (int i = 0; i < n; i++) { Object item = _get(list, i); rows.add(tr(td(i + 1 + ".", "align", "right") + td(renderInput(name + "_" + i, ((HCRUD_Data.FlexibleLengthList) r).itemRenderer, item)))); } return meta + htag("table", lines(rows)); } if (r instanceof HCRUD_Data.NotEditable) return "Not editable"; return renderInput_default(name, value); } transient public IVF1 customizeACEEditor; public void customizeACEEditor(HTMLAceEditor ace) { if (customizeACEEditor != null) customizeACEEditor.get(ace); else customizeACEEditor_base(ace); } final public void customizeACEEditor_fallback(IVF1 _f, HTMLAceEditor ace) { if (_f != null) _f.get(ace); else customizeACEEditor_base(ace); } public void customizeACEEditor_base(HTMLAceEditor ace) { } public String renderMetaInfo(String metaInfo, String name) { if (empty(metaInfo)) return ""; return hhidden("metaInfo_" + dropPrefix(fieldPrefix, name), metaInfo); } public String renderInput_default(String name, Object value) { return renderTextField(name, strOrEmpty(value), defaultTextFieldCols); } public String renderTextField(String name, String value, int cols) { if (showTextFieldsAsAutoExpandingTextAreas) { return htextarea(value, "name", name, "class", "auto-expand", "style", "width: " + cols + "ch", "autofocus", eq(mapGet(params, "autofocus"), name) ? html_valueLessParam() : null, "onkeydown", jquery_submitFormOnCtrlEnter()); } return htextfield(name, value, "size", cols, "style", "font-family: monospace"); } public String renderNewForm() { return renderNewForm(data.emptyObject()); } public String renderNewFormWithParams(Map params) { Map filteredMap = subMapStartingWith_dropPrefix(params, fieldPrefix); Map map = joinMaps(data.emptyObject(), (Map) filteredMap); data.rawFormValues = params; for (Map.Entry __0 : _entrySet(filteredMap)) { String key = __0.getKey(); String value = __0.getValue(); List l = splitAt(key, "_"); if (l(l) == 2) { String field = first(l); int idx = parseInt(second(l)); List list = (List) (map.get(field)); if (!(list instanceof ArrayList)) map.put(field, list = new ArrayList()); listPut(list, idx, value); } } return renderNewForm(map); } public String renderNewForm(Map map) { String buttons = p(hsubmit("Create")); return hpostform(hhidden("action", "create") + formExtraHiddens() + stringIf(buttonsOnTop, buttons) + renderForm(map) + stringIf(buttonsOnBottom, buttons), paramsPlus(formParameters(), "action", baseLink)); } transient public IF0 formParameters; public Object[] formParameters() { return formParameters != null ? formParameters.get() : formParameters_base(); } final public Object[] formParameters_fallback(IF0 _f) { return _f != null ? _f.get() : formParameters_base(); } public Object[] formParameters_base() { return litparams("id", formID); } public String idField() { return data.idField(); } public String renderEditForm(String id) { if (!actuallyAllowEdit()) return "Can't edit objects in this table"; if (!data.objectCanBeEdited(id)) return htmlEncode2("Object " + id + " can't be edited"); Map map = data.getObjectForEdit(id); if (map == null) return htmlEncode2("Entry " + id + " not found"); String onlyFields = mapGet(params, "onlyFields"); if (nempty(onlyFields)) map = onlyKeys(map, itemPlus(idField(), tok_identifiersOnly(onlyFields))); String buttons = p_vbar(hsubmit("Save changes"), !showQuickSaveButton ? "" : hbuttonOnClick_noSubmit("Save & keep editing", "\r\n $.ajax({\r\n type: 'POST',\r\n url: $('#crudForm').attr('action'),\r\n data: $('#crudForm').serialize(), \r\n success: function(response) { successNotification(\"Saved\"); },\r\n }).error(function() { errorNotification(\"Couldn't save\"); });\r\n "), deleteObjectHTML(id)); return hpostform(hhidden("action", "update") + formExtraHiddens() + hhidden("id", id) + p("Object ID: " + htmlEncode2(id)) + stringIf(buttonsOnTop, buttons) + renderForm(map) + stringIf(buttonsOnBottom, buttons), paramsPlus(formParameters(), "action", baseLink + "#obj" + id)); } public String renderPage(Map params) { setParams(params); { String __4 = handleComboSearch(params); if (!empty(__4)) return __4; } if (eqGet(params, "cmd", "new")) { if (!actuallyAllowCreate()) return "Can't create objects in ths table"; return frame(customTitleOr("New " + itemName()), renderNewFormWithParams(params)); } if (nempty(params.get("edit"))) return frame("Edit " + itemName(), renderEditForm(params.get("edit"))); if (nempty(params.get("duplicate"))) return frame("New " + itemName(), renderNewForm(data.getObjectForDuplication(params.get("duplicate")))); String rendered = render(mutationRights, params); String title = null; if (singleton) title = ahref(baseLink, firstToUpper(data.itemName())); else { if (objectIDToHighlight != null) title = data.titleForObjectID(objectIDToHighlight); if (empty(title)) title = (showEntryCountInTitle ? n2(entryCount) + " " : "") + ahref(baseLink, firstToUpper(data.itemNamePlural())); } return frame(customTitleOr(title), rendered); } public HCRUD makeFrame(MakeFrame makeFrame) { super.makeFrame(makeFrame); return this; } public String cmdsKey() { return ""; } public String checkBoxKey() { return ""; } public String itemName() { return data.itemName(); } transient public IF2, Map, Map> postProcessTableRow; public Map postProcessTableRow(Map data, Map rendered) { return postProcessTableRow != null ? postProcessTableRow.get(data, rendered) : postProcessTableRow_base(data, rendered); } final public Map postProcessTableRow_fallback(IF2, Map, Map> _f, Map data, Map rendered) { return _f != null ? _f.get(data, rendered) : postProcessTableRow_base(data, rendered); } public Map postProcessTableRow_base(Map data, Map rendered) { return rendered; } public Object itemID(Map item) { Object id = mapGet(item, data.idField()); if (cleanItemIDs) id = htmlDecode_dropTags(strOrNull(getVarOpt(id))); return id; } public long itemIDAsLong(Map item) { return parseLong(itemID(item)); } transient public IF1, List> additionalCmds; public List additionalCmds(Map item) { return additionalCmds != null ? additionalCmds.get(item) : additionalCmds_base(item); } final public List additionalCmds_fallback(IF1, List> _f, Map item) { return _f != null ? _f.get(item) : additionalCmds_base(item); } public List additionalCmds_base(Map item) { return null; } transient public IF1, String> renderCmds; public String renderCmds(Map item) { return renderCmds != null ? renderCmds.get(item) : renderCmds_base(item); } final public String renderCmds_fallback(IF1, String> _f, Map item) { return _f != null ? _f.get(item) : renderCmds_base(item); } public String renderCmds_base(Map item) { Object id = itemID(item); List additionalCmds = additionalCmds(item); return joinNemptiesWithVBar(!actuallyAllowEdit() || !data.objectCanBeEdited(id) ? null : ahref(editLink(id), "EDIT"), deleteObjectHTML(id), !actuallyAllowCreate() ? null : targetBlankIf(duplicateInNewTab, duplicateLink(id), "dup", "title", "duplicate"), empty(additionalCmds) ? null : hPopDownButton(additionalCmds)); } public boolean actuallyAllowCreate() { return !singleton && allowCreateOrDelete && allowCreate; } public boolean actuallyAllowEdit() { return allowCreateOrDelete && allowEdit; } public boolean actuallyAllowDelete() { return !singleton && allowCreateOrDelete; } transient public IVF2, List>> massageFormMatrix; public void massageFormMatrix(Map map, List> matrix) { if (massageFormMatrix != null) massageFormMatrix.get(map, matrix); else massageFormMatrix_base(map, matrix); } final public void massageFormMatrix_fallback(IVF2, List>> _f, Map map, List> matrix) { if (_f != null) _f.get(map, matrix); else massageFormMatrix_base(map, matrix); } public void massageFormMatrix_base(Map map, List> matrix) { } public String renderComboBox(String name, String value, List entries, boolean editable) { if (haveSelectizeJS) { String id = aGlobalID(); return hselect_list(entries, value, "name", name, "id", id) + hjs("$('#" + id + "').selectize" + "\r\n ({\r\n searchField: 'text',\r\n openOnFocus: true,\r\n dropdownParent: 'body',\r\n create: " + jsBool(editable) + "\r\n /*allowEmptyOption: true*/\r\n " + unnull(moreSelectizeOptions2(name)) + "\r\n });\r\n ") + selectizeLayoutFix(); } if (haveJQuery) { String id = aGlobalID(); return tag("datalist", mapToLines(__38 -> hoption(__38), entries), "id", id) + tag("input", "", "name", name, "list", id); } if (editable) return hinputfield(name, value); return hselect_list(entries, value, "name", name); } public String renderDynamicComboBox(String name, String value, String info, boolean editable) { return renderDynamicComboBox(name, value, info, editable, null); } public String renderDynamicComboBox(String name, String value, String info, boolean editable, String url) { assertTrue("haveSelectizeJS", haveSelectizeJS); String id = aGlobalID(); String ajaxURL = or2(url, baseLink); return hselect_list(llNempties(value), value, "name", name, "id", id) + hjs("$('#" + id + "').selectize" + "\r\n ({\r\n searchField: 'text',\r\n valueField: 'text',\r\n labelField: 'text',\r\n openOnFocus: true,\r\n dropdownParent: 'body',\r\n create: " + jsBool(editable) + ",\r\n load: function(query, callback) {\r\n if (!query.length) return callback();\r\n var data = {\r\n comboSearchInfo: " + jsQuote(info) + ",\r\n comboSearchQuery: query\r\n };\r\n console.log(\"Loading \" + " + jsQuote(baseLink) + " + \" with \" + JSON.stringify(data));\r\n $.ajax({\r\n url: " + jsQuote(ajaxURL) + ",\r\n type: 'GET',\r\n dataType: 'json',\r\n data: data,\r\n error: function() {\r\n console.log(\"Got error\");\r\n callback();\r\n },\r\n success: function(res) {\r\n //console.log(\"Got data: \" + res);\r\n var converted = res.map(x => { return {text: x}; });\r\n //console.log(\"Converted: \" + converted);\r\n callback(converted);\r\n }\r\n });\r\n }\r\n /*allowEmptyOption: true*/\r\n " + moreSelectizeOptions2(name) + "\r\n });\r\n ") + selectizeLayoutFix(); } public void processSortParameter(Map params) { String sort = mapGet(params, sortParameter); if (nempty(sort)) if (startsWith(sort, "-")) { descending = true; sortByField = substring(sort, 1); } else { descending = false; sortByField = sort; } } public String deleteObjectHTML(Object id) { return !actuallyAllowDelete() ? null : !data.objectCanBeDeleted(id) ? span_title("Object can't be deleted, either there are references to it or you are not authorized", htmlEncode2(unicode_DEL())) : ahrefWithConfirm("Really delete item " + id + "?", deleteLink(id), htmlEncode2(unicode_DEL()), "title", "delete"); } public String addHelpText(String helpText, String html) { return empty(helpText) ? html : html + p(small(helpText), "style", "text-align: right"); } public String moreSelectizeOptions2(String name) { return unnull(moreSelectizeOptions(name)) + (!haveSelectizeClickable ? "" : "\r\n , plugins: ['clickable']\r\n , render: {\r\n option: function(item) {\r\n var id = item.text.match(/\\d+/)[0];\r\n return '';\r\n }\r\n }\r\n "); } transient public IF1 moreSelectizeOptions; public String moreSelectizeOptions(String name) { return moreSelectizeOptions != null ? moreSelectizeOptions.get(name) : moreSelectizeOptions_base(name); } final public String moreSelectizeOptions_fallback(IF1 _f, String name) { return _f != null ? _f.get(name) : moreSelectizeOptions_base(name); } public String moreSelectizeOptions_base(String name) { return ""; } public String handleComboSearch(Map params) { String query = params.get("comboSearchQuery"); if (nempty(query)) { String info = params.get("comboSearchInfo"); return jsonEncode_shallowLineBreaks(data.comboBoxSearch(info, query)); } return null; } transient public IF1, Map> preprocessUpdateParams; public Map preprocessUpdateParams(Map params) { return preprocessUpdateParams != null ? preprocessUpdateParams.get(params) : preprocessUpdateParams_base(params); } final public Map preprocessUpdateParams_fallback(IF1, Map> _f, Map params) { return _f != null ? _f.get(params) : preprocessUpdateParams_base(params); } public Map preprocessUpdateParams_base(Map params) { return params; } public void disableAllMutationRights() { mutationRights = allowCreateOrDelete = allowCreate = allowEdit = false; } transient public IF1 keepParamInPagination; public boolean keepParamInPagination(String name) { return keepParamInPagination != null ? keepParamInPagination.get(name) : keepParamInPagination_base(name); } final public boolean keepParamInPagination_fallback(IF1 _f, String name) { return _f != null ? _f.get(name) : keepParamInPagination_base(name); } public boolean keepParamInPagination_base(String name) { return eq(name, "search"); } public String customTitleOr(String title) { return or2(customTitle, or2(mapGet(params, "title"), title)); } transient public IF0 selectizeLayoutFix; public String selectizeLayoutFix() { return selectizeLayoutFix != null ? selectizeLayoutFix.get() : selectizeLayoutFix_base(); } final public String selectizeLayoutFix_fallback(IF0 _f) { return _f != null ? _f.get() : selectizeLayoutFix_base(); } public String selectizeLayoutFix_base() { return hcss(".selectize-input, .selectize-control { min-width: 300px }"); } public String formExtraHiddens() { String redirectAfterSave = mapGet(params, "redirectAfterSave"); return empty(redirectAfterSave) ? "" : hhidden("redirectAfterSave", redirectAfterSave); } public void processRenames(Map params) { if (!allowFieldRenaming) return; for (String key1 : keysList(params)) { String field = dropPrefixOrNull("rename_", key1); if (field == null) continue; String newName = trim(params.get(key1)); if (newName == null || eq(field, newName)) continue; print("Renaming " + field + " to " + or2(newName, "")); params.remove("rename_" + field); String re = "^([^_]+_)" + regexpQuote(field) + "(_[^_]+)?$"; for (String key : keysList(params)) { List groups = regexpGroups(re, key); if (groups != null) { String newKey = empty(newName) ? null : first(groups) + newName + unnull(second(groups)); mapPut(params, newKey, params.get(key)); params.put(key, ""); print("Renaming key: " + key + " => " + newKey); } } } } } static public class AppendableChain extends MinimalChain implements Iterable { public MinimalChain last; public int size; public AppendableChain() { } public AppendableChain(A element) { this.element = element; size = 1; last = this; } public AppendableChain(A element, AppendableChain next) { this.next = next; this.element = element; if (next == null) return; MinimalChain b = new MinimalChain(); b.element = next.element; b.next = next.next; this.next = b; last = next.last; size = next.size + 1; } public String toString() { return str(toList()); } public boolean add(A a) { MinimalChain newLast = new MinimalChain(a); last.next = newLast; last = newLast; ++size; return true; } public AppendableChain popFirst() { if (next == null) return null; element = next.element; if (last == next) last = this; next = next.next; --size; return this; } public ArrayList toList() { ArrayList l = emptyList(size); MinimalChain c = this; while (c != null) { l.add(c.element); c = c.next; } return l; } public class ACIt extends IterableIterator { public MinimalChain c = AppendableChain.this; public boolean hasNext() { return c != null; } public A next() { var a = c.element; c = c.next; return a; } } public IterableIterator iterator() { return new ACIt(); } } final static public class ConceptFieldIndexDesc extends ConceptFieldIndexBase { public ConceptFieldIndexDesc(Class cc, String field) { super(cc, field); } public ConceptFieldIndexDesc(Concepts concepts, Class cc, String field) { super(concepts, cc, field); } public void init() { valueToObject = treeMultiSetMap(reverseOrder()); } public void register() { concepts.addFieldIndex(cc, field, this); } public void close() { concepts.removeFieldIndex(cc, field, this); super.close(); } synchronized public List objectsWithValueGreaterThan(Object value) { SortedMap> subMap = ((SortedMap>) valueToObject.data).headMap(value); return concatLists(values(subMap)); } } static public class Fail extends RuntimeException implements IFieldsToList { public Object[] objects; public Fail() { } public Fail(Object... objects) { this.objects = objects; } public Object[] _fieldsToList() { return new Object[] { objects }; } public Fail(Throwable cause, Object... objects) { super(cause); this.objects = objects; } public String toString() { return joinNemptiesWithColon("Fail", commaCombine(getCause(), objects)); } } static public class Rect implements WidthAndHeight, IFieldsToList { static final public String _fieldOrder = "x y w h"; public int x; public int y; public int w; public int h; public Rect() { } public Rect(int x, int y, int w, int h) { this.h = h; this.w = w; this.y = y; this.x = x; } public boolean equals(Object o) { if (!(o instanceof Rect)) return false; Rect __1 = (Rect) o; return x == __1.x && y == __1.y && w == __1.w && h == __1.h; } public int hashCode() { int h = 2543108; h = boostHashCombine(h, _hashCode(x)); h = boostHashCombine(h, _hashCode(y)); h = boostHashCombine(h, _hashCode(w)); h = boostHashCombine(h, _hashCode(h)); return h; } public Object[] _fieldsToList() { return new Object[] { x, y, w, h }; } public Rect(Rectangle r) { x = r.x; y = r.y; w = r.width; h = r.height; } public Rect(Pt p, int w, int h) { this.h = h; this.w = w; x = p.x; y = p.y; } public Rect(Rect r) { x = r.x; y = r.y; w = r.w; h = r.h; } final public Rectangle getRectangle() { return new Rectangle(x, y, w, h); } public String toString() { return x + "," + y + " / " + w + "," + h; } final public int x1() { return x; } final public int y1() { return y; } final public int x2() { return x + w; } final public int y2() { return y + h; } final public boolean contains(Pt p) { return contains(p.x, p.y); } final public boolean contains(int _x, int _y) { return _x >= x && _y >= y && _x < x + w && _y < y + h; } final public boolean contains(Rectangle r) { return rectContains(this, r); } final public boolean empty() { return w <= 0 || h <= 0; } final public int getWidth() { return w; } final public int getHeight() { return h; } final public int area() { return w * h; } } static public class ProgramScan { static public int threads = isWindows() ? 500 : 10; static public int timeout = 5000; static public String ip = "127.0.0.1"; static public int quickScanFrom = 10000, quickScanTo = 10999; static public int maxNumberOfVMs_android = 4; static public int maxNumberOfVMs_nonAndroid = 50; static public int maxNumberOfVMs; static public boolean verbose = false; static public class Program { public int port; public String helloString; public Program(int port, String helloString) { this.helloString = helloString; this.port = port; } } static public List scan() { try { return scan(1, 65535); } catch (Exception __e) { throw rethrow(__e); } } static public List scan(int fromPort, int toPort) { return scan(fromPort, toPort, new int[0]); } static public List scan(int fromPort, int toPort, int[] preferredPorts) { try { Set preferredPortsSet = new HashSet(asList(preferredPorts)); int scanSize = toPort - fromPort + 1; String name = toPort < 10000 ? "bot" : "program"; int threads = isWindows() ? min(500, scanSize) : min(scanSize, 10); final ExecutorService es = Executors.newFixedThreadPool(threads); if (verbose) print(firstToUpper(name) + "-scanning " + ip + " with timeout " + timeout + " ms in " + threads + " threads."); startTiming(); List> futures = new ArrayList(); List ports = new ArrayList(); for (int port : preferredPorts) { futures.add(checkPort(es, ip, port, timeout)); ports.add(port); } for (int port = fromPort; port <= toPort; port++) if (!preferredPortsSet.contains(port) && !forbiddenPort(port)) { futures.add(checkPort(es, ip, port, timeout)); ports.add(port); } es.shutdown(); List programs = new ArrayList(); long time = now(); int i = 0; for (final Future f : futures) { if (verbose) print("Waiting for port " + get(ports, i++) + " at time " + (now() - time)); Program p = f.get(); if (p != null) programs.add(p); } if (verbose) print("Found " + programs.size() + " " + name + "(s) on " + ip); return programs; } catch (Exception __e) { throw rethrow(__e); } } static public Future checkPort(final ExecutorService es, final String ip, final int port, final int timeout) { return es.submit(new Callable() { @Override public Program call() { try { Socket socket = new Socket(); try { socket.setSoTimeout(timeout); socket.connect(new InetSocketAddress(ip, port), timeout); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8")); String hello = or(in.readLine(), "?"); return new Program(port, hello); } finally { socket.close(); } } catch (Exception ex) { return null; } } }); } static public List quickScan() { return scan(quickScanFrom, quickScanTo); } static public List quickBotScan() { return quickBotScan(new int[0]); } static public List quickBotScan(int[] preferredPorts) { if (maxNumberOfVMs == 0) maxNumberOfVMs = isAndroid() ? maxNumberOfVMs_android : maxNumberOfVMs_nonAndroid; return scan(4999, 5000 + maxNumberOfVMs - 1, preferredPorts); } } static public class Pt implements Comparable, IDoublePt { public int x, y; public Pt() { } public Pt(Point p) { x = p.x; y = p.y; } public Pt(int x, int y) { this.y = y; this.x = x; } public Point getPoint() { return new Point(x, y); } public boolean equals(Object o) { return o instanceof Pt && x == ((Pt) o).x && y == ((Pt) o).y; } public int hashCode() { return boostHashCombine(x, y); } public int compareTo(Pt p) { if (y != p.y) return cmp(y, p.y); return cmp(x, p.x); } public String toString() { return x + ", " + y; } public double length() { return sqrt(x * x + y * y); } public Pt minus(Pt p) { return ptMinus(this, p); } public double x_double() { return x; } public double y_double() { return y; } } static public class ConceptFieldIndex extends ConceptFieldIndexBase { public ConceptFieldIndex(Class cc, String field) { super(cc, field); } public ConceptFieldIndex(Concepts concepts, Class cc, String field) { super(concepts, cc, field); } public void init() { valueToObject = new MultiSetMap(); } public void register() { concepts.addFieldIndex(cc, field, this); } } static public interface IRef extends IF0 { public default void replaceValue(A oldValue, A newValue) { } } static abstract public class F0 { abstract public A get(); } static abstract public class F1 { abstract public B get(A a); } static abstract public class IterableIterator implements Iterator, Iterable { public Iterator iterator() { return this; } public void remove() { unsupportedOperation(); } } static public class Flag implements Runnable { public boolean up = false; public synchronized boolean raise() { if (!up) { up = true; notifyAll(); return true; } else return false; } public synchronized void waitUntilUp() { try { while (!up) { wait(); } } catch (Exception __e) { throw rethrow(__e); } } public boolean waitUntilUp(double timeout) { if (timeout == infinity()) { waitUntilUp(); return isUp(); } else return waitUntilUp(toMS(timeout)); } public synchronized boolean waitUntilUp(long timeout) { try { if (!up) { wait(timeout); } return isUp(); } catch (Exception __e) { throw rethrow(__e); } } public synchronized boolean isUp() { return up; } public boolean get() { return isUp(); } public String toString() { return isUp() ? "up" : "down"; } public void waitForThisOr(Flag otherFlag) { try { while (!isUp() && !otherFlag.isUp()) Thread.sleep(50); } catch (Exception __e) { throw rethrow(__e); } } public void run() { raise(); } } static public interface MakesBufferedImage extends WidthAndHeight { public BufferedImage getBufferedImage(); public default void drawAt(Graphics2D g, int x, int y) { g.drawImage(getBufferedImage(), x, y, null); } } final static public class ContentsIndexedList extends RandomAccessAbstractList implements IContentsIndexedList, IContentsIndexedList2 { public Map>> index = new HashMap(); final public ArrayList> list = new ArrayList(); final static public class Elem extends HasIndex { public A s; public String toString() { return "Elem " + quote(s) + "@" + idx; } } public ContentsIndexedList() { } public ContentsIndexedList(Map>> index) { this.index = index; } public ContentsIndexedList(Collection l) { addAll(l); } public A get(int i) { return list.get(i).s; } public int size() { return list.size(); } public A set(int i, A s) { Elem t = list.get(i); A old = t.s; if (eq(old, s)) return old; removeFromIdx(t); t.s = s; addToIdx(t); return old; } public boolean add(A s) { ++modCount; Elem t = new Elem(); t.s = s; t.idx = size(); list.add(t); addToIdx(t); return true; } public void add(int i, A s) { ++modCount; Elem t = new Elem(); t.s = s; t.idx = i; list.add(i, t); reorder(i + 1); addToIdx(t); } public boolean addAll(int i, Collection l) { int n = l.size(); if (n == 0) return false; ++modCount; List> l2 = emptyList(n); int j = i; for (A s : l) { Elem t = new Elem(); t.s = s; t.idx = j++; l2.add(t); } list.addAll(i, l2); reorder(i + n); for (Elem t : l2) addToIdx(t); return true; } public A remove(int i) { ++modCount; Elem t = list.get(i); removeFromIdx(t); list.remove(i); reorder(i); return t.s; } public void reorder(int fromIdx) { int n = size(); for (int i = fromIdx; i < n; i++) list.get(i).idx = i; } public void removeFromIdx(Elem t) { TreeSet> idx = index.get(t.s); idx.remove(t); if (idx.isEmpty()) index.remove(t.s); } public void addToIdx(Elem t) { TreeSet> idx = index.get(t.s); if (idx == null) index.put(t.s, idx = new TreeSet()); idx.add(t); } @Override public int indexOf(Object s) { TreeSet> l = index.get(s); return l == null ? -1 : first(l).idx; } @Override public int lastIndexOf(Object s) { TreeSet> l = index.get(s); return l == null ? -1 : last(l).idx; } @Override public boolean contains(Object s) { return index.containsKey(s); } public void clear() { ++modCount; index.clear(); list.clear(); } public void removeRange(int fromIndex, int toIndex) { if (fromIndex == toIndex) return; ++modCount; for (int i = fromIndex; i < toIndex; i++) removeFromIdx(list.get(i)); list.subList(fromIndex, toIndex).clear(); reorder(fromIndex); } public int[] indicesOf(A o) { TreeSet> idx = index.get(o); if (idx == null) return emptyIntArray(); int[] a = new int[idx.size()]; int i = 0; for (Elem t : idx) a[i++] = t.idx; return a; } public TreeSet indicesOf_treeSetOfHasIndex(A o) { return (TreeSet) index.get(o); } } static public class SynchronizedNavigableMap extends SynchronizedSortedMap implements NavigableMap { public SynchronizedNavigableMap() { } public NavigableMap innerMap() { return (NavigableMap) m; } public SynchronizedNavigableMap(NavigableMap m) { super(m); } public SynchronizedNavigableMap(NavigableMap m, Object mutex) { super(m, mutex); } public Entry lowerEntry(K key) { synchronized (mutex) { return innerMap().lowerEntry(key); } } public K lowerKey(K key) { synchronized (mutex) { return innerMap().lowerKey(key); } } public Entry floorEntry(K key) { synchronized (mutex) { return innerMap().floorEntry(key); } } public K floorKey(K key) { synchronized (mutex) { return innerMap().floorKey(key); } } public Entry ceilingEntry(K key) { synchronized (mutex) { return innerMap().ceilingEntry(key); } } public K ceilingKey(K key) { synchronized (mutex) { return innerMap().ceilingKey(key); } } public Entry higherEntry(K key) { synchronized (mutex) { return innerMap().higherEntry(key); } } public K higherKey(K key) { synchronized (mutex) { return innerMap().higherKey(key); } } public Entry firstEntry() { synchronized (mutex) { return innerMap().firstEntry(); } } public Entry lastEntry() { synchronized (mutex) { return innerMap().lastEntry(); } } public Entry pollFirstEntry() { synchronized (mutex) { return innerMap().pollFirstEntry(); } } public Entry pollLastEntry() { synchronized (mutex) { return innerMap().pollLastEntry(); } } public NavigableMap descendingMap() { synchronized (mutex) { return new SynchronizedNavigableMap<>(innerMap().descendingMap(), mutex); } } public NavigableSet keySet() { return navigableKeySet(); } public NavigableSet navigableKeySet() { synchronized (mutex) { return new SynchronizedNavigableSet<>(innerMap().navigableKeySet(), mutex); } } public NavigableSet descendingKeySet() { synchronized (mutex) { return new SynchronizedNavigableSet<>(innerMap().descendingKeySet(), mutex); } } public SortedMap subMap(K fromKey, K toKey) { synchronized (mutex) { return new SynchronizedNavigableMap<>(innerMap().subMap(fromKey, true, toKey, false), mutex); } } public SortedMap headMap(K toKey) { synchronized (mutex) { return new SynchronizedNavigableMap<>(innerMap().headMap(toKey, false), mutex); } } public SortedMap tailMap(K fromKey) { synchronized (mutex) { return new SynchronizedNavigableMap<>(innerMap().tailMap(fromKey, true), mutex); } } public NavigableMap subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) { synchronized (mutex) { return new SynchronizedNavigableMap<>(innerMap().subMap(fromKey, fromInclusive, toKey, toInclusive), mutex); } } public NavigableMap headMap(K toKey, boolean inclusive) { synchronized (mutex) { return new SynchronizedNavigableMap<>(innerMap().headMap(toKey, inclusive), mutex); } } public NavigableMap tailMap(K fromKey, boolean inclusive) { synchronized (mutex) { return new SynchronizedNavigableMap<>(innerMap().tailMap(fromKey, inclusive), mutex); } } } public static interface IF0 { public A get(); } static public interface Hasher { public int hashCode(A a); public boolean equals(A a, A b); } static abstract public class CloseableIterableIterator extends IterableIterator implements AutoCloseable { public void close() throws Exception { } } static public interface IF2 { public C get(A a, B b); } static public interface Producer { public A next(); } static public interface IF1 { public B get(A a); } static public interface IVF1 { public void get(A a); } static public interface IIntPred { public boolean get(int a); } static public class SynchronizedList extends SynchronizedCollection implements List { public SynchronizedList() { } public List list; public SynchronizedList(List list) { super(list); this.list = list; } public SynchronizedList(List list, Object mutex) { super(list, mutex); this.list = list; } public boolean equals(Object o) { if (this == o) return true; synchronized (mutex) { return list.equals(o); } } public int hashCode() { synchronized (mutex) { return list.hashCode(); } } public E get(int index) { synchronized (mutex) { return list.get(index); } } public E set(int index, E element) { synchronized (mutex) { return list.set(index, element); } } public void add(int index, E element) { synchronized (mutex) { list.add(index, element); } } public E remove(int index) { synchronized (mutex) { return list.remove(index); } } public int indexOf(Object o) { synchronized (mutex) { return list.indexOf(o); } } public int lastIndexOf(Object o) { synchronized (mutex) { return list.lastIndexOf(o); } } public boolean addAll(int index, Collection c) { synchronized (mutex) { return list.addAll(index, c); } } public ListIterator listIterator() { return list.listIterator(); } public ListIterator listIterator(int index) { return list.listIterator(index); } public List subList(int fromIndex, int toIndex) { synchronized (mutex) { return new SynchronizedList<>(list.subList(fromIndex, toIndex), mutex); } } @Override public void replaceAll(java.util.function.UnaryOperator operator) { synchronized (mutex) { list.replaceAll(operator); } } @Override public void sort(Comparator c) { synchronized (mutex) { list.sort(c); } } @java.io.Serial final public Object readResolve() { return (list instanceof RandomAccess ? new SynchronizedRandomAccessList<>(list) : this); } } static public class Cache { public Object maker; public A value; public long loaded; static public boolean debug = false; public long changeCount; public Lock lock = lock(); public Cache() { } public Cache(Object maker) { this.maker = maker; } public Cache(IF0 maker) { this.maker = maker; } public A get() { if (hasLock(lock)) return value; Lock __0 = lock; lock(__0); try { if (loaded == 0) { value = make(); changeCount++; loaded = sysNow(); } return value; } finally { unlock(__0); } } public void clear() { Lock __1 = lock; lock(__1); try { if (debug && loaded != 0) print("Clearing cache"); value = null; changeCount++; loaded = 0; } finally { unlock(__1); } } public void clear(double seconds) { Lock __2 = lock; lock(__2); try { if (seconds != 0 && loaded != 0 && sysNow() >= loaded + seconds * 1000) clear(); } finally { unlock(__2); } } public void set(A a) { Lock __3 = lock; lock(__3); try { value = a; ++changeCount; loaded = sysNow(); } finally { unlock(__3); } } public A make() { return (A) callF(maker); } } final static public class _MethodCache { final public Class c; final public HashMap> cache = new HashMap(); public _MethodCache(Class c) { this.c = c; _init(); } public void _init() { Class _c = c; java.lang.Module myModule = getClass().getModule(); boolean anyHiddenClasses = false; while (_c != null) { boolean exported = classIsExportedTo(_c, myModule); if (!exported) anyHiddenClasses = true; else for (Method m : _c.getDeclaredMethods()) if ((anyHiddenClasses || !isAbstract(m)) && !reflection_isForbiddenMethod(m)) multiMapPut(cache, m.getName(), makeAccessible(m)); _c = _c.getSuperclass(); } for (Class intf : allInterfacesImplementedBy(c)) for (Method m : intf.getDeclaredMethods()) if ((anyHiddenClasses || m.isDefault()) && !reflection_isForbiddenMethod(m)) multiMapPut(cache, m.getName(), makeAccessible(m)); } public Method findMethod(String method, Object[] args) { try { List m = cache.get(method); if (m == null) return null; int n = m.size(); for (int i = 0; i < n; i++) { Method me = m.get(i); if (call_checkArgs(me, args, false)) return me; } return null; } catch (Exception __e) { throw rethrow(__e); } } public Method findStaticMethod(String method, Object[] args) { try { List m = cache.get(method); if (m == null) return null; int n = m.size(); for (int i = 0; i < n; i++) { Method me = m.get(i); if (isStaticMethod(me) && call_checkArgs(me, args, false)) return me; } return null; } catch (Exception __e) { throw rethrow(__e); } } } static public class Matches { public String[] m; public Matches() { } public Matches(String... m) { this.m = m; } public String get(int i) { return i < m.length ? m[i] : null; } public String unq(int i) { return unquote(get(i)); } public String tlc(int i) { return unq(i).toLowerCase(); } public boolean bool(int i) { return "true".equals(unq(i)); } public String rest() { return m[m.length - 1]; } public int psi(int i) { return Integer.parseInt(unq(i)); } public String toString() { return "Matches(" + joinWithComma(quoteAll(asList(m))) + ")"; } public int hashCode() { return _hashCode(toList(m)); } public boolean equals(Object o) { return o instanceof Matches && arraysEqual(m, ((Matches) o).m); } } static public class Symbol implements CharSequence { public String text; public Symbol() { } public Symbol(String text, boolean dummy) { this.text = text; } public int hashCode() { return _hashCode(text); } public String toString() { return text; } public boolean equals(Object o) { return this == o; } public int length() { return text.length(); } public char charAt(int index) { return text.charAt(index); } public CharSequence subSequence(int start, int end) { return text.substring(start, end); } } static public interface IMeta { public void _setMeta(Object meta); public Object _getMeta(); default public IAutoCloseableF0 _tempMetaMutex() { return new IAutoCloseableF0() { public Object get() { return IMeta.this; } public void close() { } }; } default public Object getMeta(Object obj, Object key) { return metaGet(obj, key); } default public Object metaGet(Object obj, Object key) { return metaMapGet(obj, key); } default public Object metaGet(String key, Object obj) { return metaMapGet(obj, key); } default public Object getMeta(Object key) { return metaGet(key); } default public Object metaGet(Object key) { if (key == null) return null; Object meta = _getMeta(); if (meta instanceof Map) return ((Map) meta).get(key); return null; } default public void metaSet(IMeta obj, Object key, Object value) { metaPut(obj, key, value); } default public void metaPut(IMeta obj, Object key, Object value) { metaMapPut(obj, key, value); } default public void metaSet(Object key, Object value) { metaPut(key, value); } default public void metaPut(Object key, Object value) { if (key == null) return; Map map = convertObjectMetaToMap(this); syncMapPutOrRemove(map, key, value); } } static public class HCRUD_Concepts extends HCRUD_Data { public Concepts cc = db_mainConcepts(); public Class cClass; public List> onCreateOrUpdate = new ArrayList(); public List> onCreate = new ArrayList(); public IVF2> afterUpdate; public Map filters; public Map ciFilters; public IF1, Collection> customFilter; public ValueConverterForField valueConverter; public boolean referencesBlockDeletion = false; public boolean trimAllSingleLineValues = false; public Set fieldsToHideInCreationForm; public boolean lockDB = false; public boolean verbose = false; public boolean dropEmptyListValues = true; public boolean lsMagic = false; public boolean convertConceptValuesToRefs = false; public A currentConcept; public boolean useDynamicComboBoxes = false; public IF1 useDynamicComboBoxesForField; public int dynamicComboBoxesThreshold = 1000; public HCRUD_Concepts(Class cClass) { this.cClass = cClass; } public HCRUD_Concepts(Concepts cc, Class cClass) { this.cClass = cClass; this.cc = cc; } transient public IF0 itemName; public String itemName() { return itemName != null ? itemName.get() : itemName_base(); } final public String itemName_fallback(IF0 _f) { return _f != null ? _f.get() : itemName_base(); } public String itemName_base() { return humanizeShortName(cClass); } transient public IF0 itemNamePlural; public String itemNamePlural() { return itemNamePlural != null ? itemNamePlural.get() : itemNamePlural_base(); } final public String itemNamePlural_fallback(IF0 _f) { return _f != null ? _f.get() : itemNamePlural_base(); } public String itemNamePlural_base() { return super.itemNamePlural(); } public List itemsForListing() { return defaultSort(asList(listConcepts())); } @Override public List> list() { return lazyMap(itemsForListing(), a -> new Item(str(a.id)) { public Map calcFullMap() { return itemToMapForList(a); } }); } @Override public List> list(IntRange range) { return lambdaMap(__39 -> itemToMapForList(__39), subListOrFull(itemsForListing(), range)); } public Collection listConcepts() { Collection l = listConcepts_firstStep(); return postProcess(customFilter, l); } transient public IF0> listConcepts_firstStep; public Collection listConcepts_firstStep() { return listConcepts_firstStep != null ? listConcepts_firstStep.get() : listConcepts_firstStep_base(); } final public Collection listConcepts_firstStep_fallback(IF0> _f) { return _f != null ? _f.get() : listConcepts_firstStep_base(); } public Collection listConcepts_firstStep_base() { if (empty(ciFilters)) return conceptsWhere(cc, cClass, mapToParams(filters)); else if (empty(filters)) return conceptsWhereCI(cc, cClass, mapToParams(ciFilters)); else { Collection l = conceptsWhere(cc, cClass, mapToParams(filters)); return filterConceptsIC(l, mapToParams(ciFilters)); } } transient public IF0> defaultSortField; public Pair defaultSortField() { return defaultSortField != null ? defaultSortField.get() : defaultSortField_base(); } final public Pair defaultSortField_fallback(IF0> _f) { return _f != null ? _f.get() : defaultSortField_base(); } public Pair defaultSortField_base() { return pair("id", true); } transient public IF1, List> defaultSort; public List defaultSort(List l) { return defaultSort != null ? defaultSort.get(l) : defaultSort_base(l); } final public List defaultSort_fallback(IF1, List> _f, List l) { return _f != null ? _f.get(l) : defaultSort_base(l); } public List defaultSort_base(List l) { return sortedByConceptIDDesc(l); } transient public IF0 emptyConcept; public A emptyConcept() { return emptyConcept != null ? emptyConcept.get() : emptyConcept_base(); } final public A emptyConcept_fallback(IF0 _f) { return _f != null ? _f.get() : emptyConcept_base(); } public A emptyConcept_base() { return unlisted(cClass); } transient public IF0> emptyObject; public Map emptyObject() { return emptyObject != null ? emptyObject.get() : emptyObject_base(); } final public Map emptyObject_fallback(IF0> _f) { return _f != null ? _f.get() : emptyObject_base(); } public Map emptyObject_base() { A c = emptyConcept(); Map map = itemToMap(c); return mapMinusKeys(fieldsToHideInCreationForm, map); } public Map itemToMap(A c) { if (c == null) return null; return putKeysFirst(getFieldOrder(c), conceptToMap_gen_withNullValues(c)); } public Map itemToMapForList(A c) { if (c == null) return null; Map map = itemToMap(c); massageItemMapForList(c, map); return map; } transient public IVF2> massageItemMapForList; public void massageItemMapForList(A c, Map map) { if (massageItemMapForList != null) massageItemMapForList.get(c, map); else massageItemMapForList_base(c, map); } final public void massageItemMapForList_fallback(IVF2> _f, A c, Map map) { if (_f != null) _f.get(c, map); else massageItemMapForList_base(c, map); } public void massageItemMapForList_base(A c, Map map) { } transient public IVF2> massageItemMapForUpdate; public void massageItemMapForUpdate(A c, Map map) { if (massageItemMapForUpdate != null) massageItemMapForUpdate.get(c, map); else massageItemMapForUpdate_base(c, map); } final public void massageItemMapForUpdate_fallback(IVF2> _f, A c, Map map) { if (_f != null) _f.get(c, map); else massageItemMapForUpdate_base(c, map); } public void massageItemMapForUpdate_base(A c, Map map) { Collection refLFields = nonStaticNonTransientFieldObjectsOfType(Concept.RefL.class, c); printVars_str("refLFields", refLFields, "c", c); for (Field f : refLFields) { TreeMap values = new TreeMap(); Matches m = new Matches(); for (Map.Entry __2 : _entrySet(cloneMap(map))) { String key = __2.getKey(); Object value = __2.getValue(); if (startsWith(key, f.getName() + "_", m) && isInteger(m.rest())) { Concept concept = getConceptFromString((String) value); if (concept != null || !dropEmptyListValues) values.put(parseInt(m.rest()), concept); map.remove(key); } } if (!dropEmptyListValues) while (nempty(values) && lastValue(values) == null) { if (verbose) print("Dropping value " + lastEntry(values)); removeLastKey(values); } map.put(f.getName(), valuesAsList(values)); } for (String name : cloneKeys(map)) { String metaInfo = metaInfoFromForm(name); print("metaInfo for " + name + ": " + metaInfo); if (eqic(metaInfo, "concept")) replaceStringValueWithConcept(map, name); else if (eqic(metaInfo, "bool")) replaceStringValueWithBool(map, name); } for (Field f : nonStaticNonTransientFieldObjectsOfType(Concept.Ref.class, c)) replaceStringValueWithConcept(map, f.getName()); if (trimAllSingleLineValues) for (Map.Entry e : map.entrySet()) { String val = optCastString(e.getValue()); if (val != null && isSingleLine(val) && isUntrimmed(val)) e.setValue(trim(val)); } if (lsMagic) for (Field f : nonStaticNonTransientFieldObjectsOfType(List.class, c)) { if (eqOneOf(f.getName(), "refs", "backRefs")) continue; TreeMap values = new TreeMap(); Matches m = new Matches(); for (Map.Entry __1 : _entrySet(cloneMap(map))) { String key = __1.getKey(); Object value = __1.getValue(); if (startsWith(key, f.getName() + "_", m) && isInteger(m.rest())) { if (!dropEmptyListValues || nempty((String) value)) { if (verbose) print("Adding value " + m.rest() + " / " + value); mapPut(values, parseInt(m.rest()), (String) value); } map.remove(key); } } if (!dropEmptyListValues) while (nempty(values) && empty(lastValue(values))) { if (verbose) print("Dropping value " + lastEntry(values)); removeLastKey(values); } map.put(f.getName(), valuesAsList(values)); } for (Field f : nonStaticNonTransientFieldObjectsOfType(SecretValue.class, c)) map.remove(f.getName()); } public void replaceStringValueWithConcept(Map map, String key) { Object value = map.get(key); if (value instanceof String) { Concept concept = getConceptFromString((String) value); map.put(key, concept); } } public void replaceStringValueWithBool(Map map, String key) { Object value = map.get(key); if (value instanceof String) { map.put(key, englishStringToBool((String) value)); } } transient public IF1> getObject; public Map getObject(Object id) { return getObject != null ? getObject.get(id) : getObject_base(id); } final public Map getObject_fallback(IF1> _f, Object id) { return _f != null ? _f.get(id) : getObject_base(id); } public Map getObject_base(Object id) { return itemToMap(conceptForID(id)); } public Map getObjectForEdit(Object id) { currentConcept = conceptForID(id); return getObject(id); } public Object createObject(Map fullMap, String fieldPrefix) { rawFormValues = fullMap; try { Map map = extractFieldValues(fullMap, fieldPrefix); A c = cnew(cc, cClass); setValues(c, mapMinusKeys(map, filteredFields()), true); cset(c, mapToParams(filters)); cset(c, mapToParams(ciFilters)); pcallFAll(onCreate, c); pcallFAll(onCreateOrUpdate, c); callOpt(c, "_onCreated"); return c.id; } finally { rawFormValues = null; } } public void setValues(A c, Map map, boolean creating) { Lock __3 = lockDB && !creating ? dbLock(cc) : null; lock(__3); try { Map map2 = (Map) cloneMap(map); massageItemMapForUpdate(c, map2); if (verbose) { print("setValues " + map); print("backRefs: " + c.backRefs); } Map oldValues = !creating && afterUpdate != null ? cgetAll_cloneLists(c, keys(map2)) : null; if (convertConceptValuesToRefs) convertAllConceptValuesToRefs(c, map2); if (valueConverter == null) cSmartSet(c, mapToParams(map2)); else cSmartSet_withConverter_pcall(verbose, valueConverter, c, mapToParams(map2)); if (oldValues != null) callF(afterUpdate, c, oldValues); if (verbose) print("backRefs: " + c.backRefs); } finally { unlock(__3); } } public void convertAllConceptValuesToRefs(A c, Map map) { for (Map.Entry __0 : _entrySet(cloneMap(map))) { String key = __0.getKey(); Object value = __0.getValue(); if (value instanceof Concept) if (!hasField(c, key)) { print("Converting value to ref: " + key); map.put(key, c.new Ref((Concept) value)); } } } public A conceptForID(Object id) { return _getConcept(cc, cClass, toLong(id)); } public String updateObject(Object id, Map fullMap, String fieldPrefix) { rawFormValues = fullMap; try { Map map = extractFieldValues(fullMap, fieldPrefix); A c = conceptForID(id); if (c == null) return "Object " + id + " not found"; { String __5 = checkFilters(c); if (!empty(__5)) return __5; } setValues(c, map, false); pcallFAll(onCreateOrUpdate, c); return "Object " + id + " updated"; } finally { rawFormValues = null; } } public String deleteObject(Object id) { A c = conceptForID(id); if (c == null) return "Object " + id + " not found"; { String __6 = checkFilters(c); if (!empty(__6)) return __6; } actuallyDeleteConcept(c); return "Object " + id + " deleted"; } transient public IVF1 actuallyDeleteConcept; public void actuallyDeleteConcept(A c) { if (actuallyDeleteConcept != null) actuallyDeleteConcept.get(c); else actuallyDeleteConcept_base(c); } final public void actuallyDeleteConcept_fallback(IVF1 _f, A c) { if (_f != null) _f.get(c); else actuallyDeleteConcept_base(c); } public void actuallyDeleteConcept_base(A c) { deleteConcept(c); } public String checkFilters(A c) { if (!checkConceptFields(c, mapToParams(filters)) || !checkConceptFieldsIC(c, mapToParams(ciFilters))) return "Object " + c.id + " not in view"; return ""; } public HCRUD_Concepts addFilters(Map map) { for (Map.Entry __7 : _entrySet(unnullForIteration(map))) { String field = __7.getKey(); Object value = __7.getValue(); addFilter(field, value); } return this; } public HCRUD_Concepts addFilter(String field, Object value) { filters = orderedMapPutOrCreate(filters, field, value); return this; } transient public IF1 isEditableValue; public boolean isEditableValue(Object value) { return isEditableValue != null ? isEditableValue.get(value) : isEditableValue_base(value); } final public boolean isEditableValue_fallback(IF1 _f, Object value) { return _f != null ? _f.get(value) : isEditableValue_base(value); } public boolean isEditableValue_base(Object value) { if (value instanceof List) return true; if (value instanceof Collection) return false; return true; } public Renderer getRenderer(String field) { if (!isEditableValue(currentValue)) return new NotEditable(); Class type = fieldType(or(currentConcept, cClass), field); String metaInfo = metaInfoFromForm(field); if (eq(type, boolean.class)) return new CheckBox(); if (eq(type, Boolean.class)) return new ComboBox(ll("", "yes", "no"), b -> trueFalseNull((Boolean) b, "yes", "no", "")); if (isSubtypeOf(type, Concept.Ref.class)) { Class c = fieldTypeArg(field); AbstractComboBox cb = makeConceptsComboBox(field, c); cb.metaInfo = "concept"; return cb; } Object val = deref(currentValue); if (val instanceof Concept) { Class c = ((Concept) val).getClass(); AbstractComboBox cb = makeConceptsComboBox(field, c); cb.metaInfo = "concept"; return cb; } if (eqic(metaInfo, "concept")) { printVars_str("metaInfo value", "field", field, "val", val); AbstractComboBox cb = makeConceptsComboBox(field, Concept.class); cb.metaInfo = "concept"; return cb; } if (eq(type, Concept.RefL.class)) { Class c = fieldTypeArg(field); return new FlexibleLengthList(makeConceptsComboBox(field, c)); } if (eq(type, List.class)) { return new FlexibleLengthList(new TextField(80)); } if (val instanceof Boolean) return new CheckBox(); return super.getRenderer(field); } public DynamicComboBox makeDynamicComboBox(String field, Class c) { DynamicComboBox cb = new DynamicComboBox(field); cb.valueToEntry = value -> { value = deref(value); long id = 0; if (value instanceof Concept) id = conceptID((Concept) value); else if (value instanceof String && isInteger((String) value)) id = parseLong(value); if (id != 0) return comboBoxItem(_getConcept(cc, id)); return null; }; return cb; } public AbstractComboBox makeConceptsComboBox(String field, Class c) { if (c == null) throw fail(("Null type for field " + field + ". currentConcept: ") + currentConcept); if (useDynamicComboBoxes || useDynamicComboBoxesForField != null && useDynamicComboBoxesForField.get(field)) return makeDynamicComboBox(field, c); Collection concepts = listConceptClass(c); if (l(concepts) >= dynamicComboBoxesThreshold) return makeDynamicComboBox(field, c); List entries = comboBoxItems(concepts); ComboBox cb = new ComboBox(entries); cb.valueToEntry = value -> { value = deref(value); long id = 0; if (value instanceof Concept) id = conceptID((Concept) value); else if (value instanceof String && isInteger((String) value)) id = parseLong(value); if (id != 0) { String entry = firstWhereFirstLongIs(entries, id); return entry; } return null; }; return cb; } public Collection listConceptClass(Class c) { return cc.list(c); } public List comboBoxItemsForConceptClass(Class c) { return comboBoxItems(listConceptClass(c)); } public List comboBoxItems(Collection l) { return comboBoxItems_static(l); } static public List comboBoxItems_static(Collection l) { return itemPlus("", lmap(__40 -> comboBoxItem_static(__40), l)); } public String comboBoxItem(Concept val) { return comboBoxItem_static(val); } static public String comboBoxItem_static(Concept val) { return val == null ? null : shorten(val.id + ": " + val); } transient public IF1 objectCanBeDeleted; public boolean objectCanBeDeleted(Object id) { return objectCanBeDeleted != null ? objectCanBeDeleted.get(id) : objectCanBeDeleted_base(id); } final public boolean objectCanBeDeleted_fallback(IF1 _f, Object id) { return _f != null ? _f.get(id) : objectCanBeDeleted_base(id); } public boolean objectCanBeDeleted_base(Object id) { return !referencesBlockDeletion || !hasBackRefs(conceptForID(id)); } public Set filteredFields() { return joinSets(keys(filters), keys(ciFilters)); } public Class fieldTypeArg(String field) { return getTypeArgumentAsClass(genericFieldType(or(currentConcept, cClass), field)); } transient public IF2> conceptClassForComboBoxSearch; public Class conceptClassForComboBoxSearch(String info, String query) { return conceptClassForComboBoxSearch != null ? conceptClassForComboBoxSearch.get(info, query) : conceptClassForComboBoxSearch_base(info, query); } final public Class conceptClassForComboBoxSearch_fallback(IF2> _f, String info, String query) { return _f != null ? _f.get(info, query) : conceptClassForComboBoxSearch_base(info, query); } public Class conceptClassForComboBoxSearch_base(String info, String query) { if (!isIdentifier(info)) return cClass; String field = info; Class c = fieldTypeArg(field); if (c == null) c = cClass; return c; } transient public IF2> comboBoxSearchBaseItems; public List comboBoxSearchBaseItems(String info, String query) { return comboBoxSearchBaseItems != null ? comboBoxSearchBaseItems.get(info, query) : comboBoxSearchBaseItems_base(info, query); } final public List comboBoxSearchBaseItems_fallback(IF2> _f, String info, String query) { return _f != null ? _f.get(info, query) : comboBoxSearchBaseItems_base(info, query); } public List comboBoxSearchBaseItems_base(String info, String query) { var c = conceptClassForComboBoxSearch(info, query); if (c == null) return emptyList(); return comboBoxItemsForConceptClass(c); } public List comboBoxSearch(String info, String query) { List items = comboBoxSearchBaseItems(info, query); return takeFirst(10, scoredSearch(query, items)); } public A conceptForMap(Map map) { if (map == null) return null; long id = toLong(map.get(idField())); return id == 0 ? null : (A) _getConcept(cc, id); } public A getConcept(Map map) { return conceptForMap(map); } public Map extractFieldValues(Map fullMap, String fieldPrefix) { return subMapStartingWith_dropPrefix(fullMap, fieldPrefix); } public Concept getConceptFromString(String s) { long conceptID = parseFirstLong(s); return _getConcept(cc, conceptID); } public String metaInfoFromForm(String field) { return mapGet(rawFormValues, "metaInfo_" + field); } public void addCIFilter(String field, String value) { ciFilters = putOrCreate(ciFilters, field, value); } transient public IF1 titleForObjectID; public String titleForObjectID(Object id) { return titleForObjectID != null ? titleForObjectID.get(id) : titleForObjectID_base(id); } final public String titleForObjectID_fallback(IF1 _f, Object id) { return _f != null ? _f.get(id) : titleForObjectID_base(id); } public String titleForObjectID_base(Object id) { return htmlEncode2(strOrNull(conceptForID(id))); } } static public class BetterThread extends Thread { public Runnable target; public BetterThread(Runnable target) { this.target = target; _created(); } public BetterThread(Runnable target, String name) { super(name); this.target = target; _created(); } public void _created() { vmBus_send("threadCreated", this); } public void run() { try { try { vmBus_send("threadStarted", this); if (target != null) target.run(); } finally { vmBus_send("threadEnded", this); } } catch (Exception __e) { throw rethrow(__e); } } public Runnable getTarget() { return target; } } static public boolean NanoHTTPD_debug = false; static abstract public class NanoHTTPD implements AutoCloseable { public boolean decodePercentInURI = false; public boolean noQueryStringParameter = true; public boolean collectHeaderLines = false; static public ThreadLocal currentSession = new ThreadLocal(); static public List badClients = synchroList(); public interface AsyncRunner { public void closeAll(); public void closed(ClientHandler clientHandler); public void exec(ClientHandler code); } public class ClientHandler implements Runnable { final public InputStream inputStream; public OutputStream outputStream; final public Socket acceptSocket; public boolean specialHandler = false; public ClientHandler(InputStream inputStream, Socket acceptSocket) { this.inputStream = inputStream; this.acceptSocket = acceptSocket; } public void close() { if (NanoHTTPD_debug) printVars("ClientHandler.close", "specialHandler", specialHandler); if (specialHandler) return; safeClose(this.outputStream); safeClose(this.inputStream); safeClose(this.acceptSocket); } @Override public void run() { try { outputStream = this.acceptSocket.getOutputStream(); TempFileManager tempFileManager = NanoHTTPD.this.tempFileManagerFactory.create(); HTTPSession session = new HTTPSession(tempFileManager, acceptSocket, this.inputStream, outputStream, this.acceptSocket.getInetAddress()); if (NanoHTTPD_debug) print("NanoHTTPD: Have session"); while (!this.acceptSocket.isClosed() && !session.badClient) { if (NanoHTTPD_debug) print("session execute"); session.execute(); if (NanoHTTPD_debug) print("specialHandler", session.specialHandler); if (session.specialHandler) { specialHandler = true; return; } } } catch (Exception e) { print("NanoHTTPD: Error " + e); if (!(e instanceof SocketException && "NanoHttpd Shutdown".equals(e.getMessage())) && !(e instanceof SocketTimeoutException)) { NanoHTTPD.LOG.log(Level.FINE, "Communication with the client broken", e); } } finally { close(); NanoHTTPD.this.asyncRunner.closed(this); if (NanoHTTPD_debug) print("NanoHTTPD: finally branch done"); } } } public static class Cookie { public static String getHTTPTime(int days) { Calendar calendar = Calendar.getInstance(); SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); calendar.add(Calendar.DAY_OF_MONTH, days); return dateFormat.format(calendar.getTime()); } final public String n, v, e; public String domain, path; public Cookie(String name, String value) { this(name, value, 30); } public Cookie(String name, String value, int numDays) { this.n = name; this.v = value; this.e = getHTTPTime(numDays); } public Cookie(String name, String value, String expires) { this.n = name; this.v = value; this.e = expires; } public String getHTTPHeader() { StringBuilder buf = new StringBuilder(); buf.append(n).append("=").append(v).append("; expires=").append(e); if (nempty(domain)) buf.append("; Domain=").append(domain); if (nempty(path)) buf.append("; Path=").append(path); return buf.toString(); } } public class CookieHandler implements Iterable { final public HashMap cookies = new HashMap(); final public ArrayList queue = new ArrayList(); public CookieHandler(Map httpHeaders) { String raw = httpHeaders.get("cookie"); if (raw != null) { String[] tokens = raw.split(";"); for (String token : tokens) { String[] data = token.trim().split("="); if (data.length == 2) { this.cookies.put(data[0], data[1]); } } } } public void delete(String name) { set(name, "-delete-", -30); } @Override public Iterator iterator() { return this.cookies.keySet().iterator(); } public String read(String name) { return this.cookies.get(name); } public void set(Cookie cookie) { this.queue.add(cookie); } public Cookie set(String name, String value, int expires) { return addAndReturn(this.queue, new Cookie(name, value, Cookie.getHTTPTime(expires))); } public void unloadQueue(Response response) { for (Cookie cookie : this.queue) { response.addHeader("Set-Cookie", cookie.getHTTPHeader()); } } } public static class DefaultAsyncRunner implements AsyncRunner { public long requestCount; final public List running = Collections.synchronizedList(new ArrayList()); public List getRunning() { return running; } @Override public void closeAll() { for (ClientHandler clientHandler : new ArrayList(this.running)) { clientHandler.close(); } } @Override public void closed(ClientHandler clientHandler) { this.running.remove(clientHandler); } @Override public void exec(ClientHandler clientHandler) { ++this.requestCount; Thread t = new Thread(clientHandler); String clientIP = "?"; try { clientIP = clientHandler.acceptSocket.getInetAddress().getHostAddress().toString(); } catch (Throwable __e) { printStackTrace(__e); } t.setName("NanoHttpd serving request #" + this.requestCount + " to " + clientIP); this.running.add(clientHandler); t.start(); } } public static class DefaultTempFile implements TempFile { final public File file; final public OutputStream fstream; public DefaultTempFile(String tempdir) throws IOException { this.file = File.createTempFile("NanoHTTPD-", "", new File(tempdir)); this.fstream = new FileOutputStream(this.file); System.err.println("Temp file created: " + file); } @Override public void delete() throws Exception { safeClose(this.fstream); System.err.println("Temp file deleted: " + file); if (!this.file.delete()) { throw new Exception("could not delete temporary file"); } } @Override public String getName() { return this.file.getAbsolutePath(); } @Override public OutputStream open() throws Exception { return this.fstream; } } public static class DefaultTempFileManager implements TempFileManager { final public String tmpdir; final public List tempFiles; public DefaultTempFileManager() { this.tmpdir = tempDir().getPath(); this.tempFiles = new ArrayList(); } @Override public void clear() { for (TempFile file : this.tempFiles) { try { file.delete(); } catch (Exception ignored) { NanoHTTPD.LOG.log(Level.WARNING, "could not delete file ", ignored); } } this.tempFiles.clear(); } @Override public TempFile createTempFile() throws Exception { DefaultTempFile tempFile = new DefaultTempFile(this.tmpdir); this.tempFiles.add(tempFile); return tempFile; } } public class DefaultTempFileManagerFactory implements TempFileManagerFactory { @Override public TempFileManager create() { return new DefaultTempFileManager(); } } static final public String CONTENT_DISPOSITION_REGEX = "([ |\t]*Content-Disposition[ |\t]*:)(.*)"; static final public Pattern CONTENT_DISPOSITION_PATTERN = Pattern.compile(CONTENT_DISPOSITION_REGEX, Pattern.CASE_INSENSITIVE); static final public String CONTENT_TYPE_REGEX = "([ |\t]*content-type[ |\t]*:)(.*)"; static final public Pattern CONTENT_TYPE_PATTERN = Pattern.compile(CONTENT_TYPE_REGEX, Pattern.CASE_INSENSITIVE); static final public String CONTENT_DISPOSITION_ATTRIBUTE_REGEX = "[ |\t]*([a-zA-Z]*)[ |\t]*=[ |\t]*['|\"]([^\"^']*)['|\"]"; static final public Pattern CONTENT_DISPOSITION_ATTRIBUTE_PATTERN = Pattern.compile(CONTENT_DISPOSITION_ATTRIBUTE_REGEX); public class HTTPSession implements IHTTPSession { public boolean badClient = false; public boolean specialHandler = false; public long opened = sysNow(); public static final int BUFSIZE = 8192; final public TempFileManager tempFileManager; public Socket socket; final public OutputStream outputStream; final public PushbackInputStream inputStream; public int splitbyte; public int rlen; public String uri; public Method method; public Map parms; public Map headers; public Map files = new HashMap(); public CookieHandler cookies; public String queryParameterString; public String remoteIp; public String protocolVersion; public String fullURI; public List headerLines = collectHeaderLines ? new ArrayList() : null; public HTTPSession(TempFileManager tempFileManager, Socket socket, InputStream inputStream, OutputStream outputStream) { this.socket = socket; this.tempFileManager = tempFileManager; this.inputStream = new PushbackInputStream(inputStream, HTTPSession.BUFSIZE); this.outputStream = outputStream; } public String getProtocolVersion() { return protocolVersion; } public String getFullURI() { return fullURI; } public List getHeaderLines() { return headerLines; } public HTTPSession(TempFileManager tempFileManager, Socket socket, InputStream inputStream, OutputStream outputStream, InetAddress inetAddress) { this.socket = socket; this.tempFileManager = tempFileManager; this.inputStream = new PushbackInputStream(inputStream, HTTPSession.BUFSIZE); this.outputStream = outputStream; this.remoteIp = inetAddress.isLoopbackAddress() || inetAddress.isAnyLocalAddress() ? "127.0.0.1" : inetAddress.getHostAddress().toString(); this.headers = new LinkedHashMap(); } public void badClient(boolean b) { badClient = b; } public void specialHandler(boolean b) { specialHandler = b; } final public void decodeHeader(BufferedReader in, Map pre, Map parms, Map headers, Map files) throws ResponseException { try { String inLine = in.readLine(); if (inLine == null) { return; } StringTokenizer st = new StringTokenizer(inLine); if (!st.hasMoreTokens()) { throw new ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Syntax error. Usage: GET /example/file.html"); } pre.put("method", st.nextToken()); if (!st.hasMoreTokens()) { throw new ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Missing URI. Usage: GET /example/file.html"); } String uri = st.nextToken(); fullURI = uri; int qmi = uri.indexOf('?'); if (qmi >= 0) { String query = uri.substring(qmi + 1); files.put("query", query); decodeParms(query, parms); uri = uri.substring(0, qmi); } if (decodePercentInURI) uri = decodePercent(uri); if (st.hasMoreTokens()) { protocolVersion = st.nextToken(); } else { protocolVersion = "HTTP/1.1"; NanoHTTPD.LOG.log(Level.FINE, "no protocol version specified, strange. Assuming HTTP/1.1."); } String line = in.readLine(); while (line != null && line.trim().length() > 0) { { if (headerLines != null) headerLines.add(line); } int p = line.indexOf(':'); if (p >= 0) { headers.put(line.substring(0, p).trim().toLowerCase(Locale.US), line.substring(p + 1).trim()); } line = in.readLine(); } pre.put("uri", uri); } catch (IOException ioe) { throw new ResponseException(Status.INTERNAL_ERROR, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage(), ioe); } } final public void decodeMultipartFormData(String boundary, java.nio.ByteBuffer fbuf, Map parms, Map files) throws ResponseException { try { int[] boundary_idxs = getBoundaryPositions(fbuf, boundary.getBytes()); if (boundary_idxs.length < 2) { throw new ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but contains less than two boundary strings."); } final int MAX_HEADER_SIZE = 1024; byte[] part_header_buff = new byte[MAX_HEADER_SIZE]; for (int bi = 0; bi < boundary_idxs.length - 1; bi++) { fbuf.position(boundary_idxs[bi]); int len = (fbuf.remaining() < MAX_HEADER_SIZE) ? fbuf.remaining() : MAX_HEADER_SIZE; fbuf.get(part_header_buff, 0, len); ByteArrayInputStream bais = new ByteArrayInputStream(part_header_buff, 0, len); BufferedReader in = new BufferedReader(new InputStreamReader(bais, Charset.forName("US-ASCII"))); String mpline = in.readLine(); if (!mpline.contains(boundary)) { throw new ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but chunk does not start with boundary."); } String part_name = null, file_name = null, content_type = null; mpline = in.readLine(); while (mpline != null && mpline.trim().length() > 0) { Matcher matcher = CONTENT_DISPOSITION_PATTERN.matcher(mpline); if (matcher.matches()) { String attributeString = matcher.group(2); matcher = CONTENT_DISPOSITION_ATTRIBUTE_PATTERN.matcher(attributeString); while (matcher.find()) { String key = matcher.group(1); if (key.equalsIgnoreCase("name")) { part_name = matcher.group(2); } else if (key.equalsIgnoreCase("filename")) { file_name = matcher.group(2); } } } matcher = CONTENT_TYPE_PATTERN.matcher(mpline); if (matcher.matches()) { content_type = matcher.group(2).trim(); } mpline = in.readLine(); } int part_header_len = len - (int) in.skip(MAX_HEADER_SIZE); if (part_header_len >= len - 4) { throw new ResponseException(Status.INTERNAL_ERROR, "Multipart header size exceeds MAX_HEADER_SIZE."); } int part_data_start = boundary_idxs[bi] + part_header_len; int part_data_end = boundary_idxs[bi + 1] - 4; fbuf.position(part_data_start); if (content_type == null) { byte[] data_bytes = new byte[part_data_end - part_data_start]; fbuf.get(data_bytes); parms.put(part_name, new String(data_bytes)); } else { String path = saveTmpFile(fbuf, part_data_start, part_data_end - part_data_start); if (!files.containsKey(part_name)) { files.put(part_name, path); } else { int count = 2; while (files.containsKey(part_name + count)) { count++; } files.put(part_name + count, path); } parms.put(part_name, file_name); } } } catch (ResponseException re) { throw re; } catch (Exception e) { throw new ResponseException(Status.INTERNAL_ERROR, e.toString()); } } final public void decodeParms(String parms, Map p) { if (parms == null) { this.queryParameterString = ""; return; } this.queryParameterString = parms; StringTokenizer st = new StringTokenizer(parms, "&"); while (st.hasMoreTokens()) { String e = st.nextToken(); int sep = e.indexOf('='); if (sep >= 0) { p.put(decodePercent(e.substring(0, sep)).trim(), decodePercent(e.substring(sep + 1))); } else { p.put(decodePercent(e).trim(), ""); } } } @Override public void execute() throws IOException { Response r = null; try { byte[] buf = new byte[HTTPSession.BUFSIZE]; this.splitbyte = 0; this.rlen = 0; int read = -1; try { read = this.inputStream.read(buf, 0, HTTPSession.BUFSIZE); } catch (Exception e) { safeClose(this.inputStream); safeClose(this.outputStream); throw new SocketException("NanoHttpd Shutdown"); } if (read == -1) { safeClose(this.inputStream); safeClose(this.outputStream); throw new SocketException("NanoHttpd Shutdown"); } while (read > 0) { this.rlen += read; this.splitbyte = findHeaderEnd(buf, this.rlen); if (this.splitbyte > 0) break; if (rlen >= buf.length) { if (NanoHTTPD_debug) printWithIndent("HEADER> ", new String(buf)); throw fail("Header too big (" + rlen + " bytes)"); } read = this.inputStream.read(buf, this.rlen, HTTPSession.BUFSIZE - this.rlen); } if (this.splitbyte < this.rlen) { this.inputStream.unread(buf, this.splitbyte, this.rlen - this.splitbyte); } this.parms = new HashMap(); if (null == this.headers) { this.headers = new HashMap(); } else { this.headers.clear(); } if (null != this.remoteIp) { this.headers.put("remote-addr", this.remoteIp); this.headers.put("http-client-ip", this.remoteIp); } BufferedReader hin = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buf, 0, this.rlen))); Map pre = new LinkedHashMap(); decodeHeader(hin, pre, this.parms, this.headers, this.files); this.method = Method.lookup(pre.get("method")); if (this.method == null) { throw new ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Syntax error."); } this.uri = pre.get("uri"); this.cookies = new CookieHandler(this.headers); String connection = this.headers.get("connection"); boolean keepAlive = protocolVersion.equals("HTTP/1.1") && (connection == null || !connection.matches("(?i).*close.*")); r = serve(this); if (badClient || specialHandler) return; if (r == null) { throw new ResponseException(Status.INTERNAL_ERROR, "SERVER INTERNAL ERROR: Serve() returned a null response."); } else { String acceptEncoding = this.headers.get("accept-encoding"); this.cookies.unloadQueue(r); r.setRequestMethod(this.method); r.setGzipEncoding(useGzipWhenAccepted(r) && acceptEncoding != null && acceptEncoding.contains("gzip")); r.setKeepAlive(keepAlive); r.send(this.outputStream); } if (!keepAlive || "close".equalsIgnoreCase(r.getHeader("connection"))) { throw new SocketException("NanoHttpd Shutdown"); } } catch (SocketException e) { throw e; } catch (SocketTimeoutException ste) { throw ste; } catch (IOException ioe) { Response resp = newFixedLengthResponse(Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage()); resp.send(this.outputStream); safeClose(this.outputStream); } catch (ResponseException re) { Response resp = newFixedLengthResponse(re.getStatus(), NanoHTTPD.MIME_PLAINTEXT, re.getMessage()); resp.send(this.outputStream); safeClose(this.outputStream); } finally { if (badClient) badClients.add(this); else if (!specialHandler) safeClose(r); this.tempFileManager.clear(); } } final public int findHeaderEnd(final byte[] buf, int rlen) { int splitbyte = 0; while (splitbyte + 3 < rlen) { if (buf[splitbyte] == '\r' && buf[splitbyte + 1] == '\n' && buf[splitbyte + 2] == '\r' && buf[splitbyte + 3] == '\n') { return splitbyte + 4; } splitbyte++; } return 0; } final public int[] getBoundaryPositions(java.nio.ByteBuffer b, byte[] boundary) { int[] res = new int[0]; if (b.remaining() < boundary.length) { return res; } int search_window_pos = 0; byte[] search_window = new byte[4 * 1024 + boundary.length]; int first_fill = (b.remaining() < search_window.length) ? b.remaining() : search_window.length; b.get(search_window, 0, first_fill); int new_bytes = first_fill - boundary.length; do { for (int j = 0; j < new_bytes; j++) { for (int i = 0; i < boundary.length; i++) { if (search_window[j + i] != boundary[i]) break; if (i == boundary.length - 1) { int[] new_res = new int[res.length + 1]; System.arraycopy(res, 0, new_res, 0, res.length); new_res[res.length] = search_window_pos + j; res = new_res; } } } search_window_pos += new_bytes; System.arraycopy(search_window, search_window.length - boundary.length, search_window, 0, boundary.length); new_bytes = search_window.length - boundary.length; new_bytes = (b.remaining() < new_bytes) ? b.remaining() : new_bytes; b.get(search_window, boundary.length, new_bytes); } while (new_bytes > 0); return res; } @Override public CookieHandler getCookies() { return this.cookies; } @Override public final Map getHeaders() { return this.headers; } @Override public final Map getFiles() { return this.files; } public Socket getSocket() { return socket; } @Override public final InputStream getInputStream() { return this.inputStream; } @Override public final OutputStream getOutputStream() { return this.outputStream; } @Override public final Method getMethod() { return this.method; } @Override public final Map getParms() { return this.parms; } @Override public String getQueryParameterString() { return this.queryParameterString; } final public RandomAccessFile getTmpBucket() { try { TempFile tempFile = this.tempFileManager.createTempFile(); return new RandomAccessFile(tempFile.getName(), "rw"); } catch (Exception e) { throw new Error(e); } } @Override public final String getUri() { return this.uri; } @Override public void parseBody() throws IOException, ResponseException { final int REQUEST_BUFFER_LEN = 512; final int MEMORY_STORE_LIMIT = 1024; RandomAccessFile randomAccessFile = null; try { long size; if (this.headers.containsKey("content-length")) { size = Integer.parseInt(this.headers.get("content-length")); } else if (this.splitbyte < this.rlen) { size = this.rlen - this.splitbyte; } else { size = 0; } ByteArrayOutputStream baos = null; DataOutput request_data_output = null; if (size < MEMORY_STORE_LIMIT) { baos = new ByteArrayOutputStream(); request_data_output = new DataOutputStream(baos); } else { randomAccessFile = getTmpBucket(); request_data_output = randomAccessFile; } byte[] buf = new byte[REQUEST_BUFFER_LEN]; while (this.rlen >= 0 && size > 0) { this.rlen = this.inputStream.read(buf, 0, (int) Math.min(size, REQUEST_BUFFER_LEN)); size -= this.rlen; if (this.rlen > 0) { request_data_output.write(buf, 0, this.rlen); } } java.nio.ByteBuffer fbuf = null; if (baos != null) { fbuf = java.nio.ByteBuffer.wrap(baos.toByteArray(), 0, baos.size()); } else { fbuf = randomAccessFile.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, randomAccessFile.length()); randomAccessFile.seek(0); } if (Method.POST.equals(this.method)) { String contentType = ""; String contentTypeHeader = this.headers.get("content-type"); StringTokenizer st = null; if (contentTypeHeader != null) { st = new StringTokenizer(contentTypeHeader, ",; "); if (st.hasMoreTokens()) { contentType = st.nextToken(); } } if ("multipart/form-data".equalsIgnoreCase(contentType)) { if (!st.hasMoreTokens()) { throw new ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but boundary missing. Usage: GET /example/file.html"); } String boundaryStartString = "boundary="; int boundaryContentStart = contentTypeHeader.indexOf(boundaryStartString) + boundaryStartString.length(); String boundary = contentTypeHeader.substring(boundaryContentStart, contentTypeHeader.length()); if (boundary.startsWith("\"") && boundary.endsWith("\"")) { boundary = boundary.substring(1, boundary.length() - 1); } decodeMultipartFormData(boundary, fbuf, this.parms, files); } else { byte[] postBytes = new byte[fbuf.remaining()]; if (NanoHTTPD_debug) print("NanoHTTPD: Handling POST data (" + l(postBytes) + " bytes)"); fbuf.get(postBytes); String postLine = new String(postBytes).trim(); if ("application/x-www-form-urlencoded".equalsIgnoreCase(contentType)) { decodeParms(postLine, this.parms); } else if (postLine.length() != 0) { files.put("postData", postLine); } } } else if (Method.PUT.equals(this.method)) { files.put("content", saveTmpFile(fbuf, 0, fbuf.limit())); } } finally { safeClose(randomAccessFile); } } final public String saveTmpFile(java.nio.ByteBuffer b, int offset, int len) { String path = ""; if (len > 0) { FileOutputStream fileOutputStream = null; try { TempFile tempFile = this.tempFileManager.createTempFile(); java.nio.ByteBuffer src = b.duplicate(); fileOutputStream = new FileOutputStream(tempFile.getName()); FileChannel dest = fileOutputStream.getChannel(); src.position(offset).limit(offset + len); dest.write(src.slice()); path = tempFile.getName(); } catch (Exception e) { throw new Error(e); } finally { safeClose(fileOutputStream); } } return path; } public String remoteIp() { return remoteIp; } } public interface IHTTPSession { public void badClient(boolean b); public void specialHandler(boolean b); public void execute() throws IOException; public CookieHandler getCookies(); public Map getHeaders(); public Map getFiles(); public Socket getSocket(); public InputStream getInputStream(); public OutputStream getOutputStream(); public Method getMethod(); public String getProtocolVersion(); public String getFullURI(); public List getHeaderLines(); public Map getParms(); public String getQueryParameterString(); public String getUri(); public void parseBody() throws IOException, ResponseException; public String remoteIp(); } public enum Method { GET, PUT, POST, DELETE, HEAD, OPTIONS, TRACE, CONNECT, PATCH; static public Method lookup(String method) { for (Method m : Method.values()) { if (m.toString().equalsIgnoreCase(method)) { return m; } } return null; } } public static class Response implements Closeable { public String toString() { return "HttpResponse " + status + " " + mimeType; } static public class ChunkedOutputStream extends FilterOutputStream { public ChunkedOutputStream(OutputStream out) { super(out); } @Override public void write(int b) throws IOException { byte[] data = { (byte) b }; write(data, 0, 1); } @Override public void write(byte[] b) throws IOException { write(b, 0, b.length); } @Override public void write(byte[] b, int off, int len) throws IOException { if (len == 0) return; out.write(String.format("%x\r\n", len).getBytes()); out.write(b, off, len); out.write("\r\n".getBytes()); } public void finish() throws IOException { out.write("0\r\n\r\n".getBytes()); } } public IStatus status; public String mimeType; public InputStream data; public long contentLength; final public Map header = lithashmap("X-Powered-By", "JavaX"); public Method requestMethod; public boolean chunkedTransfer = false; public boolean encodeAsGzip = false; public boolean keepAlive = false; public Response(IStatus status, String mimeType, InputStream data, long totalBytes) { this.status = status; this.mimeType = mimeType; if (data == null) { this.data = new ByteArrayInputStream(new byte[0]); this.contentLength = 0L; } else { this.data = data; this.contentLength = totalBytes; } this.chunkedTransfer = this.contentLength < 0; keepAlive = true; } @Override public void close() throws IOException { if (this.data != null) { this.data.close(); } } public void addHeader(String name, String value) { this.header.put(name, value); } public InputStream getData() { return this.data; } public String getHeader(String name) { for (String headerName : header.keySet()) { if (headerName.equalsIgnoreCase(name)) { return header.get(headerName); } } return null; } public String getMimeType() { return this.mimeType; } public Method getRequestMethod() { return this.requestMethod; } public IStatus getStatus() { return this.status; } public void setGzipEncoding(boolean encodeAsGzip) { this.encodeAsGzip = encodeAsGzip; } public void setKeepAlive(boolean useKeepAlive) { this.keepAlive = useKeepAlive; } final public boolean headerAlreadySent(Map header, String name) { boolean alreadySent = false; for (String headerName : header.keySet()) { alreadySent |= headerName.equalsIgnoreCase(name); } return alreadySent; } public void send(OutputStream outputStream) { String mime = this.mimeType; SimpleDateFormat gmtFrmt = new SimpleDateFormat("E, d MMM yyyy HH:mm:ss 'GMT'", Locale.US); gmtFrmt.setTimeZone(TimeZone.getTimeZone("GMT")); try { if (this.status == null) { throw new Error("sendResponse(): Status can't be null."); } PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8")), false); pw.print("HTTP/1.1 " + this.status.getDescription() + " \r\n"); if (mime != null) { pw.print("Content-Type: " + mime + "\r\n"); } if (this.header == null || this.header.get("Date") == null) { pw.print("Date: " + gmtFrmt.format(new Date()) + "\r\n"); } if (this.header != null) { for (String key : this.header.keySet()) { String value = this.header.get(key); pw.print(key + ": " + value + "\r\n"); } } if (!headerAlreadySent(header, "connection")) { pw.print("Connection: " + (this.keepAlive ? "keep-alive" : "close") + "\r\n"); } if (headerAlreadySent(this.header, "content-length")) { encodeAsGzip = false; } if (encodeAsGzip) { pw.print("Content-Encoding: gzip\r\n"); setChunkedTransfer(true); } long pending = this.data != null ? this.contentLength : 0; if (this.requestMethod != Method.HEAD && this.chunkedTransfer) { pw.print("Transfer-Encoding: chunked\r\n"); } else if (!encodeAsGzip) { pending = sendContentLengthHeaderIfNotAlreadyPresent(pw, this.header, pending); } pw.print("\r\n"); pw.flush(); sendBodyWithCorrectTransferAndEncoding(outputStream, pending); outputStream.flush(); safeClose(this.data); } catch (IOException ioe) { NanoHTTPD.LOG.log(Level.SEVERE, "Could not send response to the client", ioe); } } final public void sendBodyWithCorrectTransferAndEncoding(OutputStream outputStream, long pending) throws IOException { if (this.requestMethod != Method.HEAD && this.chunkedTransfer) { ChunkedOutputStream chunkedOutputStream = new ChunkedOutputStream(outputStream); sendBodyWithCorrectEncoding(chunkedOutputStream, -1); chunkedOutputStream.finish(); } else { sendBodyWithCorrectEncoding(outputStream, pending); } } final public void sendBodyWithCorrectEncoding(OutputStream outputStream, long pending) throws IOException { if (encodeAsGzip) { GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream); sendBody(gzipOutputStream, -1); gzipOutputStream.finish(); } else { sendBody(outputStream, pending); } } final public void sendBody(OutputStream outputStream, long pending) throws IOException { long BUFFER_SIZE = 16 * 1024; byte[] buff = new byte[(int) BUFFER_SIZE]; boolean sendEverything = pending == -1; while (pending > 0 || sendEverything) { long bytesToRead = sendEverything ? BUFFER_SIZE : Math.min(pending, BUFFER_SIZE); int read = this.data.read(buff, 0, (int) bytesToRead); if (read <= 0) { break; } outputStream.write(buff, 0, read); if (!sendEverything) { pending -= read; } } } public long sendContentLengthHeaderIfNotAlreadyPresent(PrintWriter pw, Map header, long size) { for (String headerName : header.keySet()) { if (headerName.equalsIgnoreCase("content-length")) { try { return Long.parseLong(header.get(headerName)); } catch (NumberFormatException ex) { return size; } } } pw.print("Content-Length: " + size + "\r\n"); return size; } public void setChunkedTransfer(boolean chunkedTransfer) { this.chunkedTransfer = chunkedTransfer; } public void setData(InputStream data) { this.data = data; } public void setMimeType(String mimeType) { this.mimeType = mimeType; } public void setRequestMethod(Method requestMethod) { this.requestMethod = requestMethod; } public void setStatus(IStatus status) { this.status = status; } } public static final class ResponseException extends Exception { static final public long serialVersionUID = 6569838532917408380L; final public Status status; public ResponseException(Status status, String message) { super(message); this.status = status; } public ResponseException(Status status, String message, Exception e) { super(message, e); this.status = status; } public Status getStatus() { return this.status; } } public class ServerRunnable implements Runnable { final public int timeout; public IOException bindException; public boolean hasBinded = false; public ServerRunnable(int timeout) { this.timeout = timeout; } @Override public void run() { try { myServerSocket.bind(hostname != null ? new InetSocketAddress(hostname, myPort) : new InetSocketAddress(myPort)); hasBinded = true; } catch (IOException e) { print("Was trying to bind to port: " + myPort + (hostname == null ? "" : " on " + hostname)); this.bindException = e; return; } do { try { final Socket finalAccept = NanoHTTPD.this.myServerSocket.accept(); if (NanoHTTPD_debug) print("NanoHTTPD: New socket."); if (this.timeout > 0) { finalAccept.setSoTimeout(this.timeout); } final InputStream inputStream = wrapStuff("SocketInputStream", finalAccept.getInputStream(), finalAccept, NanoHTTPD.this.myServerSocket); if (NanoHTTPD_debug) print("NanoHTTPD: Have input stream."); NanoHTTPD.this.asyncRunner.exec(createClientHandler(finalAccept, inputStream)); } catch (IOException e) { NanoHTTPD.LOG.log(Level.FINE, "Communication with the client broken", e); } } while (!NanoHTTPD.this.myServerSocket.isClosed()); } } public interface TempFile { public void delete() throws Exception; public String getName(); public OutputStream open() throws Exception; } public interface TempFileManager { public void clear(); public TempFile createTempFile() throws Exception; } public interface TempFileManagerFactory { public TempFileManager create(); } public static int SOCKET_READ_TIMEOUT = 24 * 3600 * 1000; public static final String MIME_PLAINTEXT = "text/plain; charset=utf-8"; public static final String MIME_HTML = "text/html; charset=utf-8"; static final public String QUERY_STRING_PARAMETER = "NanoHttpd.QUERY_STRING"; static final public Logger LOG = Logger.getLogger(NanoHTTPD.class.getName()); public static SSLServerSocketFactory makeSSLSocketFactory(KeyStore loadedKeyStore, KeyManager[] keyManagers) throws IOException { SSLServerSocketFactory res = null; try { TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(loadedKeyStore); SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(keyManagers, trustManagerFactory.getTrustManagers(), null); res = ctx.getServerSocketFactory(); } catch (Exception e) { throw new IOException(e.getMessage()); } return res; } public static SSLServerSocketFactory makeSSLSocketFactory(KeyStore loadedKeyStore, KeyManagerFactory loadedKeyFactory) throws IOException { SSLServerSocketFactory res = null; try { TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(loadedKeyStore); SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(loadedKeyFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); res = ctx.getServerSocketFactory(); } catch (Exception e) { throw new IOException(e.getMessage()); } return res; } public static SSLServerSocketFactory makeSSLSocketFactory(String keyAndTrustStoreClasspathPath, char[] passphrase) throws IOException { SSLServerSocketFactory res = null; try { KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); InputStream keystoreStream = NanoHTTPD.class.getResourceAsStream(keyAndTrustStoreClasspathPath); keystore.load(keystoreStream, passphrase); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keystore); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keystore, passphrase); SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); res = ctx.getServerSocketFactory(); } catch (Exception e) { throw new IOException(e.getMessage()); } return res; } static final public void safeClose(Object closeable) { try { if (closeable != null) { if (closeable instanceof Closeable) { ((Closeable) closeable).close(); } else if (closeable instanceof Socket) { ((Socket) closeable).close(); } else if (closeable instanceof ServerSocket) { ((ServerSocket) closeable).close(); } else { throw new IllegalArgumentException("Unknown object to close"); } } } catch (IOException e) { NanoHTTPD.LOG.log(Level.SEVERE, "Could not close", e); } } final public String hostname; final public int myPort; public ServerSocket myServerSocket; public SSLServerSocketFactory sslServerSocketFactory; public Thread myThread; public AsyncRunner asyncRunner; public TempFileManagerFactory tempFileManagerFactory; public NanoHTTPD(int port) { this(null, port); } public NanoHTTPD(String hostname, int port) { this.hostname = hostname; this.myPort = port; setTempFileManagerFactory(new DefaultTempFileManagerFactory()); setAsyncRunner(new DefaultAsyncRunner()); } public synchronized void closeAllConnections() { stop(); } public ClientHandler createClientHandler(final Socket finalAccept, final InputStream inputStream) { return new ClientHandler(inputStream, finalAccept); } public ServerRunnable createServerRunnable(final int timeout) { return new ServerRunnable(timeout); } public Map> decodeParameters(Map parms) { return this.decodeParameters(parms.get(NanoHTTPD.QUERY_STRING_PARAMETER)); } public Map> decodeParameters(String queryString) { Map> parms = new HashMap>(); if (queryString != null) { StringTokenizer st = new StringTokenizer(queryString, "&"); while (st.hasMoreTokens()) { String e = st.nextToken(); int sep = e.indexOf('='); String propertyName = sep >= 0 ? decodePercent(e.substring(0, sep)).trim() : decodePercent(e).trim(); if (!parms.containsKey(propertyName)) { parms.put(propertyName, new ArrayList()); } String propertyValue = sep >= 0 ? decodePercent(e.substring(sep + 1)) : null; { parms.get(propertyName).add(propertyValue); } } } return parms; } public String decodePercent(String str) { String decoded = null; try { decoded = URLDecoder.decode(str, "UTF8"); } catch (UnsupportedEncodingException ignored) { NanoHTTPD.LOG.log(Level.WARNING, "Encoding not supported, ignored", ignored); } return decoded; } public boolean useGzipWhenAccepted(Response r) { return r.getMimeType() != null && r.getMimeType().toLowerCase().contains("text/"); } public final int getListeningPort() { return this.myServerSocket == null ? -1 : this.myServerSocket.getLocalPort(); } public final boolean isAlive() { return wasStarted() && !this.myServerSocket.isClosed() && this.myThread.isAlive(); } public void join() throws InterruptedException { myThread.join(); } public void makeSecure(SSLServerSocketFactory sslServerSocketFactory) { this.sslServerSocketFactory = sslServerSocketFactory; } public static Response newChunkedResponse(IStatus status, String mimeType, InputStream data) { return new Response(status, mimeType, data, -1); } public static Response newFixedLengthResponse(IStatus status, String mimeType, InputStream data, long totalBytes) { return new Response(status, mimeType, data, totalBytes); } public static Response newFixedLengthResponse(IStatus status, String mimeType, String txt) { if (txt == null) { return newFixedLengthResponse(status, mimeType, new ByteArrayInputStream(new byte[0]), 0); } else { byte[] bytes; try { bytes = txt.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { NanoHTTPD.LOG.log(Level.SEVERE, "encoding problem, responding nothing", e); bytes = new byte[0]; } return newFixedLengthResponse(status, mimeType, new ByteArrayInputStream(bytes), bytes.length); } } public static Response newFixedLengthResponse(String msg) { return newFixedLengthResponse(Status.OK, NanoHTTPD.MIME_HTML, msg); } public Response serve(IHTTPSession session) { if (specialHandling(session)) { session.specialHandler(true); return null; } return serve_2(session); } public Response serve_2(IHTTPSession session) { currentSession.set(session); Method method = session.getMethod(); if (Method.PUT.equals(method) || Method.POST.equals(method)) { try { session.parseBody(); } catch (IOException ioe) { return newFixedLengthResponse(Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage()); } catch (ResponseException re) { return newFixedLengthResponse(re.getStatus(), NanoHTTPD.MIME_PLAINTEXT, re.getMessage()); } } Map parms = session.getParms(); if (!noQueryStringParameter) parms.put(NanoHTTPD.QUERY_STRING_PARAMETER, session.getQueryParameterString()); return serve(session.getUri(), method, session.getHeaders(), parms, session.getFiles()); } @Deprecated public Response serve(String uri, Method method, Map headers, Map parms, Map files) { return newFixedLengthResponse(Status.NOT_FOUND, NanoHTTPD.MIME_PLAINTEXT, "Not Found"); } public void setAsyncRunner(AsyncRunner asyncRunner) { this.asyncRunner = asyncRunner; } public void setTempFileManagerFactory(TempFileManagerFactory tempFileManagerFactory) { this.tempFileManagerFactory = tempFileManagerFactory; } public void start() throws IOException { start(NanoHTTPD.SOCKET_READ_TIMEOUT); } public void start(final int timeout) throws IOException { boolean ssl = this.sslServerSocketFactory != null; if (ssl) { SSLServerSocket ss = (SSLServerSocket) this.sslServerSocketFactory.createServerSocket(); ss.setNeedClientAuth(false); this.myServerSocket = ss; } else { this.myServerSocket = new ServerSocket(); } this.myServerSocket.setReuseAddress(true); ServerRunnable serverRunnable = createServerRunnable(timeout); this.myThread = new Thread(serverRunnable); this.myThread.setName("NanoHttpd Main Listener"); this.myThread.start(); while (!serverRunnable.hasBinded && serverRunnable.bindException == null) { try { Thread.sleep(10L); } catch (Throwable e) { } } if (serverRunnable.bindException != null) { throw serverRunnable.bindException; } System.out.println("HTTP" + (ssl ? "S" : "") + " server started (listening on port " + getListeningPort() + "!)"); printMyIPs(); } public void stop() { try { safeClose(this.myServerSocket); this.asyncRunner.closeAll(); if (this.myThread != null) { this.myThread.join(); } } catch (Exception e) { NanoHTTPD.LOG.log(Level.SEVERE, "Could not stop all connections", e); } } public final boolean wasStarted() { return this.myServerSocket != null && this.myThread != null; } static public void printMyIPs() { String ip; try { Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { NetworkInterface iface = interfaces.nextElement(); if (iface.isLoopback() || !iface.isUp()) continue; Enumeration addresses = iface.getInetAddresses(); while (addresses.hasMoreElements()) { InetAddress addr = addresses.nextElement(); ip = addr.getHostAddress(); if (ip.startsWith("127.")) continue; boolean local = addr.isSiteLocalAddress() || ip.startsWith("fe"); System.out.println(iface.getDisplayName() + " " + ip + " " + (local ? "(private address)" : "(public address)")); } } } catch (Throwable e) { e.printStackTrace(); } } static public interface IStatus { public String getDescription(); public int getRequestStatus(); } static public enum Status implements IStatus { SWITCH_PROTOCOL(101, "Switching Protocols"), OK(200, "OK"), CREATED(201, "Created"), ACCEPTED(202, "Accepted"), NO_CONTENT(204, "No Content"), PARTIAL_CONTENT(206, "Partial Content"), REDIRECT(301, "Moved Permanently"), NOT_MODIFIED(304, "Not Modified"), BAD_REQUEST(400, "Bad Request"), UNAUTHORIZED(401, "Unauthorized"), FORBIDDEN(403, "Forbidden"), NOT_FOUND(404, "Not Found"), METHOD_NOT_ALLOWED(405, "Method Not Allowed"), REQUEST_TIMEOUT(408, "Request Timeout"), RANGE_NOT_SATISFIABLE(416, "Requested Range Not Satisfiable"), INTERNAL_ERROR(500, "Internal Server Error"), UNSUPPORTED_HTTP_VERSION(505, "HTTP Version Not Supported"); final public int requestStatus; final public String description; Status(int requestStatus, String description) { this.requestStatus = requestStatus; this.description = description; } @Override public String getDescription() { return "" + this.requestStatus + " " + this.description; } @Override public int getRequestStatus() { return this.requestStatus; } } public int getPort() { return myPort; } public void close() { stop(); } transient public IF1 specialHandling; public boolean specialHandling(IHTTPSession session) { return specialHandling != null ? specialHandling.get(session) : specialHandling_base(session); } final public boolean specialHandling_fallback(IF1 _f, IHTTPSession session) { return _f != null ? _f.get(session) : specialHandling_base(session); } public boolean specialHandling_base(IHTTPSession session) { return false; } } static public class MultiMap implements IMultiMap { public Map> data = new HashMap>(); public int fullSize; public MultiMap() { } public MultiMap(boolean useTreeMap) { if (useTreeMap) data = new TreeMap(); } public MultiMap(MultiMap map) { putAll(map); } public MultiMap(Map> data) { this.data = data; } public void put(A key, B value) { synchronized (data) { List list = data.get(key); if (list == null) data.put(key, list = _makeEmptyList()); list.add(value); ++fullSize; } } public void add(A key, B value) { put(key, value); } public void addAll(A key, Collection values) { putAll(key, values); } public void addAllIfNotThere(A key, Collection values) { synchronized (data) { for (B value : values) setPut(key, value); } } public void setPut(A key, B value) { synchronized (data) { if (!containsPair(key, value)) put(key, value); } } public boolean containsPair(A key, B value) { synchronized (data) { return get(key).contains(value); } } public void putAll(Collection keys, B value) { synchronized (data) { for (A key : unnullForIteration(keys)) put(key, value); } } public void putAll(A key, Collection values) { synchronized (data) { if (nempty(values)) getActual(key).addAll(values); } } public void putAll(Iterable> pairs) { synchronized (data) { for (Pair p : unnullForIteration(pairs)) put(p.a, p.b); } } public void removeAll(A key, Collection values) { synchronized (data) { for (B value : values) remove(key, value); } } public List get(A key) { synchronized (data) { List list = data.get(key); return list == null ? Collections.emptyList() : list; } } public List getOpt(A key) { synchronized (data) { return data.get(key); } } public List getAndClear(A key) { synchronized (data) { List l = cloneList(data.get(key)); remove(key); return l; } } public List getActual(A key) { synchronized (data) { List list = data.get(key); if (list == null) data.put(key, list = _makeEmptyList()); return list; } } public void clean(A key) { synchronized (data) { List list = data.get(key); if (list != null && list.isEmpty()) { fullSize -= l(list); data.remove(key); } } } final public Set keys() { return keySet(); } public Set keySet() { synchronized (data) { return data.keySet(); } } public void remove(A key) { synchronized (data) { fullSize -= l(this.getOpt(key)); data.remove(key); } } final public void remove(Pair p) { removePair(p); } public void removePair(Pair p) { if (p != null) remove(p.a, p.b); } public void remove(A key, B value) { synchronized (data) { List list = data.get(key); if (list != null) { if (list.remove(value)) fullSize--; if (list.isEmpty()) data.remove(key); } } } public void clear() { synchronized (data) { data.clear(); } } public boolean containsKey(A key) { synchronized (data) { return data.containsKey(key); } } public B getFirst(A key) { synchronized (data) { List list = get(key); return list.isEmpty() ? null : list.get(0); } } public void addAll(MultiMap map) { putAll(map); } public void putAll(MultiMap map) { synchronized (data) { for (A key : map.keySet()) putAll(key, map.get(key)); } } public void putAll(Map map) { synchronized (data) { if (map != null) for (Map.Entry e : map.entrySet()) put(e.getKey(), e.getValue()); } } final public int keyCount() { return keysSize(); } public int keysSize() { synchronized (data) { return l(data); } } final public int fullSize() { return size(); } public int size() { synchronized (data) { return fullSize; } } public List reverseGet(B b) { synchronized (data) { List l = new ArrayList(); for (A key : data.keySet()) if (data.get(key).contains(b)) l.add(key); return l; } } public Map> asMap() { synchronized (data) { return cloneMap(data); } } public boolean isEmpty() { synchronized (data) { return data.isEmpty(); } } public List _makeEmptyList() { return new ArrayList(); } public Collection> allLists() { synchronized (data) { return new ArrayList(data.values()); } } public Collection> values() { return allLists(); } public List allValues() { return concatLists(data.values()); } public Object mutex() { return data; } public String toString() { return "mm" + str(data); } } static public class SynchronizedSet extends SynchronizedCollection implements Set { public SynchronizedSet() { } public SynchronizedSet(Set s) { super(s); } public SynchronizedSet(Set s, Object mutex) { super(s, mutex); } public boolean equals(Object o) { if (this == o) return true; synchronized (mutex) { return c.equals(o); } } public int hashCode() { synchronized (mutex) { return c.hashCode(); } } } static public class SynchronizedMap implements Map, Serializable { public SynchronizedMap() { } public Map m; public Object mutex; public SynchronizedMap(Map m) { this.m = Objects.requireNonNull(m); mutex = this; } public SynchronizedMap(Map m, Object mutex) { this.m = m; this.mutex = mutex; } public Map innerMap() { return m; } public int size() { synchronized (mutex) { return m.size(); } } public boolean isEmpty() { synchronized (mutex) { return m.isEmpty(); } } public boolean containsKey(Object key) { synchronized (mutex) { return m.containsKey(key); } } public boolean containsValue(Object value) { synchronized (mutex) { return m.containsValue(value); } } public V get(Object key) { synchronized (mutex) { return m.get(key); } } public V put(K key, V value) { synchronized (mutex) { return m.put(key, value); } } public V remove(Object key) { synchronized (mutex) { return m.remove(key); } } public void putAll(Map map) { synchronized (mutex) { m.putAll(map); } } public void clear() { synchronized (mutex) { m.clear(); } } transient public Set keySet; transient public Set> entrySet; transient public Collection values; public Set keySet() { synchronized (mutex) { if (keySet == null) keySet = new SynchronizedSet<>(m.keySet(), mutex); return keySet; } } public Set> entrySet() { synchronized (mutex) { if (entrySet == null) entrySet = new SynchronizedSet<>(m.entrySet(), mutex); return entrySet; } } public Collection values() { synchronized (mutex) { if (values == null) values = new SynchronizedCollection<>(m.values(), mutex); return values; } } public boolean equals(Object o) { if (this == o) return true; synchronized (mutex) { return m.equals(o); } } public int hashCode() { synchronized (mutex) { return m.hashCode(); } } public String toString() { synchronized (mutex) { return m.toString(); } } @Override public V getOrDefault(Object k, V defaultValue) { synchronized (mutex) { return m.getOrDefault(k, defaultValue); } } @Override public void forEach(BiConsumer action) { synchronized (mutex) { m.forEach(action); } } @Override public void replaceAll(BiFunction function) { synchronized (mutex) { m.replaceAll(function); } } @Override public V putIfAbsent(K key, V value) { synchronized (mutex) { return m.putIfAbsent(key, value); } } @Override public boolean remove(Object key, Object value) { synchronized (mutex) { return m.remove(key, value); } } @Override public boolean replace(K key, V oldValue, V newValue) { synchronized (mutex) { return m.replace(key, oldValue, newValue); } } @Override public V replace(K key, V value) { synchronized (mutex) { return m.replace(key, value); } } @Override public V computeIfAbsent(K key, java.util.function.Function mappingFunction) { synchronized (mutex) { return m.computeIfAbsent(key, mappingFunction); } } @Override public V computeIfPresent(K key, BiFunction remappingFunction) { synchronized (mutex) { return m.computeIfPresent(key, remappingFunction); } } @Override public V compute(K key, BiFunction remappingFunction) { synchronized (mutex) { return m.compute(key, remappingFunction); } } @Override public V merge(K key, V value, BiFunction remappingFunction) { synchronized (mutex) { return m.merge(key, value, remappingFunction); } } @java.io.Serial final public void writeObject(ObjectOutputStream s) throws IOException { synchronized (mutex) { s.defaultWriteObject(); } } } static public class Lowest { public A best; public double score; transient public Object onChange; synchronized public boolean isNewBest(double score) { return best == null || score < this.score; } synchronized public double bestScore() { return best == null ? Double.NaN : score; } public double score() { return bestScore(); } synchronized public float floatScore() { return best == null ? Float.NaN : (float) score; } synchronized public float floatScoreOr(float defaultValue) { return best == null ? defaultValue : (float) score; } public boolean put(A a, double score) { boolean change = false; synchronized (this) { if (a != null && isNewBest(score)) { best = a; this.score = score; change = true; } } if (change) pcallF(onChange); return change; } synchronized public void clear() { best = null; score = 0; } synchronized public A get() { return best; } synchronized public boolean has() { return best != null; } synchronized public Pair pair() { return best == null ? null : new Pair(best, bestScore()); } public String toString() { return "Score " + formatDouble_significant2(score, 4) + ": " + best; } } static public interface IResourceLoader { public String loadSnippet(String snippetID); public String getTranspiled(String snippetID); public int getSnippetType(String snippetID); public String getSnippetTitle(String snippetID); public File loadLibrary(String snippetID); default public File pathToJavaXJar() { return pathToJavaxJar_noResourceLoader(); } default public File getSnippetJar(String snippetID, String transpiledSrc) { return null; } } static final public class WeakHasherMap extends AbstractMap implements Map { public Hasher hasher = null; final public boolean keyEquals(Object k1, Object k2) { return (hasher == null ? k1.equals(k2) : hasher.equals(k1, k2)); } final public int keyHashCode(Object k1) { return (hasher == null ? k1.hashCode() : hasher.hashCode(k1)); } final public WeakKey WeakKeyCreate(K k) { if (k == null) return null; else return new WeakKey(k); } final public WeakKey WeakKeyCreate(K k, ReferenceQueue q) { if (k == null) return null; else return new WeakKey(k, q); } final public class WeakKey extends WeakReference { public int hash; public WeakKey(K k) { super(k); hash = keyHashCode(k); } final public WeakKey create(K k) { if (k == null) return null; else return new WeakKey(k); } public WeakKey(K k, ReferenceQueue q) { super(k, q); hash = keyHashCode(k); } final public WeakKey create(K k, ReferenceQueue q) { if (k == null) return null; else return new WeakKey(k, q); } @Override public boolean equals(Object o) { if (o == null) return false; if (this == o) return true; if (!(o.getClass().equals(WeakKey.class))) return false; Object t = this.get(); @SuppressWarnings("unchecked") Object u = ((WeakKey) o).get(); if ((t == null) || (u == null)) return false; if (t == u) return true; return keyEquals(t, u); } @Override public int hashCode() { return hash; } } public HashMap hash; public ReferenceQueue queue = new ReferenceQueue(); @SuppressWarnings("unchecked") final public void processQueue() { WeakKey wk; while ((wk = (WeakKey) queue.poll()) != null) { hash.remove(wk); } } public WeakHasherMap(int initialCapacity, float loadFactor) { hash = new HashMap(initialCapacity, loadFactor); } public WeakHasherMap(int initialCapacity) { hash = new HashMap(initialCapacity); } public WeakHasherMap() { hash = new HashMap(); } public WeakHasherMap(Hasher h) { hash = new HashMap(); hasher = h; } @Override public int size() { return entrySet().size(); } @Override public boolean isEmpty() { return entrySet().isEmpty(); } @Override public boolean containsKey(Object key) { @SuppressWarnings("unchecked") K kkey = (K) key; return hash.containsKey(WeakKeyCreate(kkey)); } @Override public V get(Object key) { @SuppressWarnings("unchecked") K kkey = (K) key; return hash.get(WeakKeyCreate(kkey)); } @Override public V put(K key, V value) { processQueue(); return hash.put(WeakKeyCreate(key, queue), value); } @Override public V remove(Object key) { processQueue(); @SuppressWarnings("unchecked") K kkey = (K) key; return hash.remove(WeakKeyCreate(kkey)); } @Override public void clear() { processQueue(); hash.clear(); } @SuppressWarnings("TypeParameterShadowing") final public class Entry implements Map.Entry { public Map.Entry ent; public K key; public Entry(Map.Entry ent, K key) { this.ent = ent; this.key = key; } @Override public K getKey() { return key; } @Override public V getValue() { return ent.getValue(); } @Override public V setValue(V value) { return ent.setValue(value); } final public boolean keyvalEquals(K o1, K o2) { return (o1 == null) ? (o2 == null) : keyEquals(o1, o2); } final public boolean valEquals(V o1, V o2) { return (o1 == null) ? (o2 == null) : o1.equals(o2); } @SuppressWarnings("NonOverridingEquals") public boolean equals(Map.Entry e) { return (keyvalEquals(key, e.getKey()) && valEquals(getValue(), e.getValue())); } @Override public int hashCode() { V v; return (((key == null) ? 0 : keyHashCode(key)) ^ (((v = getValue()) == null) ? 0 : v.hashCode())); } } final public class EntrySet extends AbstractSet> { public Set> hashEntrySet = hash.entrySet(); @Override public Iterator> iterator() { return new Iterator>() { public Iterator> hashIterator = hashEntrySet.iterator(); public Map.Entry next = null; @Override public boolean hasNext() { while (hashIterator.hasNext()) { Map.Entry ent = hashIterator.next(); WeakKey wk = ent.getKey(); K k = null; if ((wk != null) && ((k = wk.get()) == null)) { continue; } next = new Entry(ent, k); return true; } return false; } @Override public Map.Entry next() { if ((next == null) && !hasNext()) throw new NoSuchElementException(); Map.Entry e = next; next = null; return e; } @Override public void remove() { hashIterator.remove(); } }; } @Override public boolean isEmpty() { return !(iterator().hasNext()); } @Override public int size() { int j = 0; for (Iterator> i = iterator(); i.hasNext(); i.next()) j++; return j; } @Override public boolean remove(Object o) { processQueue(); if (!(o instanceof Map.Entry)) return false; @SuppressWarnings("unchecked") Map.Entry e = (Map.Entry) o; Object ev = e.getValue(); WeakKey wk = WeakKeyCreate(e.getKey()); Object hv = hash.get(wk); if ((hv == null) ? ((ev == null) && hash.containsKey(wk)) : hv.equals(ev)) { hash.remove(wk); return true; } return false; } @Override public int hashCode() { int h = 0; for (Iterator> i = hashEntrySet.iterator(); i.hasNext(); ) { Map.Entry ent = i.next(); WeakKey wk = ent.getKey(); Object v; if (wk == null) continue; h += (wk.hashCode() ^ (((v = ent.getValue()) == null) ? 0 : v.hashCode())); } return h; } } public Set> entrySet = null; @Override public Set> entrySet() { if (entrySet == null) entrySet = new EntrySet(); return entrySet; } public K findKey(Object key) { processQueue(); K kkey = (K) key; WeakKey wkey = WeakKeyCreate(kkey); WeakKey found = hashMap_findKey(hash, wkey); return found == null ? null : found.get(); } } public interface TransientObject { } static public class MMOPattern { static public class Phrase extends MMOPattern implements IFieldsToList { public String phrase; public boolean quoted = false; public Phrase() { } public Phrase(String phrase, boolean quoted) { this.quoted = quoted; this.phrase = phrase; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + phrase + ", " + quoted + ")"; } public boolean equals(Object o) { if (!(o instanceof Phrase)) return false; Phrase __1 = (Phrase) o; return eq(phrase, __1.phrase) && eq(quoted, __1.quoted); } public int hashCode() { int h = -1905095975; h = boostHashCombine(h, _hashCode(phrase)); h = boostHashCombine(h, _hashCode(quoted)); return h; } public Object[] _fieldsToList() { return new Object[] { phrase, quoted }; } } static public class And extends MMOPattern implements IFieldsToList { public List l; public And() { } public And(List l) { this.l = l; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + l + ")"; } public boolean equals(Object o) { if (!(o instanceof And)) return false; And __2 = (And) o; return eq(l, __2.l); } public int hashCode() { int h = 65975; h = boostHashCombine(h, _hashCode(l)); return h; } public Object[] _fieldsToList() { return new Object[] { l }; } } static public class Or extends MMOPattern implements IFieldsToList { public List l; public Or() { } public Or(List l) { this.l = l; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + l + ")"; } public boolean equals(Object o) { if (!(o instanceof Or)) return false; Or __3 = (Or) o; return eq(l, __3.l); } public int hashCode() { int h = 2563; h = boostHashCombine(h, _hashCode(l)); return h; } public Object[] _fieldsToList() { return new Object[] { l }; } } static public class Not extends MMOPattern implements IFieldsToList { public MMOPattern p; public Not() { } public Not(MMOPattern p) { this.p = p; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + p + ")"; } public boolean equals(Object o) { if (!(o instanceof Not)) return false; Not __4 = (Not) o; return eq(p, __4.p); } public int hashCode() { int h = 78515; h = boostHashCombine(h, _hashCode(p)); return h; } public Object[] _fieldsToList() { return new Object[] { p }; } } static public class Weighted extends MMOPattern implements IFieldsToList { static final public String _fieldOrder = "weight p"; public double weight; public MMOPattern p; public Weighted() { } public Weighted(double weight, MMOPattern p) { this.p = p; this.weight = weight; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + weight + ", " + p + ")"; } public boolean equals(Object o) { if (!(o instanceof Weighted)) return false; Weighted __5 = (Weighted) o; return weight == __5.weight && eq(p, __5.p); } public int hashCode() { int h = -446368457; h = boostHashCombine(h, _hashCode(weight)); h = boostHashCombine(h, _hashCode(p)); return h; } public Object[] _fieldsToList() { return new Object[] { weight, p }; } } static public class StartOfLine extends MMOPattern implements IFieldsToList { public MMOPattern p; public StartOfLine() { } public StartOfLine(MMOPattern p) { this.p = p; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + p + ")"; } public boolean equals(Object o) { if (!(o instanceof StartOfLine)) return false; StartOfLine __6 = (StartOfLine) o; return eq(p, __6.p); } public int hashCode() { int h = -326863539; h = boostHashCombine(h, _hashCode(p)); return h; } public Object[] _fieldsToList() { return new Object[] { p }; } } static public class EndOfLine extends MMOPattern implements IFieldsToList { public MMOPattern p; public EndOfLine() { } public EndOfLine(MMOPattern p) { this.p = p; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + p + ")"; } public boolean equals(Object o) { if (!(o instanceof EndOfLine)) return false; EndOfLine __7 = (EndOfLine) o; return eq(p, __7.p); } public int hashCode() { int h = -810372346; h = boostHashCombine(h, _hashCode(p)); return h; } public Object[] _fieldsToList() { return new Object[] { p }; } } } static public class proxy_InvocationHandler implements InvocationHandler { public Object target; public proxy_InvocationHandler() { } public proxy_InvocationHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) { return call(target, method.getName(), unnull(args)); } } static public class Pair implements Comparable> { final public Pair setA(A a) { return a(a); } public Pair a(A a) { this.a = a; return this; } final public A getA() { return a(); } public A a() { return a; } public A a; final public Pair setB(B b) { return b(b); } public Pair b(B b) { this.b = b; return this; } final public B getB() { return b(); } public B b() { return b; } public B b; public Pair() { } public Pair(A a, B b) { this.b = b; this.a = a; } public int hashCode() { return hashCodeFor(a) + 2 * hashCodeFor(b); } public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Pair)) return false; Pair t = (Pair) o; return eq(a, t.a) && eq(b, t.b); } public String toString() { return "<" + a + ", " + b + ">"; } public int compareTo(Pair p) { if (p == null) return 1; int i = ((Comparable) a).compareTo(p.a); if (i != 0) return i; return ((Comparable) b).compareTo(p.b); } } static public interface IResourceHolder { public A add(A a); public Collection takeAll(); } static abstract public class DialogIO implements AutoCloseable { public String line; public boolean eos, loud, noClose; public Lock lock = lock(); abstract public String readLineImpl(); abstract public boolean isStillConnected(); abstract public void sendLine(String line); abstract public boolean isLocalConnection(); abstract public Socket getSocket(); public int getPort() { Socket s = getSocket(); return s == null ? 0 : s.getPort(); } public boolean helloRead = false; public int shortenOutputTo = 500; public String readLineNoBlock() { String l = line; line = null; return l; } public boolean waitForLine() { try { ping(); if (line != null) return true; line = readLineImpl(); if (line == null) eos = true; return line != null; } catch (Exception __e) { throw rethrow(__e); } } public String readLine() { waitForLine(); helloRead = true; return readLineNoBlock(); } public String ask(String s, Object... args) { if (loud) return askLoudly(s, args); if (!helloRead) readLine(); if (args.length != 0) s = format3(s, args); sendLine(s); return readLine(); } public String askLoudly(String s, Object... args) { if (!helloRead) readLine(); if (args.length != 0) s = format3(s, args); print("> " + shorten(s, shortenOutputTo)); sendLine(s); String answer = readLine(); print("< " + shorten(answer, shortenOutputTo)); return answer; } public void pushback(String l) { if (line != null) throw fail(); line = l; helloRead = false; } } static abstract public class DialogHandler { abstract public void run(DialogIO io); } static public class IntRange { public int start, end; public IntRange() { } public IntRange(int start, int end) { this.end = end; this.start = start; } public IntRange(IntRange r) { start = r.start; end = r.end; } public boolean equals(Object o) { return stdEq2(this, o); } public int hashCode() { return stdHash2(this); } final public int length() { return end - start; } final public boolean empty() { return start >= end; } final public boolean isEmpty() { return start >= end; } static public String _fieldOrder = "start end"; public String toString() { return "[" + start + ";" + end + "]"; } } static public class MRUCache extends LinkedHashMap { public int maxSize = 10; public MRUCache() { } public MRUCache(int maxSize) { this.maxSize = maxSize; } public boolean removeEldestEntry(Map.Entry eldest) { return size() > maxSize; } public Object _serialize() { return ll(maxSize, cloneLinkedHashMap(this)); } static public MRUCache _deserialize(List l) { MRUCache m = new MRUCache(); m.maxSize = (int) first(l); m.putAll((LinkedHashMap) second(l)); return m; } } static public class PersistableThrowable extends DynamicObject { public String className; public String msg; public String stacktrace; public PersistableThrowable() { } public PersistableThrowable(Throwable e) { if (e == null) className = "Crazy Null Error"; else { className = getClassName(e).replace('/', '.'); msg = e.getMessage(); stacktrace = getStackTrace_noRecord(e); } } public String toString() { return nempty(msg) ? className + ": " + msg : className; } public RuntimeException asRuntimeException() { return new Fail(this); } } static public class SynchronizedSortedMap extends SynchronizedMap implements SortedMap { public SynchronizedSortedMap() { } public SortedMap innerMap() { return (SortedMap) m; } public SynchronizedSortedMap(SortedMap m) { super(m); } public SynchronizedSortedMap(SortedMap m, Object mutex) { super(m, mutex); } public Comparator comparator() { synchronized (mutex) { return innerMap().comparator(); } } public SortedMap subMap(K fromKey, K toKey) { synchronized (mutex) { return new SynchronizedSortedMap<>(innerMap().subMap(fromKey, toKey), mutex); } } public SortedMap headMap(K toKey) { synchronized (mutex) { return new SynchronizedSortedMap<>(innerMap().headMap(toKey), mutex); } } public SortedMap tailMap(K fromKey) { synchronized (mutex) { return new SynchronizedSortedMap<>(innerMap().tailMap(fromKey), mutex); } } public K firstKey() { synchronized (mutex) { return innerMap().firstKey(); } } public K lastKey() { synchronized (mutex) { return innerMap().lastKey(); } } } static public class PingSourceCancelledException extends RuntimeException implements IFieldsToList { public PingSource pingSource; public PingSourceCancelledException() { } public PingSourceCancelledException(PingSource pingSource) { this.pingSource = pingSource; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + pingSource + ")"; } public Object[] _fieldsToList() { return new Object[] { pingSource }; } } static public class MultiSetMap implements IMultiMap { public Map> data = new HashMap>(); public int size; public MultiSetMap() { } public MultiSetMap(boolean useTreeMap) { if (useTreeMap) data = new TreeMap(); } public MultiSetMap(MultiSetMap map) { putAll(map); } public MultiSetMap(Map> data) { this.data = data; } public boolean put(A key, B value) { synchronized (data) { Set set = data.get(key); if (set == null) data.put(key, set = _makeEmptySet()); if (!set.add(value)) return false; { ++size; return true; } } } public boolean add(A key, B value) { return put(key, value); } public void addAll(A key, Collection values) { synchronized (data) { putAll(key, values); } } public void addAllIfNotThere(A key, Collection values) { synchronized (data) { for (B value : values) setPut(key, value); } } public void setPut(A key, B value) { synchronized (data) { if (!containsPair(key, value)) put(key, value); } } final public boolean contains(A key, B value) { return containsPair(key, value); } public boolean containsPair(A key, B value) { synchronized (data) { return get(key).contains(value); } } public void putAll(A key, Collection values) { synchronized (data) { for (B value : values) put(key, value); } } public void removeAll(A key, Collection values) { synchronized (data) { for (B value : values) remove(key, value); } } public Set get(A key) { synchronized (data) { Set set = data.get(key); return set == null ? Collections.emptySet() : set; } } public List getAndClear(A key) { synchronized (data) { List l = cloneList(data.get(key)); remove(key); return l; } } public Set getOpt(A key) { synchronized (data) { return data.get(key); } } public Set getActual(A key) { synchronized (data) { Set set = data.get(key); if (set == null) data.put(key, set = _makeEmptySet()); return set; } } public void clean(A key) { synchronized (data) { Set list = data.get(key); if (list != null && list.isEmpty()) data.remove(key); } } final public Set keys() { return keySet(); } public Set keySet() { synchronized (data) { return data.keySet(); } } public void remove(A key) { synchronized (data) { size -= l(data.get(key)); data.remove(key); } } public void remove(A key, B value) { synchronized (data) { Set set = data.get(key); if (set != null) { if (set.remove(value)) { --size; if (set.isEmpty()) data.remove(key); } } } } public void clear() { synchronized (data) { data.clear(); size = 0; } } public boolean containsKey(A key) { synchronized (data) { return data.containsKey(key); } } public B getFirst(A key) { synchronized (data) { return first(get(key)); } } public void addAll(MultiSetMap map) { putAll(map); } public void putAll(MultiSetMap map) { synchronized (data) { for (A key : map.keySet()) putAll(key, map.get(key)); } } public void putAll(Map map) { synchronized (data) { if (map != null) for (Map.Entry e : map.entrySet()) put(e.getKey(), e.getValue()); } } final public int keyCount() { return keysSize(); } public int keysSize() { synchronized (data) { return l(data); } } public int size() { synchronized (data) { return size; } } public int getSize(A key) { return l(data.get(key)); } public int count(A key) { return getSize(key); } public Set reverseGet(B b) { synchronized (data) { Set l = new HashSet(); for (A key : data.keySet()) if (data.get(key).contains(b)) l.add(key); return l; } } public A keyForValue(B b) { synchronized (data) { for (A key : data.keySet()) if (data.get(key).contains(b)) return key; return null; } } public Map> asMap() { synchronized (data) { return cloneMap(data); } } public boolean isEmpty() { synchronized (data) { return data.isEmpty(); } } public Set _makeEmptySet() { return new HashSet(); } public Collection> allLists() { synchronized (data) { return new HashSet(data.values()); } } public List allValues() { return concatLists(values(data)); } public List> allEntries() { synchronized (data) { List> l = emptyList(size); for (Map.Entry> __0 : _entrySet(data)) { A a = __0.getKey(); Set set = __0.getValue(); for (B b : set) l.add(pair(a, b)); } return l; } } public Object mutex() { return data; } public String toString() { return "mm" + str(data); } public Pair firstEntry() { synchronized (data) { if (empty(data)) return null; Map.Entry> entry = data.entrySet().iterator().next(); return pair(entry.getKey(), first(entry.getValue())); } } public A firstKey() { synchronized (data) { return main.firstKey(data); } } public A lastKey() { synchronized (data) { return (A) ((NavigableMap) data).lastKey(); } } public A higherKey(Object a) { synchronized (data) { return (A) ((NavigableMap) data).higherKey(a); } } } static public class FileBasedLock implements AutoCloseable { public File lockFile; public double timeout = 60.0; public boolean verbose = false; public boolean haveLock = false; public java.util.Timer touchTimer; final public FileBasedLock setContentsForLockFile(String contentsForLockFile) { return contentsForLockFile(contentsForLockFile); } public FileBasedLock contentsForLockFile(String contentsForLockFile) { this.contentsForLockFile = contentsForLockFile; return this; } final public String getContentsForLockFile() { return contentsForLockFile(); } public String contentsForLockFile() { return contentsForLockFile; } public String contentsForLockFile; public FileBasedLock() { } public FileBasedLock(File lockFile) { this.lockFile = lockFile; } public FileBasedLock(File lockFile, double timeout) { this.timeout = timeout; this.lockFile = lockFile; } synchronized public boolean tryToLock() { if (haveLock) return true; if (fileExists(lockFile)) { double age = fileAgeInSeconds(lockFile); double remaining = timeout - age; print("Lock file age: " + lockFile + ": " + iround(age) + " s" + (remaining <= 0 ? " - old, deleting" : " - please start again in " + nSeconds(iceil(remaining)))); if (remaining <= 0) { print("Deleting old lock file (program crashed?): " + lockFile + " (age: " + iround(age) + " seconds)"); deleteFile(lockFile); } } try { mkdirsForFile(lockFile); java.nio.file.Files.createFile(toPath(lockFile)); if (nempty(contentsForLockFile)) writeContents(); acquired(); return true; } catch (Throwable e) { printExceptionShort("Can't lock", e); return false; } } public void writeContents() { saveTextFileWithoutTemp(lockFile, unnull(contentsForLockFile)); } final public void acquired() { haveLock = true; startTouchTimer(); } public void forceLock() { try { print("Force-locking " + lockFile); writeContents(); acquired(); } catch (Exception __e) { throw rethrow(__e); } } public String lockError() { return "Couldn't aquire lock file: " + lockFile; } public void lockOrFail() { if (!tryToLock()) throw fail(lockError()); } synchronized public void startTouchTimer() { if (touchTimer != null) return; double interval = timeout / 2; touchTimer = doEvery(interval, new Runnable() { public void run() { try { doTouch(); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "doTouch();"; } }); if (verbose) print("Touch timer started for " + lockFile + " (" + interval + "s)"); } synchronized public void doTouch() { try { if (haveLock) { if (verbose) print("Touching lock file: " + lockFile); touchExistingFile(lockFile); } } catch (Throwable __e) { printStackTrace(__e); } } public synchronized void close() { try { { cleanUp(touchTimer); touchTimer = null; } if (haveLock) { haveLock = false; if (verbose) print("Deleting lock file: " + lockFile); deleteFile(lockFile); } } catch (Throwable __e) { printStackTrace(__e); } } synchronized public void _simulateCrash() { { cleanUp(touchTimer); touchTimer = null; } } public void deleteOnExit() { if (haveLock) lockFile.deleteOnExit(); } public String actualContents() { return loadTextFile(lockFile); } public boolean hasExpectedContents() { return eq(unnull(contentsForLockFile), actualContents()); } } static public interface ValueConverterForField { public OrError convertValue(Object object, Field field, Object value); } static public class ThreadPool implements AutoCloseable { public int max = numberOfCores(); public List all = new ArrayList(); public Set used = new HashSet(); public Set free = new HashSet(); public boolean verbose, retired; public class InternalPingSource extends PingSource { } public InternalPingSource internalPingSource = new InternalPingSource(); public MultiSleeper sleeper = new MultiSleeper(); public ThreadPool() { } public ThreadPool(int max) { this.max = max; } synchronized public int maxSize() { return max; } synchronized public int total() { return l(used) + l(free); } transient public Set onCustomerMustWaitAlert; public ThreadPool onCustomerMustWaitAlert(Runnable r) { onCustomerMustWaitAlert = createOrAddToSyncLinkedHashSet(onCustomerMustWaitAlert, r); return this; } public ThreadPool removeCustomerMustWaitAlertListener(Runnable r) { main.remove(onCustomerMustWaitAlert, r); return this; } public void customerMustWaitAlert() { if (onCustomerMustWaitAlert != null) for (var listener : onCustomerMustWaitAlert) pcallF_typed(listener); } public void fireCustomerMustWaitAlert() { vmBus_send("customerMustWaitAlert", this, currentThread()); customerMustWaitAlert(); } public PooledThread acquireThreadOrQueue(Runnable action) { if (action == null) return null; PooledThread t; synchronized (this) { if (_hasFreeAfterCreating()) { t = _firstFreeThread(); markUsed(t); } else t = _anyThread(); } t.addWork(action); return t; } public boolean _hasFreeAfterCreating() { checkNotRetired(); if (nempty(free)) return true; if (total() < max) { PooledThread t = newThread(); all.add(t); free.add(t); return true; } return false; } public PooledThread acquireThreadOrWait(Runnable action) { try { if (action == null) return null; PooledThread t; while (true) { synchronized (this) { if (_hasFreeAfterCreating()) { t = _firstFreeThread(); break; } else _waitWaitWait(); } } t.addWork(action); return t; } catch (Exception __e) { throw rethrow(__e); } } public PooledThread _firstFreeThread() { return first(free); } public PooledThread _anyThread() { return random(used); } public class PooledThread extends Thread { public PooledThread(String name) { super(name); } public AppendableChain q; synchronized public Runnable _grabWorkOrSleep() { try { Runnable r = first(q); if (r == null) { markFree(this); if (verbose) print("Thread sleeps"); synchronized (this) { wait(); } if (verbose) print("Thread woke up"); return null; } q = popFirst(q); return r; } catch (Exception __e) { throw rethrow(__e); } } public void run() { try { pingSource_tl().set(internalPingSource); while (!retired()) { ping(); Runnable r = _grabWorkOrSleep(); if (verbose) print(this + " work: " + r); if (r != null) try { if (verbose) print(this + " running: " + r); r.run(); pingSource_tl().set(internalPingSource); if (verbose) print(this + " done"); } catch (Throwable e) { pingSource_tl().set(internalPingSource); if (verbose) print(this + " error"); printStackTrace(e); } finally { pingSource_tl().set(internalPingSource); if (verbose) print("ThreadPool finally"); } } } catch (Exception __e) { throw rethrow(__e); } } synchronized public boolean isEmpty() { return empty(q); } public void addWork(Runnable r) { if (verbose) print("Added work to " + this + ": " + r); synchronized (this) { q = chainPlus(q, r); notifyAll(); } } } public PooledThread newThread() { PooledThread t = new PooledThread("Thread Pool Inhabitant " + n2(total() + 1)); t.start(); return t; } synchronized public void markFree(PooledThread t) { used.remove(t); free.add(t); notifyAll(); } synchronized public void markUsed(PooledThread t) { free.remove(t); used.add(t); } synchronized public String toString() { return retired() ? "Retired ThreadPool" : "ThreadPool " + roundBracket(commaCombine(n2(used) + " used out of " + n2(total()), max <= total() ? null : "could grow to " + n2(max))); } synchronized public boolean retired() { return retired; } synchronized public void retire() { if (verbose) print("ThreadPool Retiring"); retired = true; for (var thread : free) syncNotifyAll(thread); } public void checkNotRetired() { if (retired()) throw fail("retired"); } synchronized public void close() { try { retire(); } catch (Exception __e) { throw rethrow(__e); } } public void _waitWaitWait() { try { do { fireCustomerMustWaitAlert(); wait(); checkNotRetired(); } while (empty(free)); } catch (Exception __e) { throw rethrow(__e); } } public void dO(String text, Runnable r) { if (r == null) return; new PingSource(this, text).dO(r); } public ISleeper_v2 sleeper() { return sleeper; } } static public class HTML implements IF0, IFieldsToList { public String html; public HTML() { } public HTML(String html) { this.html = html; } public boolean equals(Object o) { if (!(o instanceof HTML)) return false; HTML __1 = (HTML) o; return eq(html, __1.html); } public int hashCode() { int h = 2228139; h = boostHashCombine(h, _hashCode(html)); return h; } public Object[] _fieldsToList() { return new Object[] { html }; } public String get() { return html; } public String toString() { return html; } } static public class SecretValue extends Var { public SecretValue() { } public SecretValue(A a) { super(a); } public String toString() { return "Secret value"; } } static public interface IContentsIndexedList extends List { public int[] indicesOf(A o); } abstract static public class ConceptFieldIndexBase implements IConceptIndex, IFieldIndex, IConceptCounter, AutoCloseable { public Concepts concepts; public Class cc; public String field; public Map objectToValue = syncHashMap(); public MultiSetMap valueToObject; public ConceptFieldIndexBase() { init(); } public ConceptFieldIndexBase(Class cc, String field) { this(db_mainConcepts(), cc, field); } public ConceptFieldIndexBase(Concepts concepts, Class cc, String field) { this(); this.field = field; this.cc = cc; this.concepts = concepts; concepts.addConceptIndex(this); updateAll(); register(); updateAll(); } public void updateAll() { for (A c : setToIndex()) updateImpl(c); } public Collection setToIndex() { return list(concepts, cc); } abstract public void init(); abstract public void register(); public void update(Concept c) { if (!isInstance(cc, c)) return; updateImpl((A) c); } synchronized public void updateImpl(A c) { Val newValue = (Val) (cget(c, field)); Val oldValue = objectToValue.get(c); if (newValue == oldValue && (oldValue != null || objectToValue.containsKey(c))) return; valueToObject.remove(oldValue, c); valueToObject.put(newValue, c); put(objectToValue, c, newValue); } public synchronized void remove(Concept c) { if (!isInstance(cc, c)) return; if (!objectToValue.containsKey(c)) return; Val value = objectToValue.get(c); objectToValue.remove(c); valueToObject.remove(value, (A) c); } synchronized public A get(Val value) { return valueToObject.getFirst(value); } public synchronized Collection getAll(Val value) { return valueToObject.get(value); } public synchronized List allValues() { return cloneKeys_noSync(valueToObject.data); } public IterableIterator objectIterator() { return navigableMultiSetMapValuesIterator_concurrent(valueToObject, this); } public synchronized MultiSet allValues_multiSet() { return multiSetMapToMultiSet(valueToObject); } public Class conceptClass() { return cc; } public int countConcepts() { return l(objectToValue); } public Collection allConcepts() { return (Collection) keys(objectToValue); } public Object mutex() { return this; } public void close() { try { concepts.removeConceptIndex(this); } catch (Exception __e) { throw rethrow(__e); } } } static public class SynchronizedCollection implements Collection, Serializable { public SynchronizedCollection() { } @java.io.Serial static final public long serialVersionUID = 3053995032091335093L; @SuppressWarnings("serial") public Collection c; @SuppressWarnings("serial") public Object mutex; public SynchronizedCollection(Collection c) { this.c = Objects.requireNonNull(c); mutex = this; } public SynchronizedCollection(Collection c, Object mutex) { this.c = Objects.requireNonNull(c); this.mutex = Objects.requireNonNull(mutex); } public int size() { synchronized (mutex) { return c.size(); } } public boolean isEmpty() { synchronized (mutex) { return c.isEmpty(); } } public boolean contains(Object o) { synchronized (mutex) { return c.contains(o); } } public Object[] toArray() { synchronized (mutex) { return c.toArray(); } } public T[] toArray(T[] a) { synchronized (mutex) { return c.toArray(a); } } public T[] toArray(java.util.function.IntFunction f) { synchronized (mutex) { return c.toArray(f); } } public Iterator iterator() { return c.iterator(); } public boolean add(E e) { synchronized (mutex) { return c.add(e); } } public boolean remove(Object o) { synchronized (mutex) { return c.remove(o); } } public boolean containsAll(Collection coll) { synchronized (mutex) { return c.containsAll(coll); } } public boolean addAll(Collection coll) { synchronized (mutex) { return c.addAll(coll); } } public boolean removeAll(Collection coll) { synchronized (mutex) { return c.removeAll(coll); } } public boolean retainAll(Collection coll) { synchronized (mutex) { return c.retainAll(coll); } } public void clear() { synchronized (mutex) { c.clear(); } } public String toString() { synchronized (mutex) { return c.toString(); } } @Override public void forEach(java.util.function.Consumer consumer) { synchronized (mutex) { c.forEach(consumer); } } @Override public boolean removeIf(java.util.function.Predicate filter) { synchronized (mutex) { return c.removeIf(filter); } } @Override public Spliterator spliterator() { return c.spliterator(); } @Override public java.util.stream.Stream stream() { return c.stream(); } @Override public java.util.stream.Stream parallelStream() { return c.parallelStream(); } @java.io.Serial final public void writeObject(ObjectOutputStream s) throws IOException { synchronized (mutex) { s.defaultWriteObject(); } } } static public class SynchronizedRandomAccessList extends SynchronizedList implements RandomAccess { public SynchronizedRandomAccessList() { } public SynchronizedRandomAccessList(List list) { super(list); } public SynchronizedRandomAccessList(List list, Object mutex) { super(list, mutex); } public List subList(int fromIndex, int toIndex) { synchronized (mutex) { return new SynchronizedRandomAccessList<>(list.subList(fromIndex, toIndex), mutex); } } @java.io.Serial static final public long serialVersionUID = 1530674583602358482L; @java.io.Serial final public Object writeReplace() { return new SynchronizedList<>(list); } } static public class HTMLAceEditor implements Htmlable { public String text; public String name = "text"; public String id; public Map divParams = litmap("style", "width: 80ch; height: 20em"); public String onKeyDown; public HTMLAceEditor() { } public HTMLAceEditor(String text) { this.text = text; } public String headStuff() { return hscriptsrc("https://botcompany.de/ace-builds/src-noconflict/ace.js") + hscriptsrc("https://botcompany.de/ace-builds/src-noconflict/ext-language_tools.js"); } public String html() { id = "ace_" + name; return div(htmlEncode2(text), params_stylePlus("display: none", paramsPlus(mapToParams(divParams), "id", id))) + hhiddenWithIDAndName(name) + hscript(replaceDollarVars(" (function() {\r\n ace.require(\"ace/ext/language_tools\");\r\n var editor = ace.edit($id);\r\n editor.setTheme(\"ace/theme/ambience\");\r\n editor.getSession().setTabSize(2);\r\n editor.getSession().setUseSoftTabs(true);\r\n editor.getSession().setUseWrapMode(true);\r\n document.getElementById($id).style.fontSize='15px';\r\n editor.setOptions({\r\n enableBasicAutocompletion: true\r\n });\r\n \r\n var div = $(\"#\" + $id);\r\n var hiddenVal = document.getElementById($name);\r\n function updateHidden() {\r\n div.trigger('input'); // for auto-expand\r\n //hiddenVal.value = editor.getValue();\r\n var newVal = editor.getValue();\r\n if (hiddenVal.value != newVal)\r\n $(hiddenVal).val(newVal).trigger('change');\r\n }\r\n updateHidden();\r\n \r\n editor.session.on('change', updateHidden);\r\n $onKeyDown\r\n \r\n div.show();\r\n //editor.focus();\r\n })() ", "id", jsQuote(id), "name", jsQuote(name), "onKeyDown", empty(onKeyDown) ? "" : "editor.textInput.getElement().onkeydown = " + onKeyDown + ";")); } public String complete() { return linesLL(headStuff(), html()); } } public interface IMultiMap { public Set keySet(); public Collection get(A a); public int size(); public int keyCount(); } static public class MultiSet implements IMultiSet { public Map map = new HashMap(); public int size; public MultiSet(boolean useTreeMap) { if (useTreeMap) map = new TreeMap(); } public MultiSet(TreeMap map) { this.map = map; } public MultiSet() { } public MultiSet(Iterable c) { addAll(c); } public MultiSet(MultiSet ms) { synchronized (ms) { for (A a : ms.keySet()) add(a, ms.get(a)); } } public synchronized int add(A key) { return add(key, 1); } synchronized public void addAll(Iterable c) { if (c != null) for (A a : c) add(a); } synchronized public void addAll(MultiSet ms) { for (A a : ms.keySet()) add(a, ms.get(a)); } synchronized public int add(A key, int count) { if (count <= 0) return 0; size += count; Integer i = map.get(key); map.put(key, i != null ? (count += i) : count); return count; } synchronized public void put(A key, int count) { int oldCount = get(key); if (count == oldCount) return; size += count - oldCount; if (count != 0) map.put(key, count); else map.remove(key); } public synchronized int get(A key) { Integer i = map.get(key); return i != null ? i : 0; } synchronized public boolean contains(A key) { return map.containsKey(key); } synchronized public void remove(A key) { Integer i = map.get(key); if (i != null) { --size; if (i > 1) map.put(key, i - 1); else map.remove(key); } } synchronized public List topTen() { return getTopTen(); } synchronized public List getTopTen() { return getTopTen(10); } synchronized public List getTopTen(int maxSize) { List list = getSortedListDescending(); return list.size() > maxSize ? list.subList(0, maxSize) : list; } synchronized public List highestFirst() { return getSortedListDescending(); } synchronized public List lowestFirst() { return reversedList(getSortedListDescending()); } synchronized public List getSortedListDescending() { List list = new ArrayList(map.keySet()); Collections.sort(list, new Comparator() { public int compare(A a, A b) { return map.get(b).compareTo(map.get(a)); } }); return list; } synchronized public int getNumberOfUniqueElements() { return map.size(); } synchronized public int uniqueSize() { return map.size(); } synchronized public Set asSet() { return map.keySet(); } synchronized public NavigableSet navigableSet() { return navigableKeys((NavigableMap) map); } synchronized public Set keySet() { return map.keySet(); } synchronized public A getMostPopularEntry() { int max = 0; A a = null; for (Map.Entry entry : map.entrySet()) { if (entry.getValue() > max) { max = entry.getValue(); a = entry.getKey(); } } return a; } synchronized public void removeAll(A key) { size -= get(key); map.remove(key); } synchronized public int size() { return size; } synchronized public MultiSet mergeWith(MultiSet set) { MultiSet result = new MultiSet(); for (A a : set.asSet()) { result.add(a, set.get(a)); } return result; } synchronized public boolean isEmpty() { return map.isEmpty(); } synchronized public String toString() { return str(map); } synchronized public void clear() { map.clear(); size = 0; } final public Map toMap() { return asMap(); } synchronized public Map asMap() { return cloneMap(map); } } static public class HTMLPaginator { public String startParam = "start"; public String baseLink; public int start, step = 50; public int max; public void processParams(Map params) { start = parseInt(mapGet(params, startParam)); } public String renderNav(Object... __) { return pageNav2(baseLink, max, start, step, startParam, __); } public IntRange visibleRange() { return intRange(start, min(max, start + step)); } } static public class HCRUD_Data { public Map renderers = new HashMap(); public Map fieldHelp = new HashMap(); public Object currentValue; public boolean humanizeFieldNames = true; public Map rawFormValues; abstract static public class Renderer { public String metaInfo; transient public IF1 preprocessValue; public Object preprocessValue(Object value) { return preprocessValue != null ? preprocessValue.get(value) : preprocessValue_base(value); } final public Object preprocessValue_fallback(IF1 _f, Object value) { return _f != null ? _f.get(value) : preprocessValue_base(value); } public Object preprocessValue_base(Object value) { return value; } } static public class NotEditable extends Renderer { } static public class TextArea extends Renderer implements IFieldsToList { public int cols; public int rows; public TextArea() { } public TextArea(int cols, int rows) { this.rows = rows; this.cols = cols; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + cols + ", " + rows + ")"; } public boolean equals(Object o) { if (!(o instanceof TextArea)) return false; TextArea __1 = (TextArea) o; return cols == __1.cols && rows == __1.rows; } public int hashCode() { int h = -939552902; h = boostHashCombine(h, _hashCode(cols)); h = boostHashCombine(h, _hashCode(rows)); return h; } public Object[] _fieldsToList() { return new Object[] { cols, rows }; } public TextArea(int cols, int rows, IF1 preprocessValue) { this.cols = cols; this.rows = rows; this.preprocessValue = preprocessValue; } } static public class AceEditor extends TextArea { public AceEditor() { } public AceEditor(int cols, int rows) { this.rows = rows; this.cols = cols; } } static public class TextField extends Renderer implements IFieldsToList { public int cols; public TextField() { } public TextField(int cols) { this.cols = cols; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + cols + ")"; } public boolean equals(Object o) { if (!(o instanceof TextField)) return false; TextField __2 = (TextField) o; return cols == __2.cols; } public int hashCode() { int h = 942981037; h = boostHashCombine(h, _hashCode(cols)); return h; } public Object[] _fieldsToList() { return new Object[] { cols }; } } static public class AbstractComboBox extends Renderer implements IFieldsToList { public AbstractComboBox() { } public String toString() { return shortClassName_dropNumberPrefix(this); } public boolean equals(Object o) { return o instanceof AbstractComboBox; } public int hashCode() { int h = -1802496065; return h; } public Object[] _fieldsToList() { return null; } public boolean editable = false; transient public IF1 valueToEntry; public String valueToEntry(Object value) { return valueToEntry != null ? valueToEntry.get(value) : valueToEntry_base(value); } final public String valueToEntry_fallback(IF1 _f, Object value) { return _f != null ? _f.get(value) : valueToEntry_base(value); } public String valueToEntry_base(Object value) { return strOrNull(value); } } static public class ComboBox extends AbstractComboBox implements IFieldsToList { public List entries; public ComboBox() { } public ComboBox(List entries) { this.entries = entries; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + entries + ")"; } public boolean equals(Object o) { if (!(o instanceof ComboBox)) return false; ComboBox __3 = (ComboBox) o; return eq(entries, __3.entries); } public int hashCode() { int h = -547674755; h = boostHashCombine(h, _hashCode(entries)); return h; } public Object[] _fieldsToList() { return new Object[] { entries }; } public ComboBox(String... entries) { this(asList(entries)); } public ComboBox(boolean editable, String... entries) { this(entries); this.editable = editable; } public ComboBox(boolean editable, List entries) { this(entries); this.editable = editable; } public ComboBox(List entries, IF1 valueToEntry) { this.entries = entries; this.valueToEntry = valueToEntry; } } static public class DynamicComboBox extends AbstractComboBox implements IFieldsToList { public String info; public DynamicComboBox() { } public DynamicComboBox(String info) { this.info = info; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + info + ")"; } public boolean equals(Object o) { if (!(o instanceof DynamicComboBox)) return false; DynamicComboBox __4 = (DynamicComboBox) o; return eq(info, __4.info); } public int hashCode() { int h = -737505636; h = boostHashCombine(h, _hashCode(info)); return h; } public Object[] _fieldsToList() { return new Object[] { info }; } public String url; } static public class CheckBox extends Renderer implements IFieldsToList { public CheckBox() { } public String toString() { return shortClassName_dropNumberPrefix(this); } public boolean equals(Object o) { return o instanceof CheckBox; } public int hashCode() { int h = 1601505219; return h; } public Object[] _fieldsToList() { return null; } { metaInfo = "Bool"; } } static public class FlexibleLengthList extends Renderer implements IFieldsToList { public Renderer itemRenderer; public FlexibleLengthList() { } public FlexibleLengthList(Renderer itemRenderer) { this.itemRenderer = itemRenderer; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + itemRenderer + ")"; } public boolean equals(Object o) { if (!(o instanceof FlexibleLengthList)) return false; FlexibleLengthList __5 = (FlexibleLengthList) o; return eq(itemRenderer, __5.itemRenderer); } public int hashCode() { int h = -1874811153; h = boostHashCombine(h, _hashCode(itemRenderer)); return h; } public Object[] _fieldsToList() { return new Object[] { itemRenderer }; } } public String itemName() { return "object"; } public String itemNamePlural() { return plural(itemName()); } public List> list() { return null; } public List> list(IntRange range) { return subListOrFull(list(), range); } public String idField() { return "id"; } public Map emptyObject() { return null; } public Map getObject(Object id) { return null; } public Map getObjectForEdit(Object id) { return getObject(id); } transient public IF1> getObjectForDuplication; public Map getObjectForDuplication(Object id) { return getObjectForDuplication != null ? getObjectForDuplication.get(id) : getObjectForDuplication_base(id); } final public Map getObjectForDuplication_fallback(IF1> _f, Object id) { return _f != null ? _f.get(id) : getObjectForDuplication_base(id); } public Map getObjectForDuplication_base(Object id) { return getObject(id); } public Object createObject(Map fullMap, String fieldPrefix) { throw unimplemented(); } public String deleteObject(Object id) { throw unimplemented(); } public boolean objectCanBeDeleted(Object id) { return true; } transient public IF1 objectCanBeEdited; public boolean objectCanBeEdited(Object id) { return objectCanBeEdited != null ? objectCanBeEdited.get(id) : objectCanBeEdited_base(id); } final public boolean objectCanBeEdited_fallback(IF1 _f, Object id) { return _f != null ? _f.get(id) : objectCanBeEdited_base(id); } public boolean objectCanBeEdited_base(Object id) { return true; } public String updateObject(Object id, Map fullMap, String fieldPrefix) { throw unimplemented(); } public Renderer getRenderer(String field) { return renderers.get(field); } final public Renderer getRenderer(String field, Object value) { this.currentValue = value; try { return getRenderer(field); } finally { this.currentValue = null; } } public String fieldHelp(String field) { return fieldHelp.get(field); } public HCRUD_Data addRenderer(String field, Renderer renderer) { renderers.put(field, renderer); return this; } public HCRUD_Data fieldHelp(String field, String help, String... more) { fieldHelp.put(field, help); for (int i = 0; i + 1 < l(more); i += 2) fieldHelp.put(more[i], more[i + 1]); return this; } public String fieldNameToHTML(String name) { String help = fieldHelp.get(name); return spanTitle(help, htmlencode2(humanizeFieldNames ? humanizeLabel(name) : name)); } public Set filteredFields() { return null; } public List comboBoxSearch(String info, String query) { return null; } public String titleForObjectID(Object id) { return null; } public Pair defaultSortField() { return null; } abstract public class Item extends AbstractMap { public Object id; public Map fullMap; public Item(Object id) { this.id = id; } abstract public Map calcFullMap(); public Map fullMap() { if (fullMap == null) fullMap = calcFullMap(); return fullMap; } public int size() { return l(fullMap()); } public Set> entrySet() { return fullMap().entrySet(); } public boolean containsKey(Object o) { return fullMap().containsKey(o); } public Object get(Object o) { if (fullMap == null && eq(o, idField())) return id; return fullMap().get(o); } public Object put(String key, Object value) { return fullMap().put(key, value); } } } static public class MinimalChain implements Iterable { public A element; public MinimalChain next; public MinimalChain() { } public MinimalChain(A element) { this.element = element; } public MinimalChain(A element, MinimalChain next) { this.next = next; this.element = element; } public String toString() { return str(toList()); } public ArrayList toList() { ArrayList l = new ArrayList(); MinimalChain c = this; while (c != null) { l.add(c.element); c = c.next; } return l; } public void setElement(A a) { element = a; } public void setNext(MinimalChain next) { this.next = next; } public Iterator iterator() { return toList().iterator(); } public A get() { return element; } } static public interface ISetter { public void set(A a); } static public interface IConceptCounter { public Class conceptClass(); public int countConcepts(); public Collection allConcepts(); } static public interface IAutoCloseableF0 extends IF0, AutoCloseable { } abstract static public class HAbstractRenderable { public String baseLink = ""; public MakeFrame makeFrame = (title, contents) -> h1_title(title) + contents; static public interface MakeFrame { public String makeFrame(String title, String contents); } public HAbstractRenderable() { } public HAbstractRenderable(String baseLink) { this.baseLink = baseLink; } public HAbstractRenderable makeFrame(MakeFrame makeFrame) { this.makeFrame = makeFrame; return this; } public String baseLinkPlus(String uri) { return nempty(uri) ? appendSlash(baseLink) + uri : baseLink; } public String frame(String title, String contents) { return makeFrame.makeFrame(title, contents); } public String refreshWithMsgs(String... msgs) { return refreshWithMsgs(asList(msgs)); } public String refreshWithMsgs(List msgs, Object... __) { String anchor = (String) (optPar("anchor", __)); Map params = (Map) (optPar("params", __)); return hrefresh(addAnchorToURL(appendQueryToURL(baseLink, mapPlus(params, "msg", htmlEncode_nlToBr(lines_rtrim(msgs)))), anchor)); } public String renderMsgs(Map params) { return pUnlessEmpty(params.get("msg")); } } abstract static public class RandomAccessAbstractList extends AbstractList implements RandomAccess { } static public class RemoteDB implements AutoCloseable { public DialogIO db; public String name; public RemoteDB(String s) { this(s, false); } public RemoteDB(String s, boolean autoStart) { name = s; if (isSnippetID(s)) name = dbBotName(s); db = findBot(name); if (db == null) if (autoStart) { nohupJavax(fsI(s)); waitForBotStartUp(name); assertNotNull("Weird problem", db = findBot(s)); } else throw fail("DB " + s + " not running"); } public boolean functional() { return db != null; } public List list() { return adopt((List) rpc(db, "xlist")); } public List list(String className) { return adopt((List) rpc(db, "xlist", className)); } public List xlist() { return list(); } public List xlist(String className) { return list(className); } public List adopt(List l) { if (l != null) for (RC rc : l) adopt(rc); return l; } public RC adopt(RC rc) { if (rc != null) rc.db = this; return rc; } public Object adopt(Object o) { if (o instanceof RC) return adopt((RC) o); return o; } public String xclass(RC o) { return (String) rpc(db, "xclass", o); } public Object xget(RC o, String field) { return adopt(rpc(db, "xget", o, field)); } public String xS(RC o, String field) { return (String) xget(o, field); } public RC xgetref(RC o, String field) { return adopt((RC) xget(o, field)); } public void xset(RC o, String field, Object value) { rpc(db, "xset", o, field, value); } public RC uniq(String className) { RC ref = first(list(className)); if (ref == null) ref = xnew(className); return ref; } public RC xuniq(String className) { return uniq(className); } public RC xnew(String className, Object... values) { return adopt((RC) rpc(db, "xnew", className, values)); } public void xdelete(RC o) { rpc(db, "xdelete", o); } public void xdelete(List l) { rpc(db, "xdelete", l); } public void close() { _close(db); } public String fullgrab() { return (String) rpc(db, "xfullgrab"); } public String xfullgrab() { return fullgrab(); } public void xshutdown() { rpc(db, "xshutdown"); } public long xchangeCount() { return (long) rpc(db, "xchangeCount"); } public int xcount() { return (int) rpc(db, "xcount"); } public void reconnect() { close(); db = findBot(name); } public RC rc(long id) { return new RC(this, id); } } public interface ChangeTriggerable { public void change(); } static public class Not implements IFieldsToList, Transformable, Visitable { public A a; public Not() { } public Not(A a) { this.a = a; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + a + ")"; } public boolean equals(Object o) { if (!(o instanceof Not)) return false; Not __0 = (Not) o; return eq(a, __0.a); } public int hashCode() { int h = 78515; h = boostHashCombine(h, _hashCode(a)); return h; } public Object[] _fieldsToList() { return new Object[] { a }; } public Object transformUsing(IF1 f) { return new Not((A) f.get(a)); } public void visitUsing(IVF1 f) { f.get(a); } public Boolean get(Object o) { return not((Boolean) callF(a, o)); } } static public interface IContentsIndexedList2 extends List { public TreeSet indicesOf_treeSetOfHasIndex(A o); } static public interface IFieldsToList { public Object[] _fieldsToList(); } static public interface ISleeper_v2 { public Sleeping doLater(Timestamp targetTime, Runnable r); public default Sleeping doAfter(double seconds, Runnable r) { return doLater(tsNow().plusSeconds(seconds), r); } } static public interface IVF2 { public void get(A a, B b); } public interface IDoublePt { public double x_double(); public double y_double(); } static public interface IVar extends IF0 { public void set(A a); public A get(); default public Class getType() { return null; } default public boolean has() { return get() != null; } default public void clear() { set(null); } } static public class HasIndex implements Comparable { public int idx; public HasIndex() { } public HasIndex(int idx) { this.idx = idx; } public int compareTo(HasIndex h) { return idx - h.idx; } final public int get() { return idx; } } static public interface WidthAndHeight { default public int w() { return getWidth(); } public int getWidth(); default public int h() { return getHeight(); } public int getHeight(); public default Rect bounds() { return rect(0, 0, getWidth(), getHeight()); } default public int area() { return toInt(areaAsLong()); } default public long areaAsLong() { return longMul(w(), h()); } } static public class SynchronizedNavigableSet extends SynchronizedSortedSet implements NavigableSet { public SynchronizedNavigableSet() { } @java.io.Serial static final public long serialVersionUID = -5505529816273629798L; @SuppressWarnings("serial") public NavigableSet ns; public SynchronizedNavigableSet(NavigableSet s) { super(s); ns = s; } public SynchronizedNavigableSet(NavigableSet s, Object mutex) { super(s, mutex); ns = s; } public E lower(E e) { synchronized (mutex) { return ns.lower(e); } } public E floor(E e) { synchronized (mutex) { return ns.floor(e); } } public E ceiling(E e) { synchronized (mutex) { return ns.ceiling(e); } } public E higher(E e) { synchronized (mutex) { return ns.higher(e); } } public E pollFirst() { synchronized (mutex) { return ns.pollFirst(); } } public E pollLast() { synchronized (mutex) { return ns.pollLast(); } } public NavigableSet descendingSet() { synchronized (mutex) { return new SynchronizedNavigableSet<>(ns.descendingSet(), mutex); } } public Iterator descendingIterator() { synchronized (mutex) { return descendingSet().iterator(); } } public NavigableSet subSet(E fromElement, E toElement) { synchronized (mutex) { return new SynchronizedNavigableSet<>(ns.subSet(fromElement, true, toElement, false), mutex); } } public NavigableSet headSet(E toElement) { synchronized (mutex) { return new SynchronizedNavigableSet<>(ns.headSet(toElement, false), mutex); } } public NavigableSet tailSet(E fromElement) { synchronized (mutex) { return new SynchronizedNavigableSet<>(ns.tailSet(fromElement, true), mutex); } } public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { synchronized (mutex) { return new SynchronizedNavigableSet<>(ns.subSet(fromElement, fromInclusive, toElement, toInclusive), mutex); } } public NavigableSet headSet(E toElement, boolean inclusive) { synchronized (mutex) { return new SynchronizedNavigableSet<>(ns.headSet(toElement, inclusive), mutex); } } public NavigableSet tailSet(E fromElement, boolean inclusive) { synchronized (mutex) { return new SynchronizedNavigableSet<>(ns.tailSet(fromElement, inclusive), mutex); } } } static public interface Htmlable { default public String headStuff() { return ""; } public String html(); } static public class OrError extends Var { public Object error; public OrError() { } public OrError(A value) { super(value); } public OrError(boolean dummy, Object error) { this.error = error; assertNotNull(error); } public boolean ok() { return error == null; } public Object error() { return error; } static public OrError ok(B a) { return new OrError(a); } static public OrError error(Object error) { return new OrError(true, error); } public String toString() { return ok() ? super.toString() : str(error); } } static public interface IMultiSet { public int add(A key); public int get(A key); } abstract static public class Sleeping implements AutoCloseable, IFieldsToList { public Timestamp targetTime; public Runnable action; public Sleeping() { } public Sleeping(Timestamp targetTime, Runnable action) { this.action = action; this.targetTime = targetTime; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + targetTime + ", " + action + ")"; } public Object[] _fieldsToList() { return new Object[] { targetTime, action }; } public long remainingMS() { return targetTime.minus(tsNow()); } } static public class MultiSleeper extends RestartableCountdown implements ISleeper_v2 { public TreeMultiMap entries = new TreeMultiMap(); public void check() { var time = nextWakeUpTime(); var action = firstValue(entries); setTargetTime(time == null ? 0 : time.sysTime(), new Runnable() { public void run() { try { List toCall; synchronized (MultiSleeper.this) { toCall = entries.get(time); entries.remove(time); } check(); pcallFAll(toCall); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "List toCall;\r\n synchronized(MultiSleeper.this) {\r\n toCa..."; } }); } synchronized public void removeEntry(Timestamp targetTime, Runnable action) { entries.remove(targetTime, action); } synchronized public Timestamp nextWakeUpTime() { return firstKey(entries); } public synchronized Sleeping doLater(Timestamp targetTime, Runnable r) { if (r == null || targetTime == null) return null; targetTime = max(targetTime, tsNow()); entries.put(targetTime, r); check(); return new Sleeping(targetTime, r) { public void close() { try { removeEntry(targetTime, r); } catch (Exception __e) { throw rethrow(__e); } } }; } } static public class SynchronizedSortedSet extends SynchronizedSet implements SortedSet { public SynchronizedSortedSet() { } @java.io.Serial static final public long serialVersionUID = 8695801310862127406L; @SuppressWarnings("serial") public SortedSet ss; public SynchronizedSortedSet(SortedSet s) { super(s); ss = s; } public SynchronizedSortedSet(SortedSet s, Object mutex) { super(s, mutex); ss = s; } public Comparator comparator() { synchronized (mutex) { return ss.comparator(); } } public SortedSet subSet(E fromElement, E toElement) { synchronized (mutex) { return new SynchronizedSortedSet<>(ss.subSet(fromElement, toElement), mutex); } } public SortedSet headSet(E toElement) { synchronized (mutex) { return new SynchronizedSortedSet<>(ss.headSet(toElement), mutex); } } public SortedSet tailSet(E fromElement) { synchronized (mutex) { return new SynchronizedSortedSet<>(ss.tailSet(fromElement), mutex); } } public E first() { synchronized (mutex) { return ss.first(); } } public E last() { synchronized (mutex) { return ss.last(); } } } static public interface Visitable { public void visitUsing(IVF1 f); } static public interface Transformable { public Object transformUsing(IF1 f); } static public class Timestamp implements Comparable, IFieldsToList { public long date; public Timestamp(long date) { this.date = date; } public boolean equals(Object o) { if (!(o instanceof Timestamp)) return false; Timestamp __1 = (Timestamp) o; return date == __1.date; } public int hashCode() { int h = 2059094262; h = boostHashCombine(h, _hashCode(date)); return h; } public Object[] _fieldsToList() { return new Object[] { date }; } public Timestamp() { date = now(); } public long unixDate() { return date; } public String toString() { return formatLocalDateWithSeconds(date); } public int compareTo(Timestamp t) { return t == null ? 1 : cmp(date, t.date); } public Timestamp plus(Seconds seconds) { return plus(seconds == null ? null : seconds.getDouble()); } final public Timestamp plusSeconds(double seconds) { return plus(seconds); } public Timestamp plus(double seconds) { return new Timestamp(date + toMS(seconds)); } public long minus(Timestamp ts) { return unixDate() - ts.unixDate(); } public long sysTime() { return clockTimeToSystemTime(date); } public Duration minusAsDuration(Timestamp ts) { return Duration.ofMillis(minus(ts)); } } static public class RestartableCountdown implements AutoCloseable { public java.util.Timer timer; public long targetTime; public long totalSleepTime; synchronized public void setTargetTime(long targetTime, Runnable action) { if (targetTime <= 0) stop(); else if (targetTime != this.targetTime) { start(targetTime - sysNow(), action); this.targetTime = targetTime; } } synchronized public void start(long delayMS, Object action) { stop(); if (delayMS <= 0) { startThread(new Runnable() { public void run() { try { callF(action); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "callF(action);"; } }); } else { totalSleepTime += delayMS; timer = doLater_daemon(delayMS, action); targetTime = sysNow() + delayMS; } } public void start(double delaySeconds, Object action) { start(toMS(delaySeconds), action); } synchronized public void stop() { cancelTimer(timer); timer = null; targetTime = 0; } public void close() { stop(); } } static public class Seconds implements Comparable, IFieldsToList { public double seconds; public Seconds() { } public Seconds(double seconds) { this.seconds = seconds; } public boolean equals(Object o) { if (!(o instanceof Seconds)) return false; Seconds __1 = (Seconds) o; return seconds == __1.seconds; } public int hashCode() { int h = -660217249; h = boostHashCombine(h, _hashCode(seconds)); return h; } public Object[] _fieldsToList() { return new Object[] { seconds }; } final public double get() { return seconds(); } final public double getDouble() { return seconds(); } public double seconds() { return seconds; } public String toString() { return formatDouble(seconds, 3) + " s"; } public int compareTo(Seconds s) { return cmp(seconds, s.seconds); } public Seconds div(double x) { return new Seconds(get() / x); } public Seconds minus(Seconds x) { return new Seconds(get() - x.get()); } } static public class TreeMultiMap extends MultiMap { public TreeMultiMap() { super(true); } public TreeMultiMap(MultiMap map) { this(); putAll(map); } } static public Lock dbLock() { return db_mainConcepts().lock; } static public Lock dbLock(Concepts cc) { return cc == null ? null : cc.lock; } static public Lock dbLock(Concept c) { return dbLock(c == null ? null : c._concepts); } static public boolean bareDBMode_on = false; static public void bareDBMode() { bareDBMode(null); } static public void bareDBMode(Integer autoSaveInterval) { bareDBMode_on = true; conceptsAndBot(autoSaveInterval); } static public float clamp(float x, float a, float b) { return x < a ? a : x > b ? b : x; } static public double clamp(double x, double a, double b) { return x < a ? a : x > b ? b : x; } static public int clamp(int x, int a, int b) { return x < a ? a : x > b ? b : x; } static public long clamp(long x, long a, long b) { return x < a ? a : x > b ? b : x; } static public void add(BitSet bs, int i) { bs.set(i); } static public boolean add(Collection c, A a) { return c != null && c.add(a); } static public void add(Container c, Component x) { addToContainer(c, x); } static public long add(AtomicLong l, long b) { return l.addAndGet(b); } static public A _print(String s, A a) { return print(s, a); } static public A _print(A a) { return print(a); } static public void _print() { print(); } static public boolean _eq(Object a, Object b) { return eq(a, b); } static public String toString(Object o) { return strOrNull(o); } static public String formatDouble(double d, int digits) { String format = digits <= 0 ? "0" : "0." + rep(digits, '#'); return decimalFormatEnglish(format, d); } static public String formatDouble(double d) { return str(d); } static public double ratioToPercent(double x, double y) { return x * 100 / y; } static public BetterThreadLocal pingSource_tl_var = new BetterThreadLocal() { @Override public PingSource initialValue() { return ping_v3_pingSourceMaker().get(); } }; static public BetterThreadLocal pingSource_tl() { return pingSource_tl_var; } static public List getAll(Map map, Collection l) { return lookupAllOpt(map, l); } static public List getAll(Collection l, Map map) { return lookupAllOpt(map, l); } static public > List getAll(Iterable l) { return getVars(l); } static public > List allValues(Map map) { List out = new ArrayList(); for (var l : values(map)) addAll(out, l); return out; } static public String shortClassName_dropNumberPrefix(Object o) { return dropNumberPrefix(shortClassName(o)); } static public int boostHashCombine(int a, int b) { return a ^ (b + 0x9e3779b9 + (a << 6) + (a >>> 2)); } static public int _hashCode(Object a) { return a == null ? 0 : a.hashCode(); } static public NavigableMap synchroTreeMap() { return synchroNavigableMap(new TreeMap()); } static public boolean hasConcept(Class c, Object... params) { return hasConcept(db_mainConcepts(), c, params); } static public boolean hasConcept(Concepts cc, Class c, Object... params) { return findConceptWhere(cc, c, params) != null; } static public Object load(String varName) { readLocally(varName); return get(mc(), varName); } static public Object load(String progID, String varName) { readLocally(progID, varName); return get(mc(), varName); } static public void clearConcepts() { db_mainConcepts().clearConcepts(); } static public void clearConcepts(Concepts concepts) { concepts.clearConcepts(); } static public Map unstructureMap(String s) { return (Map) unstructure(s); } static public Map unstructureMap(String text, boolean allDynamic, Object classFinder) { return (Map) unstructure(text, allDynamic, classFinder); } static public boolean exceptionMessageContains(Throwable e, String s) { return cic(getInnerMessage(e), s); } static public void printShortException(Throwable e) { print(exceptionToStringShort(e)); } static public void printShortException(String s, Throwable e) { print(s, exceptionToStringShort(e)); } static public Object unstructureGZFile(File f) { return unstructureGZFile(f, null); } static public Object unstructureGZFile(File f, IF1 classFinder) { try { if (!fileExists(f)) return null; BufferedReader reader = utf8BufferedReader(gzInputStream(f)); return unstructure_tok(javaTokC_noMLS_onReader(reader), false, classFinder); } catch (Exception __e) { throw rethrow(__e); } } static public File conceptsFile(String progID) { return getProgramFile(progID, conceptsFileName()); } static public File conceptsFile() { return conceptsFile(dbProgramID()); } static public File conceptsFile(Concepts concepts) { return concepts.conceptsFile(); } static public IF1 toIF1(final Object f) { if (f == null) return null; if (f instanceof IF1) return (IF1) f; if (isString(f)) { throw fail("callF_legacy"); } return new IF1() { public Object get(Object a) { return callF(f, a); } }; } static public int done_minPrint = 10; static public long done(long startTime, String desc) { long time = now() - startTime; if (time >= done_minPrint) print(desc + " [" + time + " ms]"); return time; } static public long done(String desc, long startTime) { return done(startTime, desc); } static public long done(long startTime) { return done(startTime, ""); } static public RemoteDB connectToDBOpt(String dbNameOrID) { try { return new RemoteDB(dbNameOrID); } catch (Throwable __e) { return null; } } static public List> mapToPairs(Map map) { List> l = emptyList(l(map)); if (map != null) for (Map.Entry e : map.entrySet()) l.add(pair(e.getKey(), e.getValue())); return l; } static public Collection values(Map map) { return map == null ? emptyList() : map.values(); } static public Collection values(Object map) { return values((Map) map); } static public Collection values(MultiMap mm) { return mm == null ? emptyList() : concatLists(values(mm.data)); } static public A lastKey(SortedMap map) { return empty(map) ? null : map.lastKey(); } static public File conceptsDir() { return conceptsDir(db_mainConcepts()); } static public File conceptsDir(Concepts cc) { return cc.conceptsDir(); } static public File conceptsDir(String subName) { return conceptsDir(db_mainConcepts(), subName); } static public File conceptsDir(Concepts cc, String subName) { return newFile(conceptsDir(cc), subName); } static public void callRunnableWithWrapper(Object wrapper, Runnable r) { if (wrapper == null) callF(r); else callF(wrapper, r); } static public List callFAll(Collection l, Object... args) { return callF_all(l, args); } static public long saveGZStructureToFile(String file, Object o) { return saveGZStructureToFile(getProgramFile(file), o); } static public long saveGZStructureToFile(File file, Object o) { return saveGZStructureToFile(file, o, new structure_Data()); } static public long saveGZStructureToFile(File file, Object o, structure_Data data) { try { File parentFile = file.getParentFile(); if (parentFile != null) parentFile.mkdirs(); File tempFile = tempFileFor(file); if (tempFile.exists()) try { String saveName = tempFile.getPath() + ".saved." + now(); copyFile(tempFile, new File(saveName)); } catch (Throwable e) { printStackTrace(e); } FileOutputStream fileOutputStream = newFileOutputStream(tempFile.getPath()); CountingOutputStream cos; try { GZIPOutputStream gos = new GZIPOutputStream(fileOutputStream); cos = new CountingOutputStream(gos); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(cos, "UTF-8"); PrintWriter printWriter = new PrintWriter(outputStreamWriter); structureToPrintWriter(o, printWriter, data); printWriter.close(); gos.close(); fileOutputStream.close(); } catch (Throwable e) { fileOutputStream.close(); tempFile.delete(); throw rethrow(e); } if (file.exists() && !file.delete()) throw new IOException("Can't delete " + file.getPath()); if (!tempFile.renameTo(file)) throw new IOException("Can't rename " + tempFile + " to " + file); return cos.getFilePointer(); } catch (Exception __e) { throw rethrow(__e); } } static public long toM(long l) { return (l + 1024 * 1024 - 1) / (1024 * 1024); } static public String toM(long l, int digits) { return formatDouble(toM_double(l), digits); } static public String javaTokWordWrap(String s) { return javaTokWordWrap(120, s); } static public String javaTokWordWrap(int cols, String s) { int col = 0; List tok = javaTok(s); for (int i = 0; i < l(tok); i++) { String t = tok.get(i); if (odd(i) && col >= cols && !containsNewLine(t)) tok.set(i, t = rtrimSpaces(t) + "\n"); int idx = t.lastIndexOf('\n'); if (idx >= 0) col = l(t) - (idx + 1); else col += l(t); } return join(tok); } static public String fileName(File f) { return f == null ? null : f.getName(); } static public String ymd() { return ymd(now()); } static public String ymd(long now) { return year(now) + formatInt(month(now), 2) + formatInt(dayOfMonth(now), 2); } static public String ymd(long now, TimeZone tz) { return year(now, tz) + formatInt(month(now, tz), 2) + formatInt(dayOfMonth(now, tz), 2); } static public String formatInt(int i, int digits) { return padLeft(str(i), '0', digits); } static public String formatInt(long l, int digits) { return padLeft(str(l), '0', digits); } static public int hours() { return hours(java.util.Calendar.getInstance()); } static public int hours(java.util.Calendar c) { return c.get(java.util.Calendar.HOUR_OF_DAY); } static public int hours(long time) { return hours(calendarFromTime(time)); } static public int hours(long time, TimeZone tz) { return hours(calendarFromTime(time, tz)); } static public int roundDownTo_rev(int x, int n) { return roundDownTo(n, x); } static public long roundDownTo_rev(long x, long n) { return roundDownTo(n, x); } static public int minutes() { return minutes(java.util.Calendar.getInstance()); } static public int minutes(java.util.Calendar c) { return c.get(java.util.Calendar.MINUTE); } static public long toK(long l) { return (l + 1023) / 1024; } static public Collection allConcepts() { return db_mainConcepts().allConcepts(); } static public Collection allConcepts(Concepts concepts) { return concepts.allConcepts(); } static public FixedRateTimer doEvery_daemon(long delay, final Object r) { return doEvery_daemon(defaultTimerName(), delay, r); } static public FixedRateTimer doEvery_daemon(String timerName, long delay, final Object r) { return doEvery_daemon(timerName, delay, delay, r); } static public FixedRateTimer doEvery_daemon(long delay, long firstDelay, final Object r) { return doEvery_daemon(defaultTimerName(), delay, firstDelay, r); } static public FixedRateTimer doEvery_daemon(String timerName, long delay, long firstDelay, final Object r) { FixedRateTimer timer = new FixedRateTimer(true); timer.scheduleAtFixedRate(smartTimerTask(r, timer, delay), firstDelay, delay); return timer; } static public FixedRateTimer doEvery_daemon(double delaySeconds, final Object r) { return doEvery_daemon(toMS(delaySeconds), r); } static public float abs(float f) { return Math.abs(f); } static public int abs(int i) { return Math.abs(i); } static public double abs(double d) { return Math.abs(d); } static public double abs(Complex c) { return c.abs(); } static public void sleepInCleanUp(long ms) { try { if (ms < 0) return; Thread.sleep(ms); } catch (Exception __e) { throw rethrow(__e); } } static public boolean cleanUp_interruptThreads = false; static public void cleanUp(Object c) { if (c == null) return; if (c instanceof AutoCloseable) { close_pcall((AutoCloseable) c); return; } if (c instanceof java.util.Timer) { ((java.util.Timer) c).cancel(); return; } if (c instanceof Collection) { cleanUp((Collection) c); return; } if (c instanceof Map) { for (Object o : keys((Map) c)) cleanUp(o); for (Object o : values((Map) c)) cleanUp(o); ((Map) c).clear(); return; } try { preCleanUp(c); setOpt_raw(c, "ping_pauseAll", false); innerCleanUp(c); List androids = (List) getOpt(c, "record_list"); for (Object android : unnull(androids)) pcallOpt(android, "dispose"); List classes = (List) (getOpt(c, "hotwire_classes")); if (classes != null) for (WeakReference cc : classes) { try { cleanUp(cc.get()); } catch (Throwable __e) { printStackTrace(__e); } } if (cleanUp_interruptThreads) { List threads = registeredThreads(c); if (nempty(threads)) { print("cleanUp: Interrupting " + n2(threads, "thread") + ": " + joinWithComma(allToString(threads))); interruptThreads(threads); } } } catch (Throwable __e) { printStackTrace(__e); } setOpt_raw(c, "cleaningUp_flag", false); if (c instanceof Class && ((Class) c).getName().equals("main")) retireClassLoader(((Class) c).getClassLoader()); } static public void cleanUp(Collection l) { if (l == null) return; for (Object c : l) cleanUp(c); l.clear(); } static public A firstOfType(Collection c, Class type) { for (Object x : c) if (isInstanceX(type, x)) return (A) x; return null; } static public List conceptsOfType(String type) { return db_mainConcepts().conceptsOfType(type); } static public List concatLists_conservative(List a, List b) { if (empty(a)) return b; if (empty(b)) return a; return concatLists(a, b); } static public List concatLists_conservative(Collection a, Collection b) { if (empty(a) && b instanceof List) return ((List) b); if (empty(b) && a instanceof List) return ((List) a); return concatLists(a, b); } static public List filterByType(Iterable c, Class type) { List l = new ArrayList(); if (c != null) for (Object x : c) if (isInstanceX(type, x)) l.add((A) x); return l; } static public List filterByType(Object[] c, Class type) { return filterByType(asList(c), type); } static public List filterByType(Class type, Iterable c) { return filterByType(c, type); } static public List filterByDynamicType(Collection c, String type) { List l = new ArrayList(); for (A x : c) if (eq(dynamicClassName(x), type)) l.add(x); return l; } static public boolean hasType(Collection c, Class type) { for (Object x : c) if (isInstanceX(type, x)) return true; return false; } static public A findBackRef(Concept c, Class type) { for (Concept.Ref r : c.backRefs) if (instanceOf(r.concept(), type)) return (A) r.concept(); return null; } static public A findBackRef(Class type, Concept c) { return findBackRef(c, type); } static public void mapRemove(Map map, A key) { if (map != null && key != null) map.remove(key); } static public B firstValue(Map map) { return first(values(map)); } static public B firstValue(MultiSetMap map) { return map == null ? null : first(firstValue(map.data)); } static public B firstValue(MultiMap map) { return map == null ? null : first(firstValue(map.data)); } static public String loadConceptsStructure(String progID) { return loadTextFilePossiblyGZipped(getProgramFile(progID, "concepts.structure")); } static public String loadConceptsStructure() { return loadConceptsStructure(dbProgramID()); } static public boolean containsKey(Map map, A key) { return map != null && map.containsKey(key); } static public boolean syncAdd(Collection c, A b) { if (c == null) return false; synchronized (collectionMutex(c)) { return c.add(b); } } static public void syncAdd(List l, int idx, A b) { if (l != null) synchronized (collectionMutex(l)) { l.add(idx, b); } } static public boolean syncRemove(Collection c, A b) { if (c == null) return false; synchronized (collectionMutex(c)) { return c.remove(b); } } static public A syncRemove(List l, int idx) { if (l == null) return null; synchronized (collectionMutex(l)) { return l.remove(idx); } } static public B syncRemove(Map map, A key) { return map == null ? null : map.remove(key); } static public List syncAddOrCreate(List l, A a) { if (l == null) l = syncList(); l.add(a); return l; } static public String nConcepts(long n) { return n2(n, "concept"); } static public String nConcepts(Collection l) { return nConcepts(l(l)); } static public String nConcepts(Map map) { return nConcepts(l(map)); } static public int identityHashCode(Object o) { return System.identityHashCode(o); } static public boolean dynamicObjectIsLoading() { return isUnstructuring(); } static public void assertIsInstance(Class type, Object o) { if (!isInstance(type, o)) throw fail(_getClass(o) + " is not a subclass of " + type); } static public void assertIsInstance(Object o, Class type) { assertIsInstance(type, o); } static public String b(Object contents, Object... params) { return tag("b", contents, params); } static public void change() { callOpt(getOptMC("mainConcepts"), "allChanged"); } static public boolean has(String a, String b, String c) { return false; } static public boolean has(T3 t) { return false; } static public void removeLast(List l) { if (!l.isEmpty()) l.remove(l(l) - 1); } static public void removeLast(List l, int n) { removeSubList(l, l(l) - n); } static public void removeLast(int n, List l) { removeLast(l, n); } static public A syncGet(List l, int idx) { if (l == null || idx < 0) return null; synchronized (l) { return idx < l(l) ? l.get(idx) : null; } } static public B syncGet(Map map, A a) { if (map == null) return null; synchronized (map) { return map.get(a); } } static public int syncL(Collection l) { if (l == null) return 0; synchronized (collectionMutex(l)) { return l.size(); } } static public int syncL(Map map) { if (map == null) return 0; synchronized (collectionMutex(map)) { return map.size(); } } static public List syncL() { return syncList(); } static public List addDyn_quickSync(List l, A a) { if (l == null) l = new ArrayList(); syncAdd(l, a); return l; } static public List removeDyn_quickSync(List l, A a) { if (l == null) return null; synchronized (collectionMutex(l)) { l.remove(a); return empty(l) ? null : l; } } static public void crenameField_noOverwrite(Concept c, String oldField, String newField) { if (c == null || eq(oldField, newField)) return; Object value = cget(c, oldField); if (newField != null && cget(c, newField) == null) cset(c, newField, value); cset(c, oldField, null); } static public Collection scanConceptForRefs(Concept c) { Set refs = new HashSet(); if (c != null) for (Object o : values(objectToMap(c))) { if (o instanceof Concept.Ref) refs.add((Concept.Ref) o); else if (o instanceof Concept.RefL) addAll(refs, ((Concept.RefL) o).l); } return refs; } static public String divUnlessEmpty(String s, Object... params) { return empty(s) ? "" : div(s, params); } static public String hInlineSearchForm(String query, String action) { return hInlineSearchForm("q", query, action); } static public String hInlineSearchForm(String queryField, String query, String action) { return hform(hinputfield(queryField, query, "style", "width: 75px") + " " + hsubmit("Search"), "style", "display: inline", "action", action); } static public List keysDeprefixNemptyValue(Map map, String prefix) { List l = new ArrayList(); for (String s : keys(map)) if (startsWith(s, prefix) && nempty(map.get(s))) l.add(s.substring(l(prefix))); return l; } static public String hhiddenStuff(String secretHTML) { String id = aGlobalID(); String js = "document.getElementById(" + jsQuote(id) + ").innerHTML = " + jsQuote(secretHTML) + "; return false;"; return span(ahref("#", "show", "onclick", js), "id", id); } static public String yesNo_short(boolean b) { return b ? "yes" : "no"; } static public String htmlEncode_nlToBr_withIndents(String s) { return nlToBr_withIndents(htmlEncode(s)); } static public > List sortByTransformedMapKey_alphaNum(IF1 transform, Iterable c, B key) { List l = cloneList(c); sort(l, (a, b) -> cmpAlphaNum(transform.get(mapGet(a, key)), transform.get(mapGet(b, key)))); return l; } static public List reversed(Iterable l) { return reversedList(l); } static public List reversed(A[] l) { return reversedList(asList(l)); } static public String reversed(String s) { return reversedString(s); } static public List lazyMap(final Object f, final List l) { return lazilyMap(f, l); } static public List lazyMap(List l, IF1 f) { return lazilyMap(f, l); } static public List lazyMap(IF1 f, List l) { return lazilyMap(f, l); } static public Map mapMinusKeys(Map map, A... keys) { return mapMinusKeys(map, asList(keys)); } static public Map mapMinusKeys(Map map, Collection keys) { if (empty(keys) || empty(map)) return map; keys = asSet(keys); Map m2 = similarEmptyMap(map); for (Map.Entry __0 : _entrySet(map)) { A key = __0.getKey(); B val = __0.getValue(); if (!keys.contains(key)) m2.put(key, val); } return m2; } static public Map mapMinusKeys(Collection keys, Map map) { return mapMinusKeys(map, keys); } static public Map mapToMap(IF1> f, Iterable l) { Map map = new HashMap(); for (A o : unnullForIteration(l)) { Pair p = callF(f, o); map.put(p.a, p.b); } return map; } static public Map mapToMap(Iterable l, IF1> f) { return mapToMap(f, l); } static public Map mapToMap(Map m, IF2> f) { return mapMapToMap(f, m); } static public Map mapToMap(IF2> f, Map m) { return mapMapToMap(f, m); } static public B mapPut_returnValue(Map map, A key, B value) { mapPut(map, key, value); return value; } static public A firstKey(Map map) { return first(keys(map)); } static public A firstKey(IMultiMap map) { return map == null ? null : first(map.keySet()); } static public String aname(String anchor) { return aname(anchor, ""); } static public String aname(String anchor, Object contents, Object... params) { return tag("a", contents, concatArrays(new Object[] { "name", anchor }, params)); } static public String addParamsToURL(String url, Map params) { return appendQueryToURL(url, params); } static public String addParamsToURL(String url, Object... data) { return appendQueryToURL(url, data); } static public Map filterKeys(Map map, Object f) { return filterMapByFunctionOnKey(map, f); } static public Map filterKeys(Object f, Map map) { return filterMapByFunctionOnKey(f, map); } static public Map filterKeys(IF1 f, Map map) { return filterMapByFunctionOnKey((Object) f, map); } static public Map filterKeys(Map map, IF1 f) { return filterKeys(f, map); } static public List subListOrFull(List l, IntRange r) { return r == null ? l : subList(l, r.start, r.end); } static public List llNonNulls(A... a) { List l = new ArrayList(); for (A x : a) if (x != null) l.add(x); return l; } static public String span_title(String title, Object contents) { return spanTitle(title, contents); } static public String unicode_downOrUpPointingTriangle(boolean down) { return down ? unicode_downPointingTriangle() : unicode_upPointingTriangle(); } static public Object[] litobjectarray(Object... l) { return litObjectArray(l); } static public String htmldecode_dropTagsAndComments(String html) { return htmldecode(dropTagsAndHTMLComments(html)); } static public String hCheckBoxMultiSelect_v2(Object... __) { boolean verbose = boolPar("verbose", __); return hscript(replaceDollarVars("\r\n var lastChecked;\r\n\r\n $(document).ready(function() {\r\n console.log(\"document ready\");\r\n $(\"input[type=checkbox]\").click(function(e) {\r\n var verbose = $verbose;\r\n var cls = this.className;\r\n if (verbose) console.log(\"cls=\" + cls);\r\n if (!cls) return;\r\n \r\n if (!lastChecked || lastChecked.className != cls) {\r\n lastChecked = this;\r\n return;\r\n }\r\n \r\n var $chkboxes = $('input[type=checkbox].' + cls);\r\n \r\n if (e.shiftKey) {\r\n var start = $chkboxes.index(this);\r\n var end = $chkboxes.index(lastChecked);\r\n\r\n // change checkboxes, trigger their change event in case there are handlers installed\r\n $chkboxes.slice(Math.min(start, end), Math.max(start,end)+1).prop('checked', lastChecked.checked)\r\n .each(function(idx, chkbox) {\r\n chkbox.dispatchEvent(new Event('change'));\r\n });\r\n }\r\n \r\n lastChecked = this;\r\n });\r\n });\r\n ", "verbose", verbose)); } static public String lines_rtrim(Collection lines) { return rtrim_fromLines(lines); } static public String hselect(String name, Map map, Object... params) { return hselect(map, paramsPlus_skipFirst(params, "name", name)); } static public String hselect(Map map, Object... params) { StringBuilder buf = new StringBuilder(); String selected = null; if (odd(l(params))) { selected = str(first(params)); params = dropFirst(params); } int i = indexOf(params, "allowEmpty"); if (even(i)) { buf.append("\n"); params[i] = params[i + 1] = null; } if (nempty(map)) for (Object key : keys(map)) { Object value = map.get(key); String k = str(key); buf.append(tag("option", htmlencode(str(or(value, ""))), "value", k, "selected", eq(selected, k) ? "selected" : null)).append("\n"); } return tag("select", buf, params) + "\n"; } static public Map putKeysFirst(Map map, Object... keys) { Map m2 = litorderedmap(); Map remaining = cloneMap(map); for (Object key : keys) { if (remaining.containsKey(key)) { m2.put(key, remaining.get(key)); remaining.remove(key); } } m2.putAll(remaining); return m2; } static public Map putKeysFirst(List keys, Map map) { return putKeysFirst(map, toObjectArray(keys)); } static public Object[] litparams(Object... l) { int n = 0, n1 = l(l); for (int i = 0; i < n1; i += 2) if (l[i] != null && l[i + 1] != null) ++n; if (n == 0) return null; Object[] params = new Object[n * 2]; int j = 0; for (int i = 0; i < n1; i += 2) { Object key = l[i], value = l[i + 1]; if (key != null && value != null) { params[j++] = key; params[j++] = value; } } return params; } static public Map mapWithoutKey(Map map, A key) { if (map == null || !map.containsKey(key)) return map; Map m = cloneMap(map); m.remove(key); return m; } static public Map mapWithoutKey(A key, Map map) { return mapWithoutKey(map, key); } static public String hinputfield(String name, Object... params) { return htextinput(name, params); } static public String htableRaw_valignTop(List data, Object... params) { return htableRaw2(data, asList(params), ll(), ll("valign", "top")); } static public String htextarea(String text, Object... params) { params = html_massageAutofocusParam(params); return hopeningTag("textarea", params) + htmlencode2(text) + ""; } static public String htrickcheckboxWithText(String name, String text, boolean checked, Object... params) { String id = randomID(); return hhidden(name, checked ? "1" : "0") + hcheckbox(null, checked, paramsPlus(params, "id", id, "onclick", "this.previousElementSibling.value=this.checked ? 1 : 0")) + " " + hlabelFor(id, htmlEncode2(text)); } static public String htrickcheckboxWithText(String name, String text) { return htrickcheckboxWithText(name, text, false); } static public A _get(List l, int idx) { return l != null && idx >= 0 && idx < l(l) ? l.get(idx) : null; } static public Object _get(Object o, String field) { return get(o, field); } static public Object _get(String field, Object o) { return get(o, field); } static public A _get(A[] l, int idx) { return idx >= 0 && idx < l(l) ? l[idx] : null; } static public String td(Object contents, Object... params) { return hfulltag("td", contents, params); } static public String td() { return td(""); } static public String jquery_submitFormOnCtrlEnter() { return "if ((event.keyCode == 10 || event.keyCode == 13) && event.ctrlKey) $(this).closest('form').submit();"; } static public String htextfield(String name, Object... params) { return htextinput(name, params); } static public Map subMapStartingWith_dropPrefix(Map map, String prefix) { if (map == null) return null; Map map2 = new HashMap(); for (Map.Entry __0 : _entrySet(map)) { String key = __0.getKey(); T value = __0.getValue(); if (startsWith(key, prefix)) map2.put(substring(key, l(prefix)), value); } return map2; } static public Map joinMaps(Map map1, Map map2) { if (empty(map2)) return map1; if (empty(map1)) return map2; Map map3 = cloneMap(map1); putAll(map3, map2); return map3; } static public List splitAt(String s, String splitter) { if (empty(splitter)) return null; List parts = new ArrayList(); int i = 0; if (s != null) while (i < l(s)) { int j = indexOf(s, splitter, i); if (j < 0) j = l(s); parts.add(substring(s, i, j)); i = j + l(splitter); } return parts; } static public void listPut(List l, int i, A a, A emptyElement) { listSet(l, i, a, emptyElement); } static public void listPut(List l, int i, A a) { listSet(l, i, a); } static public String stringIf(boolean b, String s) { return stringIfTrue(b, s); } static public String stringIf(String s, boolean b) { return stringIf(b, s); } static public Map onlyKeys(Map map, Collection keys) { Set keySet = asSet(keys); return filterKeys(map, a -> contains(keySet, a)); } static public Map onlyKeys(Map map, A... keys) { return onlyKeys(map, litset(keys)); } static public List itemPlus(A a, Collection l) { return itemPlusList(a, l); } static public List tok_identifiersOnly(String s) { return tok_identifiersInOrder(s); } static public String p_vbar(String... items) { return p_vbar(asList(items)); } static public String p_vbar(Collection items, Object... __) { return pUnlessEmpty(joinNemptiesWithVBar(items), __); } static public String hbuttonOnClick_noSubmit(String text, String onClick, Object... params) { return hfulltag("button", text, paramsPlus(params, "onclick", onClick, "type", "button")); } static public String firstToUpper(String s) { if (empty(s)) return s; return Character.toUpperCase(s.charAt(0)) + s.substring(1); } static public String htmlDecode_dropTags(String html) { return htmldecode_dropAllTags(html); } static public Object getVarOpt(Object o) { return o instanceof IF0 ? ((IF0) o).get() : o; } static public String targetBlankIf(String link, Object contents, boolean targetBlank, Object... params) { return ahref_possiblyTargetBlank(link, contents, targetBlank, params); } static public String targetBlankIf(boolean targetBlank, String link, Object contents, Object... params) { return ahref_possiblyTargetBlank(targetBlank, link, contents, params); } static public String hPopDownButton(String... entries) { String id = "dropdown-" + aGlobalID(), outerID = "outer-" + id; String onclick = replaceDollarVars("\r\n var x = document.getElementById($id);\r\n x.style.display = window.getComputedStyle(x).display === \"none\" ? \"block\" : \"none\";\r\n console.log(\"popup \" + id + \" display: \" + x.style.display);\r\n ", "$id", jsQuote(id)); return hstyle(replaceDollarVars("\r\n #$id ul {\r\n list-style-type: none;\r\n margin: 0;\r\n padding: 0;\r\n width: 200px;\r\n background-color: #f1f1f1;\r\n }\r\n \r\n #$id {\r\n position: absolute;\r\n display:none;\r\n background-color: #f9f9f9;\r\n width:auto;\r\n height:200px;\r\n overflow: auto;\r\n \r\n min-width: 160px;\r\n box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);\r\n \r\n z-index: 99;\r\n }\r\n \r\n #$id li a {\r\n text-decoration: none;\r\n color: #000;\r\n }\r\n\r\n #$id li { \r\n display: block;\r\n border-bottom: 1px solid #555;\r\n padding: 8px 16px;\r\n color: #000;\r\n }\r\n " + "\r\n #$id li:hover, #$id li:hover > a {\r\n background-color: #3399ff;\r\n color: white;\r\n }\r\n ", "$id", id)) + hdiv(span(htmlEncode2(unicode_smallDownPointingTriangle()), "onclick", onclick) + hdiv(ul(entries), "id", id), "style", "position: relative; display: inline-block; cursor: context-menu", "id", outerID) + hscript(replaceDollarVars("\r\n if (typeof $ !== 'undefined')\r\n $('body').click(function(e) {\r\n //console.log(\"target=\" + e.target + \", outerID=$outerID\");\r\n if (!$(e.target).closest('#$outerID').length) {\r\n //console.log(\"hiding $id\");\r\n $(\"#$id\").hide();\r\n }\r\n });\r\n ", "id", id, "outerID", outerID)); } static public String hPopDownButton(Collection entries) { return hPopDownButton(toStringArray(entries)); } static public String aGlobalID() { return randomID(globalIDLength()); } static public String aGlobalID(Random random) { return randomID(random, globalIDLength()); } static public String hselect_list(String name, Collection entries, Object... params) { return hselect_list(entries, paramsPlus_skipFirst(params, "name", name)); } static public String hselect_list(Collection entries, Object... params) { StringBuilder buf = new StringBuilder(); String selected = null; if (odd(l(params))) { selected = str(first(params)); params = dropFirst(params); } int i = indexOf(params, "allowEmpty"); if (even(i)) { buf.append("\n"); params[i] = params[i + 1] = null; } if (nempty(entries)) for (String k : entries) { String value = k; boolean isSelected = eq(selected, k); buf.append(hfulltag("option", htmlencode(str(or(value, ""))), "value", k, "selected", isSelected ? html_valueLessParam() : null)).append("\n"); } return hfulltag("select", buf, params) + "\n"; } static public String hjs(String script) { return hjs(script, (Object[]) null); } static public String hjs(String script, Object... __) { return hjavascript(script, __); } static public String hjs(JS script) { return hjs(script, (Object[]) null); } static public String hjs(JS script, Object... __) { return hjavascript(script == null ? null : script.get(), __); } static public String jsBool(boolean b) { return b ? "true" : "false"; } static public String hoption(String text) { return tag("option", htmlEncode2(text)); } static public List llNempties(String... a) { ArrayList l = new ArrayList(a.length); if (a != null) for (String x : a) if (nempty(x)) l.add(x); return l; } static public String unicode_DEL() { return unicodeFromCodePoint(0x2421); } static public String small(Object contents, Object... params) { return tag("small", contents, params); } static public String jsonEncode_shallowLineBreaks(Object o) { return jsonEncode_breakAtLevel1(o); } static public void jsonEncode_shallowLineBreaks(Object o, StringBuilder buf, int level) { jsonEncode_breakAtLevel1(o, buf, level); } static public List keysList(Map map) { return cloneListSynchronizingOn(keys(map), map); } static public List keysList(MultiSet ms) { return ms == null ? null : keysList(ms.map); } static public String dropPrefixOrNull(String prefix, String s) { return s != null && s.startsWith(prefix) ? s.substring(l(prefix)) : null; } static public List regexpGroups(String pat, String s) { return regexpFirstGroups(pat, s); } static public MultiSetMap treeMultiSetMap() { return new MultiSetMap(true); } static public MultiSetMap treeMultiSetMap(Comparator comparator) { return new MultiSetMap(new TreeMap>(comparator)); } static public Comparator reverseOrder() { return new Comparator() { public int compare(Object a, Object b) { return cmp(b, a); } }; } static public String joinNemptiesWithColon(String... strings) { return joinNempties(": ", strings); } static public String joinNemptiesWithColon(Collection strings) { return joinNempties(": ", strings); } static public String commaCombine(Object... l) { return joinNemptiesWithComma(flattenCollectionsAndArrays(ll(l))); } public static boolean isWindows() { return System.getProperty("os.name").contains("Windows"); } static public long stopTiming_defaultMin = 10; static public long startTiming_startTime; static public void startTiming() { startTiming_startTime = now(); } static public void stopTiming() { stopTiming(null); } static public void stopTiming(String text) { stopTiming(text, stopTiming_defaultMin); } static public void stopTiming(String text, long minToPrint) { long time = now() - startTiming_startTime; if (time >= minToPrint) { text = or2(text, "Time: "); print(text + time + " ms"); } } static public double sqrt(double x) { return Math.sqrt(x); } static public Pt ptMinus(Pt a, Pt b) { if (b == null) return a; return new Pt(a.x - b.x, a.y - b.y); } static public UnsupportedOperationException unsupportedOperation() { throw new UnsupportedOperationException(); } static public double infinity() { return positiveInfinity(); } static public long toMS(double seconds) { return (long) (seconds * 1000); } static public A floorKey(NavigableMap map, A key) { if (map == null) return null; return map.floorKey(key); } static public Map.Entry higherEntry(NavigableMap map, A key) { return map == null ? null : map.higherEntry(key); } static public Map.Entry firstEntry(Map map) { return empty(map) ? null : first(map.entrySet()); } static public Map.Entry lastEntry(NavigableMap map) { return map == null ? null : map.lastEntry(); } static public Set keySet(Map map) { return map == null ? new HashSet() : map.keySet(); } static public Set keySet(Object map) { return keys((Map) map); } static public Set keySet(MultiSet ms) { return ms.keySet(); } static public Set keySet(MultiMap mm) { return mm.keySet(); } static public SortedMap subMap(SortedMap map, A fromKey, A toKey) { return map == null ? null : map.subMap(fromKey, toKey); } static public void remove(List l, int i) { if (l != null && i >= 0 && i < l(l)) l.remove(i); } static public void remove(Collection l, A a) { if (l != null) l.remove(a); } static public B remove(Map map, Object a) { return map == null ? null : map.remove(a); } static public void remove(BitSet bs, int i) { bs.clear(i); } static public ListIterator listIterator(List l) { return l == null ? emptyListIterator() : l.listIterator(); } static public boolean hasLock(Lock lock) { return ((ReentrantLock) lock).isHeldByCurrentThread(); } static public boolean classIsExportedTo(Class c, java.lang.Module destModule) { if (c == null || destModule == null) return false; java.lang.Module srcModule = c.getModule(); String packageName = c.getPackageName(); return srcModule.isExported(packageName, destModule); } static public Set allInterfacesImplementedBy(Object o) { return allInterfacesImplementedBy(_getClass(o)); } static public Set allInterfacesImplementedBy(Class c) { if (c == null) return null; HashSet set = new HashSet(); allInterfacesImplementedBy_find(c, set); return set; } static public void allInterfacesImplementedBy_find(Class c, Set set) { if (c.isInterface() && !set.add(c)) return; do { for (Class intf : c.getInterfaces()) allInterfacesImplementedBy_find(intf, set); } while ((c = c.getSuperclass()) != null); } static public Method findStaticMethod(Class c, String method, Object... args) { Class _c = c; while (c != null) { for (Method m : c.getDeclaredMethods()) { if (!m.getName().equals(method)) continue; if ((m.getModifiers() & Modifier.STATIC) == 0 || !findStaticMethod_checkArgs(m, args)) continue; return m; } c = c.getSuperclass(); } return null; } static public boolean findStaticMethod_checkArgs(Method m, Object[] args) { Class[] types = m.getParameterTypes(); if (types.length != args.length) return false; for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) return false; return true; } static public List quoteAll(String[] l) { return quoteAll(asList(l)); } static public List quoteAll(Collection l) { List x = new ArrayList(); for (String s : l) x.add(quote(s)); return x; } static public boolean arraysEqual(Object[] a, Object[] b) { if (a.length != b.length) return false; for (int i = 0; i < a.length; i++) if (neq(a[i], b[i])) return false; return true; } static public Object metaGet(IMeta o, Object key) { return metaMapGet(o, key); } static public Object metaGet(Object o, Object key) { return metaMapGet(o, key); } static public Object metaGet(String key, IMeta o) { return metaMapGet(o, key); } static public Object metaGet(String key, Object o) { return metaMapGet(o, key); } static public Object metaMapGet(IMeta o, Object key) { return o == null ? null : o.metaGet(key); } static public Object metaMapGet(Object o, Object key) { return metaMapGet(toIMeta(o), key); } static public void metaPut(IMeta o, Object key, Object value) { metaMapPut(o, key, value); } static public void metaPut(Object o, Object key, Object value) { metaMapPut(o, key, value); } static public Map convertObjectMetaToMap(IMeta o) { return convertObjectMetaToMap(o, () -> makeObjectMetaMap()); } static public Map convertObjectMetaToMap(IMeta o, IF0 createEmptyMap) { if (o == null) return null; Object meta = o._getMeta(); if (meta instanceof Map) return ((Map) meta); var mutex = tempMetaMutex(o); try { var actualMutex = mutex.get(); synchronized (actualMutex) { meta = o._getMeta(); if (meta instanceof Map) return ((Map) meta); Map map = createEmptyMap.get(); if (meta != null) map.put("previousMeta", meta); o._setMeta(map); return map; } } finally { _close(mutex); } } static public void syncMapPutOrRemove(Map map, A key, B value) { syncMapPut2(map, key, value); } static public String humanizeShortName(Object o) { return humanizeLabel(shortName(o)); } static public A postProcess(Object f, A a) { return callPostProcessor(f, a); } static public A postProcess(IF1 f, A a) { return callPostProcessor(f, a); } static public Collection conceptsWhereCI(Class c, Object... params) { return findConceptsWhereCI(c, params); } static public Collection conceptsWhereCI(String c, Object... params) { return findConceptsWhereCI(c, params); } static public Collection conceptsWhereCI(Concepts concepts, Class c, Object... params) { return findConceptsWhereCI(concepts, c, params); } static public List conceptsWhereCI(Concepts concepts, String c, Object... params) { return findConceptsWhereCI(concepts, c, params); } static public List filterConceptsIC(Collection list, Object... params) { List l = new ArrayList(); if (list != null) for (A x : list) if (checkConceptFieldsIC(x, params)) l.add(x); return l; } static public List sortedByConceptIDDesc(Collection c) { return sortedByCalculatedFieldDesc(__66 -> conceptID(__66), c); } static public Map conceptToMap_gen_withNullValues(Object c) { Map map = litorderedmap("id", str(getLong(c, "id"))); for (String field : conceptFields_gen(c)) map.put(field, getOpt(c, field)); return map; } static public List nonStaticNonTransientFieldObjectsOfType(Class type, Object o) { return filter(nonStaticNonTransientFieldObjects(o), f -> eq(f.getType(), type)); } static public B lastValue(NavigableMap map) { if (map == null) return null; Map.Entry entry = map.lastEntry(); return entry == null ? null : entry.getValue(); } static public void removeLastKey(SortedMap map) { if (nempty(map)) map.remove(lastKey(map)); } static public List valuesAsList(Map map) { return valuesList(map); } static public List cloneKeys(Map map) { return cloneList(keys(map)); } static public String optCastString(Object o) { return optCastToString(o); } static public boolean isSingleLine(String s) { return !containsNewLine(s); } static public boolean isUntrimmed(String s) { return neq(s, trim(s)); } static public boolean englishStringToBool(String s) { return swicOneOf(s, "y", "t", "1"); } static public Map cgetAll_cloneLists(Concept c, Collection fields) { return mapToValues(fields, f -> cloneIfList(cget(c, f))); } static public int cSmartSet(Concept c, Object... values) { try { if (c == null) return 0; warnIfOddCount(values = expandParams(c.getClass(), values)); int changes = 0; for (int i = 0; i + 1 < l(values); i += 2) if (_cSmartSetField(c, (String) values[i], values[i + 1])) ++changes; return changes; } catch (Exception __e) { throw rethrow(__e); } } static public int cSmartSet_withConverter_pcall(Concept c, Object... values) { return cSmartSet_withConverter_pcall(false, c, values); } static public int cSmartSet_withConverter_pcall(boolean verbose, Concept c, Object... values) { return cSmartSet_withConverter_pcall(verbose, new DefaultValueConverterForField(), c, values); } static public int cSmartSet_withConverter_pcall(ValueConverterForField converter, Concept c, Object... values) { return cSmartSet_withConverter_pcall(false, converter, c, values); } static public int cSmartSet_withConverter_pcall(boolean verbose, ValueConverterForField converter, Concept c, Object... values) { try { if (c == null) return 0; warnIfOddCount(values = unrollAndExpandParams(c.getClass(), values)); int changes = 0; for (int i = 0; i + 1 < l(values); i += 2) { try { if (cSmartSetField_withConverter(c, (String) values[i], values[i + 1], converter, verbose)) ++changes; } catch (Throwable __e) { printStackTrace(__e); } } return changes; } catch (Exception __e) { throw rethrow(__e); } } static public boolean hasField(Object o, String field) { return findField2(o, field) != null; } static public Concept _getConcept(long id) { return getConcept(id); } static public Concept _getConcept(Concepts concepts, long id) { return getConcept(concepts, id); } static public A _getConcept(Class cc, long id) { return getConcept(cc, id); } static public A _getConcept(Concepts concepts, Class cc, long id) { return getConcept(concepts, cc, id); } static public long toLong(Object o) { if (o instanceof Number) return ((Number) o).longValue(); if (o instanceof String) return parseLong((String) o); return 0; } static public void deleteConcept(long id) { db_mainConcepts().deleteConcept(id); } static public void deleteConcept(Concepts concepts, long id) { concepts.deleteConcept(id); } static public void deleteConcept(Concept c) { if (c != null) c.delete(); } static public void deleteConcept(Concept.Ref ref) { if (ref != null) deleteConcept(ref.get()); } static public boolean checkConceptFieldsIC(Concept x, Object... data) { for (int i = 0; i < l(data); i += 2) if (!eqicOrEq(cget(x, (String) data[i]), deref(data[i + 1]))) return false; return true; } static public Map orderedMapPutOrCreate(Map map, A key, B value) { if (key != null && value != null) { if (map == null) map = new LinkedHashMap(); map.put(key, value); } return map; } static public Class fieldType(Object o, String field) { Field f = getField(o, field); return f == null ? null : f.getType(); } static public A trueFalseNull(Boolean b, A onTrue, A onFalse, A onNull) { return b == null ? onNull : b.booleanValue() ? onTrue : onFalse; } static public long conceptID(Concept c) { return c == null ? 0 : c.id; } static public long conceptID(Concept.Ref ref) { return conceptID(cDeref(ref)); } static public String firstWhereFirstLongIs(Collection l, long i) { return firstThat(l, s -> parseFirstLong(s) == i); } static public boolean hasBackRefs(Concept c) { return c != null && syncNempty(c.backRefs); } static public Class getTypeArgumentAsClass(Type type) { if (type instanceof ParameterizedType) return typeToClass(first(((ParameterizedType) type).getActualTypeArguments())); return null; } static public Type genericFieldType(Object o, String field) { Field f = getField(o, field); return f == null ? null : f.getGenericType(); } static public List scoredSearch(String query, Iterable data) { Map scores = new HashMap(); List searchTerms = scoredSearch_prepare(query); if (empty(searchTerms)) return asList(data); for (String s : data) { int score = scoredSearch_score(s, searchTerms); if (score != 0) scores.put(s, score); } return keysSortedByValuesDesc(scores); } static public long parseFirstLong(String s) { return parseLong(jextract("", s)); } static public Map putOrCreate(Map map, A key, B value) { if (map == null) map = new HashMap(); map.put(key, value); return map; } static public void printVars(Object... params) { printVars_str(params); } static public void close(AutoCloseable c) { _close(c); } static public A addAndReturn(Collection c, A a) { if (c != null) c.add(a); return a; } static public File tempDir() { return makeTempDir(); } static public File createTempFile() { return createTempFile("tmp", null); } static public File createTempFile(String prefix, String suffix) { try { prefix = nohup_sanitize(prefix); suffix = nohup_sanitize(suffix); if (shouldKeepTempFiles()) return mkdirsForFile(javaxCachesDir("Temp/" + prefix + "-" + randomID() + "-" + suffix)); File f = File.createTempFile(takeFirst(10, pad(prefix, 3, '-')), suffix); f.deleteOnExit(); return f; } catch (Exception __e) { throw rethrow(__e); } } static public A printWithIndent(A o) { return printIndent(o); } static public A printWithIndent(String indent, A o) { return printIndent(indent, o); } static public void printWithIndent(int indent, Object o) { printIndent(indent, o); } static public HashMap lithashmap(Object... x) { return litmap(x); } static public A wrapStuff(String name, A object, Object... args) { return or((A) callOpt(mc(), "_wrap", object, asList(args)), object); } static public void printMyIPs() { String ip; try { Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { NetworkInterface iface = interfaces.nextElement(); if (iface.isLoopback() || !iface.isUp()) continue; Enumeration addresses = iface.getInetAddresses(); while (addresses.hasMoreElements()) { InetAddress addr = addresses.nextElement(); ip = addr.getHostAddress(); if (ip.startsWith("127.")) continue; boolean local = addr.isSiteLocalAddress() || ip.startsWith("fe"); System.out.println(iface.getDisplayName() + " " + ip + " " + (local ? "(private address)" : "(public address)")); } } } catch (Throwable e) { e.printStackTrace(); } } static public A getAndClear(IVar v) { A a = v.get(); v.set(null); return a; } static public int keysSize(MultiMap mm) { return lKeys(mm); } static public A reverseGet(List l, int idx) { if (l == null || idx < 0) return null; int n = l(l); return idx < n ? l.get(n - 1 - idx) : null; } static public String formatDouble_significant2(double d, int digits) { try { digits -= max(0, Math.floor(Math.log10(abs(d)) + 1)); return formatDouble(d, digits); } catch (Throwable _e) { print("Had number: " + d + ", digits: " + digits); throw rethrow(_e); } } static public File loadLibrary(String snippetID) { return loadBinarySnippet(snippetID); } static public File pathToJavaxJar() { IResourceLoader rl = vm_getResourceLoader(); if (rl != null) return rl.pathToJavaXJar(); return pathToJavaxJar_noResourceLoader(); } static public File pathToJavaxJar_noResourceLoader() { try { int x = latestInstalledJavaX(); File xfile = new File(userHome(), ".javax/x" + Math.max(x, 30) + ".jar"); if (!xfile.isFile()) { print("Saving " + f2s(xfile)); String url = x30JarServerURL(); byte[] data = loadBinaryPage(url); if (data.length < 1000000) throw fail("Could not load " + url); saveBinaryFile(xfile.getPath(), data); } return xfile; } catch (Exception __e) { throw rethrow(__e); } } static public Method hashMap_findKey_method; static public A hashMap_findKey(HashMap map, Object key) { try { if (hashMap_findKey_method == null) hashMap_findKey_method = findMethodNamed(HashMap.class, "getNode"); Map.Entry entry = (Map.Entry) hashMap_findKey_method.invoke(map, hashMap_internalHash(key), key); return entry == null ? null : entry.getKey(); } catch (Exception __e) { throw rethrow(__e); } } static public int hashCodeFor(Object a) { return a == null ? 0 : a.hashCode(); } static public boolean stdEq2(Object a, Object b) { if (a == null) return b == null; if (b == null) return false; if (a.getClass() != b.getClass()) return false; for (String field : allFields(a)) if (neq(getOpt(a, field), getOpt(b, field))) return false; return true; } static public int stdHash2(Object a) { if (a == null) return 0; return stdHash(a, toStringArray(allFields(a))); } static public LinkedHashMap cloneLinkedHashMap(Map map) { return map == null ? new LinkedHashMap() : new LinkedHashMap(map); } static public Set emptySet() { return new HashSet(); } static public double fileAgeInSeconds(File f) { return f == null ? -1 : msToSeconds(now() - fileModificationTime(f)); } static public String nSeconds(long n) { return n2(n, "second"); } static public String nSeconds(Collection l) { return nSeconds(l(l)); } static public boolean deleteFile(File file) { return file != null && file.delete(); } static public Path toPath(File f) { return f == null ? null : f.toPath(); } static public void printExceptionShort(Throwable e) { printExceptionShort("", e); } static public void printExceptionShort(String prefix, Throwable e) { print(prefix, exceptionToStringShort(e)); } static public File saveTextFileWithoutTemp(File file, String contents) { try { mkdirsForFile(file); var fileOutputStream = newFileOutputStream(file); try { var outputStreamWriter = new OutputStreamWriter(fileOutputStream, "UTF-8"); var printWriter = new PrintWriter(outputStreamWriter); printWriter.print(unnull(contents)); printWriter.close(); return file; } finally { _close(fileOutputStream); } } catch (Exception __e) { throw rethrow(__e); } } static public FixedRateTimer doEvery(long delay, final Object r) { return doEvery(delay, delay, r); } static public FixedRateTimer doEvery(long delay, long firstDelay, final Object r) { FixedRateTimer timer = new FixedRateTimer(shorten(programID() + ": " + r, 80)); timer.scheduleAtFixedRate(smartTimerTask(r, timer, toInt(delay)), toInt(firstDelay), toInt(delay)); return vmBus_timerStarted(timer); } static public FixedRateTimer doEvery(double initialSeconds, double delaySeconds, final Object r) { return doEvery(toMS(delaySeconds), toMS(initialSeconds), r); } static public FixedRateTimer doEvery(double delaySeconds, final Object r) { return doEvery(toMS(delaySeconds), r); } static public void touchExistingFile(File file) { try { if (file == null) return; java.nio.file.Files.setLastModifiedTime(toPath(file), java.nio.file.attribute.FileTime.from(java.time.Instant.now())); } catch (Exception __e) { throw rethrow(__e); } } static volatile public int numberOfCores_value; static public int numberOfCores() { if (numberOfCores_value == 0) numberOfCores_value = Runtime.getRuntime().availableProcessors(); return numberOfCores_value; } static public Set createOrAddToSyncLinkedHashSet(Set set, A a) { if (set == null) set = syncLinkedHashSet(); set.add(a); return set; } static public A pcallF_typed(F0 f) { try { return f == null ? null : f.get(); } catch (Throwable __e) { printStackTrace(__e); } return null; } static public B pcallF_typed(F1 f, A a) { try { return f == null ? null : f.get(a); } catch (Throwable __e) { printStackTrace(__e); } return null; } static public void pcallF_typed(VF1 f, A a) { try { { if (f != null) f.get(a); } } catch (Throwable __e) { printStackTrace(__e); } } static public void pcallF_typed(IVF1 f, A a) { try { { if (f != null) f.get(a); } } catch (Throwable __e) { printStackTrace(__e); } } static public void pcallF_typed(IVF2 f, A a, B b) { try { { if (f != null) f.get(a, b); } } catch (Throwable __e) { printStackTrace(__e); } } static public Object pcallF_typed(Runnable r) { try { { if (r != null) r.run(); } } catch (Throwable __e) { printStackTrace(__e); } return null; } static public A pcallF_typed(IF0 f) { try { return f == null ? null : f.get(); } catch (Throwable __e) { printStackTrace(__e); } return null; } static public B pcallF_typed(IF1 f, A a) { try { return f == null ? null : f.get(a); } catch (Throwable __e) { printStackTrace(__e); } return null; } static public Chain chainPlus(Chain chain, A a) { return new Chain(a, chain); } static public Chain chainPlus(Chain chain, A... l) { for (A a : unnullForIteration(l)) chain = chainPlus(chain, a); return chain; } static public ReverseChain chainPlus(ReverseChain chain, A a) { return new ReverseChain(chain, a); } static public ReverseChain chainPlus(ReverseChain chain, A... l) { for (A a : unnullForIteration(l)) chain = chainPlus(chain, a); return chain; } static public AppendableChain chainPlus(AppendableChain chain, A a) { if (chain == null) return new AppendableChain(a); chain.add(a); return chain; } static public AppendableChain chainPlus(AppendableChain chain, A... l) { for (A a : unnullForIteration(l)) chain = chainPlus(chain, a); return chain; } static public void syncNotifyAll(Object o) { if (o != null) synchronized (o) { o.notifyAll(); } } static public void register(Concept c) { registerConcept(c); } static public List cloneKeys_noSync(Map map) { return cloneList_noSync(keys(map)); } static public IterableIterator navigableMultiSetMapValuesIterator_concurrent(final MultiSetMap mm) { return navigableMultiSetMapValuesIterator_concurrent(mm, mm.data); } static public IterableIterator navigableMultiSetMapValuesIterator_concurrent(final MultiSetMap mm, Object mutex) { return iteratorFromFunction(new F0() { public Iterator> it = concurrentlyIterateValues((NavigableMap) mm.data, mutex); public Iterator it2; public B get() { while (it2 == null || !it2.hasNext()) { if (!it.hasNext()) return null; it2 = iterator(asList(it.next())); } return it2.next(); } }); } static public MultiSet multiSetMapToMultiSet(MultiSetMap mm) { MultiSet ms = new MultiSet(); for (A a : keys(mm)) ms.add(a, l(mm.get(a))); return ms; } static public String hscriptsrc(String src) { return hjavascript_src(src); } static public String div(Object contents, Object... params) { return hfulltag("div", contents, params); } static public String div() { return div(""); } static public BigInteger div(BigInteger a, BigInteger b) { return a.divide(b); } static public BigInteger div(BigInteger a, int b) { return a.divide(bigint(b)); } static public Complex div(Complex a, double b) { return new Complex(a.re / b, a.im / b); } static public double div(double a, double b) { return a / b; } static public double div(double a, int b) { return a / b; } static public int div(int a, int b) { return a / b; } static public Object[] params_stylePlus(Map params, String style) { return paramsPlus(params, "style", joinNemptiesWithSemicolon(stringPar("style", params), style)); } static public Object[] params_stylePlus(Object[] params, String style) { return paramsPlus(params, "style", joinNemptiesWithSemicolon(stringPar("style", params), style)); } static public Object[] params_stylePlus(String style, Object... params) { return params_stylePlus(params, style); } static public String hhiddenWithIDAndName(String idAndName) { return hhiddenWithIDAndName(idAndName, null); } static public String hhiddenWithIDAndName(String idAndName, Object value, Object... params) { return tag("input", "", paramsPlus(params, "type", "hidden", "id", idAndName, "name", idAndName, "value", value)); } static public String hscript(String script) { return hjavascript(script); } static public String replaceDollarVars(String s, Object... params) { if (empty(params)) return s; Map vars = mapKeys(__67 -> dropDollarPrefix(__67), (Map) litcimap(params)); return replaceDollarVars_dyn(s, var -> strOrNull(vars.get(var))); } static public String replaceDollarVars(String s, IF1 f) { return replaceDollarVars_dyn(s, f); } static public String linesLL(Object... x) { return lines(ll(x)); } static public List reversedList(Iterable l) { List x = cloneList(l); Collections.reverse(x); return x; } static public Set asSet(Object[] array) { HashSet set = new HashSet(); for (Object o : array) if (o != null) set.add(o); return set; } static public Set asSet(String[] array) { TreeSet set = new TreeSet(); for (String o : array) if (o != null) set.add(o); return set; } static public Set asSet(Iterable l) { if (l instanceof Set) return (Set) l; HashSet set = new HashSet(); for (A o : unnull(l)) if (o != null) set.add(o); return set; } static public Set asSet(MultiSet ms) { return ms == null ? null : ms.asSet(); } static public NavigableSet navigableKeys(NavigableMap map) { return map == null ? new TreeSet() : map.navigableKeySet(); } static public NavigableSet navigableKeys(MultiSet ms) { return ((NavigableMap) ms.map).navigableKeySet(); } static public NavigableSet navigableKeys(MultiMap mm) { return ((NavigableMap) mm.data).navigableKeySet(); } static public Map> toMap(MultiMap m) { return multiMapToMap(m); } static public String pageNav2(String baseLink, int count, int value, int step, String nVar, Object... __) { List l = new ArrayList(); baseLink = unnull(baseLink) + (contains(baseLink, "?") ? "&" : "?") + urlencode(nVar) + "="; if (value > 0) l.add(ahref(baseLink + max(0, value - step), stringPar("leftArrow", __, htmlencode(unicode_leftPointingTriangle())))); for (int i = 0; i < count; i += step) { int n = i / step + 1; if (pageNav2_showPage(value, i, step, count)) if (value == i) l.add(b(n)); else l.add(ahref(baseLink + i, n)); } if (value + step < count) l.add(ahref(baseLink + (value + step), stringPar("rightArrow", __, htmlencode(unicode_rightPointingTriangle())))); return p("Pages: " + lines(l)); } static public boolean pageNav2_showPage(int actual, int i, int step, int count) { int diff = abs(actual - i) / step; return i == 0 || i >= (count - 1) / step * step || diff <= 10 || diff <= 100 && ((i / step) % 10) == 9 || diff <= 1000 && ((i / step) % 100) == 99 || ((i / step) % 1000) == 999; } static public IntRange intRange(int start, int end) { return new IntRange(start, end); } static public String plural(String s) { return getPlural(s); } static public RuntimeException unimplemented() { throw fail("TODO"); } static public RuntimeException unimplemented(String msg) { throw fail("TODO: " + msg); } static public RuntimeException unimplemented(Object obj) { throw fail("TODO: implement method in " + className(obj)); } static public String spanTitle(String title, Object contents) { return empty(title) ? str(contents) : span(contents, "title", title); } static public String htmlencode2(String s) { return htmlencode_noQuotes(s); } static public String humanizeLabel(String s) { return humanizeFormLabel(s); } static public String h1_title(String s) { return htitle_h1(s); } static public String appendSlash(String s) { return addSlash(s); } static public String addAnchorToURL(String url, String anchor) { int i = smartIndexOf(url, '#'); url = takeFirst(url, i); if (nempty(anchor)) url += "#" + anchor; return url; } static public String pUnlessEmpty(String s, Object... __) { return empty(s) ? "" : p(s, __); } static public long waitForBotStartUp_timeoutSeconds = 60; static public String waitForBotStartUp(String botName) { for (int i = 0; i < waitForBotStartUp_timeoutSeconds; i++) { sleepSeconds(i == 0 ? 0 : 1); String addr = getBotAddress(botName); if (addr != null) return addr; } throw fail("Bot not found: " + quote(botName)); } static public Object rpc(String botName, String method, Object... args) { return unstructure_matchOK2OrFail(sendToLocalBot(botName, rpc_makeCall(method, args))); } static public Object rpc(DialogIO bot, String method, Object... args) { return unstructure_matchOK2OrFail(bot.ask(rpc_makeCall(method, args))); } static public String rpc_makeCall(String method, Object... args) { if (empty(args)) return "call " + method; return format("call *", concatLists((List) ll(method), asList(args))); } static public Boolean not(Boolean b) { return b == null ? null : !b; } static public java.util.Timer doLater(long delay, final Object r) { ping(); final java.util.Timer timer = new java.util.Timer(); timer.schedule(timerTask(r, timer), delay); return vmBus_timerStarted(timer); } static public java.util.Timer doLater(double delaySeconds, final Object r) { return doLater(toMS(delaySeconds), r); } static public Timestamp tsNow() { return new Timestamp(); } static public int getWidth(Component c) { return c == null ? 0 : (int) swingCall(c, "getWidth"); } static public int getHeight(Component c) { return c == null ? 0 : (int) swingCall(c, "getHeight"); } static public Rect rect(int x, int y, int w, int h) { return new Rect(x, y, w, h); } static public Rect rect(Pt p, int w, int h) { return new Rect(p.x, p.y, w, h); } static public Rect rect(int w, int h) { return new Rect(0, 0, w, h); } static public long longMul(long a, long b) { return a * b; } static public String lower(String s) { return s == null ? null : s.toLowerCase(); } static public char lower(char c) { return Character.toLowerCase(c); } static public double floor(double d) { return Math.floor(d); } static public String ok(Object o) { return format("ok *", o); } static public String formatLocalDateWithSeconds(long time) { return localDateWithSeconds(time); } static public String formatLocalDateWithSeconds() { return localDateWithSeconds(); } static public BigInteger plus(BigInteger a, BigInteger b) { return a.add(b); } static public BigInteger plus(BigInteger a, long b) { return a.add(bigint(b)); } static public long plus(long a, long b) { return a + b; } static public int plus(int a, int b) { return a + b; } static public float plus(float a, float b) { return a + b; } static public double plus(double a, double b) { return a + b; } static public long clockTimeToSystemTime(long now) { return now == 0 ? 0 : now + clockToSysTimeDiff(); } static public List minus(Collection a, Object... b) { Set set = asSet(b); List l = new ArrayList(); for (Object s : unnull(a)) if (!set.contains(s)) l.add(s); return l; } static public BigInteger minus(BigInteger a, BigInteger b) { return a.subtract(b); } static public Complex minus(Complex c) { return c == null ? null : complex(-c.re(), -c.im()); } static public int minus(int a, int b) { return a - b; } static public double minus(double a, double b) { return a - b; } static public java.util.Timer doLater_daemon(long delay, final Object r) { final java.util.Timer timer = new java.util.Timer(true); timer.schedule(timerTask(r, timer), delay); return timer; } static public java.util.Timer doLater_daemon(double delaySeconds, final Object r) { return doLater_daemon(toMS(delaySeconds), r); } static public void cancelTimer(javax.swing.Timer timer) { if (timer != null) timer.stop(); } static public void cancelTimer(java.util.Timer timer) { if (timer != null) timer.cancel(); } static public void cancelTimer(Object o) { if (o instanceof java.util.Timer) cancelTimer((java.util.Timer) o); else if (o instanceof javax.swing.Timer) cancelTimer((javax.swing.Timer) o); else if (o instanceof AutoCloseable) { try { ((AutoCloseable) o).close(); } catch (Throwable __e) { printStackTrace(__e); } } } static public int seconds() { return seconds(java.util.Calendar.getInstance()); } static public int seconds(java.util.Calendar c) { return c.get(java.util.Calendar.SECOND); } static public void addToContainer(Container a, Component... b) { if (a == null) return; { swing(() -> { for (Component c : unnullForIteration(b)) if (c != null) a.add(c); }); } } static public String decimalFormatEnglish(String format, double d) { return decimalFormatEnglish(format).format(d); } static public java.text.DecimalFormat decimalFormatEnglish(String format) { return new java.text.DecimalFormat(format, new java.text.DecimalFormatSymbols(Locale.ENGLISH)); } static public IF0 ping_v3_pingSourceMaker_cache; static public IF0 ping_v3_pingSourceMaker() { if (ping_v3_pingSourceMaker_cache == null) ping_v3_pingSourceMaker_cache = ping_v3_pingSourceMaker_load(); return ping_v3_pingSourceMaker_cache; } static public IF0 ping_v3_pingSourceMaker_load() { return or((IF0) vm_generalMap_get("ping_v3_pingSourceMaker"), () -> null); } static public List lookupAllOpt(Map map, Collection l) { List out = new ArrayList(); if (l != null) for (A a : l) addIfNotNull(out, map.get(a)); return out; } static public List lookupAllOpt(Collection l, Map map) { return lookupAllOpt(map, l); } static public > List getVars(Iterable l) { return lambdaMap(__68 -> getVar(__68), l); } static public String dropNumberPrefix(String s) { return dropFirst(s, indexOfNonDigit(s)); } static public void readLocally(String progID, String varNames) { readLocally2(mc(), progID, varNames); } static public void readLocally(String varNames) { readLocally2(mc(), programID(), varNames); } static public void readLocally2(Object obj, String varNames) { readLocally2(obj, programID(), varNames); } static public int readLocally_stringLength; static public ThreadLocal readLocally2_allDynamic = new ThreadLocal(); static public ThreadLocal readLocally2_classFinder = new ThreadLocal(); static public void readLocally2(Object obj, String progID, String varNames) { try { boolean allDynamic = isTrue(getAndClearThreadLocal(readLocally2_allDynamic)); for (String variableName : javaTokC(varNames)) { File textFile = new File(programDir(progID), variableName + ".text"); String value = loadTextFile(textFile); if (value != null) set(main.class, variableName, value); else { File structureFile = new File(programDir(progID), variableName + ".structure"); value = loadTextFile(structureFile); if (value == null) { File structureGZFile = new File(programDir(progID), variableName + ".structure.gz"); if (!structureGZFile.isFile()) return; InputStream fis = new FileInputStream(structureGZFile); try { GZIPInputStream gis = newGZIPInputStream(fis); InputStreamReader reader = new InputStreamReader(gis, "UTF-8"); BufferedReader bufferedReader = new BufferedReader(reader); Object o = unstructure_tok(javaTokC_noMLS_onReader(bufferedReader), allDynamic, readLocally2_classFinder.get()); readLocally_set(obj, variableName, o); return; } finally { _close(fis); } } readLocally_stringLength = l(value); if (nempty(value)) readLocally_set(obj, variableName, unstructure(value, allDynamic, readLocally2_classFinder.get())); } } } catch (Exception __e) { throw rethrow(__e); } } static public void readLocally_set(Object c, String varName, Object value) { Object oldValue = get(c, varName); if (oldValue instanceof List && !(oldValue instanceof ArrayList) && value != null) { value = synchroList((List) value); } set(c, varName, value); } static public boolean cic(Collection l, String s) { return containsIgnoreCase(l, s); } static public boolean cic(Collection l, Symbol s) { return contains(l, s); } static public boolean cic(String[] l, String s) { return containsIgnoreCase(l, s); } static public boolean cic(String s, char c) { return containsIgnoreCase(s, c); } static public boolean cic(String a, String b) { return containsIgnoreCase(a, b); } static public String conceptsFileName() { return "concepts.structure.gz"; } static public String dbProgramID() { return getDBProgramID(); } static public boolean isString(Object o) { return o instanceof String; } static public List callF_all(Collection l, Object... args) { return map(l, f -> callF(f, args)); } static public File tempFileFor(File f) { return new File(f.getPath() + "_temp"); } static public double toM_double(long l) { return l / (1024 * 1024.0); } static public boolean containsNewLine(String s) { return contains(s, '\n'); } public static String rtrimSpaces(String s) { if (s == null) return null; int i = s.length(); while (i > 0 && " \t".indexOf(s.charAt(i - 1)) >= 0) --i; return i < s.length() ? s.substring(0, i) : s; } static public int year() { return localYear(); } static public int year(long now) { return localYear(now); } static public int year(long now, TimeZone tz) { return parseInt(simpleDateFormat("y", tz).format(now)); } static public int month() { return localMonth(); } static public int month(long now) { return localMonth(now); } static public int month(long now, TimeZone tz) { return parseInt(simpleDateFormat("M", tz).format(now)); } static public int dayOfMonth() { return localDayOfMonth(); } static public int dayOfMonth(long now) { return localDayOfMonth(now); } static public int dayOfMonth(long now, TimeZone tz) { return parseInt(simpleDateFormat("d", tz).format(now)); } static public String padLeft(String s, char c, int n) { return rep(c, n - l(s)) + s; } static public String padLeft(String s, int n) { return padLeft(s, ' ', n); } static public java.util.Calendar calendarFromTime(long time, TimeZone tz) { java.util.Calendar c = java.util.Calendar.getInstance(tz); c.setTimeInMillis(time); return c; } static public java.util.Calendar calendarFromTime(long time) { java.util.Calendar c = java.util.Calendar.getInstance(); c.setTimeInMillis(time); return c; } static public int roundDownTo(int n, int x) { return x / n * n; } static public long roundDownTo(long n, long x) { return x / n * n; } static public String defaultTimerName_name; static public String defaultTimerName() { if (defaultTimerName_name == null) defaultTimerName_name = "A timer by " + programID(); return defaultTimerName_name; } static public TimerTask smartTimerTask(Object r, java.util.Timer timer, long delay) { return new SmartTimerTask(r, timer, delay, _threadInfo()); } static public class SmartTimerTask extends TimerTask implements IFieldsToList { public Object r; public java.util.Timer timer; public long delay; public Object threadInfo; public SmartTimerTask() { } public SmartTimerTask(Object r, java.util.Timer timer, long delay, Object threadInfo) { this.threadInfo = threadInfo; this.delay = delay; this.timer = timer; this.r = r; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + r + ", " + timer + ", " + delay + ", " + threadInfo + ")"; } public Object[] _fieldsToList() { return new Object[] { r, timer, delay, threadInfo }; } public long lastRun; public void run() { if (!licensed()) timer.cancel(); else { _threadInheritInfo(threadInfo); AutoCloseable __1 = tempActivity(r); try { lastRun = fixTimestamp(lastRun); long now = now(); if (now >= lastRun + delay * 0.9) { lastRun = now; if (eq(false, pcallF(r))) timer.cancel(); } } finally { _close(__1); } } } } static public void close_pcall(AutoCloseable c) { if (c != null) { try { c.close(); } catch (Throwable __e) { printStackTrace(__e); } } } static public void preCleanUp(Object c) { if (c instanceof Collection) { for (Object o : ((Collection) c)) preCleanUp(o); return; } callOpt(c, "licensed_off"); setOpt_raw(c, "ping_anyActions", true); setOpt_raw(c, "cleaningUp_flag", true); } static public void innerCleanUp(Object c) { if (!isFalse(pcallOpt(c, "cleanMeUp"))) for (String name : sorted(methodsStartingWith(c, "cleanMeUp_"))) try { callOpt(c, name); } catch (Throwable e) { print("Error cleaning up: " + programID(c)); _handleException(e); } } static public void innerCleanUp() { innerCleanUp(mc()); } static public List registeredThreads(Object o) { Map map = (Map) (getOpt(o, "_registerThread_threads")); if (map == null) return ll(); map.size(); synchronized (map) { return asList(keys(map)); } } static public List registeredThreads() { _registerThread_threads.size(); return asList(keys(_registerThread_threads)); } static public void interruptThreads(Collection threads) { for (Thread t : unnull(threads)) interruptThread(t); } static public void interruptThreads(Class mainClass) { interruptThreads(registeredThreads(mainClass)); } static public void retireClassLoader(ClassLoader cl) { try { if (isJavaXClassLoader(cl)) setOptAll(cl, "retired", true, "retiredMarker", new DefunctClassLoader()); } catch (Throwable __e) { printStackTrace(__e); } } static public String dynamicClassName(Object o) { if (o instanceof DynamicObject && ((DynamicObject) o).className != null) return "main$" + ((DynamicObject) o).className; return className(o); } static public String loadTextFilePossiblyGZipped(String fileName) { return loadTextFilePossiblyGZipped(fileName, null); } static public String loadTextFilePossiblyGZipped(String fileName, String defaultContents) { File gz = new File(fileName + ".gz"); return gz.exists() ? loadGZTextFile(gz) : loadTextFile(fileName, defaultContents); } static public String loadTextFilePossiblyGZipped(File fileName) { return loadTextFilePossiblyGZipped(fileName, null); } static public String loadTextFilePossiblyGZipped(File fileName, String defaultContents) { return loadTextFilePossiblyGZipped(fileName.getPath(), defaultContents); } static public List syncList() { return synchroList(); } static public List syncList(List l) { return synchroList(l); } static public boolean isUnstructuring() { return isTrue(getTL(dynamicObjectIsLoading_threadLocal())); } static public Object getOptMC(String field) { return getOpt(mc(), field); } static public String hform(Object contents, Object... params) { return htag("form", contents, params); } static public String span(Object contents, Object... params) { return hfulltag("span", contents, params); } static public String span() { return span(""); } static public String nlToBr_withIndents(String s) { s = nlToBr(s); StringBuilder buf = new StringBuilder(); int i = 0; while (i < l(s)) { while (charAt(s, i) == ' ') { ++i; buf.append(" "); } int j = smartIndexOf(s, i, '\n') + 1; buf.append(substring(s, i, j)); i = j; } return str(buf); } static public int cmpAlphaNum(String a, String b) { return alphaNumComparator().compare(a, b); } static public String reversedString(String s) { return reverseString(s); } static public List lazilyMap(IF1 f, List l) { return lazyMap((Object) f, l); } static public List lazilyMap(final Object f, final List l) { return new RandomAccessAbstractList() { final public int size = l(l); public HashMap data = new HashMap(); public int size() { return size; } public Object get(int i) { if (data.containsKey(i)) return data.get(i); Object o = callF(f, l.get(i)); data.put(i, o); return o; } }; } static public Map mapMapToMap(IF2> f, Map m) { if (m == null) return null; Map map = similarEmptyMap(m); for (Map.Entry e : m.entrySet()) { Pair p = f.get(e.getKey(), e.getValue()); map.put(p.a, p.b); } return map; } static public Map mapMapToMap(Map m, IF2> f) { return mapMapToMap(f, m); } static public Map filterMapByFunctionOnKey(Map map, Object f) { Map m2 = similarEmptyMap(map); for (A a : keys(map)) { if (isTrue(callF(f, a))) m2.put(a, map.get(a)); } return m2; } static public Map filterMapByFunctionOnKey(Object f, Map map) { return filterMapByFunctionOnKey(map, f); } static public String unicode_downPointingTriangle() { return charToString(0x25BC); } static public String unicode_upPointingTriangle() { return charToString(0x25B2); } static public Object[] litObjectArray(Object... l) { return l; } static public List dropTagsAndHTMLComments(List tok) { return dropHTMLComments(dropTags(tok)); } static public String dropTagsAndHTMLComments(String html) { return join(dropTagsAndHTMLComments(htmlTok(html))); } static public String rtrim_fromLines(Collection lines) { StringBuilder buf = new StringBuilder(); if (lines != null) { boolean first = true; for (Object line : lines) { if (first) first = false; else buf.append('\n'); buf.append(str(line)); } } return buf.toString(); } static public Object[] paramsPlus_skipFirst(Object[] a1, Object... a2) { if (odd(l(a1))) return itemPlusArray(first(a1), paramsPlus(dropFirst(a1), a2)); return paramsPlus(a1, a2); } static public String htextinput(String name, Object... params) { Object value = ""; if (odd(l(params))) { value = params[0]; params = dropFirst(params); } params = html_massageAutofocusParam(params); return tag("input", "", concatArrays(new Object[] { "type", "text", "name", name, "value", value }, params)); } static public String htextinput(String name) { return htextinput(name, ""); } static public String htableRaw2(List data, List paramsTable, List paramsTR, List paramsTD) { StringBuilder buf = new StringBuilder(); for (List row : data) { buf.append(hopeningTag("tr", toObjectArray(paramsTR))); for (Object cell : row) buf.append(htd(cell, toObjectArray(paramsTD))).append("\n"); buf.append("\n"); } return htag("table", buf, toObjectArray(paramsTable)); } static public Object[] html_massageAutofocusParam(Object[] params) { Object autofocus = optPar("autofocus", params); return changeParam(params, "autofocus", eqOneOf(autofocus, html_valueLessParam(), true, 1, "1", "autofocus") ? html_valueLessParam() : null); } static public void listSet(List l, int i, A a, A emptyElement) { if (i < 0) return; while (i >= l(l)) l.add(emptyElement); l.set(i, a); } static public void listSet(List l, int i, A a) { listSet(l, i, a, null); } static public String stringIfTrue(boolean b, String s) { return b ? s : ""; } static public List itemPlusList(A a, Collection l) { return concatLists(ll(a), l); } static public List tok_identifiersInOrder(String s) { return filter(__69 -> isIdentifier(__69), javaTokC(s)); } static public List tok_identifiersInOrder(List tok) { return filter(__70 -> isIdentifier(__70), codeTokens(tok)); } static public String ahref_possiblyTargetBlank(String link, Object contents, boolean targetBlank, Object... params) { return ahref(link, contents, targetBlank ? paramsPlus(params, "target", "_blank") : params); } static public String ahref_possiblyTargetBlank(boolean targetBlank, String link, Object contents, Object... params) { return ahref_possiblyTargetBlank(link, contents, targetBlank, params); } static public String hstyle(Object contents) { return hcss(contents); } static public String hdiv(Object contents, Object... params) { return div(contents, params); } static public String unicode_smallDownPointingTriangle() { return charToString(0x25BE); } static public String ul(String... list) { return ul(asList(list)); } static public String ul(Collection list, Object... params) { StringBuilder buf = new StringBuilder(); int i = indexOf(params, null); if (i == -1) i = l(params); for (Object s : withoutNulls(list)) buf.append(tag("li", s, subArray(params, i + 1))).append("\n"); return containerTag("ul", buf, subArray(params, 0, i)) + "\n"; } static public int globalIDLength() { return 16; } static public String hjavascript(String scriptOrURL, Object... __) { if (isRelativeOrAbsoluteURL(scriptOrURL) && !startsWithOneOf(scriptOrURL, "//", "/*")) return hjavascript_src(scriptOrURL, __); else return tag("script", scriptOrURL, paramsPlus(__, "type", "text/javascript")); } static public String unicodeFromCodePoint(int codePoint) { return codePointToString(codePoint); } static public String jsonEncode_breakAtLevel1(Object o) { StringBuilder buf = new StringBuilder(); jsonEncode_breakAtLevel1(o, buf, 1); return str(buf); } static public void jsonEncode_breakAtLevel1(Object o, StringBuilder buf, int level) { if (o == null) buf.append("null"); else if (o instanceof String) buf.append(quote((String) o)); else if (o instanceof Number || o instanceof Boolean) buf.append(o); else if (o instanceof Map) { Map map = (Map) o; buf.append("{"); boolean first = true; for (Object key : keys(map)) { if (first) first = false; else buf.append(","); if (level == 1) buf.append("\n "); buf.append(quote((String) key)); buf.append(":"); jsonEncode_breakAtLevel1(map.get(key), buf, level + 1); } if (level == 1) buf.append("\n"); buf.append("}"); } else if (o instanceof Collection) { Collection l = (Collection) o; buf.append("["); boolean first = true; for (Object element : l) { if (first) first = false; else buf.append(","); if (level == 1) buf.append("\n "); jsonEncode_breakAtLevel1(element, buf, level + 1); } if (level == 1) buf.append("\n"); buf.append("]"); } else throw fail("Unknown object for JSON encoding: " + className(o)); } static public ArrayList cloneListSynchronizingOn(Collection l, Object mutex) { if (l == null) return new ArrayList(); synchronized (mutex) { return new ArrayList(l); } } static public List regexpFirstGroups(String pat, String s) { if (s == null) return null; Matcher m = regexp(pat, s); return m.find() ? regexpGetGroups(m) : null; } static public String joinNemptiesWithComma(Object... strings) { return joinNempties(", ", strings); } static public String joinNemptiesWithComma(Iterable strings) { return joinNempties(", ", strings); } static public List flattenCollectionsAndArrays(Iterable a) { List l = new ArrayList(); for (Object x : a) if (x instanceof Collection) l.addAll(flattenCollectionsAndArrays((Collection) x)); else if (x instanceof Object[]) l.addAll(flattenCollectionsAndArrays(asList((Object[]) x))); else l.add(x); return l; } static public double positiveInfinity() { return Double.POSITIVE_INFINITY; } static public ListIterator emptyListIterator() { return Collections.emptyListIterator(); } static public IMeta toIMeta(Object o) { return initIMeta(o); } static public Map makeObjectMetaMap() { return new CompactHashMap(); } static public IAutoCloseableF0 tempMetaMutex(IMeta o) { return o == null ? null : o._tempMetaMutex(); } static public void syncMapPut2(Map map, A key, B value) { if (map != null && key != null) synchronized (collectionMutex(map)) { if (value != null) map.put(key, value); else map.remove(key); } } static public String shortName(Object o) { return shortClassName(o); } static public A callPostProcessor(Object f, A a) { return f == null ? a : (A) callF(f, a); } static public A callPostProcessor(IF1 f, A a) { return f == null ? a : f.get(a); } static public Collection findConceptsWhereCI(Class c, Object... params) { return findConceptsWhereCI(db_mainConcepts(), c, params); } static public List findConceptsWhereCI(String c, Object... params) { return findConceptsWhereCI(db_mainConcepts(), c, params); } static public Collection findConceptsWhereCI(Concepts concepts, Class c, Object... params) { Collection l = findConceptsWhereCI_noParent(concepts, c, params); if (concepts.parent == null) return l; return concatCollections_conservative(l, findConceptsWhereCI(concepts.parent, c, params)); } static public Collection findConceptsWhereCI_noParent(Concepts concepts, Class c, Object... params) { params = expandParams(c, params); if (concepts.ciFieldIndices != null) for (int i = 0; i < l(params); i += 2) { IFieldIndex index = concepts.getCIFieldIndex(c, (String) params[i]); if (index != null) { Collection rawList = index.getAll(params[i + 1]); params = dropEntryFromParams(params, i); if (params == null) return rawList; List l = new ArrayList(); for (A x : rawList) if (checkConceptFieldsIC(x, params)) l.add(x); return l; } } return filterConceptsIC(concepts.list(c), params); } static public List findConceptsWhereCI(Concepts concepts, String c, Object... params) { return filterConceptsIC(concepts.list(c), params); } static public List sortedByCalculatedFieldDesc(Collection c, final Object f) { return sortByCalculatedFieldDesc(c, f); } static public List sortedByCalculatedFieldDesc(Object f, Collection c) { return sortByCalculatedFieldDesc(f, c); } static public List sortedByCalculatedFieldDesc(Iterable c, IF1 f) { return sortByCalculatedFieldDesc(c, f); } static public List sortedByCalculatedFieldDesc(IF1 f, Iterable c) { return sortByCalculatedFieldDesc(f, c); } static public long getLong(Object o, String field) { return toLong(getOpt(o, field)); } static public long getLong(String field, Object o) { return getLong(o, field); } static public String[] conceptFields_gen_drop = { "className", "fieldValues", "id", "created", "_modified", "refs", "backRefs", "_concepts" }; static public Set conceptFields_gen(Object c) { return setMinus(mergeTreeSets(allNonStaticNonTransientFields(c), keys((Map) getOpt_raw(c, "fieldValues"))), conceptFields_gen_drop); } static public Set conceptFields_gen(Class c) { return setMinus(allNonStaticNonTransientFields(c), conceptFields_gen_drop); } static public List nonStaticNonTransientFieldObjects(Object o) { if (o == null) return null; List fields = new ArrayList(); Class _c = _getClass(o); do { for (Field f : _c.getDeclaredFields()) if ((f.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) == 0) fields.add(makeAccessible(f)); _c = _c.getSuperclass(); } while (_c != null); return fields; } static public List valuesList(Map map) { return cloneListSynchronizingOn(values(map), map); } static public List valuesList(MultiMap mm) { return mm == null ? emptyList() : concatLists(values(mm.data)); } static public String optCastToString(Object o) { return o instanceof String ? (String) o : null; } static public boolean swicOneOf(String s, String... l) { for (String x : l) if (swic(s, x)) return true; return false; } static public boolean swicOneOf(String s, Matches m, String... l) { for (String x : l) if (swic(s, x, m)) return true; return false; } static public Map mapToValues(Iterable l, Object f) { return mapKeyAndFunction(l, f); } static public Map mapToValues(Object f, Iterable l) { return mapKeyAndFunction(f, l); } static public Map mapToValues(Iterable l, IF1 f) { return mapKeyAndFunction(f, l); } static public Map mapToValues(IF1 f, Iterable l) { return mapKeyAndFunction(f, l); } static public Map mapToValues(Map map, IF2 f) { return mapKeyAndFunction(map, f); } static public Object cloneIfList(Object o) { return o instanceof List ? cloneList((List) o) : o; } static public boolean _cSmartSetField(Concept c, String field, Object value) { try { Field f = setOpt_findField(c.getClass(), field); if (f != null && value != null) { Class actualType = f.getType(); Class type = primitiveToBoxedTypeOpt(actualType); if (type == Integer.class && !(value instanceof Integer)) { if (!setField_trueIfChanged(f, c, toInt(trimIfString(value)))) return false; if (!isTransient(f)) c.change(); return true; } if (type == Boolean.class && value instanceof String) if (actualType == Boolean.class && eq(value, "")) return _csetField(c, field, null); else return _csetField(c, field, eqicOneOf((String) value, "1", "true", "yes")); } return _csetField(c, field, value); } catch (Exception __e) { throw rethrow(__e); } } static public Object[] unrollAndExpandParams(Class c, Object[] params) { return expandParams(c, unrollParams(params)); } static public boolean cSmartSetField_withConverter(Concept c, String field, Object value) { return cSmartSetField_withConverter(c, field, value, false); } static public boolean cSmartSetField_withConverter(Concept c, String field, Object value, boolean verbose) { return cSmartSetField_withConverter(c, field, value, new DefaultValueConverterForField(), verbose); } static public boolean cSmartSetField_withConverter(Concept c, String field, Object value, ValueConverterForField converter) { return cSmartSetField_withConverter(c, field, value, converter, false); } static public boolean cSmartSetField_withConverter(Concept c, String field, Object value, ValueConverterForField converter, boolean verbose) { try { Field f = setOpt_findField(c.getClass(), field); if (f != null) { if (verbose) print("cSmartSetField_withConverter: setting " + f + " = " + value); if (converter != null && value != null) { OrError result = converter.convertValue(c, f, value); if (result == null) throw fail("Unknown conversion " + className(value) + " => " + f); if (!result.ok()) throw fail("Unknown conversion " + className(value) + " => " + f + ": " + result.error()); value = result.get(); } if (verbose) print("cSmartSetField_withConverter: converted value=" + value); if (value instanceof List && f.getType() == Concept.RefL.class) { Concept.RefL l = (Concept.RefL) (f.get(c)); if (verbose) print("cSmartSetField_withConverter: RefL=" + l); l.replaceWithList((List) value); if (verbose) print("cSmartSetField_withConverter: backrefs=" + c.backRefs); return true; } if (value instanceof Concept && f.getType() == Concept.Ref.class) return ((Concept.Ref) f.get(c)).set((Concept) value); } return _csetField(c, field, value); } catch (Exception __e) { throw rethrow(__e); } } static public Field findField2(Object o, String field) { Class c = o.getClass(); HashMap map; synchronized (getOpt_cache) { map = getOpt_cache.get(c); if (map == null) map = getOpt_makeCache(c); } if (map == getOpt_special) { if (o instanceof Class) return findField2_findStaticField((Class) o, field); } return map.get(field); } static public Field findField2_findStaticField(Class c, String field) { Class _c = c; do { for (Field f : _c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) return f; _c = _c.getSuperclass(); } while (_c != null); return null; } static public boolean eqicOrEq(Object a, Object b) { return a instanceof String && b instanceof String ? eqic((String) a, (String) b) : eq(a, b); } static public Field getField(Object o, String field) { if (o == null) return null; return setOpt_findField(_getClass(o), field); } static public Object getField(Field field, Object o) { return fieldGet(field, o); } static public A cDeref(Concept.Ref ref) { return ref == null ? null : ref.get(); } static public boolean syncNempty(Collection l) { return !syncEmpty(l); } static public Class typeToClass(Type type) { if (type == null) return null; if (type instanceof Class) return ((Class) type); if (type instanceof ParameterizedType) return optCast(Class.class, ((ParameterizedType) type).getRawType()); return null; } static public List scoredSearch_prepare(String query) { return map(__71 -> replacePlusWithSpace(__71), splitAtSpace(query)); } static public int scoredSearch_score(Iterable l, List words) { int score = 0; if (l != null) for (String s : l) score += scoredSearch_score(s, words); return score; } static public int scoredSearch_score(String s, List words) { int score = 0; if (nempty(s)) for (String word : unnullForIteration(words)) score += scoredSearch_score_single(s, word); return score; } static public int scoredSearch_score(String s, String query) { return scoredSearch_score(s, scoredSearch_prepare(query)); } static public List keysSortedByValuesDesc(final Map map) { List l = new ArrayList(map.keySet()); sort(l, mapComparatorDesc(map)); return l; } static public String jextract(String pat, String s) { return jextract(pat, javaTok(s)); } static public String jextract(String pat, List tok) { List tokpat = javaTok(pat); jfind_preprocess(tokpat); int i = jfind(tok, tokpat); if (i < 0) return null; int j = i + l(tokpat) - 2; return joinSubList(tok, i, j); } static public File makeTempDir() { return (File) call(getJavaX(), "TempDirMaker_make"); } static public String nohup_sanitize(String s) { return empty(s) ? s : takeFirst(50, s.replaceAll("[^.a-zA-Z0-9\\-_]", "")); } static public IF0 shouldKeepTempFiles; static public boolean shouldKeepTempFiles() { return shouldKeepTempFiles != null ? shouldKeepTempFiles.get() : shouldKeepTempFiles_base(); } final static public boolean shouldKeepTempFiles_fallback(IF0 _f) { return _f != null ? _f.get() : shouldKeepTempFiles_base(); } static public boolean shouldKeepTempFiles_base() { return false; } static public String pad(Object s, int l) { return pad(s, l, ' '); } static public String pad(Object s, int l, char c) { String _s = str(s); if (lengthOfString(_s) >= l) return _s; return rep(c, l - lengthOfString(_s)) + _s; } static public String pad(int l, Object s) { return pad(s, l); } static public A printIndent(A o) { print(indentx(str(o))); return o; } static public A printIndent(String indent, A o) { print(indentx(indent, str(o))); return o; } static public void printIndent(int indent, Object o) { print(indentx(indent, str(o))); } static public int lKeys(MultiMap mm) { return mm == null ? 0 : mm.keysSize(); } static public File loadBinarySnippet(String snippetID) { IResourceLoader rl = vm_getResourceLoader(); if (rl != null) return rl.loadLibrary(snippetID); return loadBinarySnippet_noResourceLoader(snippetID); } static public File loadBinarySnippet_noResourceLoader(String snippetID) { try { long id = parseSnippetID(snippetID); if (isImageServerSnippet(id)) return loadImageAsFile(snippetID); File f = DiskSnippetCache_getLibrary(id); if (fileSize(f) == 0) f = loadDataSnippetToFile_noResourceLoader(snippetID); return f; } catch (Exception __e) { throw rethrow(__e); } } static public int latestInstalledJavaX() { File[] files = new File(userHome(), ".javax").listFiles(); int v = 0; if (files != null) for (File f : files) { Matcher m = regexpMatcher("x(\\d\\d\\d?)\\.jar", f.getName()); if (m.matches()) v = Math.max(v, Integer.parseInt(m.group(1))); } return v; } static public String x30JarServerURL() { return "http://botcompany.de:8081/x30.jar"; } static public ThreadLocal>> loadBinaryPage_responseHeaders = new ThreadLocal(); static public ThreadLocal> loadBinaryPage_extraHeaders = new ThreadLocal(); static public byte[] loadBinaryPage(String url) { try { print("Loading " + url); return loadBinaryPage(loadPage_openConnection(new URL(url))); } catch (Exception __e) { throw rethrow(__e); } } static public byte[] loadBinaryPage(URLConnection con) { try { Map extraHeaders = getAndClearThreadLocal(loadBinaryPage_extraHeaders); setHeaders(con); for (String key : keys(extraHeaders)) con.setRequestProperty(key, extraHeaders.get(key)); return loadBinaryPage_noHeaders(con); } catch (Exception __e) { throw rethrow(__e); } } static public byte[] loadBinaryPage_noHeaders(URLConnection con) { try { ByteArrayOutputStream buf = new ByteArrayOutputStream(); InputStream inputStream = con.getInputStream(); loadBinaryPage_responseHeaders.set(con.getHeaderFields()); long len = 0; try { len = con.getContentLength(); } catch (Throwable e) { printStackTrace(e); } int n = 0; while (true) { int ch = inputStream.read(); if (ch < 0) break; buf.write(ch); if (++n % 100000 == 0) println(" " + n + (len != 0 ? "/" + len : "") + " bytes loaded."); } inputStream.close(); return buf.toByteArray(); } catch (Exception __e) { throw rethrow(__e); } } public static byte[] saveBinaryFile(String fileName, byte[] contents) { try { File file = new File(fileName); File parentFile = file.getParentFile(); if (parentFile != null) parentFile.mkdirs(); String tempFileName = fileName + "_temp"; FileOutputStream fileOutputStream = newFileOutputStream(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); vmBus_send("wroteFile", file); return contents; } catch (Exception __e) { throw rethrow(__e); } } static public byte[] saveBinaryFile(File fileName, byte[] contents) { return saveBinaryFile(fileName.getPath(), contents); } static public int hashMap_internalHash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } static public Map> allFields_cache = weakHashMap(); static public Set allFields(Object o) { if (o == null) return emptySet(); Class _c = _getClass(o); Set fields = allFields_cache.get(_c); if (fields == null) allFields_cache.put(_c, fields = asTreeSet(keys(getOpt_getFieldMap(o)))); return fields; } static public int stdHash(Object a, String... fields) { if (a == null) return 0; int hash = getClassName(a).hashCode(); for (String field : fields) hash = boostHashCombine(hash, hashCode(getOpt(a, field))); return hash; } static public double msToSeconds(long ms) { return toSeconds(ms); } static public double msToSeconds(double ms) { return toSeconds(ms); } static public long fileModificationTime(File f) { return f == null ? 0 : f.lastModified(); } static public A vmBus_timerStarted(A timer) { vmBus_send("timerStarted", timer, costCenter()); return timer; } static public Set syncLinkedHashSet() { return synchroLinkedHashSet(); } static public A registerConcept(A c) { return registerConcept(db_mainConcepts(), c); } static public A registerConcept(Concepts cc, A c) { { if (cc != null) cc.register(c); } return c; } static public ArrayList cloneList_noSync(Iterable l) { return l instanceof Collection ? cloneList_noSync((Collection) l) : asList(l); } static public ArrayList cloneList_noSync(Collection l) { if (l == null) return new ArrayList(); return new ArrayList(l); } static public IterableIterator iteratorFromFunction(final Object f) { class IFF extends IterableIterator { public A a; public boolean done = false; public boolean hasNext() { getNext(); return !done; } public A next() { getNext(); if (done) throw fail(); A _a = a; a = null; return _a; } public void getNext() { if (done || a != null) return; a = (A) callF(f); done = a == null; } } ; return new IFF(); } static public IterableIterator iteratorFromFunction(F0 f) { return iteratorFromFunction_f0(f); } static public IterableIterator iteratorFromFunction(IF0 f) { return iteratorFromFunction_if0(f); } static public IterableIterator concurrentlyIterateValues(NavigableMap map) { return concurrentlyIterateValues(map, map); } static public IterableIterator concurrentlyIterateValues(final NavigableMap map, Object mutex) { return iteratorFromFunction(new F0() { public Iterator it = keys(map).iterator(); public A key; public B get() { synchronized (mutex) { try { if (!it.hasNext()) return null; return map.get(key = it.next()); } catch (ConcurrentModificationException e) { print("Re-iterating"); it = map.tailMap(key, false).keySet().iterator(); if (!it.hasNext()) return null; return map.get(key = it.next()); } } } }); } static public String hjavascript_src(String src, Object... __) { return hfulltag("script", "", paramsPlus(__, "src", src)); } static public BigInteger bigint(String s) { return new BigInteger(s); } static public BigInteger bigint(long l) { return BigInteger.valueOf(l); } static public String joinNemptiesWithSemicolon(String... strings) { return joinNempties("; ", strings); } static public String joinNemptiesWithSemicolon(Collection strings) { return joinNempties("; ", strings); } static public String stringPar(Object[] params, String name) { return stringOptPar(params, name); } static public String stringPar(String name, Object[] params) { return stringOptPar(params, name); } static public String stringPar(String name, Map params) { return (String) optPar(name, params); } static public String stringPar(String name, Object[] params, String defaultValue) { return optPar(name, params, defaultValue); } static public Map mapKeys(Object func, Map map) { Map m = similarEmptyMap(map); for (Object key : keys(map)) m.put(callF(func, key), map.get(key)); return m; } static public Map mapKeys(Map map, Object func) { return mapKeys(func, map); } static public Map mapKeys(Map map, IF1 func) { return mapKeys(map, (Object) func); } static public Map mapKeys(IF1 func, Map map) { return mapKeys(map, func); } static public MultiMap mapKeys(IF1 f, MultiMap mm) { return mapMultiMapKeys(f, mm); } static public MultiSetMap mapKeys(IF1 f, MultiSetMap mm) { return mapMultiSetMapKeys(f, mm); } static public String dropDollarPrefix(String s) { return dropPrefix("$", s); } static public TreeMap litcimap(Object... x) { return litCIMap(x); } static public String replaceDollarVars_dyn(String s, IF1 f) { if (f == null) return s; return regexpReplaceIC(s, "\\$(\\w+)", matcher -> { String var = matcher.group(1); String val = f.get(var); return val == null ? matcher.group() : str(val); }); } static public Map> multiMapToMap(MultiMap m) { return m == null ? null : m.data; } static public Object leftArrow(String script) { GazelleV_LeftArrowScriptParser parser = new GazelleV_LeftArrowScriptParser(); parser.allowTheWorld(); return parser.parse(script).get(); } static public String unicode_leftPointingTriangle() { return unicodeFromCodePoint(0x25C2); } static public String unicode_rightPointingTriangle() { return charToString(0x25B8); } static public Map humanizeFormLabel_replacements = litmap("id", "ID", "md5", "MD5"); static public String humanizeFormLabel(String s) { if (containsSpace(s)) return s; return firstToUpper(joinWithSpace(replaceElementsUsingMap(splitCamelCase(s), humanizeFormLabel_replacements)).replace("I D", "ID")); } static public String htitle_h1(String s) { return htitle_noEncode(dropTags(s)) + h1(s); } static public String getBotAddress(String bot) { List l = fullBotScan(bot); return empty(l) ? null : first(l).address; } static public Object unstructure_matchOK2OrFail(String s) { if (swic(s, "ok ")) return unstructure_startingAtIndex(s, 3); else throw fail(s); } static public String sendToLocalBot(String bot, String text, Object... args) { text = format3(text, args); DialogIO channel = findBot(bot); try { if (channel == null) throw fail(quote(bot) + " not found"); try { channel.readLine(); print(bot + "> " + shorten(text, 80)); channel.sendLine(text); String s = channel.readLine(); print(bot + "< " + shorten(s, 80)); return s; } catch (Throwable e) { e.printStackTrace(); return null; } } finally { _close(channel); } } static public String sendToLocalBot(int port, String text, Object... args) { text = format3(text, args); DialogIO channel = talkTo(port); try { try { channel.readLine(); print(port + "> " + shorten(text, 80)); channel.sendLine(text); String s = channel.readLine(); print(port + "< " + shorten(s, 80)); return s; } catch (Throwable e) { e.printStackTrace(); return null; } } finally { _close(channel); } } static public TimerTask timerTask(final Object r, final java.util.Timer timer) { return new TimerTask() { public void run() { if (!licensed()) timer.cancel(); else pcallF(r); } }; } static public Object swingCall(final Object o, final String method, final Object... args) { return swing(new F0() { public Object get() { try { return call(o, method, args); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "return call(o, method, args);"; } }); } static public String localDateWithSeconds(long time) { SimpleDateFormat format = simpleDateFormat_local("yyyy/MM/dd HH:mm:ss"); return format.format(time); } static public String localDateWithSeconds() { return localDateWithSeconds(now()); } static public long clockToSysTimeDiff() { return sysNow() - now(); } static public Complex complex(double re, double im) { return new Complex(re, im); } static public Complex complex(double re) { return new Complex(re, 0.0); } static public Complex complex(double[] reIm) { if (empty(reIm)) return null; if (l(reIm) != 2) throw fail("Need 2 doubles to make complex number"); return complex(reIm[0], reIm[1]); } static public boolean addIfNotNull(Collection l, A a) { return a != null && l != null & l.add(a); } static public void addIfNotNull(MultiSet ms, A a) { if (a != null && ms != null) ms.add(a); } static public int indexOfNonDigit(String s) { int n = l(s); for (int i = 0; i < n; i++) if (!isDigit(s.charAt(i))) return i; return -1; } static public boolean containsIgnoreCase(Collection l, String s) { if (l != null) for (String x : l) if (eqic(x, s)) return true; return false; } static public boolean containsIgnoreCase(String[] l, String s) { if (l != null) for (String x : l) if (eqic(x, s)) return true; return false; } static public boolean containsIgnoreCase(String s, char c) { return indexOfIgnoreCase(s, String.valueOf(c)) >= 0; } static public boolean containsIgnoreCase(String a, String b) { return indexOfIgnoreCase(a, b) >= 0; } static public int localYear() { return localYear(now()); } static public int localYear(long time) { return parseInt(simpleDateFormat_local("yyyy").format(time)); } static public java.text.SimpleDateFormat simpleDateFormat(String format, TimeZone timeZone) { java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat(format); sdf.setTimeZone(timeZone); return sdf; } static public int localMonth(long time) { return parseInt(simpleDateFormat_local("MM").format(time)); } static public int localMonth() { return localMonth(now()); } static public int localDayOfMonth(long time) { return parseInt(simpleDateFormat_local("dd").format(time)); } static public int localDayOfMonth() { return localDayOfMonth(now()); } static public AutoCloseable tempActivity(Object r) { return null; } static public long fixTimestamp(long timestamp) { return timestamp > now() ? 0 : timestamp; } static public List sorted(Collection c, Object comparator) { List l = cloneList(c); sort(l, makeComparator(comparator)); return l; } static public List sorted(Collection c) { List l = cloneList(c); sort(l); return l; } static public List sorted(Comparator comparator, Collection c) { List l = cloneList(c); sort(l, comparator); return l; } static public List methodsStartingWith(Object o, final String prefix) { return filter(allMethodNames(o), new F1() { public Object get(String s) { try { return startsWith(s, prefix); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "startsWith(s, prefix)"; } }); } static volatile public PersistableThrowable _handleException_lastException; static public List _handleException_onException = synchroList(ll((IVF1) (__1 -> printStackTrace2(__1)))); static public boolean _handleException_showThreadCancellations = false; static public void _handleException(Throwable e) { _handleException_lastException = persistableThrowable(e); Throwable e2 = innerException(e); if (e2.getClass() == RuntimeException.class && eq(e2.getMessage(), "Thread cancelled.") || e2 instanceof InterruptedException) { if (_handleException_showThreadCancellations) System.out.println(getStackTrace_noRecord(e2)); return; } for (Object f : cloneList(_handleException_onException)) try { callF(f, e); } catch (Throwable e3) { try { printStackTrace2(e3); } catch (Throwable e4) { System.out.println(getStackTrace(e3)); System.out.println(getStackTrace(e4)); } } } static public boolean interruptThread_verbose = false; static public void interruptThread(Thread t) { if (t == null) return; if (interruptThread_verbose) print("Interrupting thread " + t); vm_threadInterruptionReasonsMap().put(t, getStackTrace()); t.interrupt(); URLConnection c = (URLConnection) (vm_generalSubMap("URLConnection per thread").get(t)); if (c != null) { try { print("Closing URLConnection of interrupted thread."); call(c, "disconnect"); } catch (Throwable __e) { printStackTrace(__e); } } } static public boolean isJavaXClassLoader(ClassLoader cl) { return startsWithOneOf(className(cl), "main$JavaXClassLoader", "x30$JavaXClassLoader"); } static public void setOptAll(Object o, Map fields) { if (fields == null) return; for (String field : keys(fields)) setOpt(o, field, fields.get(field)); } static public void setOptAll(Object o, Object... values) { warnIfOddCount(values); for (int i = 0; i + 1 < l(values); i += 2) { String field = (String) values[i]; Object value = values[i + 1]; setOpt(o, field, value); } } static public String loadGZTextFile(File file) { try { if (!file.isFile()) return null; ping(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); InputStream fis = new FileInputStream(file); try { GZIPInputStream gis = newGZIPInputStream(fis); byte[] buffer = new byte[1024]; int len; while ((len = gis.read(buffer)) != -1) baos.write(buffer, 0, len); baos.close(); return fromUtf8(baos.toByteArray()); } finally { _close(fis); } } catch (Exception __e) { throw rethrow(__e); } } static public Object getTL(Object o, String name) { return getThreadLocal(o, name); } static public A getTL(ThreadLocal tl) { return getThreadLocal(tl); } static public A getTL(ThreadLocal tl, A defaultValue) { return getThreadLocal(tl, defaultValue); } static public AlphanumComparator alphaNumComparator_instance; static public Comparator alphaNumComparator() { if (alphaNumComparator_instance == null) alphaNumComparator_instance = new AlphanumComparator(); return alphaNumComparator_instance; } static public String reverseString(String s) { return empty(s) ? s : new StringBuilder(s).reverse().toString(); } static public String charToString(char c) { return String.valueOf(c); } static public String charToString(int c) { return String.valueOf((char) c); } static public List dropHTMLComments(List tok) { List l = new ArrayList(); for (int idx = 0; idx < l(tok); idx++) { String t = tok.get(idx); if (even(idx)) { int i; while ((i = t.indexOf("", i + 4); t = substring(t, 0, i) + substring(t, j + 3); } } l.add(t); } return l; } static public List htmlTok(String s) { return htmlcoarsetok(s); } static public A[] itemPlusArray(A a, A[] l) { return singlePlusArray(a, l); } static public String htd(Object contents, Object... params) { return htag("td", contents, params); } static public Object[] changeParam(Object[] params, String name, Object value) { if (eq(optPar(params, name), value)) return params; Map map = paramsToOrderedMap(params); map.put(name, value); return mapToParams(map); } static public List codeTokens(List tok) { return codeTokensOnly(tok); } static public List withoutNulls(Iterable l) { if (l instanceof List) if (!containsNulls((List) l)) return ((List) l); List l2 = new ArrayList(); for (A a : l) if (a != null) l2.add(a); return l2; } static public Map withoutNulls(Map map) { Map map2 = similarEmptyMap(map); for (A a : keys(map)) if (a != null) { B b = map.get(a); if (b != null) map2.put(a, b); } return map2; } static public List withoutNulls(A[] l) { List l2 = new ArrayList(); if (l != null) for (A a : l) if (a != null) l2.add(a); return l2; } static public int[] subArray(int[] b, int start, int end) { int[] x = new int[end - start]; System.arraycopy(b, start, x, 0, end - start); return x; } static public byte[] subArray(byte[] b, int start, int end) { start = max(start, 0); end = min(end, l(b)); if (start >= end) return new byte[0]; byte[] x = new byte[end - start]; System.arraycopy(b, start, x, 0, end - start); return x; } static public short[] subArray(short[] b, int start, int end) { if (start <= 0 && end >= l(b)) return b; short[] x = new short[end - start]; System.arraycopy(b, start, x, 0, end - start); return x; } static public float[] subArray(float[] b, int start, int end) { float[] x = new float[end - start]; System.arraycopy(b, start, x, 0, end - start); return x; } static public Object[] subArray(Object[] b, int start) { return subArray(b, start, l(b)); } static public Object[] subArray(Object[] b, int start, int end) { start = max(start, 0); end = min(end, l(b)); if (start >= end) return new Object[0]; Object[] x = new Object[end - start]; System.arraycopy(b, start, x, 0, end - start); return x; } static public String codePointToString(int codePoint) { return new String(Character.toChars(codePoint)); } static public List regexpGetGroups(Matcher matcher) { int n = matcher.groupCount(); List l = new ArrayList(); for (int i = 1; i <= n; i++) l.add(matcher.group(i)); return l; } static public List regexpGetGroups(String pat, String s) { Matcher m = regexpMatcher(pat, s); if (m.find()) return regexpGetGroups(m); return null; } static public Collection concatCollections_conservative(Collection a, Collection b) { if (empty(a)) return b; if (empty(b)) return a; return concatLists(a, b); } static public List sortByCalculatedFieldDesc(Collection c, final Object f) { return sortByCalculatedFieldDesc_inPlace(cloneList(c), f); } static public List sortByCalculatedFieldDesc(Object f, Collection c) { return sortByCalculatedFieldDesc(c, f); } static public List sortByCalculatedFieldDesc(Iterable c, IF1 f) { List l = cloneList(c); sort(l, new Comparator() { public int compare(A a, A b) { return stdcompare(f.get(b), f.get(a)); } }); return l; } static public List sortByCalculatedFieldDesc(IF1 f, Iterable c) { return sortByCalculatedFieldDesc(c, f); } static public Set mergeTreeSets(Collection... l) { TreeSet set = new TreeSet(); for (Collection o : l) if (o != null) set.addAll(o); return set; } static public Map mapKeyAndFunction(Iterable l, Object f) { return mapKeyAndFunction(f, l); } static public Map mapKeyAndFunction(Object f, Iterable l) { HashMap map = new HashMap(); if (l != null) for (Object o : l) map.put(o, callF(f, o)); return map; } static public Map mapKeyAndFunction(Map map, IF2 f) { HashMap map2 = new HashMap(); if (map != null) for (Map.Entry __0 : _entrySet(map)) { A key = __0.getKey(); B value = __0.getValue(); map2.put(key, callF(f, key, value)); } return map2; } static public Map mapKeyAndFunction(Iterable l, IF1 f) { return mapKeyAndFunction(f, l); } static public Class primitiveToBoxedTypeOpt(Class type) { return or(primitiveToBoxedType(type), type); } static public boolean setField_trueIfChanged(Field f, Object o, Object value) { try { if (eq(f.get(o), value)) return false; f.set(o, value); return true; } catch (Exception __e) { throw rethrow(__e); } } static public Object trimIfString(Object o) { return o instanceof String ? trim((String) o) : o; } static public boolean syncEmpty(Collection l) { if (l == null) return true; synchronized (l) { return l.isEmpty(); } } static public String replacePlusWithSpace(String s) { return replace(s, '+', ' '); } static public int scoredSearch_score_single(String s, String query) { int i = indexOfIC_underscore(s, query); if (i < 0) return 0; if (i > 0) return 1; return l(s) == l(query) ? 3 : 2; } static public Comparator mapComparatorDesc(final Map map) { return new Comparator() { public int compare(A a, A b) { return cmp(map.get(b), map.get(a)); } }; } static public int lengthOfString(String s) { return s == null ? 0 : s.length(); } static public File loadImageAsFile(String snippetIDOrURL) { try { if (isURL(snippetIDOrURL)) throw fail("not implemented"); if (!isSnippetID(snippetIDOrURL)) throw fail("Not a URL or snippet ID: " + snippetIDOrURL); String snippetID = "" + parseSnippetID(snippetIDOrURL); File file = imageSnippetCacheFile(snippetID); if (fileSize(file) > 0) return file; String imageURL = snippetImageURL_noHttps(snippetID); System.err.println("Loading image: " + imageURL); byte[] data = loadBinaryPage(imageURL); saveBinaryFile(file, data); return file; } catch (Exception __e) { throw rethrow(__e); } } static public File DiskSnippetCache_file(long snippetID) { return new File(getGlobalCache(), "data_" + snippetID + ".jar"); } public static File DiskSnippetCache_getLibrary(long snippetID) throws IOException { File file = DiskSnippetCache_file(snippetID); return file.exists() ? file : null; } public static File DiskSnippetCache_getLibrary(String snippetID) { try { return DiskSnippetCache_getLibrary(psI(snippetID)); } catch (Exception __e) { throw rethrow(__e); } } public static void DiskSnippetCache_putLibrary(long snippetID, byte[] data) throws IOException { saveBinaryFile(DiskSnippetCache_file(snippetID), data); } static public byte[] loadDataSnippetImpl(String snippetID) throws IOException { byte[] data; try { URL url = new URL(dataSnippetLink(snippetID)); print("Loading library: " + hideCredentials(url)); try { data = loadBinaryPage(url.openConnection()); } catch (RuntimeException e) { data = null; } if (data == null || data.length == 0) { url = new URL(tb_mainServer() + "/blobs/" + parseSnippetID(snippetID)); print("Loading library: " + hideCredentials(url)); data = loadBinaryPage(url.openConnection()); } print("Bytes loaded: " + data.length); } catch (FileNotFoundException e) { throw new IOException("Binary snippet #" + snippetID + " not found or not public"); } return data; } static public long fileSize(String path) { return getFileSize(path); } static public long fileSize(File f) { return getFileSize(f); } static public File loadDataSnippetToFile(String snippetID) { try { IResourceLoader rl = vm_getResourceLoader(); if (rl != null) return rl.loadLibrary(snippetID); return loadDataSnippetToFile_noResourceLoader(snippetID); } catch (Exception __e) { throw rethrow(__e); } } static public File loadDataSnippetToFile_noResourceLoader(String snippetID) { try { snippetID = fsI(snippetID); File f = DiskSnippetCache_file(parseSnippetID(snippetID)); List urlsTried = new ArrayList(); List errors = new ArrayList(); try { URL url = addAndReturn(urlsTried, new URL(dataSnippetLink(snippetID))); print("Loading library: " + hideCredentials(url)); try { loadBinaryPageToFile(openConnection(url), f); if (fileSize(f) == 0) throw fail(); } catch (Throwable e) { errors.add(e); url = addAndReturn(urlsTried, new URL(tb_mainServer() + "/blobs/" + psI(snippetID))); print(e); print("Trying other server: " + hideCredentials(url)); loadBinaryPageToFile(openConnection(url), f); print("Got bytes: " + fileSize(f)); } if (fileSize(f) == 0) throw fail(); System.err.println("Bytes loaded: " + fileSize(f)); } catch (Throwable e) { errors.add(e); throw fail("Binary snippet " + snippetID + " not found or not public. URLs tried: " + allToString(urlsTried) + ", errors: " + allToString(errors)); } return f; } catch (Exception __e) { throw rethrow(__e); } } static public A println(A a) { return print(a); } static public Map weakHashMap() { return newWeakHashMap(); } static public TreeSet asTreeSet(Collection set) { return set == null ? null : set instanceof TreeSet ? (TreeSet) set : new TreeSet(set); } static public int hashCode(Object a) { return a == null ? 0 : a.hashCode(); } static public int hashCode(long l) { return Long.hashCode(l); } static public int hashCode(double d) { return Double.hashCode(d); } static public double toSeconds(long ms) { return ms / 1000.0; } static public String toSeconds(long ms, int digits) { return formatDouble(toSeconds(ms), digits); } static public double toSeconds(double ms) { return ms / 1000.0; } static public String toSeconds(double ms, int digits) { return formatDouble(toSeconds(ms), digits); } static public Object costCenter() { return mc(); } static public Set synchroLinkedHashSet() { return synchronizedSet(new CompactLinkedHashSet()); } static public IterableIterator iteratorFromFunction_f0(final F0 f) { class IFF2 extends IterableIterator { public A a; public boolean done = false; public boolean hasNext() { getNext(); return !done; } public A next() { getNext(); if (done) throw fail(); A _a = a; a = null; return _a; } public void getNext() { if (done || a != null) return; a = f.get(); done = a == null; } } ; return new IFF2(); } static public IterableIterator iteratorFromFunction_if0(final IF0 f) { class IFF2 extends IterableIterator { public A a; public boolean done = false; public boolean hasNext() { getNext(); return !done; } public A next() { getNext(); if (done) throw fail(); A _a = a; a = null; return _a; } public void getNext() { if (done || a != null) return; a = f.get(); done = a == null; } } ; return new IFF2(); } static public String stringOptPar(Object[] params, String name) { return (String) optPar(params, name); } static public MultiMap mapMultiMapKeys(IF1 f, MultiMap mm) { MultiMap m = similarEmptyMultiMap(mm); for (var key : keys(mm)) m.put(f.get(key), mm.get(key)); return m; } static public MultiMap mapMultiMapKeys(MultiMap mm, IF1 f) { return mapMultiMapKeys(f, mm); } static public MultiSetMap mapMultiSetMapKeys(IF1 f, MultiSetMap mm) { MultiSetMap m = similarEmptyMultiSetMap(mm); for (var key : keys(mm)) m.put(f.get(key), mm.get(key)); return m; } static public MultiSetMap mapMultiSetMapKeys(MultiSetMap mm, IF1 f) { return mapMultiSetMapKeys(f, mm); } static public TreeMap litCIMap(Object... x) { TreeMap map = caseInsensitiveMap(); litmap_impl(map, x); return map; } static public String regexpReplaceIC(String s, String pat, Object f) { return regexReplaceIC(s, pat, f); } static public String regexpReplaceIC(String s, String pat, String replacement) { return regexReplaceIC(s, pat, replacement); } static public String regexpReplaceIC(String s, String pat, IF1 f) { return regexReplaceIC(s, pat, f); } static public boolean containsSpace(String s) { return containsSpaces(s); } static public List replaceElementsUsingMap(Iterable l, final Map map) { return map(l, new F1() { public A get(A a) { try { return getOrKeep(map, a); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "getOrKeep(map, a)"; } }); } static public List splitCamelCase(String s) { return ai_splitCamelCase(s); } static public String h1(String s, Object... params) { return hfulltag("h1", s, params); } static public class ScannedBot implements IFieldsToList { static final public String _fieldOrder = "helloString address"; public String helloString; public String address; public ScannedBot() { } public ScannedBot(String helloString, String address) { this.address = address; this.helloString = helloString; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + helloString + ", " + address + ")"; } public boolean equals(Object o) { if (!(o instanceof ScannedBot)) return false; ScannedBot __1 = (ScannedBot) o; return eq(helloString, __1.helloString) && eq(address, __1.address); } public int hashCode() { int h = 1660478935; h = boostHashCombine(h, _hashCode(helloString)); h = boostHashCombine(h, _hashCode(address)); return h; } public Object[] _fieldsToList() { return new Object[] { helloString, address }; } } static public List fullBotScan() { return fullBotScan(""); } static public List fullBotScan(String searchPattern) { List bots = new ArrayList(); for (ProgramScan.Program p : quickBotScan()) { String botName = firstPartOfHelloString(p.helloString); boolean isVM = startsWithIgnoreCase(p.helloString, "This is a JavaX VM."); boolean shouldRecurse = swic(botName, "Multi-Port") || isVM; if (swic(botName, searchPattern)) bots.add(new ScannedBot(botName, "" + p.port)); if (shouldRecurse) try { Map subBots = (Map) unstructure(sendToLocalBotQuietly(p.port, "list bots")); for (Number vport : subBots.keySet()) { botName = subBots.get(vport); if (swic(botName, searchPattern)) bots.add(new ScannedBot(botName, p.port + "/" + vport)); } } catch (Exception e) { e.printStackTrace(); } } return bots; } static public Object unstructure_startingAtIndex(String s, int i) { return unstructure_tok(javaTokC_noMLS_iterator(s, i), false, null); } static public SimpleDateFormat simpleDateFormat_local(String format) { SimpleDateFormat sdf = new SimpleDateFormat(format); sdf.setTimeZone(localTimeZone()); return sdf; } static public boolean loadBufferedImage_useImageCache = true; static public BufferedImage loadBufferedImage(String snippetIDOrURLOrFile) { try { ping(); if (snippetIDOrURLOrFile == null) return null; if (isURL(snippetIDOrURLOrFile)) return imageIO_readURL(snippetIDOrURLOrFile); if (isSnippetID(snippetIDOrURLOrFile)) { String snippetID = "" + parseSnippetID(snippetIDOrURLOrFile); IResourceLoader rl = vm_getResourceLoader(); if (rl != null) return loadBufferedImage(rl.loadLibrary(snippetID)); File dir = imageSnippetsCacheDir(); 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(); } } String imageURL = snippetImageURL_http(snippetID); print("Loading image: " + imageURL); BufferedImage image = imageIO_readURL(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")); } return image; } else return loadBufferedImage(new File(snippetIDOrURLOrFile)); } catch (Exception __e) { throw rethrow(__e); } } static public BufferedImage loadBufferedImage(File file) { return loadBufferedImageFile(file); } static public Comparator makeComparator(final Object f) { if (f instanceof Comparator) return (Comparator) f; return new Comparator() { public int compare(Object a, Object b) { return (Integer) callF(f, a, b); } }; } static public List allMethodNames(Object o) { Class c = _getClass(o); TreeSet names = new TreeSet(); while (c != null) { for (Method m : c.getDeclaredMethods()) names.add(m.getName()); c = c.getSuperclass(); } return asList(names); } static public Throwable printStackTrace2(Throwable e) { print(getStackTrace2(e)); return e; } static public void printStackTrace2() { printStackTrace2(new Throwable()); } static public void printStackTrace2(String msg) { printStackTrace2(new Throwable(msg)); } static public Throwable innerException(Throwable e) { return getInnerException(e); } static public String fromUtf8(byte[] bytes) { try { return bytes == null ? null : new String(bytes, utf8charset()); } catch (Exception __e) { throw rethrow(__e); } } static public A[] singlePlusArray(A a, A[] l) { A[] out = newObjectArrayOfSameType(l, l(l) + 1); out[0] = a; arraycopy(l, 0, out, 1, l(l)); return out; } static public List codeTokensOnly(List tok) { int n = l(tok); List l = emptyList(n / 2); for (int i = 1; i < n; i += 2) l.add(tok.get(i)); return l; } static public boolean containsNulls(Collection c) { return contains(c, null); } static public List sortByCalculatedFieldDesc_inPlace(List l, final Object f) { sort(l, new Comparator() { public int compare(A b, A a) { return stdcompare((Object) callF(f, a), (Object) callF(f, b)); } }); return l; } static public List sortByCalculatedFieldDesc_inPlace(Object f, List c) { return sortByCalculatedFieldDesc_inPlace(c, f); } static public Class primitiveToBoxedType(Class type) { if (type == boolean.class) return Boolean.class; if (type == int.class) return Integer.class; if (type == long.class) return Long.class; if (type == float.class) return Float.class; if (type == short.class) return Short.class; if (type == char.class) return Character.class; if (type == byte.class) return Byte.class; if (type == double.class) return Double.class; return null; } static public int indexOfIC_underscore(String a, String b) { int la = l(a), lb = l(b); if (la < lb) return -1; int n = la - lb; elsewhere: for (int i = 0; i <= n; i++) { for (int j = 0; j < lb; j++) { char c2 = b.charAt(j); if (c2 == '_' || eqic(c2, a.charAt(i + j))) { } else continue elsewhere; } return i; } return -1; } static public File imageSnippetCacheFile(String snippetID) { File dir = imageSnippetsCacheDir(); if (!loadBufferedImage_useImageCache) return null; return new File(dir, parseSnippetID(snippetID) + ".png"); } static public String snippetImageURL_noHttps(String snippetID) { return snippetImageURL_noHttps(snippetID, "png"); } static public String snippetImageURL_noHttps(String snippetID, String contentType) { return snippetImageURL(snippetID, contentType).replace("https://www.botcompany.de:8443/", "http://www.botcompany.de:8080/").replace("https://botcompany.de/", "http://botcompany.de/"); } static public File getGlobalCache() { File file = new File(javaxCachesDir(), "Binary Snippets"); file.mkdirs(); return file; } static public String dataSnippetLink(String snippetID) { long id = parseSnippetID(snippetID); if (id >= 1100000 && id < 1200000) return imageServerURL() + id; if (id >= 1200000 && id < 1300000) { String pw = muricaPassword(); if (empty(pw)) throw fail("Please set 'murica password by running #1008829"); return "https://botcompany.de/files/" + id + "?_pass=" + pw; } return fileServerURL() + "/" + id; } static public void loadBinaryPageToFile(String url, File file) { try { print("Loading " + url); loadBinaryPageToFile(openConnection(new URL(url)), file); } catch (Exception __e) { throw rethrow(__e); } } static public void loadBinaryPageToFile(URLConnection con, File file) { try { setHeaders(con); loadBinaryPageToFile_noHeaders(con, file); } catch (Exception __e) { throw rethrow(__e); } } static public void loadBinaryPageToFile_noHeaders(URLConnection con, File file) { try { File ftemp = new File(f2s(file) + "_temp"); FileOutputStream buf = newFileOutputStream(mkdirsFor(ftemp)); try { InputStream inputStream = con.getInputStream(); long len = 0; try { len = con.getContentLength(); } catch (Throwable e) { printStackTrace(e); } String pat = " {*}" + (len != 0 ? "/" + len : "") + " bytes loaded."; copyStreamWithPrints(inputStream, buf, pat); inputStream.close(); buf.close(); file.delete(); renameFile_assertTrue(ftemp, file); } finally { if (buf != null) buf.close(); } } catch (Exception __e) { throw rethrow(__e); } } static public MultiMap similarEmptyMultiMap(MultiMap m) { if (m instanceof TreeMultiMap) return new TreeMultiMap((TreeMultiMap) m); return similarEmptyMultiMap(m == null ? null : m.data); } static public MultiMap similarEmptyMultiMap(Map m) { MultiMap mm = new MultiMap(); if (m != null) mm.data = similarEmptyMap(m); return mm; } static public MultiSetMap similarEmptyMultiSetMap(MultiSetMap m) { return similarEmptyMultiSetMap(m == null ? null : m.data); } static public MultiSetMap similarEmptyMultiSetMap(Map m) { MultiSetMap mm = new MultiSetMap(); if (m != null) mm.data = similarEmptyMap(m); return mm; } static public String regexReplaceIC(String s, String pat, Object f) { return regexReplace(regexpMatcherIC(pat, s), f); } static public String regexReplaceIC(String s, String pat, String replacement) { return regexpReplaceIC_direct(s, pat, replacement); } static public boolean containsSpaces(String s) { return indexOf(s, ' ') >= 0; } static public List ai_splitCamelCase(String s) { int j = 0; List l = new ArrayList(); if (isAllUpperCase(s)) { l.add(s); return l; } for (int i = 0; i < l(s); i++) if (i > j && isUpperCaseLetter(s.charAt(i))) { l.add(substring(s, j, i)); j = i; } if (j < l(s)) l.add(substring(s, j)); return l; } static public TimeZone localTimeZone() { return getTimeZone(standardTimeZone()); } static public BufferedImage imageIO_readURL(String url) { try { return ImageIO.read(new URL(url)); } catch (Exception __e) { throw rethrow(__e); } } static public File imageSnippetsCacheDir() { return javaxCachesDir("Image-Snippets"); } static public String snippetImageURL_http(String snippetID) { return snippetImageURL_http(snippetID, "png"); } static public String snippetImageURL_http(String snippetID, String contentType) { return replacePrefix("https://", "http://", snippetImageURL(snippetID, contentType)).replace(":8443", ":8080"); } static public BufferedImage loadBufferedImageFile(File file) { try { return isFile(file) ? ImageIO.read(file) : null; } catch (Exception __e) { throw rethrow(__e); } } static public String getStackTrace2(Throwable e) { return hideCredentials(getStackTrace(unwrapTrivialExceptionWraps(e)) + replacePrefix("java.lang.RuntimeException: ", "FAIL: ", hideCredentials(str(innerException2(e)))) + "\n"); } static public String snippetImageURL(long snippetID) { return snippetImageURL(fsI(snippetID)); } static public String snippetImageURL(String snippetID) { return snippetImageURL(snippetID, "png"); } static public String snippetImageURL(String snippetID, String contentType) { if (snippetID == null || isURL(snippetID)) return snippetID; long id = parseSnippetID(snippetID); String url; if (isImageServerSnippet(id)) url = imageServerLink(id); else url = "https://botcompany.de/img/" + id; return url; } static public String fileServerURL() { return "https://botcompany.de/files"; } public static File mkdirsFor(File file) { return mkdirsForFile(file); } static public void copyStreamWithPrints(InputStream in, OutputStream out, String pat) { try { byte[] buf = new byte[65536]; int total = 0; while (true) { int n = in.read(buf); if (n <= 0) return; out.write(buf, 0, n); if ((total + n) / 100000 > total / 100000) print(pat.replace("{*}", str(roundDownTo(100000, total)))); total += n; } } catch (Exception __e) { throw rethrow(__e); } } static public File renameFile_assertTrue(File a, File b) { try { if (a.equals(b)) return b; if (!a.exists()) throw fail("Source file not found: " + f2s(a)); if (b.exists()) throw fail("Target file exists: " + f2s(b)); mkdirsForFile(b); if (!a.renameTo(b)) throw fail("Can't rename " + f2s(a) + " to " + f2s(b)); return b; } catch (Exception __e) { throw rethrow(__e); } } static public String regexReplace(String s, String pat, Object f) { Matcher m = Pattern.compile(pat).matcher(s); return regexReplace(m, f); } static public String regexReplace(String s, String pat, String replacement) { return regexpReplace_direct(s, pat, replacement); } static public String regexReplace(Matcher m, Object f) { StringBuffer buf = new StringBuffer(); while (m.find()) m.appendReplacement(buf, m.quoteReplacement(str(callF(f, m)))); m.appendTail(buf); return str(buf); } static public String regexReplace(String s, String pat, IF1 f) { return regexReplace(s, pat, (Object) f); } static public Matcher regexpMatcherIC(String pat, String s) { return compileRegexpIC(pat).matcher(unnull(s)); } static public String regexpReplaceIC_direct(String s, String pat, String replacement) { Matcher m = regexpIC(pat, s); StringBuffer buf = new StringBuffer(); while (m.find()) m.appendReplacement(buf, replacement); m.appendTail(buf); return str(buf); } static public boolean isAllUpperCase(String s) { return hasLettersAllUpperCase(s); } static public boolean isUpperCaseLetter(char c) { return Character.isUpperCase(c); } static public TimeZone getTimeZone(String name) { return TimeZone.getTimeZone(name); } static public String standardTimeZone_name = "Europe/Berlin"; static public String standardTimeZone() { return standardTimeZone_name; } static public boolean isFile(File f) { return f != null && f.isFile(); } static public boolean isFile(String path) { return isFile(newFile(path)); } static public Throwable unwrapTrivialExceptionWraps(Throwable e) { if (e == null) return e; while (e.getClass() == RuntimeException.class && e.getCause() != null && eq(e.getMessage(), str(e.getCause()))) e = e.getCause(); return e; } static public Throwable innerException2(Throwable e) { if (e == null) return null; while (empty(e.getMessage()) && e.getCause() != null) e = e.getCause(); return e; } static public String imageServerLink(String md5OrID) { if (possibleMD5(md5OrID)) return "https://botcompany.de/images/md5/" + md5OrID; return imageServerLink(parseSnippetID(md5OrID)); } static public String imageServerLink(long id) { return "https://botcompany.de/images/" + id; } static public String regexpReplace_direct(String s, String pat, String replacement) { Matcher m = regexp(pat, s); return regexpReplace_direct(m, replacement); } static public String regexpReplace_direct(Matcher m, String replacement) { StringBuffer buf = new StringBuffer(); while (m.find()) m.appendReplacement(buf, replacement); m.appendTail(buf); return str(buf); } static public Matcher regexpIC(Pattern pat, String s) { return pat.matcher(unnull(s)); } static public Matcher regexpIC(String pat, String s) { return compileRegexpIC(pat).matcher(unnull(s)); } static public Pattern regexpIC(String pat) { return compileRegexpIC(pat); } static public boolean hasLettersAllUpperCase(String s) { return hasLetters(s) && !containsLowerCase(s); } static public boolean possibleMD5(String s) { return isMD5(s); } static public boolean hasLetters(String s) { for (int i = 0; i < s.length(); i++) if (Character.isLetter(s.charAt(i))) return true; return false; } static public boolean containsLowerCase(String s) { for (int i = 0; i < l(s); i++) if (isLowerCase(s.charAt(i))) return true; return false; } static public boolean isMD5(String s) { return l(s) == 32 && isLowerHexString(s); } static public boolean isLowerCase(char c) { return Character.isLowerCase(c); } static public boolean isLowerHexString(String s) { for (int i = 0; i < l(s); i++) { char c = s.charAt(i); if (c >= '0' && c <= '9' || c >= 'a' && c <= 'f') { } else return false; } return true; } static public class Chain implements Iterable { public A element; public Chain next; public int size; public Chain() { } public Chain(A element) { this.element = element; size = 1; } public Chain(A element, Chain next) { this.next = next; this.element = element; size = next != null ? next.size + 1 : 1; } public String toString() { return str(toList()); } public ArrayList toList() { ArrayList l = emptyList(size); Chain c = this; while (c != null) { l.add(c.element); c = c.next; } return l; } public Iterator iterator() { return toList().iterator(); } } static public class CompactHashMap extends CompactAbstractMap { final static public int INITIAL_SIZE = 3; final static public double LOAD_FACTOR = 0.6; final static public Object nullObject = new Object(); final static public Object deletedObject = new Object(); public int elements; public int freecells; public Object[] table; public CompactHashMap() { this(INITIAL_SIZE); } public CompactHashMap(int size) { table = new Object[(size == 0 ? 1 : size) * 2]; elements = 0; freecells = tableSize(); } public CompactHashMap(Map map) { this(0); if (map != null) putAll(map); } public synchronized int size() { return elements; } public synchronized boolean isEmpty() { return elements == 0; } public synchronized void clear() { elements = 0; for (int ix = 0; ix < tableSize(); ix++) { key(ix, null); value(ix, null); } freecells = tableSize(); } public synchronized boolean containsKey(Object k) { return key(findKeyIndex(k)) != null; } public synchronized boolean containsValue(Object v) { if (v == null) v = (V) nullObject; for (int ix = 0; ix < tableSize(); ix++) if (value(ix) != null && value(ix).equals(v)) return true; return false; } public synchronized Set> entrySet() { return new EntrySet(); } public synchronized V remove(Object k) { int index = findKeyIndex(k); if (key(index) != null) { V v = value(index); key(index, deletedObject); value(index, deletedObject); elements--; return v; } else return null; } public synchronized V put(K k, V v) { if (k == null) k = (K) nullObject; int hash = k.hashCode(); int index = (hash & 0x7FFFFFFF) % tableSize(); int offset = 1; int deletedix = -1; while (key(index) != null && !(key(index).hashCode() == hash && key(index).equals(k))) { if (key(index) == deletedObject) deletedix = index; index = ((index + offset) & 0x7FFFFFFF) % tableSize(); offset = offset * 2 + 1; if (offset == -1) offset = 2; } if (key(index) == null) { if (deletedix != -1) index = deletedix; else freecells--; elements++; key(index, k); value(index, v); if (1 - (freecells / (double) tableSize()) > LOAD_FACTOR) rehash(tableSize() * 2 + 1); return null; } else { V oldv = value(index); value(index, v); return oldv; } } public void rehash(int newCapacity) { int oldCapacity = tableSize(); Object[] newTable = new Object[newCapacity * 2]; for (int ix = 0; ix < oldCapacity; ix++) { Object k = key(ix); if (k == null || k == deletedObject) continue; int hash = k.hashCode(); int index = (hash & 0x7FFFFFFF) % newCapacity; int offset = 1; while (newTable[index * 2] != null) { index = ((index + offset) & 0x7FFFFFFF) % newCapacity; offset = offset * 2 + 1; if (offset == -1) offset = 2; } newTable[index * 2] = k; newTable[index * 2 + 1] = value(ix); } table = newTable; freecells = tableSize() - elements; } public synchronized V get(Object k) { return value(findKeyIndex(k)); } public synchronized Collection values() { return new ValueCollection(); } public synchronized Set keySet() { return new KeySet(); } final public int findKeyIndex(Object k) { if (k == null) k = nullObject; int hash = k.hashCode(); int index = (hash & 0x7FFFFFFF) % tableSize(); int offset = 1; while (key(index) != null && !(key(index).hashCode() == hash && key(index).equals(k))) { index = ((index + offset) & 0x7FFFFFFF) % tableSize(); offset = offset * 2 + 1; if (offset == -1) offset = 2; } return index; } public class KeySet extends AbstractSet { public int size() { synchronized (CompactHashMap.this) { return elements; } } public boolean contains(Object k) { synchronized (CompactHashMap.this) { return containsKey(k); } } public Iterator iterator() { synchronized (CompactHashMap.this) { return new KeyIterator(); } } } public class KeyIterator implements Iterator { public int ix; public KeyIterator() { synchronized (CompactHashMap.this) { for (; ix < tableSize(); ix++) if (value(ix) != null && key(ix) != deletedObject) break; } } public boolean hasNext() { synchronized (CompactHashMap.this) { return ix < tableSize(); } } public void remove() { throw new UnsupportedOperationException("Collection is read-only"); } public K next() { synchronized (CompactHashMap.this) { if (ix >= tableSize()) throw new NoSuchElementException(); K key = (K) key(ix++); for (; ix < tableSize(); ix++) if (key(ix) != null && key(ix) != deletedObject) break; return key; } } } public class EntrySet extends AbstractSet> { public int size() { synchronized (CompactHashMap.this) { return elements; } } public boolean contains(Object o) { synchronized (CompactHashMap.this) { if (o instanceof Map.Entry) { Object key = ((Map.Entry) o).getKey(); if (!containsKey((Map.Entry) o)) return false; return eq(((Map.Entry) o).getValue(), get(key)); } return false; } } public Iterator> iterator() { return new EntryIterator(); } } public class EntryIterator implements Iterator> { public int ix; public EntryIterator() { synchronized (CompactHashMap.this) { for (; ix < tableSize(); ix++) if (value(ix) != null && key(ix) != deletedObject) break; } } public boolean hasNext() { synchronized (CompactHashMap.this) { return ix < tableSize(); } } public void remove() { throw new UnsupportedOperationException("Collection is read-only"); } public Map.Entry next() { synchronized (CompactHashMap.this) { if (ix >= tableSize()) throw new NoSuchElementException(); K key = key(ix); V val = value(ix); ++ix; for (; ix < tableSize(); ix++) if (key(ix) != null && key(ix) != deletedObject) break; return simpleMapEntry(key, val); } } } public class ValueCollection extends AbstractCollection { public int size() { synchronized (CompactHashMap.this) { return elements; } } public Iterator iterator() { return new ValueIterator(); } public boolean contains(Object v) { return containsValue(v); } } public class ValueIterator implements Iterator { public int ix; public ValueIterator() { synchronized (CompactHashMap.this) { for (; ix < table.length / 2; ix++) if (value(ix) != null && value(ix) != deletedObject) break; } } public boolean hasNext() { synchronized (CompactHashMap.this) { return ix < tableSize(); } } public void remove() { throw new UnsupportedOperationException("Collection is read-only"); } public V next() { synchronized (CompactHashMap.this) { if (ix >= tableSize()) throw new NoSuchElementException(); V value = (V) value(ix++); for (; ix < tableSize(); ix++) if (value(ix) != null && value(ix) != deletedObject) break; return value; } } } public K key(int i) { return (K) table[i * 2]; } public void key(int i, Object key) { table[i * 2] = key; } public V value(int i) { return (V) table[i * 2 + 1]; } public void value(int i, Object value) { table[i * 2 + 1] = value; } public int tableSize() { return table.length / 2; } } static public class DefunctClassLoader { } static public class JS implements IF0, Htmlable { public JS() { } public String code; public Set requiredLibraries; public Set requiredLibraries() { return requiredLibraries; } public JS(String code, Object... dollarVars) { this.code = jsDollarVars(code, dollarVars); } public String get() { return code; } public String toString() { return unnull(code); } public void requireJQuery() { require("jquery"); } public void require(Object library) { requiredLibraries = addToSet_create(requiredLibraries, library); } public String html() { return hjs(code); } } static public class GazelleV_LeftArrowScriptParser extends SimpleLeftToRightParser { public ClassNameResolver classNameResolver; public List functionContainers = new ArrayList(); final public GazelleV_LeftArrowScriptParser setLasClassLoader(ILASClassLoader lasClassLoader) { return lasClassLoader(lasClassLoader); } public GazelleV_LeftArrowScriptParser lasClassLoader(ILASClassLoader lasClassLoader) { this.lasClassLoader = lasClassLoader; return this; } final public ILASClassLoader getLasClassLoader() { return lasClassLoader(); } public ILASClassLoader lasClassLoader() { return lasClassLoader; } public ILASClassLoader lasClassLoader; final public GazelleV_LeftArrowScriptParser setClassDefPrefix(String classDefPrefix) { return classDefPrefix(classDefPrefix); } public GazelleV_LeftArrowScriptParser classDefPrefix(String classDefPrefix) { this.classDefPrefix = classDefPrefix; return this; } final public String getClassDefPrefix() { return classDefPrefix(); } public String classDefPrefix() { return classDefPrefix; } public String classDefPrefix; final public GazelleV_LeftArrowScriptParser setOptimize(boolean optimize) { return optimize(optimize); } public GazelleV_LeftArrowScriptParser optimize(boolean optimize) { this.optimize = optimize; return this; } final public boolean getOptimize() { return optimize(); } public boolean optimize() { return optimize; } public boolean optimize = true; final public GazelleV_LeftArrowScriptParser setUseFixedVarContexts(boolean useFixedVarContexts) { return useFixedVarContexts(useFixedVarContexts); } public GazelleV_LeftArrowScriptParser useFixedVarContexts(boolean useFixedVarContexts) { this.useFixedVarContexts = useFixedVarContexts; return this; } final public boolean getUseFixedVarContexts() { return useFixedVarContexts(); } public boolean useFixedVarContexts() { return useFixedVarContexts; } public boolean useFixedVarContexts = false; public LASScope scope; public LinkedHashMap knownVars = new LinkedHashMap(); public List varAccessesToFix = new ArrayList(); public Set closerTokens = litset(";", "}", ")"); public BuildingScript currentReturnableScript; public BuildingScript currentLoop; public boolean inParens = false; public int idCounter; public Map classDefs = new HashMap(); transient public Set>> onKnownVarsSnapshot; public GazelleV_LeftArrowScriptParser onKnownVarsSnapshot(IVF1> f) { onKnownVarsSnapshot = createOrAddToSyncLinkedHashSet(onKnownVarsSnapshot, f); return this; } public GazelleV_LeftArrowScriptParser removeKnownVarsSnapshotListener(IVF1> f) { main.remove(onKnownVarsSnapshot, f); return this; } public void knownVarsSnapshot(Map knownVars) { if (onKnownVarsSnapshot != null) for (var listener : onKnownVarsSnapshot) pcallF_typed(listener, knownVars); } static public class MethodOnObject implements IFieldsToList { static final public String _fieldOrder = "object method"; public Object object; public String method; public MethodOnObject() { } public MethodOnObject(Object object, String method) { this.method = method; this.object = object; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + object + ", " + method + ")"; } public boolean equals(Object o) { if (!(o instanceof MethodOnObject)) return false; MethodOnObject __15 = (MethodOnObject) o; return eq(object, __15.object) && eq(method, __15.method); } public int hashCode() { int h = 791808543; h = boostHashCombine(h, _hashCode(object)); h = boostHashCombine(h, _hashCode(method)); return h; } public Object[] _fieldsToList() { return new Object[] { object, method }; } } static public class EvaluableWrapper implements IFieldsToList { public GazelleV_LeftArrowScript.Evaluable expr; public EvaluableWrapper() { } public EvaluableWrapper(GazelleV_LeftArrowScript.Evaluable expr) { this.expr = expr; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + expr + ")"; } public boolean equals(Object o) { if (!(o instanceof EvaluableWrapper)) return false; EvaluableWrapper __16 = (EvaluableWrapper) o; return eq(expr, __16.expr); } public int hashCode() { int h = 700525824; h = boostHashCombine(h, _hashCode(expr)); return h; } public Object[] _fieldsToList() { return new Object[] { expr }; } } public class BuildingScript { public int id = ++idCounter; final public BuildingScript setReturnable(boolean returnable) { return returnable(returnable); } public BuildingScript returnable(boolean returnable) { this.returnable = returnable; return this; } final public boolean getReturnable() { return returnable(); } public boolean returnable() { return returnable; } public boolean returnable = false; final public BuildingScript setIsLoopBody(boolean isLoopBody) { return isLoopBody(isLoopBody); } public BuildingScript isLoopBody(boolean isLoopBody) { this.isLoopBody = isLoopBody; return this; } final public boolean getIsLoopBody() { return isLoopBody(); } public boolean isLoopBody() { return isLoopBody; } public boolean isLoopBody = false; public BuildingScript returnableParent, loopParent; final public BuildingScript setScope(LASScope scope) { return scope(scope); } public BuildingScript scope(LASScope scope) { this.scope = scope; return this; } final public LASScope getScope() { return scope(); } public LASScope scope() { return scope; } public LASScope scope; public GazelleV_LeftArrowScript.Script script = new GazelleV_LeftArrowScript.Script(); public List steps = new ArrayList(); public Map functionDefs = new HashMap(); public BuildingScript(boolean returnable) { this(); this.returnable = returnable; } public BuildingScript(boolean returnable, boolean isLoopBody) { this(); this.isLoopBody = isLoopBody; this.returnable = returnable; } public BuildingScript() { scope = currentScope(); } public void add(GazelleV_LeftArrowScript.Evaluable step) { if (step != null) steps.add(step); } public GazelleV_LeftArrowScript.Evaluable get() { script.scope = scope; var lastStep = last(steps); if (lastStep instanceof GazelleV_LeftArrowScript.ReturnFromScript) if (((GazelleV_LeftArrowScript.ReturnFromScript) lastStep).script == script) replaceLast(steps, ((GazelleV_LeftArrowScript.ReturnFromScript) lastStep).value); if (!returnable && l(steps) == 1 && empty(functionDefs)) return first(steps); if (nempty(functionDefs)) script.functionDefs = functionDefs; script.steps = toTypedArray(GazelleV_LeftArrowScript.Evaluable.class, steps); return script; } public String toStringLong() { return pnlToLines(steps); } public String toString() { return formatRecordVars("BuildingScript", "id", id, "returnable", returnable, "returnableParent", returnableParent, "script", script); } } public GazelleV_LeftArrowScript.Script parse(String text) { setText(text); init(); return parse(); } public GazelleV_LeftArrowScript.Script parse() { GazelleV_LeftArrowScript.Script script = parseReturnableScript(); for (var varAccess : varAccessesToFix) varAccess.resolve(); if (optimize) script = script.optimizeScript(); return script; } public GazelleV_LeftArrowScript.Script parseReturnableScript() { return (GazelleV_LeftArrowScript.Script) parseScript(new BuildingScript().returnable(true)); } public GazelleV_LeftArrowScript.Evaluable parseScript(BuildingScript script) { return linkToSrc(() -> { script.returnableParent = currentReturnableScript; script.loopParent = currentLoop; if (script.returnable) currentReturnableScript = script; if (script.isLoopBody) currentLoop = script; return parseBuildingScript(script); }); } public GazelleV_LeftArrowScript.Evaluable parseBuildingScript(BuildingScript script) { try { parseScript_2(script); var builtScript = script.get(); currentReturnableScript = script.returnableParent; currentLoop = script.loopParent; return builtScript; } catch (Throwable e) { if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("Parsed so far:\n" + script); throw rethrowAndAppendToMessage(e, squareBracketed(str(lineAndColumn(-1)))); } } public void parseScript_2(BuildingScript script) { AutoCloseable __6 = tempRestoreMap(knownVars); try { AssureAdvance assure = new AssureAdvance(); while (assure.get()) { knownVarsSnapshot(knownVars); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("parseScript_2: Next token is " + quote(token())); if (is(";")) { next(); continue; } if (isOneOf("}", ")")) break; GazelleV_LeftArrowScript.Evaluable instruction = linkToSrc(() -> parseInstruction(script)); if (instruction != null) script.add(instruction); } if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("parseScript_2 done"); knownVarsSnapshot(knownVars); } finally { _close(__6); } } public GazelleV_LeftArrowScript.Evaluable parseInstruction(BuildingScript script) { if (is("def")) { parseFunctionDefinition(currentReturnableScript.functionDefs); return null; } if (is("param")) { consume(); String var = assertIdentifier(tpp()); LASValueDescriptor valueDescriptor = new LASValueDescriptor(); if (is(":")) { var type = parseColonType(); valueDescriptor = LASValueDescriptor.nonExactCanBeNull(type); } knownVars.put(var, valueDescriptor); return null; } if (is("throw")) { consume(); return new GazelleV_LeftArrowScript.Throw(parseExpr()); } if (is("try")) { consume(); GazelleV_LeftArrowScript.Evaluable body = parseCurlyBlock(new BuildingScript()); consume("catch"); String var = consumeIdentifier(); AutoCloseable __7 = tempAddKnownVars(var); try { GazelleV_LeftArrowScript.Evaluable catchBlock = parseCurlyBlock(new BuildingScript()); return new GazelleV_LeftArrowScript.TryCatch(body, var, catchBlock); } finally { _close(__7); } } if (isOneOf("return", "ret")) { consume(); GazelleV_LeftArrowScript.Evaluable expr; if (atCmdEnd()) expr = _const(null); else expr = parseAssignmentOrExpr(); return new GazelleV_LeftArrowScript.ReturnFromScript(currentReturnableScript.script, expr); } if (is("continue")) { consume(); assertCmdEnd(); if (currentLoop == null) throw fail("continue outside of loop"); return new GazelleV_LeftArrowScript.Continue(currentLoop.script); } if (is("temp")) { consume(); GazelleV_LeftArrowScript.Evaluable tempExpr = parseExpr(); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("tempExpr", tempExpr); GazelleV_LeftArrowScript.Evaluable body = parseScript(new BuildingScript()); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("body", body); return new GazelleV_LeftArrowScript.TempBlock(tempExpr, body); } if (is("class")) return new GazelleV_LeftArrowScript.ClassDef(new ResolvableLASClass(lasClassLoader, parseClassDef())); return parseAssignmentOrExpr(); } public GazelleV_LeftArrowScript.Evaluable parseAssignmentOrExpr() { { var __3 = parseAssignmentOpt(); if (__3 != null) return __3; } return parseExpr(); } public GazelleV_LeftArrowScript.Evaluable parseAssignmentOpt() { String t = token(); if (isIdentifier(t) && eq(token(1), "<") && eq(token(2), "-")) { if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("Found assignment"); next(3); GazelleV_LeftArrowScript.Evaluable rhs = parseExpr(); assertNotNull("Expression expected", rhs); boolean newVar = !knownVars.containsKey(t); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) printVars("newVar", newVar, "t", t, "knownVars", knownVars); knownVars.put(t, new LASValueDescriptor()); return newVar ? new GazelleV_LeftArrowScript.VarDeclaration(t, null, rhs) : new GazelleV_LeftArrowScript.Assignment(t, rhs); } return null; } public GazelleV_LeftArrowScript.Evaluable parseOptionalInnerExpression() { if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) printVars("parseOptionalInnerExpression", "token", token()); if (atCmdEnd() || isOneOf("{", ",")) return null; return parseInnerExpr(); } public GazelleV_LeftArrowScript.Evaluable _const(Object o) { return new GazelleV_LeftArrowScript.Const(o); } public GazelleV_LeftArrowScript.Evaluable parseInnerExpr() { return parseExpr(true); } public GazelleV_LeftArrowScript.Evaluable parseExpr() { if (metaGet("scaffolding") != null) scaffoldCalled(this, "parseExpr"); return parseExpr(false); } public GazelleV_LeftArrowScript.Evaluable parseExpr(boolean inner) { GazelleV_LeftArrowScript.Evaluable e = linkToSrc(() -> inner ? parseExpr_impl(true) : parseFullExpr()); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("parseExpr done:\n" + GazelleV_LeftArrowScript.indentedScriptStruct(e)); return e; } public GazelleV_LeftArrowScript.Evaluable parseFullExpr() { return parseExprPlusOptionalComma(); } public GazelleV_LeftArrowScript.Evaluable parseExprPlusOptionalComma() { GazelleV_LeftArrowScript.Evaluable expr = parseExpr_impl(false); while (consumeOpt(",")) { expr = parseCall_noCmdEndCheck(expr); } return expr; } public GazelleV_LeftArrowScript.Evaluable parseExpr_impl(boolean inner) { if (atEnd()) return null; String t = token(); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) printVars("parseExpr", "token", t); if (is(";")) return null; if (is("{")) return parseCurlyBlock(new BuildingScript()); if (is("-") && empty(nextSpace()) && startsWithDigit(token(1)) || startsWithDigit(t)) { var e = parseNumberLiteral(); return inner ? e : parseCall(e); } if (isQuoted(t)) { consume(); var e = _const(unquote(t)); return inner ? e : parseCall(e); } if (startsWith(t, '\'')) { consume(); var e = _const(first(unquote(t))); return inner ? e : parseCall(e); } if (isIdentifier(t)) { if (is("while")) return parseWhileLoop(); if (is("for")) return parseForEach(); if (is("if")) return parseIfStatement(); if (is("repeat")) return parseRepeatStatement(); if (is("outer")) { consume(); var a = parseAssignmentOpt(); if (!(a instanceof GazelleV_LeftArrowScript.Assignment)) throw fail("Assignment expected"); return new GazelleV_LeftArrowScript.AssignmentToOuterVar(((GazelleV_LeftArrowScript.Assignment) a).var, ((GazelleV_LeftArrowScript.Assignment) a).expression); } consume(); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("Consumed identifier " + t + ", next token: " + token() + ", inner: " + inner); return parseExprStartingWithIdentifier(t, inner); } if (eq(t, "(")) { boolean inParensOld = inParens; inParens = true; consume(); var e = parseExpr(); consume(")"); inParens = inParensOld; return inner ? e : parseCall(e); } if (isOneOf("&", "|") && empty(nextSpace()) && is(1, token())) { return parseBinaryOperator(); } throw fail("Identifier, literal, operator or opening parentheses expected (got: " + quote(t)); } public GazelleV_LeftArrowScript.Evaluable parseNumberLiteral() { String t = consumeMultiTokenLiteral(); if (swic(t, "0x")) return _const(parseHexInt(dropFirst(t, 2))); if (swic(t, "0b")) return _const(intFromBinary(dropFirst(t, 2))); if (isInteger(t)) return _const(parseInt(t)); if (endsWith(t, "f")) return _const(parseFloat(t)); if (endsWith(t, "L")) return _const(parseLong(t)); return _const(parseDouble(t)); } public GazelleV_LeftArrowScript.Evaluable parseBinaryOperator() { boolean and = is("&"); next(2); GazelleV_LeftArrowScript.Evaluable a = parseInnerExpr(); GazelleV_LeftArrowScript.Evaluable b = parseInnerExpr(); return and ? new GazelleV_LeftArrowScript.BoolAnd(a, b) : new GazelleV_LeftArrowScript.BoolOr(a, b); } public boolean qualifiedNameContinues() { return empty(prevSpace()) && eq(token(), ".") && empty(nextSpace()) && isIdentifier(token(1)); } public GazelleV_LeftArrowScript.Evaluable parseExprStartingWithIdentifier(String t, boolean inner) { if (eq(t, "true")) return _const(true); if (eq(t, "false")) return _const(false); if (eq(t, "null")) return _const(null); if (eq(t, "new")) { String className = assertIdentifier(tpp()); parseTypeArguments(null); LASClassDef cd = classDefs.get(className); if (cd != null) return new GazelleV_LeftArrowScript.NewObject_LASClass(new ResolvableLASClass(lasClassLoader, cd)); var type = knownVars.get(className); if (type != null) return new GazelleV_LeftArrowScript.NewObject_UnknownClass(new GazelleV_LeftArrowScript.GetVar(className), parseArguments()); Object o = findExternalObject(className); if (o instanceof Class) { Class c = (Class) o; if (c == List.class) c = ArrayList.class; else if (c == Map.class) c = HashMap.class; else if (c == Set.class) c = HashSet.class; return new GazelleV_LeftArrowScript.NewObject(c, parseArguments()); } throw new ClassNotFound(className); } if (scope != null && scope.useFixedVars) { var type = scope.declaredVars.get(t); if (type != null) { var e = new GazelleV_LeftArrowScript.GetFixedVar(scope, t); e.scope(scope); e.returnType(type); varAccessesToFix.add(e); return inner ? e : parseCall(e); } } var type = knownVars.get(t); if (type != null) { var e = new GazelleV_LeftArrowScript.GetVar(t).returnType(type); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("Found var acccess: " + e + ", " + (!inner ? "Checking for call" : "Returning expression")); return inner ? e : parseCall(e); } if (!inner) { var fdef = lookupFunction(t); if (fdef != null) return new GazelleV_LeftArrowScript.CallFunction(fdef, parseArguments()); } if (eq(t, "_context")) return new GazelleV_LeftArrowScript.GetVarContext(); Object o = findExternalObject(t); if (o == null) { throw new UnknownObject(t); } else if (o instanceof EvaluableWrapper) { return inner ? ((EvaluableWrapper) o).expr : parseCall(((EvaluableWrapper) o).expr); } else if (inner) return _const(o); else if (o instanceof Class) { return parseExprStartingWithClass((Class) o); } else if (o instanceof MethodOnObject) { if (inner) throw fail("Can't call methods in arguments"); return new GazelleV_LeftArrowScript.CallMethod(_const(((MethodOnObject) o).object), ((MethodOnObject) o).method, parseArguments()); } else return parseCall(_const(o)); } public GazelleV_LeftArrowScript.Evaluable parseExprStartingWithClass(Class c) { if (atCmdEnd()) return _const(c); if (is("(")) return new GazelleV_LeftArrowScript.NewObject(c, parseArguments()); { var __4 = parseLambdaOpt(c); if (__4 != null) return __4; } if (isIdentifier()) { String name = tpp(); if (hasStaticMethodNamed(c, name)) return new GazelleV_LeftArrowScript.CallMethod(_const(c), name, parseArguments()); if (isInterface(c)) return parseLambdaMethodRef(c, name); var field = getField(c, name); if (field != null) { assertCmdEnd(); if (!isStaticField(field)) throw fail(field + " is not a static field"); return new GazelleV_LeftArrowScript.GetStaticField(field); } throw fail(name + " not found in " + c + " (looked for method or field)"); } else throw fail("Method name expected: " + token()); } public GazelleV_LeftArrowScript.Evaluable parseLambdaOpt(Class c) { int nArgs = 0; while (isIdentifier(token(nArgs))) nArgs++; if (!(is(nArgs, "-") && is(nArgs + 1, ">"))) return null; String[] argNames = consumeArray(nArgs); AutoCloseable __8 = tempAddKnownVars(argNames); try { skip(2); GazelleV_LeftArrowScript.Evaluable body; if (is("{")) body = parseReturnableScript(); else body = parseExpr(); var lambda = new GazelleV_LeftArrowScript.LambdaDef(c, argNames, body); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("parseLambdaOpt done:\n" + GazelleV_LeftArrowScript.indentedScriptStruct(lambda)); return lambda; } finally { _close(__8); } } public GazelleV_LeftArrowScript.Evaluable parseLambdaMethodRef(Class c, String name) { var fdef = lookupFunction(name); if (fdef != null) { GazelleV_LeftArrowScript.Evaluable[] curriedArguments = parseArguments(); return new GazelleV_LeftArrowScript.CurriedScriptFunctionLambda(c, fdef, curriedArguments); } Object function = findExternalObject(name); if (function == null) throw new UnknownObject(name); if (function instanceof MethodOnObject) { Object target = ((MethodOnObject) function).object; String targetMethod = ((MethodOnObject) function).method; GazelleV_LeftArrowScript.Evaluable[] curriedArguments = parseArguments(); return new GazelleV_LeftArrowScript.CurriedMethodLambda(c, target, targetMethod, curriedArguments); } else if (function instanceof Class) { Class c2 = (Class) function; assertCmdEnd(); var ctors = constructorsWithNumberOfArguments(c2, 1); if (empty(ctors)) throw fail("No single argument constructor found in " + c2); return new GazelleV_LeftArrowScript.CurriedConstructorLambda(c, toArray(Constructor.class, ctors), null); } else throw fail(function + " is not an instantiable class or callable method"); } public GazelleV_LeftArrowScript.FunctionDef lookupFunction(String name) { var script = currentReturnableScript; while (script != null) { var f = script.functionDefs.get(name); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) printVars("lookupFunction", "script", script, "name", name, "f", f); if (f != null) return f; script = script.returnableParent; } return null; } public GazelleV_LeftArrowScript.Evaluable[] parseArguments() { return toArrayOrNull(GazelleV_LeftArrowScript.Evaluable.class, parseArgumentsAsList()); } public List parseArgumentsAsList() { List l = new ArrayList(); try { while (true) { if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("parseArgumentsAsList: token is " + quote(t())); if (consumeOpt("<")) { GazelleV_LeftArrowScript.Evaluable a = parseFullExpr(); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("parseArgumentsAsList: token after expr is " + quote(t())); if (a == null) throw fail("expression expected"); l.add(a); break; } GazelleV_LeftArrowScript.Evaluable a = parseOptionalInnerExpression(); if (a == null) break; l.add(a); } return l; } catch (Throwable _e) { if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("Arguments parsed so far: " + l); throw rethrow(_e); } } public String consumeMultiTokenLiteral() { return consumeUntilSpaceOr(() -> atCmdEnd() || is(",")); } public boolean atCmdEnd() { return !inParens && atEndOrLineBreak() || closerTokens.contains(token()); } public void assertCmdEnd() { if (!atCmdEnd()) throw fail("Expected end of command, token is: " + quote(token())); } public GazelleV_LeftArrowScript.Evaluable parseCall(GazelleV_LeftArrowScript.Evaluable target) { if (atCmdEnd()) return target; return parseCall_noCmdEndCheck(target); } public GazelleV_LeftArrowScript.Evaluable parseCall_noCmdEndCheck(GazelleV_LeftArrowScript.Evaluable target) { if (!isIdentifier()) return target; var start = ptr(); String name = tpp(); if (eq(token(), "<") && eq(token(1), "-")) { next(2); GazelleV_LeftArrowScript.Evaluable rhs = parseExpr(); return new GazelleV_LeftArrowScript.SetField(target, name, rhs); } var args = parseArguments(); if (nempty(args)) return new GazelleV_LeftArrowScript.CallMethod(target, name, args); else return linkToSrc(start, new GazelleV_LeftArrowScript.CallMethodOrGetField(target, name)); } public A linkToSrc(ListAndIndex start, A a) { if (a instanceof IHasTokenRangeWithSrc) ((IHasTokenRangeWithSrc) a).setTokenRangeWithSrc(new TokenRangeWithSrc(start, ptr().plus(-1))); return a; } public A linkToSrc(IF0 a) { var start = ptr(); return linkToSrc(start, a.get()); } transient public IF1 findExternalObject; public Object findExternalObject(String name) { return findExternalObject != null ? findExternalObject.get(name) : findExternalObject_base(name); } final public Object findExternalObject_fallback(IF1 _f, String name) { return _f != null ? _f.get(name) : findExternalObject_base(name); } public Object findExternalObject_base(String name) { { var __5 = parsePrimitiveType(name); if (__5 != null) return __5; } if (qualifiedNameContinues()) { int idx = idx() - 2; do next(2); while (qualifiedNameContinues()); String fqn = joinSubList(tok, idx, idx() - 1); return classForName(fqn); } String fullName = globalClassNames().get(name); if (fullName != null) return classForName(fullName); for (var container : unnullForIteration(functionContainers)) { if (hasMethodNamed(container, name)) return new MethodOnObject(container, name); var field = getField(container, name); if (field != null && isStaticField(field)) return new EvaluableWrapper(new GazelleV_LeftArrowScript.GetStaticField(field)); } return null; } public GazelleV_LeftArrowScriptParser allowTheWorld() { return allowTheWorld(mc()); } public GazelleV_LeftArrowScriptParser allowTheWorld(Object... functionContainers) { for (Object o : unnullForIteration(reversed(functionContainers))) if (!contains(this.functionContainers, o)) { this.functionContainers.add(0, o); globalClassNames_cache = null; } return this; } public void printFunctionDefs(GazelleV_LeftArrowScript.Script script) { if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print(values(script.functionDefs)); } public AutoCloseable tempAddKnownVars(String... vars) { return tempAddKnownVars(asList(vars)); } public AutoCloseable tempAddKnownVars(Iterable vars) { var newVars = mapWithSingleValue(vars, new LASValueDescriptor()); if (scope != null) for (var __1 : _entrySet(newVars)) { var name = __1.getKey(); var type = __1.getValue(); scope.addDeclaredVar(name, type); } return tempMapPutAll(knownVars, newVars); } public GazelleV_LeftArrowScript.FunctionDef parseFunctionDefinition(Map functionDefsToAddTo) { consume("def"); String functionName = assertIdentifier(tpp()); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("parseFunctionDefinition " + functionName); List args = new ArrayList(); while (isIdentifier()) args.add(tpp()); var scope = newScope(); scope.useFixedVars(useFixedVarContexts); AutoCloseable __9 = tempScope(scope); try { AutoCloseable __10 = tempAddKnownVars(args); try { if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("Parsing function body"); var functionBody = parseReturnableCurlyBlock(); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("Defined function " + functionName + ", adding to " + functionDefsToAddTo); var fd = new GazelleV_LeftArrowScript.FunctionDef(functionName, args, functionBody); fd.scope(scope); { if (functionDefsToAddTo != null) functionDefsToAddTo.put(functionName, fd); } return fd; } finally { _close(__10); } } finally { _close(__9); } } public LASScope newScope() { return new LASScope(scope); } public LASScope currentScope() { return scope; } public AutoCloseable tempScope(LASScope scope) { var oldScope = currentScope(); this.scope = scope; return () -> { scope.resolve(); this.scope = oldScope; }; } public GazelleV_LeftArrowScript.Script parseReturnableCurlyBlock() { return (GazelleV_LeftArrowScript.Script) parseCurlyBlock(new BuildingScript().returnable(true)); } public GazelleV_LeftArrowScript.Evaluable parseCurlyBlock(BuildingScript script) { consume("{"); boolean inParensOld = inParens; inParens = false; var body = parseScript(script); consume("}"); inParens = inParensOld; return body; } public GazelleV_LeftArrowScript.Evaluable parseWhileLoop() { consume("while"); var condition = parseExpr(); var body = parseCurlyBlock(new BuildingScript().isLoopBody(true)); return new GazelleV_LeftArrowScript.While(condition, body); } public GazelleV_LeftArrowScript.Evaluable parseForEach() { return new ParseForEach().get(); } public class ParseForEach { public GazelleV_LeftArrowScript.Evaluable collection, body; public IF0 finish; public Set vars = new HashSet(); public String addVar(String var) { return addAndReturn(vars, var); } public String consumeVar() { return addVar(consumeIdentifier()); } public void parseBody() { AutoCloseable __11 = tempAddKnownVars(vars); try { body = parseCurlyBlock(new BuildingScript().isLoopBody(true)); } finally { _close(__11); } } public GazelleV_LeftArrowScript.Evaluable get() { consume("for"); if (is(1, "to")) { String var = consumeVar(); consume("to"); GazelleV_LeftArrowScript.Evaluable endValue = parseExpr(); parseBody(); return new GazelleV_LeftArrowScript.ForIntTo(endValue, var, body); } int iIn = relativeIndexOf("in"); if (iIn < 0) throw fail("for without in"); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("iIn", iIn); if (iIn == 1) { String var = consumeVar(); finish = () -> new GazelleV_LeftArrowScript.ForEach(collection, var, body); } else if (iIn == 2) { if (consumeOpt("iterator")) { String var = consumeVar(); finish = () -> new GazelleV_LeftArrowScript.ForIterator(collection, var, body); } else if (consumeOpt("nested")) { String var = consumeVar(); finish = () -> new GazelleV_LeftArrowScript.ForNested(collection, var, body); } else throw fail("Unknown pattern for 'for' loop"); } else if (iIn == 3) { if (isOneOf("pair", "Pair")) { consume(); String varA = consumeVar(); String varB = consumeVar(); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) printVars("varA", varA, "varB", varB); finish = () -> new GazelleV_LeftArrowScript.ForPairs(collection, body, varA, varB); } else { String varA = consumeVar(); consume(","); String varB = consumeVar(); finish = () -> new GazelleV_LeftArrowScript.ForKeyValue(collection, body, varA, varB); } } else if (iIn == 4) { consume("index"); String varIndex = consumeVar(); consume(","); String varElement = consumeVar(); finish = () -> new GazelleV_LeftArrowScript.ForIndex(collection, body, varIndex, varElement); } else throw fail("Unknown pattern for 'for' loop"); consume("in"); collection = parseExpr(); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print("collection", collection); parseBody(); return finish.get(); } } public GazelleV_LeftArrowScript.Evaluable parseIfStatement() { consume("if"); GazelleV_LeftArrowScript.Evaluable condition, body, elseBranch = null; { AutoCloseable __12 = tempAdd(closerTokens, "then"); try { condition = parseExpr(); } finally { _close(__12); } } if (consumeOpt("then")) { AutoCloseable __13 = tempAdd(closerTokens, "else"); try { body = parseExpr(); if (consumeOpt("else")) elseBranch = parseExpr(); } finally { _close(__13); } } else { body = parseCurlyBlock(new BuildingScript()); if (consumeOpt("else")) { if (is("if")) elseBranch = parseIfStatement(); else elseBranch = parseCurlyBlock(new BuildingScript()); } } return new GazelleV_LeftArrowScript.IfThen(condition, body, elseBranch); } public GazelleV_LeftArrowScript.Evaluable parseRepeatStatement() { consume("repeat"); var n = parseExpr(); var body = parseCurlyBlock(new BuildingScript()); return new GazelleV_LeftArrowScript.RepeatN(n, body); } public void addVar(String var) { addVar(var, new LASValueDescriptor()); } public void addVar(String var, LASValueDescriptor type) { knownVars.put(var, type); } public void addVar(String var, Class type, boolean canBeNull) { addVar(var, new LASValueDescriptor.NonExact(type, canBeNull)); } public Map globalClassNames_cache; public Map globalClassNames() { if (globalClassNames_cache == null) globalClassNames_cache = globalClassNames_load(); return globalClassNames_cache; } public Map globalClassNames_load() { var packages = mapToTreeSet(importedPackages(), pkg -> pkg + "."); Map out = new HashMap(); for (var fc : functionContainers) if (fc instanceof Class) { if (isAnonymousClass((Class) fc)) continue; out.put(shortClassName((Class) fc), className((Class) fc)); } var classContainers = classContainerPrefixes(); TreeSet classContainerSet = asTreeSet(classContainers); out.put("List", "java.util.List"); for (var className : classNameResolver().allFullyQualifiedClassNames()) { if (isAnonymousClassName(className)) continue; if (!contains(className, '$')) { String pkg = longestPrefixInTreeSet(className, packages); if (pkg != null) { String shortName = dropPrefix(pkg, className); if (!shortName.contains(".") && !out.containsKey(shortName)) out.put(shortName, className); } } String container = longestPrefixInTreeSet(className, classContainerSet); if (container != null) { String shortName = dropPrefix(container, className); String existing = out.get(shortName); if (existing != null) { int priority = indexOf(classContainers, container); String oldContainer = longestPrefixInTreeSet(existing, classContainerSet); int oldPriority = indexOf(classContainers, oldContainer); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) printVars("className", className, "shortName", shortName, "container", container, "priority", priority, "existing", existing, "oldPriority", oldPriority); if (priority > oldPriority) continue; } out.put(shortName, className); } } for (var __0 : _entrySet(javaxClassShortcuts())) { var key = __0.getKey(); var val = __0.getValue(); String fullName = out.get(val); if (fullName != null) out.put(key, fullName); } return out; } transient public IF0> importedPackages; public Collection importedPackages() { return importedPackages != null ? importedPackages.get() : importedPackages_base(); } final public Collection importedPackages_fallback(IF0> _f) { return _f != null ? _f.get() : importedPackages_base(); } public Collection importedPackages_base() { return itemPlus("java.lang", standardImports_fullyImportedPackages()); } public void addClassAlias(String alias, String longName) { String fullName = globalClassNames().get(longName); if (fullName != null) globalClassNames().put(alias, fullName); } public List classContainerPrefixes() { return map(functionContainers, fc -> className(fc) + "$"); } static public class UnknownObject extends RuntimeException implements IFieldsToList { public String name; public UnknownObject() { } public UnknownObject(String name) { this.name = name; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + name + ")"; } public Object[] _fieldsToList() { return new Object[] { name }; } public String getMessage() { return "Unknown object: " + name; } } static public class ClassNotFound extends UnknownObject { public ClassNotFound(String className) { super(className); } public String getMessage() { return "Class not found: " + name; } } public LASClassDef parseClassDef() { consume("class"); LASClassDef classDef = new LASClassDef(); classDef.verbose(scaffoldingEnabled()); if (nempty(classDefPrefix)) classDef.classDefPrefix(classDefPrefix); String name = consumeIdentifier(); classDef.userGivenName(name); consume("{"); while (!is("}")) { if (is(";")) { next(); continue; } if (is("def")) { AutoCloseable __14 = tempAddKnownVars("this"); try { GazelleV_LeftArrowScript.FunctionDef fd = parseFunctionDefinition(null); if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) printVars("knownVarsAfterFunctionDef", knownVars); classDef.methods.add(fd); continue; } finally { _close(__14); } } LASClassDef.FieldDef fd = new LASClassDef.FieldDef(); fd.name(consumeIdentifier()); var type = parseColonType(); fd.type(type); classDef.fields.add(fd); } consume("}"); classDefs.put(name, classDef); return classDef; } public Type parseColonType() { consume(":"); String typeName = consumeIdentifier(); Object type = findExternalObject(typeName); if (!(type instanceof Class)) throw fail("Class not found: " + typeName); return parseTypeArguments((Type) type); } public Type parseTypeArguments(Type type) { if (is("<") && isIdentifier(token(1))) { next(); Object arg = findExternalObject(consume()); consume(">"); if (!(arg instanceof Class)) throw fail("Class not found: " + arg); if (type != null) type = new ParameterizedTypeImpl(null, type, (Class) arg); } return type; } transient public IF1 classForName; public Class classForName(String name) { return classForName != null ? classForName.get(name) : classForName_base(name); } final public Class classForName_fallback(IF1 _f, String name) { return _f != null ? _f.get(name) : classForName_base(name); } public Class classForName_base(String name) { try { return Class.forName(name); } catch (Exception __e) { throw rethrow(__e); } } public void copyFunctionContainersFrom(GazelleV_LeftArrowScriptParser parser) { functionContainers = cloneList(parser.functionContainers); globalClassNames_cache = parser.globalClassNames(); } public ClassNameResolver classNameResolver() { if (classNameResolver == null) classNameResolver = new ClassNameResolver().byteCodePath(assertNotNull(getBytecodePathForClass(this))).init(); return classNameResolver; } public GazelleV_LeftArrowScriptParser classNameResolver(ClassNameResolver classNameResolver) { this.classNameResolver = classNameResolver; return this; } } static public class Complex implements IFieldsToList { static final public String _fieldOrder = "re im"; public double re; public double im; public Complex() { } public Complex(double re, double im) { this.im = im; this.re = re; } public boolean equals(Object o) { if (!(o instanceof Complex)) return false; Complex __1 = (Complex) o; return re == __1.re && im == __1.im; } public int hashCode() { int h = -1679819632; h = boostHashCombine(h, _hashCode(re)); h = boostHashCombine(h, _hashCode(im)); return h; } public Object[] _fieldsToList() { return new Object[] { re, im }; } public double abs() { return sqrt(re * re + im * im); } public double re() { return re; } public double im() { return im; } final public double angle() { return phase(); } public double phase() { return Math.atan2(im, re); } public double fracAngle() { return fracNonNeg(angle() / twoPi()); } public String toString() { if (im != 0) return re == 0 ? im + "i" : re + plusPrefixUnlessMinus(str(im)) + "i"; else return str(re); } } static public class CountingOutputStream extends FilterOutputStream { public long counter; public CountingOutputStream(OutputStream out) { super(out); } @Override public void write(int b) throws IOException { ++counter; out.write(b); } @Override public void write(byte[] b) throws IOException { counter += b.length; out.write(b, 0, b.length); } @Override public void write(byte[] b, int off, int len) throws IOException { if (len == 0) return; counter += len; out.write(b, off, len); } public long getFilePointer() { return counter; } } static public class DefaultValueConverterForField implements ValueConverterForField { public OrError convertValue(Object object, Field field, Object value) { Class actualType = field.getType(); Class type = primitiveToBoxedTypeOpt(actualType); if (isInstance(type, value)) return new OrError(value); if (type == Integer.class && !(value instanceof Integer)) return new OrError(toInt(trimIfString(value))); if (type == Double.class && !(value instanceof Double)) return new OrError(toDouble(trimIfString(value))); if (type == Boolean.class && value instanceof String) if (actualType == Boolean.class && eq(value, "")) return new OrError(null); else return new OrError(eqicOneOf((String) value, "1", "true", "yes")); return new OrError(value); } } static public class BetterThreadLocal { public Map map = newWeakHashMap(); public BetterThreadLocal() { } public BetterThreadLocal(A value) { set(value); } public boolean isSet() { return map.containsKey(currentThread()); } public A get() { if (map.containsKey(currentThread())) return map.get(currentThread()); A value = initialValue(); set(value); return value; } public A get(Thread thread) { return thread == null ? null : map.get(thread); } public void set(A a) { map.put(currentThread(), a); } public A initialValue() { return null; } } static public class AlphanumComparator implements Comparator { public boolean ignoreCase = false; final public boolean isDigit(char ch) { return ((ch >= 48) && (ch <= 57)); } final public String getChunk(String s, int slength, int marker) { StringBuilder chunk = new StringBuilder(); char c = s.charAt(marker); chunk.append(c); marker++; if (isDigit(c)) while (marker < slength) { c = s.charAt(marker); if (!isDigit(c)) break; chunk.append(c); marker++; } else while (marker < slength) { c = s.charAt(marker); if (isDigit(c)) break; chunk.append(c); marker++; } return chunk.toString(); } public int compare(String s1, String s2) { if (s1 == null) return s2 == null ? 0 : -1; if (s2 == null) return 1; int thisMarker = 0; int thatMarker = 0; int s1Length = s1.length(); int s2Length = s2.length(); while (thisMarker < s1Length && thatMarker < s2Length) { String thisChunk = getChunk(s1, s1Length, thisMarker); thisMarker += thisChunk.length(); String thatChunk = getChunk(s2, s2Length, thatMarker); thatMarker += thatChunk.length(); int result = 0; if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) { int thisChunkLength = thisChunk.length(); result = thisChunkLength - thatChunk.length(); if (result == 0) { for (int i = 0; i < thisChunkLength; i++) { result = thisChunk.charAt(i) - thatChunk.charAt(i); if (result != 0) { return result; } } } } else { result = thisChunk.compareTo(thatChunk); } if (result != 0) return result; } return s1Length - s2Length; } } static public class ReverseChain implements Iterable { public A element; public ReverseChain prev; public int size; public ReverseChain() { } public ReverseChain(ReverseChain prev, A element) { this.element = element; this.prev = prev; if (prev == null) size = 1; else { prev.check(); size = prev.size + 1; } } public void check() { if (size < 1) throw fail("You called the ReverseChain default constructor. Don't do that"); } public String toString() { return str(toList()); } public ArrayList toList() { check(); ArrayList l = emptyList(size); for (int i = 0; i < size; i++) l.add(null); int i = size; ReverseChain c = this; while (c != null) { l.set(--i, c.element); c = c.prev; } return l; } public Iterator iterator() { return toList().iterator(); } } static public class CompactLinkedHashSet extends AbstractSet { public UnsynchronizedCompactHashSet> entries = new UnsynchronizedCompactHashSet(); public Entry head, tail; static public class Entry { public A value; public Entry prev, next; public int hashCode() { return _hashCode(value); } public boolean equals(Object o) { return o == this || eq(value, o); } } public boolean add(A a) { if (entries.contains(a)) return false; Entry n = new Entry(); n.value = a; n.prev = tail; if (tail != null) tail.next = n; tail = n; if (head == null) head = n; entries.add(n); return true; } public boolean remove(Object a) { return remove(entries.find(a)); } public boolean remove(Entry node) { if (node == null) return false; if (node.next != null) node.next.prev = node.prev; else tail = node.prev; if (node.prev != null) node.prev.next = node.next; else head = node.next; entries.remove(node); return true; } public int size() { return entries.size(); } public IterableIterator iterator() { return new IterableIterator() { public Entry entry = head, prev = null; public boolean hasNext() { return entry != null; } public A next() { A a = entry.value; prev = entry; entry = entry.next; return a; } public void remove() { if (prev == null) throw new IllegalStateException(); CompactLinkedHashSet.this.remove(prev); prev = null; } }; } public void clear() { entries.clear(); head = tail = null; } public boolean contains(Object a) { return entries.contains(a); } public A find(Object o) { Entry e = entries.find(o); return e == null ? null : e.value; } public A prevElement(A a) { Entry e = entries.find(a); if (e == null || e.prev == null) return null; return e.prev.value; } public A nextElement(A a) { Entry e = entries.find(a); if (e == null || e.next == null) return null; return e.next.value; } public A first() { return head == null ? null : head.value; } public A last() { return tail == null ? null : tail.value; } public boolean removeIfSame(Object o) { A value = find(o); if (value == o) { remove(value); return true; } return false; } } static public class FixedRateTimer extends java.util.Timer implements AutoCloseable { public FixedRateTimer() { this(false); } public FixedRateTimer(boolean daemon) { this(defaultTimerName(), daemon); } public FixedRateTimer(String name) { this(name, false); } public FixedRateTimer(String name, boolean daemon) { super(name, daemon); _registerTimer(this); } public List entries = synchroList(); static public class Entry implements IFieldsToList { public TimerTask task; public long firstTime; public long period; public Entry() { } public Entry(TimerTask task, long firstTime, long period) { this.period = period; this.firstTime = firstTime; this.task = task; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + task + ", " + firstTime + ", " + period + ")"; } public Object[] _fieldsToList() { return new Object[] { task, firstTime, period }; } } public void scheduleAtFixedRate(TimerTask task, long delay, long period) { entries.add(new Entry(task, now() + delay, period)); super.scheduleAtFixedRate(task, delay, period); } public void cancel() { entries.clear(); super.cancel(); } public int purge() { entries.clear(); return super.purge(); } public FixedRateTimer changeRate(int newPeriod) { Object r = ((SmartTimerTask) first(entries).task).r; cancel(); return doEvery(newPeriod, r); } public void close() { try { cancel(); } catch (Exception __e) { throw rethrow(__e); } } } static public class T3 { public A a; public B b; public C c; public T3() { } public T3(A a, B b, C c) { this.c = c; this.b = b; this.a = a; } public T3(T3 t) { a = t.a; b = t.b; c = t.c; } public int hashCode() { return _hashCode(a) + 2 * _hashCode(b) - 4 * _hashCode(c); } public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof T3)) return false; T3 t = (T3) o; return eq(a, t.a) && eq(b, t.b) && eq(c, t.c); } public String toString() { return "(" + quoteBorderless(a) + ", " + quoteBorderless(b) + ", " + quoteBorderless(c) + ")"; } } static public class LASValueDescriptor { public LASValueDescriptor() { } public boolean knownValue() { return false; } public Object value() { return null; } public Class javaClass() { return null; } public boolean javaClassIsExact() { return false; } public boolean canBeNull() { return true; } public boolean canFail() { return false; } public boolean willFail() { return false; } static public class Exact extends LASValueDescriptor implements IFieldsToList { public Class c; public boolean canBeNull = false; public Exact() { } public Exact(Class c, boolean canBeNull) { this.canBeNull = canBeNull; this.c = c; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + c + ", " + canBeNull + ")"; } public boolean equals(Object o) { if (!(o instanceof Exact)) return false; Exact __1 = (Exact) o; return eq(c, __1.c) && eq(canBeNull, __1.canBeNull); } public int hashCode() { int h = 67394271; h = boostHashCombine(h, _hashCode(c)); h = boostHashCombine(h, _hashCode(canBeNull)); return h; } public Object[] _fieldsToList() { return new Object[] { c, canBeNull }; } public Class javaClass() { return c; } public boolean javaClassIsExact() { return true; } public boolean canBeNull() { return canBeNull; } } static public class NonExact extends LASValueDescriptor implements IFieldsToList { public Class c; public boolean canBeNull = false; public NonExact() { } public NonExact(Class c, boolean canBeNull) { this.canBeNull = canBeNull; this.c = c; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + c + ", " + canBeNull + ")"; } public boolean equals(Object o) { if (!(o instanceof NonExact)) return false; NonExact __2 = (NonExact) o; return eq(c, __2.c) && eq(canBeNull, __2.canBeNull); } public int hashCode() { int h = 1445514322; h = boostHashCombine(h, _hashCode(c)); h = boostHashCombine(h, _hashCode(canBeNull)); return h; } public Object[] _fieldsToList() { return new Object[] { c, canBeNull }; } public Class javaClass() { return c; } public boolean javaClassIsExact() { return false; } public boolean canBeNull() { return canBeNull; } } static public LASValueDescriptor nonExactCanBeNull(Type c) { return new NonExact(typeToClass(c), true); } static public class KnownValue extends LASValueDescriptor implements IFieldsToList { public Object value; public KnownValue() { } public KnownValue(Object value) { this.value = value; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + value + ")"; } public boolean equals(Object o) { if (!(o instanceof KnownValue)) return false; KnownValue __3 = (KnownValue) o; return eq(value, __3.value); } public int hashCode() { int h = -1456305138; h = boostHashCombine(h, _hashCode(value)); return h; } public Object[] _fieldsToList() { return new Object[] { value }; } public boolean knownValue() { return true; } public Object value() { return value; } public Class javaClass() { return value == null ? null : value.getClass(); } public boolean javaClassIsExact() { return value != null; } public boolean canBeNull() { return value == null; } } static public class WillFail extends LASValueDescriptor { public boolean canFail() { return true; } public boolean willFail() { return true; } } static public LASValueDescriptor fromClass(Class c) { return new NonExact(c, true); } } static public class TokenRangeWithSrc extends TokenRange { public List tok; public TokenRangeWithSrc() { } public TokenRangeWithSrc(List tok, int start) { this.start = start; end = start; } public TokenRangeWithSrc(List tok, int start, int end) { this.end = end; this.start = start; } public TokenRangeWithSrc(ListAndIndex startPtr, ListAndIndex endPtr) { assertNotNull("startPtr", startPtr); assertNotNull("endPtr", endPtr); assertSame(tok = startPtr.list(), endPtr.list()); start = startPtr.idx(); end = endPtr.idx(); } public ListAndIndex startPtr() { return new ListAndIndex(tok, start); } public ListAndIndex endPtr() { return new ListAndIndex(tok, end); } public LineAndColumn startLineAndCol() { return tokenToLineAndColumn(startPtr()); } public LineAndColumn endLineAndCol() { return tokenToLineAndColumn(endPtr()); } public String text() { return joinSubList(tok, start, end); } public String toString() { var start = startLineAndCol(); if (eq(start, end)) return str(start); return start + " to " + endLineAndCol(); } public String fullSourceText() { return join(tok); } } static public class ResolvableLASClass { public ResolvableLASClass() { } transient public ILASClassLoader lasClassLoader; public LASClassDef classDef; public Class resolvedClass; public ResolvableLASClass(ILASClassLoader lasClassLoader, LASClassDef classDef) { this.classDef = classDef; this.lasClassLoader = lasClassLoader; } public Class get() { if (resolvedClass == null) { if (lasClassLoader == null) throw fail("Need LASClassLoader to define " + classDef.userGivenName); resolvedClass = lasClassLoader.defineLASClass(classDef.finalClassName(), () -> classDef.toBytes()); classDef.init(resolvedClass); } return resolvedClass; } public String toString() { if (resolvedClass != null) return className(resolvedClass); { var __1 = classDef.userGivenName; if (__1 != null) return __1; } if (classDef.classHash_cache != null) return classDef.finalClassNameWithoutPrefix(); return or2(classDef.userGivenName, "script-defined class") + " [unresolved]"; } } static public class LASScope { final public LASScope setUseFixedVars(boolean useFixedVars) { return useFixedVars(useFixedVars); } public LASScope useFixedVars(boolean useFixedVars) { this.useFixedVars = useFixedVars; return this; } final public boolean getUseFixedVars() { return useFixedVars(); } public boolean useFixedVars() { return useFixedVars; } public boolean useFixedVars = false; final public Map getDeclaredVars() { return declaredVars(); } public Map declaredVars() { return declaredVars; } public Map declaredVars = new HashMap(); final public LASScope setParentScope(LASScope parentScope) { return parentScope(parentScope); } public LASScope parentScope(LASScope parentScope) { this.parentScope = parentScope; return this; } final public LASScope getParentScope() { return parentScope(); } public LASScope parentScope() { return parentScope; } public LASScope parentScope; final public LASScope setParentIsDetached(boolean parentIsDetached) { return parentIsDetached(parentIsDetached); } public LASScope parentIsDetached(boolean parentIsDetached) { this.parentIsDetached = parentIsDetached; return this; } final public boolean getParentIsDetached() { return parentIsDetached(); } public boolean parentIsDetached() { return parentIsDetached; } public boolean parentIsDetached = false; public String[] names; public LASScope() { } public LASScope(LASScope parentScope) { this.parentScope = parentScope; } public boolean resolved() { return names != null; } public void addDeclaredVar(String name, LASValueDescriptor type) { if (resolved()) throw fail("Can't add variables to resolved scope"); declaredVars.put(name, type); } public int resolveVar(String name) { resolve(); int idx = indexOfInSortedArray(names, name); if (idx < 0) throw fail("Variable not found in scope: " + name); return idx; } public void resolve() { if (names != null) return; names = empty(declaredVars) ? null : toStringArray(sortedKeys(declaredVars)); } } static public class ClassNameResolver { final public ClassNameResolver setByteCodePath(File byteCodePath) { return byteCodePath(byteCodePath); } public ClassNameResolver byteCodePath(File byteCodePath) { this.byteCodePath = byteCodePath; return this; } final public File getByteCodePath() { return byteCodePath(); } public File byteCodePath() { return byteCodePath; } public File byteCodePath = byteCodePathForClass(getClass()); public List importedPackages = itemPlusList("java.lang", endingWith_dropSuffix(standardImports(), ".*")); public Set allFullyQualifiedClassNames_cache; public Set allFullyQualifiedClassNames() { if (allFullyQualifiedClassNames_cache == null) allFullyQualifiedClassNames_cache = allFullyQualifiedClassNames_load(); return allFullyQualifiedClassNames_cache; } public Set allFullyQualifiedClassNames_load() { Set set = new HashSet(); assertNotNull(byteCodePath); set.addAll(classNamesInJarOrDir(byteCodePath)); printVars("ClassNameResolver", "byteCodePath", byteCodePath, "classesFound", l(set)); set.addAll(classNamesInLoadedJigsawModules()); return set; } public ClassNameResolver init() { allFullyQualifiedClassNames(); return this; } public String findClass(String name) { for (String pkg : importedPackages) { String fullName = pkg + "." + name; if (allFullyQualifiedClassNames().contains(fullName)) return fullName; } return null; } public void printMe() { printVars("ClassNameResolver", "byteCodePath", byteCodePath); print("importedPackages", importedPackages); } } static public class UnsynchronizedCompactHashSet extends java.util.AbstractSet { final static public int INITIAL_SIZE = 3; public final static double LOAD_FACTOR = 0.75; final static public Object nullObject = new Object(); final static public Object deletedObject = new Object(); public int elements; public int freecells; public A[] objects; public int modCount; public UnsynchronizedCompactHashSet() { this(INITIAL_SIZE); } public UnsynchronizedCompactHashSet(int size) { objects = (A[]) new Object[(size == 0 ? 1 : size)]; elements = 0; freecells = objects.length; modCount = 0; } public UnsynchronizedCompactHashSet(Collection c) { this(c.size()); addAll(c); } @Override public Iterator iterator() { return new CompactHashIterator(); } @Override public int size() { return elements; } @Override public boolean isEmpty() { return elements == 0; } @Override public boolean contains(Object o) { return find(o) != null; } public A find(Object o) { if (o == null) o = nullObject; int hash = o.hashCode(); int index = (hash & 0x7FFFFFFF) % objects.length; int offset = 1; while (objects[index] != null && !(objects[index].hashCode() == hash && objects[index].equals(o))) { index = ((index + offset) & 0x7FFFFFFF) % objects.length; offset = offset * 2 + 1; if (offset == -1) offset = 2; } return objects[index]; } public boolean removeIfSame(Object o) { A value = find(o); if (value == o) { remove(value); return true; } return false; } @Override public boolean add(Object o) { if (o == null) o = nullObject; int hash = o.hashCode(); int index = (hash & 0x7FFFFFFF) % objects.length; int offset = 1; int deletedix = -1; while (objects[index] != null && !(objects[index].hashCode() == hash && objects[index].equals(o))) { if (objects[index] == deletedObject) deletedix = index; index = ((index + offset) & 0x7FFFFFFF) % objects.length; offset = offset * 2 + 1; if (offset == -1) offset = 2; } if (objects[index] == null) { if (deletedix != -1) index = deletedix; else freecells--; modCount++; elements++; objects[index] = (A) o; if (1 - (freecells / (double) objects.length) > LOAD_FACTOR) rehash(); return true; } else return false; } @Override public boolean remove(Object o) { if (o == null) o = nullObject; int hash = o.hashCode(); int index = (hash & 0x7FFFFFFF) % objects.length; int offset = 1; while (objects[index] != null && !(objects[index].hashCode() == hash && objects[index].equals(o))) { index = ((index + offset) & 0x7FFFFFFF) % objects.length; offset = offset * 2 + 1; if (offset == -1) offset = 2; } if (objects[index] != null) { objects[index] = (A) deletedObject; modCount++; elements--; return true; } else return false; } @Override public void clear() { elements = 0; for (int ix = 0; ix < objects.length; ix++) objects[ix] = null; freecells = objects.length; modCount++; } @Override public Object[] toArray() { Object[] result = new Object[elements]; Object[] objects = this.objects; int pos = 0; for (int i = 0; i < objects.length; i++) if (objects[i] != null && objects[i] != deletedObject) { if (objects[i] == nullObject) result[pos++] = null; else result[pos++] = objects[i]; } return result; } @Override public T[] toArray(T[] a) { int size = elements; if (a.length < size) a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size); A[] objects = this.objects; int pos = 0; for (int i = 0; i < objects.length; i++) if (objects[i] != null && objects[i] != deletedObject) { if (objects[i] == nullObject) a[pos++] = null; else a[pos++] = (T) objects[i]; } return a; } public void rehash() { int garbagecells = objects.length - (elements + freecells); if (garbagecells / (double) objects.length > 0.05) rehash(objects.length); else rehash(objects.length * 2 + 1); } public void rehash(int newCapacity) { int oldCapacity = objects.length; @SuppressWarnings("unchecked") A[] newObjects = (A[]) new Object[newCapacity]; for (int ix = 0; ix < oldCapacity; ix++) { Object o = objects[ix]; if (o == null || o == deletedObject) continue; int hash = o.hashCode(); int index = (hash & 0x7FFFFFFF) % newCapacity; int offset = 1; while (newObjects[index] != null) { index = ((index + offset) & 0x7FFFFFFF) % newCapacity; offset = offset * 2 + 1; if (offset == -1) offset = 2; } newObjects[index] = (A) o; } objects = newObjects; freecells = objects.length - elements; } public class CompactHashIterator implements Iterator { public int index; public int lastReturned = -1; public int expectedModCount; @SuppressWarnings("empty-statement") public CompactHashIterator() { for (index = 0; index < objects.length && (objects[index] == null || objects[index] == deletedObject); index++) ; expectedModCount = modCount; } @Override public boolean hasNext() { return index < objects.length; } @SuppressWarnings("empty-statement") @Override public T next() { int length = objects.length; if (index >= length) { lastReturned = -2; throw new NoSuchElementException(); } lastReturned = index; for (index += 1; index < length && (objects[index] == null || objects[index] == deletedObject); index++) ; if (objects[lastReturned] == nullObject) return null; else return (T) objects[lastReturned]; } @Override public void remove() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (lastReturned == -1 || lastReturned == -2) throw new IllegalStateException(); if (objects[lastReturned] != null && objects[lastReturned] != deletedObject) { objects[lastReturned] = (A) deletedObject; elements--; modCount++; expectedModCount = modCount; } } } public int capacity() { return objects.length; } public boolean shrinkToFactor(double factor) { if (factor > LOAD_FACTOR) throw fail("Shrink factor must be equal to or smaller than load factor: " + factor + " / " + LOAD_FACTOR); int newCapacity = max(INITIAL_SIZE, iround(size() / factor)); if (newCapacity >= capacity()) return false; rehash(newCapacity); return true; } } static final public class ParameterizedTypeImpl implements ParameterizedType { public ParameterizedTypeImpl() { } public Type ownerType; public Type rawType; public Type[] typeArguments; public ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) { this.typeArguments = typeArguments; this.rawType = rawType; this.ownerType = ownerType; } public Type[] getActualTypeArguments() { return typeArguments; } public Type getRawType() { return rawType; } public Type getOwnerType() { return ownerType; } @Override public boolean equals(Object other) { if (other instanceof ParameterizedType) return eq(ownerType, ((ParameterizedType) other).getOwnerType()) && eq(rawType, ((ParameterizedType) other).getRawType()) && eq(asList(typeArguments), asList(((ParameterizedType) other).getActualTypeArguments())); return false; } @Override public int hashCode() { return Arrays.hashCode(typeArguments) ^ rawType.hashCode() ^ _hashCode(ownerType); } @Override public String toString() { int length = typeArguments.length; if (length == 0) return typeToString(rawType); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(typeToString(rawType)).append("<").append(typeToString(typeArguments[0])); for (int i = 1; i < length; i++) { stringBuilder.append(", ").append(typeToString(typeArguments[i])); } return stringBuilder.append(">").toString(); } static public String typeToString(Type type) { return type instanceof Class ? ((Class) type).getName() : type.toString(); } } public interface ILASClassLoader { public Class defineLASClass(String name, IF0 generateClass); public Object rememberClassBytes(boolean rememberClassBytes); } static public class LASClassDef { final public LASClassDef setUserGivenName(String userGivenName) { return userGivenName(userGivenName); } public LASClassDef userGivenName(String userGivenName) { this.userGivenName = userGivenName; return this; } final public String getUserGivenName() { return userGivenName(); } public String userGivenName() { return userGivenName; } public String userGivenName; final public LASClassDef setClassDefPrefix(String classDefPrefix) { return classDefPrefix(classDefPrefix); } public LASClassDef classDefPrefix(String classDefPrefix) { this.classDefPrefix = classDefPrefix; return this; } final public String getClassDefPrefix() { return classDefPrefix(); } public String classDefPrefix() { return classDefPrefix; } public String classDefPrefix = "userCode."; final public LASClassDef setFullCompilation(boolean fullCompilation) { return fullCompilation(fullCompilation); } public LASClassDef fullCompilation(boolean fullCompilation) { this.fullCompilation = fullCompilation; return this; } final public boolean getFullCompilation() { return fullCompilation(); } public boolean fullCompilation() { return fullCompilation; } public boolean fullCompilation = false; final public LASClassDef setVerbose(boolean verbose) { return verbose(verbose); } public LASClassDef verbose(boolean verbose) { this.verbose = verbose; return this; } final public boolean getVerbose() { return verbose(); } public boolean verbose() { return verbose; } public boolean verbose = true; public List fields = new ArrayList(); public List methods = new ArrayList(); public List methodBodies = new ArrayList(); static public class FieldDef { final public FieldDef setName(String name) { return name(name); } public FieldDef name(String name) { this.name = name; return this; } final public String getName() { return name(); } public String name() { return name; } public String name; final public FieldDef setType(Type type) { return type(type); } public FieldDef type(Type type) { this.type = type; return this; } final public Type getType() { return type(); } public Type type() { return type; } public Type type; } public String structForHash() { return GazelleV_LeftArrowScript.scriptStruct(litorderedmap("userGivenName", userGivenName, "fields", fields, "methods", methods, "fullCompilation", fullCompilation)); } public String classHash_cache; public String classHash() { if (classHash_cache == null) classHash_cache = classHash_load(); return classHash_cache; } public String classHash_load() { String struct = structForHash(); if (verbose) print("structForHash", struct); return md5(struct); } public String finalClassName() { return classDefPrefix() + finalClassNameWithoutPrefix(); } public String finalClassNameWithoutPrefix() { return or2(userGivenName, "C") + "_" + classHash(); } public byte[] toBytes_cache; public byte[] toBytes() { if (toBytes_cache == null) toBytes_cache = toBytes_load(); return toBytes_cache; } public byte[] toBytes_load() { ClassMaker classMaker = new ClassMaker(finalClassName()); var cp = classMaker.getConstantPool(); for (var field : fields) { var type = field.type; var fg = new FieldGen(Const.ACC_PUBLIC, typeToBCELType(type), field.name, cp); if (type instanceof ParameterizedType) fg.addAttribute(new org.apache.bcel.classfile.Signature(cp.addUtf8("Signature"), 2, cp.addUtf8(typeToVMSignature((ParameterizedType) type)), cp.getConstantPool())); classMaker.addField(fg); } for (var method : methods) if (fullCompilation) fullyCompileMethod(classMaker, method); else semiCompileMethod(classMaker, method); classMaker.addDefaultConstructor(); return classMaker.toBytes(); } public void semiCompileMethod(ClassMaker classMaker, GazelleV_LeftArrowScript.FunctionDef method) { int iMethod = l(methodBodies); methodBodies.add(method); String bodyFieldName = "_body" + iMethod; classMaker.addField(new FieldGen(Const.ACC_PUBLIC | Const.ACC_STATIC, classToBCELType(GazelleV_LeftArrowScript.Evaluable.class), bodyFieldName, classMaker.getConstantPool())); int nArgs = l(method.args); MethodMaker mm = new MethodMaker(classMaker, Object.class, method.name, repArray(Class.class, Object.class, nArgs)); int iThis = 0, iFirstArg = 1, iCtx = iFirstArg + nArgs; mm.newObject(FlexibleVarContext.class); mm.astore(iCtx); mm.aload(iCtx); mm.stringConstant("this"); mm.aload(iThis); mm.invokeVirtual(VarContext.class, void.class, "put", String.class, Object.class); for (int iArg = 0; iArg < nArgs; iArg++) { mm.aload(iCtx); mm.stringConstant(method.args[iArg]); mm.aload(iFirstArg + iArg); mm.invokeVirtual(VarContext.class, void.class, "put", String.class, Object.class); } mm.getStaticField(classMaker.className(), bodyFieldName, GazelleV_LeftArrowScript.Evaluable.class); mm.aload(iCtx); mm.invokeInterface(GazelleV_LeftArrowScript.Evaluable.class, Object.class, "get", VarContext.class); mm.areturn(); mm.done(); } public void fullyCompileMethod(ClassMaker classMaker, GazelleV_LeftArrowScript.FunctionDef method) { MethodMaker mm = new MethodMaker(classMaker, Object.class, method.name, repArray(Class.class, Object.class, l(method.args))); var tbc = new LASToByteCode(mm) { public JVMStackCellType compileGetVar(GazelleV_LeftArrowScript.GetVar code) { if (eq(code.var, "this")) { mm.aload(0); return JVMStackCellType.objValue; } int iArg = indexOf(method.args, code.var); if (iArg >= 0) { mm.aload(iArg + 1); return JVMStackCellType.objValue; } return super.compileGetVar(code); } }; tbc.postConversion = stackTop -> mm.convertToObject(stackTop); tbc.compileScript(method.body); mm.areturn(); mm.done(); } public void init(Class c) { for (int iMethod = 0; iMethod < l(methodBodies); iMethod++) { String bodyFieldName = "_body" + iMethod; set(c, bodyFieldName, methodBodies.get(iMethod).body); } } } static public class SimpleLeftToRightParser extends Meta { public String text; public List tok; final public ListAndIndex getPtr() { return ptr(); } public ListAndIndex ptr() { return ptr; } public ListAndIndex ptr; public ListAndIndex mainLoopPtr; public String currentToken; public boolean caseInsensitive = false; public List warnings = new ArrayList(); public SimpleLeftToRightParser() { } public SimpleLeftToRightParser(String text) { this.text = text; } public SimpleLeftToRightParser(List tok) { this.tok = tok; } transient public IF1> tokenize; public List tokenize(String text) { return tokenize != null ? tokenize.get(text) : tokenize_base(text); } final public List tokenize_fallback(IF1> _f, String text) { return _f != null ? _f.get(text) : tokenize_base(text); } public List tokenize_base(String text) { return javaTok(text); } final public String token() { return t(); } public String t() { return currentToken; } public String token(int i) { return get(tok, ptr.idx() + i * 2); } final public String consume() { return next(); } final public String tpp() { return next(); } public String next() { var t = t(); next(1); return t; } final public String prevSpace() { return lastSpace(); } public String lastSpace() { return get(tok, ptr.idx() - 1); } public String nextSpace() { return get(tok, ptr.idx() + 1); } public String space(int i) { return get(tok, ptr.idx() + i * 2 + 1); } public void unconsume() { next(-1); } final public boolean eqTok(String a, String b) { return tokEq(a, b); } public boolean tokEq(String a, String b) { return eqOrEqic(caseInsensitive, a, b); } public boolean tokEqOneOf(String a, String... l) { return any(l, b -> tokEq(a, b)); } public boolean is(int i, String t) { return tokEq(token(i), t); } public boolean is(String t) { return tokEq(currentToken, t); } public boolean was(String t) { return tokEq(token(-1), t); } public boolean isOneOf(String... tokens) { return tokEqOneOf(currentToken, tokens); } public String[] consumeArray(int n) { String[] array = new String[n]; for (int i = 0; i < n; i++) array[i] = consume(); return array; } public boolean isInteger() { return isInteger(t()); } public boolean isInteger(String s) { return main.isInteger(s); } public boolean isIdentifier() { return isIdentifier(t()); } public boolean isIdentifier(String s) { return main.isIdentifier(s); } public String consumeIdentifier() { return assertIdentifier(consume()); } public boolean consumeOpt(String token) { if (!is(token)) return false; consume(); return true; } public void consume(String token) { if (!is(token)) throw fail("Expected " + quote(token) + ", got " + describeToken(token())); consume(); } public String describeToken(String token) { return token == null ? "EOF" : quote(token); } public String consumeOneOf(String... tokens) { if (!isOneOf(tokens)) throw fail("Expected one of " + asList(tokens)); return consume(); } public void ptr(ListAndIndex ptr) { this.ptr = ptr; fetch(); } final public int tokIdx() { return idx(); } public int idx() { return ptr.idx(); } public int lTok() { return l(tok); } public int nRemainingTokens() { return (lTok() - idx()) / 2; } final public boolean endOfText() { return atEnd(); } public boolean atEnd() { return ptr.atEnd(); } public void fetch() { currentToken = ptr.get(); } public boolean lineBreak() { return containsLineBreak(get(tok, ptr.idx() - 1)); } public boolean atEndOrLineBreak() { return atEnd() || lineBreak(); } public void init() { if (tok == null) tok = tokenize(text); if (ptr == null) ptr(new ListAndIndex(tok, 1)); } public boolean mainLoop() { init(); if (atEnd()) return false; if (eq(mainLoopPtr, ptr)) throw fail("main loop didn't advance (current token: " + quote(token()) + ")"); mainLoopPtr = ptr; return true; } public class AssureAdvance { public ListAndIndex cur; { init(); } public boolean get() { if (atEnd()) return false; if (eq(cur, ptr)) throw fail("Parse loop didn't advance (current token: " + quote(token()) + ")"); cur = ptr; return true; } } public void unknownToken() { warn("Unknown token: " + t()); } public void warn(String msg) { warnings.add(print(msg)); } final public void skip(int n) { next(n); } public void next(int n) { ptr(min(lTok(), ptr.idx() + n * 2)); } public void ptr(int i) { ptr(new ListAndIndex(tok, min(i | 1, l(tok)))); } public LineAndColumn lineAndColumn() { return tokenToLineAndColumn(ptr); } public LineAndColumn lineAndColumn(int idx) { return tokenToLineAndColumn(ptr.plus(idx * 2)); } public String consumeUntilSpaceOr(IF0 pred) { int i = idx(); do next(); while (!atEnd() && empty(lastSpace()) && !pred.get()); return joinSubList(tok, i, idx() - 1); } public void setText(String text) { this.text = text; tok = null; ptr = null; } public int relativeIndexOf(String token) { int n = nRemainingTokens(); for (int i = 0; i < n; i++) if (eqTok(token(i), token)) return i; return -1; } } public interface IHasTokenRangeWithSrc { public void setTokenRangeWithSrc(TokenRangeWithSrc src); public TokenRangeWithSrc tokenRangeWithSrc(); default public String srcText() { var src = tokenRangeWithSrc(); return src == null ? null : src.text(); } } abstract static public class CompactAbstractMap implements Map { public int size() { return entrySet().size(); } public boolean isEmpty() { return size() == 0; } public boolean containsValue(Object value) { Iterator> i = entrySet().iterator(); if (value == null) { while (i.hasNext()) { Entry e = i.next(); if (e.getValue() == null) return true; } } else { while (i.hasNext()) { Entry e = i.next(); if (value.equals(e.getValue())) return true; } } return false; } public boolean containsKey(Object key) { Iterator> i = entrySet().iterator(); if (key == null) { while (i.hasNext()) { Entry e = i.next(); if (e.getKey() == null) return true; } } else { while (i.hasNext()) { Entry e = i.next(); if (key.equals(e.getKey())) return true; } } return false; } public V get(Object key) { Iterator> i = entrySet().iterator(); if (key == null) { while (i.hasNext()) { Entry e = i.next(); if (e.getKey() == null) return e.getValue(); } } else { while (i.hasNext()) { Entry e = i.next(); if (key.equals(e.getKey())) return e.getValue(); } } return null; } public V put(K key, V value) { throw new UnsupportedOperationException(); } public V remove(Object key) { Iterator> i = entrySet().iterator(); Entry correctEntry = null; if (key == null) { while (correctEntry == null && i.hasNext()) { Entry e = i.next(); if (e.getKey() == null) correctEntry = e; } } else { while (correctEntry == null && i.hasNext()) { Entry e = i.next(); if (key.equals(e.getKey())) correctEntry = e; } } V oldValue = null; if (correctEntry != null) { oldValue = correctEntry.getValue(); i.remove(); } return oldValue; } public void putAll(Map m) { for (Entry e : m.entrySet()) put(e.getKey(), e.getValue()); } public void clear() { entrySet().clear(); } public Set keySet() { return new AbstractSet() { public Iterator iterator() { return new Iterator() { public Iterator> i = entrySet().iterator(); public boolean hasNext() { return i.hasNext(); } public K next() { return i.next().getKey(); } public void remove() { i.remove(); } }; } public int size() { return CompactAbstractMap.this.size(); } public boolean isEmpty() { return CompactAbstractMap.this.isEmpty(); } public void clear() { CompactAbstractMap.this.clear(); } public boolean contains(Object k) { return CompactAbstractMap.this.containsKey(k); } }; } public Collection values() { return new AbstractCollection() { public Iterator iterator() { return new Iterator() { public Iterator> i = entrySet().iterator(); public boolean hasNext() { return i.hasNext(); } public V next() { return i.next().getValue(); } public void remove() { i.remove(); } }; } public int size() { return CompactAbstractMap.this.size(); } public boolean isEmpty() { return CompactAbstractMap.this.isEmpty(); } public void clear() { CompactAbstractMap.this.clear(); } public boolean contains(Object v) { return CompactAbstractMap.this.containsValue(v); } }; } public abstract Set> entrySet(); public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Map)) return false; Map m = (Map) o; if (m.size() != size()) return false; try { for (Entry e : entrySet()) { K key = e.getKey(); V value = e.getValue(); if (value == null) { if (!(m.get(key) == null && m.containsKey(key))) return false; } else { if (!value.equals(m.get(key))) return false; } } } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; } return true; } public int hashCode() { int h = 0; for (Entry entry : entrySet()) h += entry.hashCode(); return h; } public String toString() { Iterator> i = entrySet().iterator(); if (!i.hasNext()) return "{}"; StringBuilder sb = new StringBuilder(); sb.append('{'); for (; ; ) { Entry e = i.next(); K key = e.getKey(); V value = e.getValue(); sb.append(key == this ? "(this Map)" : key); sb.append('='); sb.append(value == this ? "(this Map)" : value); if (!i.hasNext()) return sb.append('}').toString(); sb.append(',').append(' '); } } public Object clone() throws CloneNotSupportedException { CompactAbstractMap result = (CompactAbstractMap) super.clone(); return result; } public static class SimpleEntry implements Entry, java.io.Serializable { @java.io.Serial static final public long serialVersionUID = -8499721149061103585L; @SuppressWarnings("serial") final public K key; @SuppressWarnings("serial") public V value; public SimpleEntry(K key, V value) { this.key = key; this.value = value; } public SimpleEntry(Entry entry) { this.key = entry.getKey(); this.value = entry.getValue(); } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { V oldValue = this.value; this.value = value; return oldValue; } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Entry e = (Entry) o; return eq(key, e.getKey()) && eq(value, e.getValue()); } public int hashCode() { return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } public String toString() { return key + "=" + value; } } public static class SimpleImmutableEntry implements Entry, java.io.Serializable { @java.io.Serial static final public long serialVersionUID = 7138329143949025153L; @SuppressWarnings("serial") final public K key; @SuppressWarnings("serial") final public V value; public SimpleImmutableEntry(K key, V value) { this.key = key; this.value = value; } public SimpleImmutableEntry(Entry entry) { this.key = entry.getKey(); this.value = entry.getValue(); } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { throw new UnsupportedOperationException(); } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Entry e = (Entry) o; return eq(key, e.getKey()) && eq(value, e.getValue()); } public int hashCode() { return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } public String toString() { return key + "=" + value; } } } static public class GazelleV_LeftArrowScript { abstract static public class Base extends HasTokenRangeWithSrc { public RuntimeException rethrowWithSrc(Throwable e) { return rethrowWithSrc("", e); } public RuntimeException rethrowWithSrc(String msg, Throwable e) { if (src != null) throw rethrowAndAppendToMessage(e, squareBracketed(joinNemptiesWithComma(msg, src))); else throw rethrow(e); } } public interface Evaluable extends IF0, IHasTokenRangeWithSrc { public default Object get() { return get(new FlexibleVarContext()); } public Object get(VarContext ctx); public default LASValueDescriptor returnType() { return null; } public default Evaluable optimize() { return this; } public default Evaluable optimizeForReturnValueNotNeeded() { return this; } } abstract static public class EvaluableBase extends Base implements Evaluable { final public EvaluableBase setReturnType(LASValueDescriptor returnType) { return returnType(returnType); } public EvaluableBase returnType(LASValueDescriptor returnType) { this.returnType = returnType; return this; } final public LASValueDescriptor getReturnType() { return returnType(); } public LASValueDescriptor returnType() { return returnType; } public LASValueDescriptor returnType; public boolean returnValueNeeded = true; public Evaluable optimizeForReturnValueNotNeeded() { returnValueNeeded = false; return optimize(); } } static public AtomicLong scriptIDCounter = new AtomicLong(); static public long scriptID() { return incAtomicLong(scriptIDCounter); } static public class Script extends EvaluableBase { transient public long id = scriptID(); public Map functionDefs; public Evaluable[] steps; final public Script setScope(LASScope scope) { return scope(scope); } public Script scope(LASScope scope) { this.scope = scope; return this; } final public LASScope getScope() { return scope(); } public LASScope scope() { return scope; } public LASScope scope; public Object get(VarContext ctx) { Object result = null; var pingSource = pingSource(); for (var step : steps) { ping(pingSource); result = step.get(ctx); var exiting = ctx.exitFromScript; if (exiting != null) { if (exiting == this) { ctx.exitFromScript = null; result = ctx.returnValue; ctx.returnValue(null); return result; } return null; } } return result; } public String toStringLong() { return pnlToLines(steps); } public String toString() { return "Script " + n2(id); } public FunctionDef getFunction(String name) { return mapGet(functionDefs, name); } final public Script optimize() { return optimizeScript(); } public Script optimizeScript() { int n = returnValueNeeded ? steps.length - 1 : steps.length; for (int i = 0; i < n; i++) steps[i] = steps[i].optimizeForReturnValueNotNeeded(); for (var f : values(functionDefs)) f.optimize(); return this; } } static public class FunctionDef extends Base implements IFieldsToList { public String name; public String[] args; public Script body; public FunctionDef() { } public FunctionDef(String name, String[] args, Script body) { this.body = body; this.args = args; this.name = name; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + name + ", " + args + ", " + body + ")"; } public Object[] _fieldsToList() { return new Object[] { name, args, body }; } final public FunctionDef setScope(LASScope scope) { return scope(scope); } public FunctionDef scope(LASScope scope) { this.scope = scope; return this; } final public LASScope getScope() { return scope(); } public LASScope scope() { return scope; } public LASScope scope; public FunctionDef(String name, List args, Script body) { this.args = toStringArray(args); this.body = body; this.name = name; } public Object call(VarContext ctx, Object... args) { VarContext ctx2 = scope != null && scope.useFixedVars ? new FixedVarContext(ctx, scope.names) : new FlexibleVarContext(ctx); int n = min(l(args), l(this.args)); for (int i = 0; i < n; i++) ctx2.put(this.args[i], args[i]); return body.get(ctx2); } public void optimize() { body = body.optimize(); } } static public class Assignment extends EvaluableBase implements IFieldsToList { public String var; public Evaluable expression; public Assignment() { } public Assignment(String var, Evaluable expression) { this.expression = expression; this.var = var; } public Object[] _fieldsToList() { return new Object[] { var, expression }; } public Object get(VarContext ctx) { Object o = expression.get(ctx); ctx.set(var, o); return o; } public String toString() { return var + " <- " + expression; } } abstract static public class FixedVarBase extends EvaluableBase { final public FixedVarBase setScope(LASScope scope) { return scope(scope); } public FixedVarBase scope(LASScope scope) { this.scope = scope; return this; } final public LASScope getScope() { return scope(); } public LASScope scope() { return scope; } public LASScope scope; public String var; public int varIdx; public String varToStr() { return var + " [" + varIdx + "]"; } public void assertResolved() { if (varIdx < 0) throw fail("Unresolved variable access: " + var); } public void resolve() { varIdx = scope.resolveVar(var); } } static public class FixedVarAssignment extends FixedVarBase { public FixedVarAssignment() { } public Evaluable expression; public FixedVarAssignment(LASScope scope, String var, Evaluable expression) { this.expression = expression; this.var = var; this.scope = scope; } public Object get(VarContext ctx) { Object o = expression.get(ctx); ((FixedVarContext) ctx).set(varIdx, o); return o; } public String toString() { return varToStr() + " <- " + expression; } } static public class VarDeclaration extends EvaluableBase implements IFieldsToList { public String var; public Class type; public Evaluable expression; public VarDeclaration() { } public VarDeclaration(String var, Class type, Evaluable expression) { this.expression = expression; this.type = type; this.var = var; } public Object[] _fieldsToList() { return new Object[] { var, type, expression }; } public Object get(VarContext ctx) { Object o = expression == null ? null : expression.get(ctx); ctx.set(var, o); return o; } public String toString() { return "var " + var + " <- " + expression; } } static public class AssignmentToOuterVar extends EvaluableBase implements IFieldsToList { public String var; public Evaluable expression; public AssignmentToOuterVar() { } public AssignmentToOuterVar(String var, Evaluable expression) { this.expression = expression; this.var = var; } public Object[] _fieldsToList() { return new Object[] { var, expression }; } public Object get(VarContext ctx) { var parent = ctx.parent(); assertNotNull("No outer variable context", parent); Object o = expression.get(ctx); parent.set(var, o); return o; } public String toString() { return "outer " + var + " <- " + expression; } } static public class NewObject extends EvaluableBase { public NewObject() { } public Class c; public Evaluable[] args; public NewObject(Class c) { this.c = c; } public NewObject(Class c, Evaluable[] args) { this.args = args; this.c = c; } public Object get(VarContext ctx) { try { return preciseNuObject(c, mapToArrayOrNull(args, arg -> arg.get(ctx))); } catch (Throwable e) { throw rethrowWithSrc(e); } } public String toString() { return "new " + formatFunctionCall(className(c), args); } } static public class NewObject_LASClass extends NewObject { public NewObject_LASClass() { } public ResolvableLASClass lasClass; public NewObject_LASClass(ResolvableLASClass lasClass) { this.lasClass = lasClass; } public NewObject_LASClass(ResolvableLASClass lasClass, Evaluable[] args) { this.args = args; this.lasClass = lasClass; } public void resolve() { if (c == null) c = lasClass.get(); } public Object get(VarContext ctx) { resolve(); return super.get(ctx); } public String toString() { return "new " + formatFunctionCall(str(lasClass), args); } } static public class NewObject_UnknownClass extends NewObject implements IFieldsToList { public Evaluable classExpr; public Evaluable[] args; public NewObject_UnknownClass() { } public NewObject_UnknownClass(Evaluable classExpr, Evaluable[] args) { this.args = args; this.classExpr = classExpr; } public Object[] _fieldsToList() { return new Object[] { classExpr, args }; } public Object get(VarContext ctx) { try { Class c = (Class) (classExpr.get(ctx)); return preciseNuObject(c, mapToArrayOrNull(args, arg -> arg.get(ctx))); } catch (Throwable e) { throw rethrowWithSrc(e); } } public String toString() { return "new " + formatFunctionCall(classExpr, args); } } static public class CallFunction extends EvaluableBase implements IFieldsToList { public FunctionDef f; public Evaluable[] args; public CallFunction() { } public CallFunction(FunctionDef f, Evaluable[] args) { this.args = args; this.f = f; } public Object[] _fieldsToList() { return new Object[] { f, args }; } public Object get(VarContext ctx) { var evaledArgs = mapToArrayOrNull(args, a -> a.get(ctx)); if (ctx.exiting()) return null; return f.call(ctx, evaledArgs); } public String toString() { return formatFunctionCall(f.name, args); } } static public class GetVar extends EvaluableBase implements IFieldsToList { public String var; public GetVar() { } public GetVar(String var) { this.var = var; } public Object[] _fieldsToList() { return new Object[] { var }; } public Object get(VarContext ctx) { return ctx.get(var); } public String toString() { return var; } } static public class GetFixedVar extends FixedVarBase { public GetFixedVar() { } public GetFixedVar(LASScope scope, String var) { this.var = var; this.scope = scope; } public Object get(VarContext ctx) { assertResolved(); try { return ((FixedVarContext) ctx).get(varIdx); } catch (ArrayIndexOutOfBoundsException e) { assertResolved(); throw e; } } public String toString() { return var + " [" + varIdx + "]"; } } static public class Const extends EvaluableBase implements IFieldsToList { public Object value; public Const() { } public Const(Object value) { this.value = value; } public Object[] _fieldsToList() { return new Object[] { value }; } public Object get(VarContext ctx) { return value; } public String toString() { return strOrClassName(value); } public LASValueDescriptor returnType() { return new LASValueDescriptor.KnownValue(value); } public Object _serialize() { boolean ok = isUnproblematicValue(value); return ok ? this : toStringWithClass(value); } } static public class GetStaticField extends EvaluableBase implements IFieldsToList { public Field field; public GetStaticField() { } public GetStaticField(Field field) { this.field = field; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + field + ")"; } public Object[] _fieldsToList() { return new Object[] { field }; } public Object get(VarContext ctx) { try { return field.get(null); } catch (Exception __e) { throw rethrow(__e); } } public String _serialize() { return str(field); } } static public class CallMethodOrGetField extends EvaluableBase implements IFieldsToList { public Evaluable target; public String name; public CallMethodOrGetField() { } public CallMethodOrGetField(Evaluable target, String name) { this.name = name; this.target = target; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + target + ", " + name + ")"; } public Object[] _fieldsToList() { return new Object[] { target, name }; } final public CallMethodOrGetField setAllowNullReference(boolean allowNullReference) { return allowNullReference(allowNullReference); } public CallMethodOrGetField allowNullReference(boolean allowNullReference) { this.allowNullReference = allowNullReference; return this; } final public boolean getAllowNullReference() { return allowNullReference(); } public boolean allowNullReference() { return allowNullReference; } public boolean allowNullReference = false; public Object handleNullReference() { if (allowNullReference) return null; else throw new NullPointerException(); } public Object get(VarContext ctx) { try { Object object = target.get(ctx); if (object == null) return handleNullReference(); return preciseGetOrCallMethod(object, name); } catch (Throwable e) { throw rethrowWithSrc("Was getting " + name, e); } } } static public class GetVarContext extends EvaluableBase { public Object get(VarContext ctx) { return ctx; } } static public class ThrowMethodNotFoundException extends EvaluableBase implements IFieldsToList { public CallMethod instruction; public ThrowMethodNotFoundException() { } public ThrowMethodNotFoundException(CallMethod instruction) { this.instruction = instruction; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + instruction + ")"; } public Object[] _fieldsToList() { return new Object[] { instruction }; } public Object get(VarContext ctx) { throw fail("Method not found: " + instruction); } } static public class ThrowNullPointerException extends EvaluableBase implements IFieldsToList { public CallMethod instruction; public ThrowNullPointerException() { } public ThrowNullPointerException(CallMethod instruction) { this.instruction = instruction; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + instruction + ")"; } public Object[] _fieldsToList() { return new Object[] { instruction }; } public Object get(VarContext ctx) { throw fail("Null pointer exception: " + instruction); } } static public class CallMethod extends EvaluableBase implements IFieldsToList { public Evaluable target; public String methodName; public Evaluable[] args; public CallMethod() { } public CallMethod(Evaluable target, String methodName, Evaluable[] args) { this.args = args; this.methodName = methodName; this.target = target; } public Object[] _fieldsToList() { return new Object[] { target, methodName, args }; } public Object get(VarContext ctx) { return newPreciseCall(target.get(ctx), methodName, mapToArrayOrNull(args, arg -> arg.get(ctx))); } public String toString() { return target + "." + formatFunctionCall(methodName, args); } public Evaluable optimize() { var targetType = target.returnType(); if (targetType != null && targetType.knownValue()) { Object o = targetType.value(); if (o == null) return new ThrowNullPointerException(this); Class[] argTypes = new Class[l(args)]; for (int i = 0; i < l(args); i++) { var type = args[i].returnType(); if (type == null || !type.javaClassIsExact()) return this; argTypes[i] = type.javaClass(); } List methods = findMethodsNamed_cached(o, methodName); if (any(methods, m -> m.isVarArgs())) return this; var __4 = findMethod_withPrimitiveWidening_onTypes(o, methodName, argTypes); var method = __4.a; var widening = __4.b; if (method == null) return new ThrowMethodNotFoundException(this); return new DirectMethodCallOnKnownTarget(widening, o instanceof Class ? null : o, method, args); } return this; } } static public class LambdaDef extends EvaluableBase implements IFieldsToList { public Class intrface; public String[] args; public Evaluable body; public LambdaDef() { } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + intrface + ", " + args + ", " + body + ")"; } public Object[] _fieldsToList() { return new Object[] { intrface, args, body }; } public Method implementedMethod; public LambdaDef(Class intrface, String[] args, Evaluable body) { this.body = body; this.args = args; this.intrface = intrface; implementedMethod = findSingleInterfaceMethodOrFail(intrface); if (implementedMethod.getParameterCount() != l(args)) throw fail("Bad parameter count for lambda: " + implementedMethod + " vs: " + joinWithComma(args)); } public Object get(VarContext ctx) { return proxyFromInvocationHandler(intrface, (proxy, method, actualArgs) -> { ping(); if (method.getDeclaringClass() == intrface) { var ctx2 = new FlexibleVarContext(ctx); var argNames = args; for (int i = 0; i < l(args); i++) ctx2.put(argNames[i], actualArgs[i]); return body.get(ctx2); } else return handleObjectMethodsInProxyInvocationHandler(this, implementedMethod, method, proxy, actualArgs); }); } } abstract static public class CurriedLambdaBase extends EvaluableBase implements IFieldsToList { public Class intrface; public Evaluable[] curriedArgs; public CurriedLambdaBase() { } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + intrface + ", " + curriedArgs + ")"; } public Object[] _fieldsToList() { return new Object[] { intrface, curriedArgs }; } public Method implementedMethod; public CurriedLambdaBase(Class intrface, Evaluable[] curriedArgs) { this.curriedArgs = curriedArgs; this.intrface = intrface; implementedMethod = findSingleInterfaceMethodOrFail(intrface); } public Object get(VarContext ctx) { Object[] curriedArguments = mapToArrayOrNull(curriedArgs, arg -> arg.get(ctx)); return proxyFromInvocationHandler(intrface, (proxy, method, actualArgs) -> { if (method.getDeclaringClass() == intrface) return forwardCall(ctx, concatMethodArgs(curriedArguments, actualArgs)); else return handleObjectMethodsInProxyInvocationHandler(this, implementedMethod, method, proxy, actualArgs); }); } abstract public Object forwardCall(VarContext ctx, Object[] args); } static public class CurriedMethodLambda extends CurriedLambdaBase { public Object target; public String targetMethod; public CurriedMethodLambda(Class intrface, Object target, String targetMethod, Evaluable[] curriedArgs) { super(intrface, curriedArgs); this.targetMethod = targetMethod; this.target = target; } public Object forwardCall(VarContext ctx, Object[] args) { return call(target, targetMethod, args); } } static public class CurriedScriptFunctionLambda extends CurriedLambdaBase { public FunctionDef f; public CurriedScriptFunctionLambda(Class intrface, FunctionDef f, Evaluable[] curriedArgs) { super(intrface, curriedArgs); this.f = f; } public Object forwardCall(VarContext ctx, Object[] args) { return f.call(ctx, args); } } static public class CurriedConstructorLambda extends CurriedLambdaBase { public Constructor[] ctors; public CurriedConstructorLambda(Class intrface, Constructor[] ctors, Evaluable[] curriedArgs) { super(intrface, curriedArgs); this.ctors = ctors; } public Object forwardCall(VarContext ctx, Object[] args) { return preciseNuObject(ctors, args); } } static public class DirectMethodCallOnKnownTarget extends EvaluableBase implements IFieldsToList { public boolean widening = false; public Object target; public Method method; public Evaluable[] args; public DirectMethodCallOnKnownTarget() { } public DirectMethodCallOnKnownTarget(boolean widening, Object target, Method method, Evaluable[] args) { this.args = args; this.method = method; this.target = target; this.widening = widening; } public Object[] _fieldsToList() { return new Object[] { widening, target, method, args }; } public Object get(VarContext ctx) { var evaluatedArgs = mapToArrayOrNull(args, arg -> arg.get(ctx)); return widening ? invokeMethodWithWidening(method, target, evaluatedArgs) : invokeMethod(method, target, evaluatedArgs); } public String toString() { return (target == null ? "" : target + ".") + formatFunctionCall(str(method), args); } public LASValueDescriptor returnType() { return LASValueDescriptor.fromClass(method.getReturnType()); } } static public class While extends EvaluableBase implements IFieldsToList { public Evaluable condition; public Evaluable body; public While() { } public While(Evaluable condition, Evaluable body) { this.body = body; this.condition = condition; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + condition + ", " + body + ")"; } public Object[] _fieldsToList() { return new Object[] { condition, body }; } public Object get(VarContext ctx) { while (!ctx.exiting() && (Boolean) condition.get(ctx)) { body.get(ctx); } return null; } } abstract static public class ForEachBase extends EvaluableBase implements IFieldsToList { public Evaluable collection; public Evaluable body; public ForEachBase() { } public ForEachBase(Evaluable collection, Evaluable body) { this.body = body; this.collection = collection; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + collection + ", " + body + ")"; } public Object[] _fieldsToList() { return new Object[] { collection, body }; } public Object get(VarContext ctx) { var coll = collection.get(ctx); Iterator iterator; List out; try { if (coll instanceof Object[]) { out = emptyList(((Object[]) coll).length); for (var element : ((Object[]) coll)) { if (ctx.exiting()) return null; processElement(ctx, out, element); } } else if (coll instanceof Iterable) { out = emptyList((Iterable) coll); for (var element : ((Iterable) coll)) { if (ctx.exiting()) return null; processElement(ctx, out, element); } } else if (coll == null) out = new ArrayList(); else throw fail("Not iterable: " + className(coll)); } finally { loopDone(ctx); } return out; } abstract public void processElement(VarContext ctx, List out, Object o); abstract public void loopDone(VarContext ctx); } static public class ForEach extends ForEachBase { public ForEach() { } public String var; public ForEach(Evaluable collection, String var, Evaluable body) { this.body = body; this.var = var; this.collection = collection; } public void processElement(VarContext ctx, List out, Object o) { ctx.set(var, o); out.add(body.get(ctx)); } public void loopDone(VarContext ctx) { ctx.unset(var); } } static public class ForIterator extends EvaluableBase implements IFieldsToList { static final public String _fieldOrder = "iterable var body"; public Evaluable iterable; public String var; public Evaluable body; public ForIterator() { } public ForIterator(Evaluable iterable, String var, Evaluable body) { this.body = body; this.var = var; this.iterable = iterable; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + iterable + ", " + var + ", " + body + ")"; } public boolean equals(Object o) { if (!(o instanceof ForIterator)) return false; ForIterator __5 = (ForIterator) o; return eq(iterable, __5.iterable) && eq(var, __5.var) && eq(body, __5.body); } public int hashCode() { int h = -214906825; h = boostHashCombine(h, _hashCode(iterable)); h = boostHashCombine(h, _hashCode(var)); h = boostHashCombine(h, _hashCode(body)); return h; } public Object[] _fieldsToList() { return new Object[] { iterable, var, body }; } public Object get(VarContext ctx) { VarContext subContext = new FlexibleVarContext(ctx); var iterable = this.iterable.get(ctx); Iterator iterator = iterator_gen(iterable); return mapI(iterator, value -> { subContext.set(var, value); return body.get(subContext); }); } } static public class ForNested extends EvaluableBase implements IFieldsToList { static final public String _fieldOrder = "iterable var body"; public Evaluable iterable; public String var; public Evaluable body; public ForNested() { } public ForNested(Evaluable iterable, String var, Evaluable body) { this.body = body; this.var = var; this.iterable = iterable; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + iterable + ", " + var + ", " + body + ")"; } public boolean equals(Object o) { if (!(o instanceof ForNested)) return false; ForNested __6 = (ForNested) o; return eq(iterable, __6.iterable) && eq(var, __6.var) && eq(body, __6.body); } public int hashCode() { int h = -1363247360; h = boostHashCombine(h, _hashCode(iterable)); h = boostHashCombine(h, _hashCode(var)); h = boostHashCombine(h, _hashCode(body)); return h; } public Object[] _fieldsToList() { return new Object[] { iterable, var, body }; } public Object get(VarContext ctx) { VarContext subContext = new FlexibleVarContext(ctx); var iterable = this.iterable.get(ctx); Iterator iterator = iterator_gen(iterable); return nestedIterator(iterator, value -> { subContext.set(var, value); return iterator_gen(body.get(subContext)); }); } } static public class ForPairs extends ForEachBase { public ForPairs() { } public String varA, varB; public ForPairs(Evaluable collection, Evaluable body, String varA, String varB) { this.varB = varB; this.varA = varA; this.body = body; this.collection = collection; } public void processElement(VarContext ctx, List out, Object o) { Pair p = (Pair) o; ctx.set(varA, p.a); ctx.set(varB, p.b); out.add(body.get(ctx)); } public void loopDone(VarContext ctx) { ctx.unset(varA); ctx.unset(varB); } } static public class ForKeyValue extends EvaluableBase implements IFieldsToList { public Evaluable map; public Evaluable body; public String varA; public String varB; public ForKeyValue() { } public ForKeyValue(Evaluable map, Evaluable body, String varA, String varB) { this.varB = varB; this.varA = varA; this.body = body; this.map = map; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + map + ", " + body + ", " + varA + ", " + varB + ")"; } public Object[] _fieldsToList() { return new Object[] { map, body, varA, varB }; } public Object get(VarContext ctx) { Map theMap = (Map) map.get(ctx); List out; try { if (theMap != null) { out = emptyList(theMap.size()); for (var entry : theMap.entrySet()) { if (ctx.exiting()) return null; ctx.set(varA, entry.getKey()); ctx.set(varB, entry.getValue()); out.add(body.get(ctx)); } } else out = new ArrayList(); } finally { ctx.unset(varA); ctx.unset(varB); } return out; } } static public class ForIntTo extends EvaluableBase implements IFieldsToList { public Evaluable endValue; public String var; public Evaluable body; public ForIntTo() { } public ForIntTo(Evaluable endValue, String var, Evaluable body) { this.body = body; this.var = var; this.endValue = endValue; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + endValue + ", " + var + ", " + body + ")"; } public Object[] _fieldsToList() { return new Object[] { endValue, var, body }; } public Evaluable optimize() { if (!returnValueNeeded) body = body.optimizeForReturnValueNotNeeded(); return this; } public Object get(VarContext ctx) { int n = (Integer) endValue.get(ctx), i = 0; List out = returnValueNeeded ? new ArrayList() : null; try { ctx.put(var, i); while (i < n) { if (ctx.exiting()) return null; Object o = body.get(ctx); { if (out != null) out.add(o); } ctx.set(var, i = (Integer) ctx.get(var) + 1); } } finally { ctx.unset(var); } return out; } } static public class ForIndex extends EvaluableBase { public ForIndex() { } public Evaluable collection, body; public String varIndex, varElement; public ForIndex(Evaluable collection, Evaluable body, String varIndex, String varElement) { this.varElement = varElement; this.varIndex = varIndex; this.body = body; this.collection = collection; } public Object get(VarContext ctx) { return new ForIndex_instance(collection, body, varIndex, varElement).get(ctx); } } static public class ForIndex_instance extends ForEachBase { public String varIndex, varElement; public int index; public ForIndex_instance(Evaluable collection, Evaluable body, String varIndex, String varElement) { this.varElement = varElement; this.varIndex = varIndex; this.body = body; this.collection = collection; } public void processElement(VarContext ctx, List out, Object o) { ctx.set(varIndex, index++); ctx.set(varElement, o); out.add(body.get(ctx)); } public void loopDone(VarContext ctx) { ctx.unset(varIndex); ctx.unset(varElement); } } static public class IfThen extends EvaluableBase implements IFieldsToList { public Evaluable condition; public Evaluable body; public Evaluable elseBranch; public IfThen() { } public IfThen(Evaluable condition, Evaluable body, Evaluable elseBranch) { this.elseBranch = elseBranch; this.body = body; this.condition = condition; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + condition + ", " + body + ", " + elseBranch + ")"; } public Object[] _fieldsToList() { return new Object[] { condition, body, elseBranch }; } public IfThen(Evaluable condition, Evaluable body) { this.condition = condition; this.body = body; } public Object get(VarContext ctx) { if ((Boolean) condition.get(ctx)) return body.get(ctx); else if (elseBranch != null) return elseBranch.get(ctx); else return null; } } static public class ReturnFromScript extends EvaluableBase implements IFieldsToList { public Script script; public Evaluable value; public ReturnFromScript() { } public ReturnFromScript(Script script, Evaluable value) { this.value = value; this.script = script; } public Object[] _fieldsToList() { return new Object[] { script, value }; } public Object get(VarContext ctx) { Object result = value.get(ctx); ctx.exitFromScript(script); ctx.returnValue(result); return null; } public String toString() { return formatFunctionCall("ReturnFromScript", script, value); } } static public class Continue extends EvaluableBase implements IFieldsToList { public Script loopBody; public Continue() { } public Continue(Script loopBody) { this.loopBody = loopBody; } public Object[] _fieldsToList() { return new Object[] { loopBody }; } public Object get(VarContext ctx) { ctx.exitFromScript(loopBody); ctx.returnValue(null); return null; } public String toString() { return formatFunctionCall("Continue", loopBody); } } static public class RepeatN extends EvaluableBase implements IFieldsToList { public Evaluable n; public Evaluable body; public RepeatN() { } public RepeatN(Evaluable n, Evaluable body) { this.body = body; this.n = n; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + n + ", " + body + ")"; } public Object[] _fieldsToList() { return new Object[] { n, body }; } public Object get(VarContext ctx) { long count = ((Number) n.get(ctx)).longValue(); for (int _repeat_0 = 0; _repeat_0 < count; _repeat_0++) { if (ctx.exiting()) return null; body.get(ctx); } return null; } } static public class BoolAnd extends EvaluableBase implements IFieldsToList { public Evaluable a; public Evaluable b; public BoolAnd() { } public BoolAnd(Evaluable a, Evaluable b) { this.b = b; this.a = a; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + a + ", " + b + ")"; } public boolean equals(Object o) { if (!(o instanceof BoolAnd)) return false; BoolAnd __7 = (BoolAnd) o; return eq(a, __7.a) && eq(b, __7.b); } public int hashCode() { int h = 1729330797; h = boostHashCombine(h, _hashCode(a)); h = boostHashCombine(h, _hashCode(b)); return h; } public Object[] _fieldsToList() { return new Object[] { a, b }; } public Object get(VarContext ctx) { if (!((Boolean) a.get(ctx))) return false; return b.get(ctx); } } static public class BoolOr extends EvaluableBase implements IFieldsToList { public Evaluable a; public Evaluable b; public BoolOr() { } public BoolOr(Evaluable a, Evaluable b) { this.b = b; this.a = a; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + a + ", " + b + ")"; } public boolean equals(Object o) { if (!(o instanceof BoolOr)) return false; BoolOr __8 = (BoolOr) o; return eq(a, __8.a) && eq(b, __8.b); } public int hashCode() { int h = 1995447949; h = boostHashCombine(h, _hashCode(a)); h = boostHashCombine(h, _hashCode(b)); return h; } public Object[] _fieldsToList() { return new Object[] { a, b }; } public Object get(VarContext ctx) { if (((Boolean) a.get(ctx))) return true; return b.get(ctx); } } static public class TempBlock extends EvaluableBase implements IFieldsToList { public Evaluable tempExpr; public Evaluable body; public TempBlock() { } public TempBlock(Evaluable tempExpr, Evaluable body) { this.body = body; this.tempExpr = tempExpr; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + tempExpr + ", " + body + ")"; } public Object[] _fieldsToList() { return new Object[] { tempExpr, body }; } public Object get(VarContext ctx) { AutoCloseable __2 = (AutoCloseable) (tempExpr.get(ctx)); try { return body.get(ctx); } finally { _close(__2); } } } static public class ClassDef extends EvaluableBase implements IFieldsToList { public ResolvableLASClass lasClass; public ClassDef() { } public ClassDef(ResolvableLASClass lasClass) { this.lasClass = lasClass; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + lasClass + ")"; } public boolean equals(Object o) { if (!(o instanceof ClassDef)) return false; ClassDef __9 = (ClassDef) o; return eq(lasClass, __9.lasClass); } public int hashCode() { int h = 757052301; h = boostHashCombine(h, _hashCode(lasClass)); return h; } public Object[] _fieldsToList() { return new Object[] { lasClass }; } public Object get(VarContext ctx) { return lasClass.get(); } } static public class SetField extends EvaluableBase implements IFieldsToList { public Evaluable target; public String name; public Evaluable expr; public SetField() { } public SetField(Evaluable target, String name, Evaluable expr) { this.expr = expr; this.name = name; this.target = target; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + target + ", " + name + ", " + expr + ")"; } public Object[] _fieldsToList() { return new Object[] { target, name, expr }; } final public SetField setAllowNullReference(boolean allowNullReference) { return allowNullReference(allowNullReference); } public SetField allowNullReference(boolean allowNullReference) { this.allowNullReference = allowNullReference; return this; } final public boolean getAllowNullReference() { return allowNullReference(); } public boolean allowNullReference() { return allowNullReference; } public boolean allowNullReference = false; public Object handleNullReference() { if (allowNullReference) return null; else throw new NullPointerException(); } public Object get(VarContext ctx) { try { Object value = expr.get(ctx); Object object = target.get(ctx); if (object == null) handleNullReference(); else set(object, name, value); return value; } catch (Throwable e) { throw rethrowWithSrc(e); } } } static public class Throw extends EvaluableBase implements IFieldsToList { public Evaluable expr; public Throw() { } public Throw(Evaluable expr) { this.expr = expr; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + expr + ")"; } public Object[] _fieldsToList() { return new Object[] { expr }; } public Object get(VarContext ctx) { throw asRuntimeException((Throwable) expr.get(ctx)); } } static public class TryCatch extends EvaluableBase implements IFieldsToList { public Evaluable body; public String var; public Evaluable catchBlock; public TryCatch() { } public TryCatch(Evaluable body, String var, Evaluable catchBlock) { this.catchBlock = catchBlock; this.var = var; this.body = body; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + body + ", " + var + ", " + catchBlock + ")"; } public Object[] _fieldsToList() { return new Object[] { body, var, catchBlock }; } public Object get(VarContext ctx) { try { return body.get(ctx); } catch (Throwable e) { AutoCloseable __3 = ctx.tempPut(var, e); try { return catchBlock.get(ctx); } finally { _close(__3); } } } } static public structure_Data structureDataForLAS() { structure_Data d = new structure_Data(); d.skipDefaultValues(true); d.shouldIncludeField = field -> { String c = shortClassName(field.getDeclaringClass()); String f = field.getName(); boolean shouldInclude = !(eq(c, "HasTokenRangeWithSrc") && eq(f, "src")); return shouldInclude; }; return d; } static public boolean isUnproblematicValue(Object o) { return o == null || o instanceof Number || o instanceof String || o instanceof Boolean || o instanceof Class; } static public String scriptStruct(Object o) { String s = struct(o, structureDataForLAS()); List tok = structTok(s); String prefix = shortName(GazelleV_LeftArrowScript.class) + "$"; for (int i = 1; i < l(tok); i += 2) tok.set(i, replacePrefix(prefix, "$", tok.get(i))); return join(tok); } static public String indentedScriptStruct(Object o) { return indentStructureString(scriptStruct(o)); } } static public class MethodMaker { public ClassGen cg; public MethodGen mg; public InstructionList il = new InstructionList(); public ConstantPoolGen cp; public InstructionFactory factory; public int frameSize; final public MethodMaker setVerboseAdd(boolean verboseAdd) { return verboseAdd(verboseAdd); } public MethodMaker verboseAdd(boolean verboseAdd) { this.verboseAdd = verboseAdd; return this; } final public boolean getVerboseAdd() { return verboseAdd(); } public boolean verboseAdd() { return verboseAdd; } public boolean verboseAdd = false; public boolean classConstantWorkaround = false; public MethodMaker(ClassMaker classMaker, Class returnType, String methodName, Class... argumentTypes) { this(classMaker.cg, returnType, methodName, argumentTypes); } public MethodMaker(ClassGen cg, Class returnType, String methodName, Class... argumentTypes) { this(cg, Const.ACC_PUBLIC, returnType, methodName, argumentTypes); } public MethodMaker(ClassGen cg, short modifiers, Class returnType, String methodName, Class... argumentTypes) { this.cg = cg; cp = cg.getConstantPool(); factory = new InstructionFactory(cg); org.apache.bcel.generic.Type[] argTypes = wrapTypes(argumentTypes); mg = new MethodGen(modifiers, wrapType(returnType), argTypes, null, methodName, cg.getClassName(), il, cp); frameSize = l(argTypes) + 1; } static public org.apache.bcel.generic.Type[] wrapTypes(Class[] classes) { org.apache.bcel.generic.Type[] types = new org.apache.bcel.generic.Type[l(classes)]; for (int i = 0; i < l(classes); i++) types[i] = wrapType(classes[i]); return types; } static public org.apache.bcel.generic.Type wrapType(Class c) { return classToBCELType(c); } public int newLocalVar() { return frameSize++; } public MethodMaker newObject(Class c, Class... argTypes) { il.append(factory.createNew(className(c))); il.append(InstructionConst.DUP); Constructor ctor = findConstructor_precise_onTypes(c, argTypes); il.append(factory.createInvoke(className(c), "", org.apache.bcel.generic.Type.VOID, wrapTypes(ctor.getParameterTypes()), Const.INVOKESPECIAL)); return this; } public MethodMaker dup() { il.append(InstructionConst.DUP); return this; } public MethodMaker astore(int var) { il.append(new ASTORE(var)); return this; } public MethodMaker aload(int var) { il.append(new ALOAD(var)); return this; } public MethodMaker stringConstant(String s) { il.append(new PUSH(cp, s)); return this; } public MethodMaker classConstant(Class c) { if (classConstantWorkaround) { stringConstant(c.getName()); invokeStatic(Class.class, Class.class, "forName", String.class); } else { var ldc = new LDC(classRef(c)); assertEquals("classConstant", ldc.getValue(cp), wrapType(c)); il.append(ldc); } return this; } final public MethodMaker intConst(int i) { return intConstant(i); } public MethodMaker intConstant(int i) { if (i >= -1 && i <= 5) return add(new ICONST(i)); if (i == (byte) i) return add(new BIPUSH((byte) i)); if (i == (short) i) return add(new SIPUSH((short) i)); return add(new LDC(cp.addInteger(i))); } final public MethodMaker doubleConst(double d) { return doubleConstant(d); } public MethodMaker doubleConstant(double d) { return add(new LDC2_W(cp.addDouble(d))); } public MethodMaker boolConstant(boolean b) { return intConstant(b ? 1 : 0); } public MethodMaker invokeVirtual(Class c, Class returnType, String methodName, Class... argTypes) { Method m = findNonStaticMethod_precise_onTypes(c, methodName, argTypes); if (m == null) throw fail("Method not found: " + className(c) + "." + formatFunctionCall(methodName, argTypes) + " returning " + className(returnType)); il.append(factory.createInvoke(className(c), methodName, wrapType(m.getReturnType()), wrapTypes(m.getParameterTypes()), Const.INVOKEVIRTUAL)); return this; } public MethodMaker invokeInterface(Class c, Class returnType, String methodName, Class... argTypes) { Method m = mostApplicableMethod_onTypes(filter(nonDefaultInterfaceMethods(c), _m -> _m.getName().equals(methodName)), argTypes); if (m == null) throw fail("Method not found: " + className(c) + "." + formatFunctionCall(methodName, argTypes) + " returning " + className(returnType)); il.append(factory.createInvoke(className(c), methodName, wrapType(m.getReturnType()), wrapTypes(m.getParameterTypes()), Const.INVOKEINTERFACE)); return this; } public MethodMaker invokeStatic(Class c, Class returnType, String methodName, Class... argTypes) { Method m = findMethod_precise_onTypes(c, methodName, argTypes); if (m == null) throw fail("Method not found: " + className(c) + "." + formatFunctionCall(methodName, argTypes) + " returning " + className(returnType)); il.append(factory.createInvoke(className(c), methodName, wrapType(m.getReturnType()), wrapTypes(m.getParameterTypes()), Const.INVOKESTATIC)); return this; } public MethodMaker areturn() { il.append(InstructionConst.ARETURN); return this; } public MethodMaker _return() { il.append(InstructionConst.RETURN); return this; } public MethodMaker add(Instruction i) { il.append(i); if (verboseAdd) print("> " + i); return this; } public A addAndReturn(A i) { add(i); return i; } public MethodMaker add(BranchInstruction i) { il.append(i); if (verboseAdd) print("> " + i); return this; } public A addAndReturn(A i) { add(i); return i; } public void done() { mg.stripAttributes(true); mg.setMaxStack(); mg.setMaxLocals(); cg.addMethod(mg.getMethod()); } public JVMStackCellType convertToObject(JVMStackCellType stackTop) { if (stackTop == JVMStackCellType.objValue) { } else if (stackTop == JVMStackCellType.intValue) invokeStatic(Integer.class, Integer.class, "valueOf", int.class); else if (stackTop == JVMStackCellType.doubleValue) invokeStatic(Double.class, Double.class, "valueOf", double.class); else if (stackTop == JVMStackCellType.none) add(new ACONST_NULL()); else throw fail("TODO: add conversion for stack cell type: " + stackTop); return JVMStackCellType.objValue; } public void discardStackTop(JVMStackCellType stackTop) { if (stackTop == JVMStackCellType.none) { } else if (stackTop == JVMStackCellType.doubleValue || stackTop == JVMStackCellType.longValue) add(new POP2()); else add(new POP()); } public int classRef(Class c) { return cp.addClass((ObjectType) wrapType(assertNotNull(c))); } public MethodMaker checkCast(Class c) { return add(new CHECKCAST(classRef(c))); } public MethodMaker loadNull() { return add(new ACONST_NULL()); } public InstructionHandle here() { return il.append(new NOP()); } public GOTO forwardGoto() { return addAndReturn(new GOTO(null)); } public void returnWithType(JVMStackCellType stackTop) { if (stackTop == JVMStackCellType.objValue) areturn(); else if (stackTop == JVMStackCellType.intValue) add(new IRETURN()); else if (stackTop == JVMStackCellType.doubleValue) add(new DRETURN()); else if (stackTop == JVMStackCellType.none) _return(); else throw fail("TODO: add return for stack cell type: " + stackTop); } public void getStaticField(String className, String fieldName, Class type) { il.append(factory.createGetStatic(className, fieldName, wrapType(type))); } } static public class FixedVarContext extends VarContext { public String[] names; public Object[] values; public FixedVarContext() { } public FixedVarContext(String[] names) { this(null, names); this.names = names; } public FixedVarContext(VarContext parent, String[] names) { super(parent); this.names = names; if (names != null) values = new Object[names.length]; } public int indexOfVar(String name) { return indexOfInSortedArray(names, name); } public int indexOfVarMandatory(String name) { int idx = indexOfVar(name); if (idx < 0) throw fail("Variable not found: " + name + ", known: " + joinWithComma(names)); return idx; } public Object get(int idx) { return values[idx]; } public Object get(String name) { int idx = indexOfVar(name); if (idx >= 0) return values[idx]; if (parent != null) return parent.get(name); return null; } public void set(int idx, Object value) { values[idx] = value; } public void set(String name, Object value) { int idx = indexOfVar(name); if (idx >= 0) values[idx] = value; else throw fail("Variable " + name + " not defined in context"); } public AutoCloseable tempSet(String name, Object value) { int idx = indexOfVar(name); if (idx >= 0) { Object old = values[idx]; values[idx] = value; return () -> values[idx] = old; } else throw fail("Variable " + name + " not defined in context"); } public void unset(String name) { set(name, null); } public Map varMap() { Map map = new HashMap(); int n = l(names); for (int i = 0; i < n; i++) map.put(names[i], values[i]); return map; } } public enum JVMStackCellType { none, objValue, intValue, longValue, floatValue, doubleValue } static public class FlexibleVarContext extends VarContext { public Map vars; public FlexibleVarContext() { } public FlexibleVarContext(VarContext parent) { super(parent); } public Object get(String name) { if (containsKey(vars, name)) return mapGet(vars, name); if (parent != null) return parent.get(name); return null; } public void set(String name, Object value) { vars = putOrCreateSyncMap(vars, name, value); } public AutoCloseable tempSet(String name, Object value) { initMap(); return main.tempPut(vars, name, value); } public void unset(String name) { remove(vars, name); } public Map varMap() { return vars; } final public void initMap() { makeThreadSafe(); } public void makeThreadSafe() { if (vars == null) vars = syncHashMap(); } } static public class LASToByteCode implements IFieldsToList { public MethodMaker m; public LASToByteCode() { } public LASToByteCode(MethodMaker m) { this.m = m; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + m + ")"; } public Object[] _fieldsToList() { return new Object[] { m }; } public boolean callPing = true; final public LASToByteCode setIVarContext(int iVarContext) { return iVarContext(iVarContext); } public LASToByteCode iVarContext(int iVarContext) { this.iVarContext = iVarContext; return this; } final public int getIVarContext() { return iVarContext(); } public int iVarContext() { return iVarContext; } public int iVarContext = -1; public GazelleV_LeftArrowScript.Script returnableScript; final public LASToByteCode setPostConversion(IF1 postConversion) { return postConversion(postConversion); } public LASToByteCode postConversion(IF1 postConversion) { this.postConversion = postConversion; return this; } final public IF1 getPostConversion() { return postConversion(); } public IF1 postConversion() { return postConversion; } public IF1 postConversion; public JVMStackCellType compileScript(GazelleV_LeftArrowScript.Script script) { returnableScript = script; var stackTop = compile(script); if (postConversion != null) stackTop = postConversion.get(stackTop); return stackTop; } public void compileToObject(GazelleV_LeftArrowScript.Evaluable code) { m.convertToObject(compile(code)); } public JVMStackCellType compile(GazelleV_LeftArrowScript.Evaluable code) { if (code instanceof GazelleV_LeftArrowScript.Const) { Object o = ((GazelleV_LeftArrowScript.Const) code).value; if (o == null) { m.add(new ACONST_NULL()); return JVMStackCellType.objValue; } else if (o instanceof String) { m.stringConstant((String) o); return JVMStackCellType.objValue; } else if (o instanceof Integer) { m.intConstant((Integer) o); return JVMStackCellType.intValue; } else if (o instanceof Double) { m.doubleConstant((Double) o); return JVMStackCellType.doubleValue; } else if (o instanceof Class) { m.classConstant((Class) o); return JVMStackCellType.objValue; } else if (o instanceof Boolean) { m.boolConstant((Boolean) o); return JVMStackCellType.intValue; } else throw fail("Can't compile const value: " + toStringWithClass(o)); } else if (code instanceof GazelleV_LeftArrowScript.Script) { var stackTop = JVMStackCellType.none; for (var step : ((GazelleV_LeftArrowScript.Script) code).steps) { if (stackTop != JVMStackCellType.none) m.add(new POP()); stackTop = compile(step); } return stackTop; } else if (code instanceof GazelleV_LeftArrowScript.CallMethod) { compileToObject(((GazelleV_LeftArrowScript.CallMethod) code).target); m.stringConstant(((GazelleV_LeftArrowScript.CallMethod) code).methodName); argumentsAsArray(((GazelleV_LeftArrowScript.CallMethod) code).args); m.invokeStatic(main.class, Object.class, "call", Object.class, String.class, Object[].class); return JVMStackCellType.objValue; } else if (code instanceof GazelleV_LeftArrowScript.CallMethodOrGetField) { compileToObject(((GazelleV_LeftArrowScript.CallMethodOrGetField) code).target); m.stringConstant(((GazelleV_LeftArrowScript.CallMethodOrGetField) code).name); m.invokeStatic(main.class, Object.class, "preciseGetOrCallMethod", Object.class, String.class); return JVMStackCellType.objValue; } else if (code instanceof GazelleV_LeftArrowScript.SetField) { compileToObject(((GazelleV_LeftArrowScript.SetField) code).target); m.stringConstant(((GazelleV_LeftArrowScript.SetField) code).name); compileToObject(((GazelleV_LeftArrowScript.SetField) code).expr); m.invokeStatic(main.class, Object.class, "set", Object.class, String.class, Object.class); return JVMStackCellType.none; } else if (code instanceof GazelleV_LeftArrowScript.NewObject) { m.classConstant(((GazelleV_LeftArrowScript.NewObject) code).c); argumentsAsArray(((GazelleV_LeftArrowScript.NewObject) code).args); m.invokeStatic(main.class, Object.class, "nuObject", Class.class, Object[].class); return JVMStackCellType.objValue; } else if (code instanceof GazelleV_LeftArrowScript.Assignment) { compileToObject(((GazelleV_LeftArrowScript.Assignment) code).expression); m.astore(iTemp()); loadVarContext(); m.stringConstant(((GazelleV_LeftArrowScript.Assignment) code).var); m.aload(iTemp()); m.invokeVirtual(VarContext.class, void.class, "set", String.class, Object.class); m.aload(iTemp()); return JVMStackCellType.objValue; } else if (code instanceof GazelleV_LeftArrowScript.While) { var loopStart = m.il.append(new NOP()); BranchInstruction branch1 = null; if (callPing) { m.invokeStatic(main.class, boolean.class, "ping"); branch1 = new IFEQ(null); m.add(branch1); } compileToBool(((GazelleV_LeftArrowScript.While) code).condition); var branch2 = new IFEQ(null); m.add(branch2); m.discardStackTop(compile(((GazelleV_LeftArrowScript.While) code).body)); m.add(new GOTO(loopStart)); var loopEnd = m.il.append(new NOP()); { if (branch1 != null) branch1.setTarget(loopEnd); } branch2.setTarget(loopEnd); return JVMStackCellType.none; } else if (code instanceof GazelleV_LeftArrowScript.IfThen) { compileToBool(((GazelleV_LeftArrowScript.IfThen) code).condition); var branch1 = new IFEQ(null); m.add(branch1); var stackTop = compile(((GazelleV_LeftArrowScript.IfThen) code).body); if (stackTop == JVMStackCellType.none) { branch1.setTarget(m.here()); return stackTop; } else { m.convertToObject(stackTop); var jumpToEnd = m.forwardGoto(); branch1.setTarget(m.here()); m.loadNull(); jumpToEnd.setTarget(m.here()); return JVMStackCellType.objValue; } } else if (code instanceof GazelleV_LeftArrowScript.GetVar) { return compileGetVar((GazelleV_LeftArrowScript.GetVar) code); } else if (code instanceof GazelleV_LeftArrowScript.ReturnFromScript) { if (((GazelleV_LeftArrowScript.ReturnFromScript) code).script != returnableScript) throw fail("Can only return from current script"); var stackTop = compile(((GazelleV_LeftArrowScript.ReturnFromScript) code).value); if (postConversion != null) stackTop = postConversion.get(stackTop); m.returnWithType(stackTop); return JVMStackCellType.none; } throw fail("Can't compile yet: " + className(code)); } public void argumentsAsArray(GazelleV_LeftArrowScript.Evaluable[] args) { int n = l(args); m.intConst(n); m.add(new ANEWARRAY(m.classRef(Object.class))); for (int iArg = 0; iArg < n; iArg++) { m.dup(); m.intConst(iArg); compileToObject(args[iArg]); m.add(new AASTORE()); } } public void loadVarContext() { assertTrue("Need VarContext", iVarContext >= 0); m.aload(iVarContext); } public Integer iTemp_cache; public int iTemp() { if (iTemp_cache == null) iTemp_cache = iTemp_load(); return iTemp_cache; } public Integer iTemp_load() { return m.newLocalVar(); } public void compileToBool(GazelleV_LeftArrowScript.Evaluable condition) { var stackTop = compile(condition); if (stackTop == JVMStackCellType.objValue) { m.checkCast(Boolean.class); m.invokeVirtual(Boolean.class, boolean.class, "booleanValue"); } else if (stackTop == JVMStackCellType.intValue) { } else throw fail("Can't convert to bool: " + stackTop); } public JVMStackCellType compileGetVar(GazelleV_LeftArrowScript.GetVar code) { loadVarContext(); m.stringConstant(code.var); m.invokeVirtual(VarContext.class, Object.class, "get", String.class); return JVMStackCellType.objValue; } } abstract static public class VarContext { final public VarContext getParent() { return parent(); } public VarContext parent() { return parent; } public VarContext parent; public VarContext() { } public VarContext(VarContext parent) { this.parent = parent; } abstract public Object get(String name); final public void put(String name, Object value) { set(name, value); } abstract public void set(String name, Object value); final public AutoCloseable tempPut(String name, Object value) { return tempSet(name, value); } abstract public AutoCloseable tempSet(String name, Object value); abstract public void unset(String name); abstract public Map varMap(); public void printMe() { pnl(varMap()); print("parent", parent); } final public VarContext setExitFromScript(Object exitFromScript) { return exitFromScript(exitFromScript); } public VarContext exitFromScript(Object exitFromScript) { this.exitFromScript = exitFromScript; return this; } final public Object getExitFromScript() { return exitFromScript(); } public Object exitFromScript() { return exitFromScript; } public Object exitFromScript; final public VarContext setReturnValue(Object returnValue) { return returnValue(returnValue); } public VarContext returnValue(Object returnValue) { this.returnValue = returnValue; return this; } final public Object getReturnValue() { return returnValue(); } public Object returnValue() { return returnValue; } public Object returnValue; public boolean exiting() { ping(); return exitFromScript != null; } } static public class LineAndColumn implements IFieldsToList { static final public String _fieldOrder = "line col getLineText"; public int line; public int col; public LineAndColumn() { } public LineAndColumn(int line, int col) { this.col = col; this.line = line; } public boolean equals(Object o) { if (!(o instanceof LineAndColumn)) return false; LineAndColumn __1 = (LineAndColumn) o; return line == __1.line && col == __1.col; } public int hashCode() { int h = -1128952231; h = boostHashCombine(h, _hashCode(line)); h = boostHashCombine(h, _hashCode(col)); return h; } public Object[] _fieldsToList() { return new Object[] { line, col }; } transient public IF1 getLineText; public String getLineText(int line) { return getLineText != null ? getLineText.get(line) : getLineText_base(line); } final public String getLineText_fallback(IF1 _f, int line) { return _f != null ? _f.get(line) : getLineText_base(line); } public String getLineText_base(int line) { return null; } public String toString() { return "Line " + n2(line) + ", col " + n2(col); } } static public class FailedRule extends RuleWithParams { public List satisfiedConditions; public Exp remainingCondition; public FailedRule() { } public FailedRule(IfThen rule, VarMatches matches, Exp remainingCondition) { this.remainingCondition = remainingCondition; this.matches = matches; this.rule = rule; } public FailedRule(IfThen rule, VarMatches matches, List satisfiedConditions, Exp remainingCondition) { this.remainingCondition = remainingCondition; this.satisfiedConditions = satisfiedConditions; this.matches = matches; this.rule = rule; } } static public class RuleWithParams implements IFieldsToList { static final public String _fieldOrder = "rule matches"; public IfThen rule; public VarMatches matches; public RuleWithParams() { } public RuleWithParams(IfThen rule, VarMatches matches) { this.matches = matches; this.rule = rule; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + rule + ", " + matches + ")"; } public boolean equals(Object o) { if (!(o instanceof RuleWithParams)) return false; RuleWithParams __7 = (RuleWithParams) o; return eq(rule, __7.rule) && eq(matches, __7.matches); } public int hashCode() { int h = 1254104616; h = boostHashCombine(h, _hashCode(rule)); h = boostHashCombine(h, _hashCode(matches)); return h; } public Object[] _fieldsToList() { return new Object[] { rule, matches }; } public String ruleID() { return rule.globalID; } } static public class IfThen implements IFieldsToList { static final public String _fieldOrder = "in out globalID options originalText"; public Exp in; public Exp out; public IfThen() { } public IfThen(Exp in, Exp out) { this.out = out; this.in = in; } public boolean equals(Object o) { if (!(o instanceof IfThen)) return false; IfThen __8 = (IfThen) o; return eq(in, __8.in) && eq(out, __8.out); } public int hashCode() { int h = -2108234502; h = boostHashCombine(h, _hashCode(in)); h = boostHashCombine(h, _hashCode(out)); return h; } public Object[] _fieldsToList() { return new Object[] { in, out }; } public String globalID; public Set options; public String originalText; public String text() { Collection opt = options; if (nempty(globalID)) opt = concatLists(ll("id: " + globalID), opt); return (nempty(opt) ? "[" + joinWithComma(opt) + "] " : "") + (in == null ? "" : in.text() + "\n => ") + nlLogic_text(out); } public String toString() { return text(); } } abstract static public class Exp { abstract public String text(); public String toString() { return text(); } } static public class Func extends Exp implements IFieldsToList { public String name; public Exp arg; public Func() { } public Func(String name, Exp arg) { this.arg = arg; this.name = name; } public boolean equals(Object o) { if (!(o instanceof Func)) return false; Func __0 = (Func) o; return eq(name, __0.name) && eq(arg, __0.arg); } public int hashCode() { int h = 2201316; h = boostHashCombine(h, _hashCode(name)); h = boostHashCombine(h, _hashCode(arg)); return h; } public Object[] _fieldsToList() { return new Object[] { name, arg }; } public List options; public Func(String name, List options, Exp arg) { this.arg = arg; this.options = options; this.name = name; } public String text() { return name + (empty(options) ? "" : "[" + joinWithComma(options) + "]") + "(" + arg.text() + ")"; } public String argText() { return nlLogic_text(arg); } } static public class And extends Exp implements IFieldsToList { public Exp a; public Exp b; public And() { } public And(Exp a, Exp b) { this.b = b; this.a = a; } public boolean equals(Object o) { if (!(o instanceof And)) return false; And __1 = (And) o; return eq(a, __1.a) && eq(b, __1.b); } public int hashCode() { int h = 65975; h = boostHashCombine(h, _hashCode(a)); h = boostHashCombine(h, _hashCode(b)); return h; } public Object[] _fieldsToList() { return new Object[] { a, b }; } public String text() { return a.text() + "\n && " + b.text(); } } static public class ExpNot extends Exp implements IFieldsToList { public Exp a; public ExpNot() { } public ExpNot(Exp a) { this.a = a; } public boolean equals(Object o) { if (!(o instanceof ExpNot)) return false; ExpNot __2 = (ExpNot) o; return eq(a, __2.a); } public int hashCode() { int h = 2089649046; h = boostHashCombine(h, _hashCode(a)); return h; } public Object[] _fieldsToList() { return new Object[] { a }; } public String text() { return "!" + a.text(); } } abstract static public class Literal extends Exp { } static public class Sentence extends Literal implements IFieldsToList { public List tok; public Sentence() { } public Sentence(List tok) { this.tok = tok; } public boolean equals(Object o) { if (!(o instanceof Sentence)) return false; Sentence __3 = (Sentence) o; return eq(tok, __3.tok); } public int hashCode() { int h = 1327381123; h = boostHashCombine(h, _hashCode(tok)); return h; } public Object[] _fieldsToList() { return new Object[] { tok }; } public String text() { return join(tok); } } static public class Sentence2 extends Literal implements IFieldsToList { public String text; public Sentence2() { } public Sentence2(String text) { this.text = text; } public boolean equals(Object o) { if (!(o instanceof Sentence2)) return false; Sentence2 __4 = (Sentence2) o; return eq(text, __4.text); } public int hashCode() { int h = -1800858097; h = boostHashCombine(h, _hashCode(text)); return h; } public Object[] _fieldsToList() { return new Object[] { text }; } public String text() { return text; } } static public class Eq extends Exp implements IFieldsToList { public Exp left; public Exp right; public Eq() { } public Eq(Exp left, Exp right) { this.right = right; this.left = left; } public boolean equals(Object o) { if (!(o instanceof Eq)) return false; Eq __5 = (Eq) o; return eq(left, __5.left) && eq(right, __5.right); } public int hashCode() { int h = 2252; h = boostHashCombine(h, _hashCode(left)); h = boostHashCombine(h, _hashCode(right)); return h; } public Object[] _fieldsToList() { return new Object[] { left, right }; } public String text() { return left.text() + " = " + right.text(); } } static public class ClassMaker { final public String getClassName() { return className(); } public String className() { return className; } public String className; public ClassGen cg; public JavaClass baked; public InMemoryClassLoader classLoader; public Class loadedClass; final public ClassMaker setPrintDisassembly(boolean printDisassembly) { return printDisassembly(printDisassembly); } public ClassMaker printDisassembly(boolean printDisassembly) { this.printDisassembly = printDisassembly; return this; } final public boolean getPrintDisassembly() { return printDisassembly(); } public boolean printDisassembly() { return printDisassembly; } public boolean printDisassembly = false; public ClassMaker(String className) { this.className = className; setClassGen(new ClassGen(className, "java.lang.Object", null, Const.ACC_PUBLIC, null)); } public ClassMaker(Class interfaceToImplement) { className = randomClassName(); setClassGen(new ClassGen(className, "java.lang.Object", null, Const.ACC_PUBLIC, new String[] { main.className(interfaceToImplement) })); addDefaultConstructor(); } public void addDefaultConstructor() { cg.addEmptyConstructor(Const.ACC_PUBLIC); } public void setClassGen(ClassGen cg) { this.cg = cg; cg.setMajor(50); cg.setMinor(0); } public JavaClass bake() { if (baked == null) { baked = cg.getJavaClass(); if (printDisassembly) printClassWithMethods(); } return baked; } public void printClassWithMethods() { print_tabToSingleSpace(bake()); for (var method : baked.getMethods()) { print_tabToSingleSpace("\n" + method); print_tabToSingleSpace(method.getCode()); } } public byte[] getBytes_cache; final public byte[] getBytes() { if (getBytes_cache == null) getBytes_cache = getBytes_load(); return getBytes_cache; } final public byte[] getBytes_load() { return toBytes(); } public byte[] toBytes() { return bake().getBytes(); } public Class load() { if (loadedClass == null) { var bytes = toBytes(); classLoader = new InMemoryClassLoader(myClassLoader()); loadedClass = (Class) classLoader.defineAClass(className, bytes); } return loadedClass; } public A newInstance() { return main.newInstance(load()); } public void addField(FieldGen fg) { cg.addField(fg.getField()); } public ConstantPoolGen getConstantPool() { return cg.getConstantPool(); } } static public class HasTokenRangeWithSrc implements IHasTokenRangeWithSrc { public TokenRangeWithSrc src; public void setTokenRangeWithSrc(TokenRangeWithSrc src) { this.src = src; } public TokenRangeWithSrc tokenRangeWithSrc() { return src; } } static public class ListAndIndex implements IFieldsToList { static final public String _fieldOrder = "list idx"; public List list; public int idx; public ListAndIndex() { } public ListAndIndex(List list, int idx) { this.idx = idx; this.list = list; } public boolean equals(Object o) { if (!(o instanceof ListAndIndex)) return false; ListAndIndex __1 = (ListAndIndex) o; return eq(list, __1.list) && idx == __1.idx; } public int hashCode() { int h = 276903961; h = boostHashCombine(h, _hashCode(list)); h = boostHashCombine(h, _hashCode(idx)); return h; } public Object[] _fieldsToList() { return new Object[] { list, idx }; } public boolean atEnd() { return idx >= l(list); } public A get() { return _get(list, idx); } public int size() { return l(list); } public String toString() { return subList(list, 0, idx) + ", then " + subList(list, idx); } public ListAndIndex plus(int ofs) { return new ListAndIndex(list, idx + ofs); } public ListAndIndex minus(int ofs) { return new ListAndIndex(list, idx - ofs); } public List list() { return list; } final public int idx() { return index(); } public int index() { return idx; } public ListAndIndex mapIdx(IF1_IntToInt f) { return new ListAndIndex(list, f.get(idx)); } } static public class TokenRange extends IntRange { public TokenRange() { } public TokenRange(int start, int end) { this.end = end; this.start = start; } } static public class InMemoryClassLoader extends ClassLoader { final public InMemoryClassLoader setRememberClassBytes(boolean rememberClassBytes) { return rememberClassBytes(rememberClassBytes); } public InMemoryClassLoader rememberClassBytes(boolean rememberClassBytes) { this.rememberClassBytes = rememberClassBytes; return this; } final public boolean getRememberClassBytes() { return rememberClassBytes(); } public boolean rememberClassBytes() { return rememberClassBytes; } transient public boolean rememberClassBytes = false; transient public Map classBytes = syncMap(); public InMemoryClassLoader(ClassLoader parent) { super(parent); } public Class defineAClass(String name, byte[] bytes) { Class c = defineClass(name, bytes, 0, bytes.length); if (rememberClassBytes) classBytes.put(c, bytes); return c; } public byte[] getClassBytes(Class c) { return classBytes.get(c); } } static public class VarMatches extends WrappedMap { public VarMatches() { super(new LinkedHashMap()); } public VarMatches(Map map) { this(); main.putAll(this, map); } } static public interface IF1_IntToInt { public int get(int i); } static public class WrappedMap extends AbstractMap { public Map map; public WrappedMap() { } public WrappedMap(Map map) { this.map = map; } public B get(Object key) { return map.get(key); } public B put(A key, B value) { return map.put(key, value); } public boolean containsKey(Object key) { return map.containsKey(key); } public Set> entrySet() { return map.entrySet(); } } static public Object preciseGetOrCallMethod(Object object, String name) { if (object == null) return null; if (canCallWithVarargs(object, name)) return call(object, name); return _get(object, name); } static public A newObject(Class c, Object... args) { return (A) nuObject(c, args); } static public Object newObject(String className, Object... args) { return nuObject(className, args); } static public boolean scaffoldingEnabled(Object o) { return metaGet(o, "scaffolding") != null; } static public Value value(A a) { return new Value(a); } static public Map.Entry simpleMapEntry(A key, B value) { return new Map.Entry() { public A getKey() { return key; } public B getValue() { return value; } public B setValue(B newValue) { throw unimplemented(); } }; } static public String jsDollarVars(String s, Object... __) { return replaceDollarVars_js(s, __); } static public Set addToSet_create(Set set, A a) { return createOrAddToSet(set, a); } static public void replaceLast(List l, A a) { replaceLastElement(l, a); } static public A[] toTypedArray(Class type, Iterable c) { return toArray(c, type); } static public String pnlToLines(String prefix, Iterable l) { return pnlToString(prefix, l); } static public String pnlToLines(Iterable l) { return pnlToString(l); } static public String pnlToLines(A[] l) { return pnlToString(l); } static public String pnlToLines(Map map) { return pnlToString(map); } static public String pnlToLines(MultiMap map) { return pnlToString(map); } static public String formatRecordVars(String recordName, Object... params) { return renderRecordVars(recordName, params); } static public boolean setText_opt = true; static public A setText(A c, Object text) { setText((JComponent) c, text); return c; } static public A setText(final A c, Object text) { final String s = strUnnull(text); { swing(() -> { c.getEditor().setItem(s); }); } return c; } static public void setText(JLabel c, Object text) { setText((JComponent) c, text); } static public JButton setText(JButton c, Object text) { setText((JComponent) c, jlabel_textAsHTML_center_ifNeeded(strUnnull(text))); return c; } static public A setText(final A c, Object text) { if (c == null) return null; final String s = strUnnull(text); { swing(() -> { if (!setText_opt || neq(callOpt(c, "getText"), s)) call(c, "setText", s); }); } return c; } static public RuntimeException rethrowAndAppendToMessage(Throwable t, String msg) { String haveMsg = t.getMessage(); if (empty(msg) || endsWith(haveMsg, " " + msg)) throw rethrow(t); throw new RuntimeException(joinWithSpace(t.getMessage(), msg), t); } static public String squareBracketed(String s) { return "[" + s + "]"; } static public AutoCloseable tempRestoreMap(Map map) { if (map == null) return null; var cloned = cloneMap(map); return () -> copyMap(cloned, map); } static public boolean is(String a, String b) { return false; } static public void scaffoldCalled(Object obj, Object function, Object... args) { printShortenedFunctionCall(200, (obj == null ? "" : shorten(20, str(obj)) + " :: ") + function, args); } static public int parseHexInt(String s) { return hexToInt(s); } static public int intFromBinary(String s) { return Integer.parseInt(s, 2); } static public boolean hasStaticMethodNamed(Class c, String method) { if (c == null) return false; var methods = getMethodCache(c).cache.get(method); if (methods != null) for (var m : methods) if (isStaticMethod(m)) return true; return false; } static public boolean isInterface(Class c) { return c != null && c.isInterface(); } static public boolean isStaticField(Field f) { return (f.getModifiers() & Modifier.STATIC) != 0; } static public List constructorsWithNumberOfArguments(Class c, int n) { return filter(getDeclaredConstructors_cached(c), con -> l(con.getParameterTypes()) == n); } static public A[] toArrayOrNull(Class type, Collection c) { if (empty(c)) return null; return toArray(type, c); } static public Map parsePrimitiveType_map = litmap("int", int.class, "char", char.class, "byte", byte.class, "short", short.class, "long", long.class, "float", float.class, "double", double.class, "bool", boolean.class); static public Class parsePrimitiveType(String s) { return parsePrimitiveType_map.get(s); } static public boolean hasMethodNamed(Object obj, String method) { if (obj == null) return false; if (obj instanceof Class) return hasMethodNamed((Class) obj, method); return hasMethodNamed(obj.getClass(), method); } static public boolean hasMethodNamed(Class c, String method) { if (c == null) return false; return getMethodCache(c).cache.containsKey(method); } static public Map mapWithSingleValue(Iterable l, B b) { HashMap map = new HashMap(); if (l != null) for (A a : l) map.put(a, b); return map; } static public AutoCloseable tempMapPutAll(Map map, Map toAdd) { if (map != null && nempty(toAdd)) { List> toRestore = new ArrayList(); for (var __0 : _entrySet(toAdd)) { var key = __0.getKey(); var value = __0.getValue(); if (key != null && value != null) { B old = map.put(key, value); if (!eq(old, value)) toRestore.add(pair(key, old)); } } return () -> { for (var p : toRestore) mapPutOrRemove(map, p.a, p.b); }; } return null; } static public AutoCloseable tempAdd(Collection l, A a) { if (l == null || l.contains(a)) return null; l.add(a); return new tempAdd_undo(l, a); } static public class tempAdd_undo implements AutoCloseable, IFieldsToList { public Collection l; public A a; public tempAdd_undo() { } public tempAdd_undo(Collection l, A a) { this.a = a; this.l = l; } public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + l + ", " + a + ")"; } public Object[] _fieldsToList() { return new Object[] { l, a }; } public void close() { try { l.remove(a); } catch (Exception __e) { throw rethrow(__e); } } } static public AutoCloseable tempAdd(Container a, Component b) { if (a == null || b == null) return null; { return swing(() -> { if (b.getParent() == a) return null; a.add(b); return () -> { swing(() -> { if (b.getParent() == a) removeFromParent(b); }); }; }); } } static public TreeSet mapToTreeSet(Object f, Iterable l) { TreeSet x = new TreeSet(); if (l != null) for (Object o : l) x.add(callF(f, o)); return x; } static public TreeSet mapToTreeSet(IF1 f, Iterable l) { TreeSet x = new TreeSet(); if (l != null) for (var o : l) x.add(f.get(o)); return x; } static public TreeSet mapToTreeSet(Iterable l, IF1 f) { return mapToTreeSet(f, l); } static public boolean isAnonymousClass(Class c) { return isAnonymousClassName(className(c)); } static public String longestPrefixInTreeSet(String s, TreeSet set) { return longestPrefixInNavigableSet(s, set); } static public Map javaxClassShortcuts_cache; static public Map javaxClassShortcuts() { if (javaxClassShortcuts_cache == null) javaxClassShortcuts_cache = javaxClassShortcuts_load(); return javaxClassShortcuts_cache; } static public Map javaxClassShortcuts_load() { return litmap("O", "Object", "S", "String", "L", "List", "Cl", "Collection"); } static public List standardImports_fullyImportedPackages() { return endingWith_dropSuffix(standardImports(), ".*"); } static public File getBytecodePathForClass(Object o) { return getBytecodePathForClass(_getClass(o)); } static public File getBytecodePathForClass(Class c) { try { return c == null ? null : new File(c.getProtectionDomain().getCodeSource().getLocation().toURI()); } catch (Exception __e) { throw rethrow(__e); } } static public double fracNonNeg(double d) { return frac_nonNeg(d); } static public double twoPi() { return Math.PI * 2; } static public String plusPrefixUnlessMinus(String s) { return startsWith(s, "-") ? s : "+" + s; } static public String find(String pattern, String text) { Matcher matcher = Pattern.compile(pattern).matcher(text); if (matcher.find()) return matcher.group(1); return null; } static public A find(Collection c, Object... data) { for (A x : c) if (checkFields(x, data)) return x; return null; } static public Set _registerTimer_list = newWeakHashSet(); static public void _registerTimer(java.util.Timer timer) { _registerTimer_list.add(timer); } static public void cleanMeUp__registerTimer() { cancelTimers(getAndClearList(_registerTimer_list)); } static public String quoteBorderless(Object o) { if (o == null) return "null"; return quoteBorderless(str(o)); } static public String quoteBorderless(String s) { if (s == null) return "null"; StringBuilder out = new StringBuilder((int) (l(s) * 1.5)); quoteBorderless_impl(s, out); return out.toString(); } static public void quoteBorderless_impl(String s, StringBuilder out) { int l = s.length(); for (int i = 0; i < l; i++) { char c = s.charAt(i); if (c == '\\' || c == '"') out.append('\\').append(c); else if (c == '\r') out.append("\\r"); else if (c == '\n') out.append("\\n"); else out.append(c); } } static public void assertSame(Object a, Object b) { assertSame("", a, b); } static public void assertSame(String msg, Object a, Object b) { if (a != b) throw fail(joinNemptiesWithColon(msg, a + " != " + b + " (" + identityHash(a) + "/" + identityHash(b) + ")")); } static public void assertSame(IF0 msg, Object a, Object b) { if (a != b) throw fail(joinNemptiesWithColon(msg.get(), a + " != " + b + " (" + identityHash(a) + "/" + identityHash(b) + ")")); } static public LineAndColumn tokenToLineAndColumn(ListAndIndex ptr) { return ptr == null ? null : tokenToLineAndColumn(ptr.list(), ptr.idx()); } static public LineAndColumn tokenToLineAndColumn(List tok, int tokenIndex) { int line = 1, col = 1; tokenIndex = min(tokenIndex, l(tok)); for (int i = 0; i < tokenIndex; i++) { String t = tok.get(i); int n = l(t); for (int j = 0; j < n; j++) if (t.charAt(j) == '\n') { ++line; col = 1; } else ++col; } return new LineAndColumn(line, col); } static public String resolve(String host) { return hostToIP(host); } static public int indexOfInSortedArray(A[] array, A a) { return array == null ? -1 : Arrays.binarySearch(array, a); } static public List sortedKeys(Map map) { return sorted(keys(map)); } static public List sortedKeys(Object map) { return sorted(keys(map)); } static public List sortedKeys(MultiSet ms) { return sorted(keys(ms)); } static public List sortedKeys(MultiMap mm) { return sorted(keys(mm)); } static public File byteCodePathForClass(Class c) { if (c == null) return null; ClassLoader cl = getClassLoader(c); Collection files = (Collection) (getOpt(cl, "files")); if (files != null) { String name = c.getName().replace('.', '/') + ".class"; for (File location : files) if (dirOrZipContainsPath(location, name)) return location; throw fail(name + " not found in: " + files); } return null; } static public File byteCodePathForClass(Object o) { return byteCodePathForClass(_getClass(o)); } static public List endingWith_dropSuffix(Collection l, String suffix) { List out = new ArrayList(); for (String s : unnullForIteration(l)) if (endsWith(s, suffix)) out.add(dropLast(l(suffix), s)); return out; } static public List endingWith_dropSuffix(String suffix, Collection l) { return endingWith_dropSuffix(l, suffix); } static public List standardImports_cache; static public List standardImports() { if (standardImports_cache == null) standardImports_cache = standardImports_load(); return standardImports_cache; } static public List standardImports_load() { return ll("java.util.*", "java.util.zip.*", "java.util.List", "java.util.regex.*", "java.util.concurrent.*", "java.util.concurrent.atomic.*", "java.util.concurrent.locks.*", "java.util.function.*", "javax.swing.*", "javax.swing.event.*", "javax.swing.text.*", "javax.swing.table.*", "java.io.*", "java.net.*", "java.lang.reflect.*", "java.lang.ref.*", "java.lang.management.*", "java.security.*", "java.security.spec.*", "java.awt.*", "java.awt.event.*", "java.awt.image.*", "java.awt.geom.*", "javax.imageio.*", "java.math.*", "java.time.Duration"); } static public List classNamesInJarOrDir(File dir) { return classNamesInJarOrDir(dir, ""); } static public List classNamesInJarOrDir(File dir, String prefixInJar) { List classes = new ArrayList(); if (dir == null) { } else if (dir.isDirectory()) { for (File f : listFiles(dir)) { String s = f.getName(); if (s.endsWith(".class")) classes.add(dropSuffix(".class", s)); } } else if (dir.isFile()) { try { JarFile jarFile = new JarFile(dir); try { Enumeration e = jarFile.entries(); while (e.hasMoreElements()) { JarEntry je = e.nextElement(); if (je.isDirectory() || je.getName().startsWith("META-INF/") || !je.getName().endsWith(".class")) continue; String className = dropSuffix(".class", je.getName()); className = dropPrefixOrNull(prefixInJar, className); if (className == null) continue; if (className.contains("-")) continue; className = className.replace('/', '.'); classes.add(className); } } finally { jarFile.close(); } } catch (Throwable __e) { printStackTrace(__e); } } return classes; } static public List classNamesInLoadedJigsawModules() { return concatMap(loadedJigsawModuleNames(), moduleName -> classNamesInJigsawModule(moduleName)); } static public Type getRawType(Type t) { if (t instanceof ParameterizedType) return ((ParameterizedType) t).getRawType(); return t; } static public String md5(String text) { try { if (text == null) return "-"; return bytesToHex(md5_impl(toUtf8(text))); } catch (Exception __e) { throw rethrow(__e); } } static public String md5(byte[] data) { if (data == null) return "-"; return bytesToHex(md5_impl(data)); } static public byte[] md5_impl(byte[] data) { try { return MessageDigest.getInstance("MD5").digest(data); } catch (Exception __e) { throw rethrow(__e); } } static public String md5(File file) { return md5OfFile(file); } static public org.apache.bcel.generic.Type typeToBCELType(Type t) { return classToBCELType(getRawTypeClass(t)); } static public String typeToVMSignature(Type t) { Class c = getRawTypeClass(t); if (t instanceof ParameterizedType) { List args = map(__81 -> getRawTypeClass(__81), ((ParameterizedType) t).getActualTypeArguments()); if (nempty(args)) return classNameToByteCodeFormat(c) + "<" + joinMap(args, arg -> classNameToByteCodeFormat(arg) + ";") + ">;"; } return classNameToByteCodeFormat(c) + ";"; } static public org.apache.bcel.generic.Type classToBCELType(Class c) { if (c == null) return null; if (isPrimitiveType(c)) { if (c == byte.class) return org.apache.bcel.generic.Type.BYTE; if (c == char.class) return org.apache.bcel.generic.Type.BYTE; if (c == short.class) return org.apache.bcel.generic.Type.BYTE; if (c == int.class) return org.apache.bcel.generic.Type.INT; if (c == long.class) return org.apache.bcel.generic.Type.LONG; if (c == double.class) return org.apache.bcel.generic.Type.DOUBLE; if (c == void.class) return org.apache.bcel.generic.Type.VOID; if (c == boolean.class) return org.apache.bcel.generic.Type.BOOLEAN; throw fail("TODO: classToBCELType " + c); } if (isArrayType(c)) { int dimensions = 0; while (c.isArray()) { ++dimensions; c = c.componentType(); } return new ArrayType(classToBCELType(c), dimensions); } return new ObjectType(className(c)); } static public Object[] repArray(Object a, int n) { return arrayrep(a, n); } static public A[] repArray(Class type, A a, int n) { return arrayrep(type, a, n); } static public boolean eqOrEqic(boolean caseInsensitive, String a, String b) { return caseInsensitive ? eqic(a, b) : eq(a, b); } static public boolean containsLineBreak(String s) { return containsNewLine(s); } static public long incAtomicLong(AtomicLong l) { return l.incrementAndGet(); } static public PingSource pingSource() { return pingSource_tl().get(); } static public PingSource pingSource(Thread thread) { return pingSource_tl().get(thread); } static public boolean preciseNuObject_debug = false; static public A preciseNuObject(Class c, Object... args) { try { Constructor[] methods = getDeclaredConstructors_cached(c); if (methods.length == 0) throw fail(c + " doesn't define any constructors"); return preciseNuObject(methods, args); } catch (Exception __e) { throw rethrow(__e); } } static public A preciseNuObject(Constructor[] methods, Object... args) { try { Constructor best = null; int bestScore = Integer.MAX_VALUE; boolean widening = false; if (preciseNuObject_debug) printVars("preciseNuObject", "c", first(methods).getDeclaringClass(), "methods", l(methods)); for (var m : methods) { int score = methodApplicabilityScore_withPrimitiveWidening(m, args); if (score == 0) return (A) m.newInstance(args); if (preciseNuObject_debug) print("Method score: " + m + " " + score); if (abs(score) < bestScore) { best = m; bestScore = abs(score); widening = score < 0; } } if (best != null) if (widening) return (A) invokeConstructorWithWidening(best, args); else return (A) best.newInstance(args); methodSearch: for (var m : methods) { { if (!(m.isVarArgs())) continue; } Object[] newArgs = massageArgsForVarArgsCall(m, args); if (newArgs != null) return (A) m.newInstance(newArgs); } var c = first(methods).getDeclaringClass(); throw fail("No matching constructor found: " + formatFunctionCall(c, map(__82 -> _getClass(__82), args))); } catch (Exception __e) { throw rethrow(__e); } } static public Object[] mapToArrayOrNull(A[] l, IF1 f) { if (l == null) return null; int n = l.length; if (n == 0) return null; Object[] array = new Object[n]; for (int i = 0; i < n; i++) array[i] = f.get(l[i]); return array; } static public Object[] mapToArrayOrNull(IF1 f, A[] l) { return mapToArrayOrNull(l, f); } static public Object[] mapToArrayOrNull(IF1 f, Collection l) { int n = l(l); if (n == 0) return null; Object[] array = new Object[n]; if (n != 0) { Iterator it = iterator(l); for (int i = 0; i < n; i++) array[i] = callF(f, it.next()); } return array; } static public Object[] mapToArrayOrNull(Collection l, IF1 f) { return mapToArrayOrNull(l, f); } static public String formatFunctionCall(String fname, Object... args) { return formatFunctionCall((Object) fname, args); } static public String formatFunctionCall(Object fname, Object... args) { return fname + "(" + joinWithComma(allToString(args)) + ")"; } static public String formatFunctionCall(String fname, Iterable args) { return formatFunctionCall((Object) fname, args); } static public String formatFunctionCall(Object fname, Iterable args) { return formatFunctionCall(fname, toObjectArray(args)); } static public String strOrClassName(Object o) { if (o instanceof Class) return className((Class) o); return str(o); } static public String toStringWithClass(Object o) { return o == null ? null : className(o) + " - " + o; } static public boolean newPreciseCall_debug = false; static public Object newPreciseCall(Object o, String method, Object... args) { try { if (o == null) return null; boolean staticCall = o instanceof Class; Class c = staticCall ? (Class) o : o.getClass(); Object target = staticCall ? null : o; _MethodCache cache = callOpt_getCache(c); List methods = cache.cache.get(method); Method best = null; int bestScore = Integer.MAX_VALUE; boolean widening = false; if (newPreciseCall_debug) printVars("newPreciseCall", "method", method, "staticCall", staticCall, "c", c, "methods", l(methods)); if (methods != null) for (Method m : methods) { if (staticCall && !isStaticMethod(m)) continue; int score = methodApplicabilityScore_withPrimitiveWidening(m, args); if (score == 0) return invokeMethod(m, target, args); if (newPreciseCall_debug) print("Method score: " + m + " " + score); if (abs(score) < bestScore) { best = m; bestScore = abs(score); widening = score < 0; } } if (best != null) if (widening) return invokeMethodWithWidening(best, target, args); else return invokeMethod(best, target, args); return callWithVarargs(o, method, args); } catch (Exception __e) { throw rethrow(__e); } } static public List findMethodsNamed_cached(Object obj, String method) { return findMethodsNamed_cached(_getClass(obj), method); } static public List findMethodsNamed_cached(Class c, String method) { if (c == null) return null; return getMethodCache(c).cache.get(method); } static public Pair findMethod_withPrimitiveWidening_onTypes(Object o, String method, Class... argTypes) { try { Lowest best = new Lowest(); boolean widening = false; if (o instanceof Class) { _MethodCache cache = callOpt_getCache((Class) o); List methods = cache.cache.get(method); if (methods != null) for (Method m : methods) { { if (!(isStaticMethod(m))) continue; } int score = methodApplicabilityScore_withPrimitiveWidening_onTypes(m, argTypes); if (abs(score) < Integer.MAX_VALUE) { best.put(m, abs(score)); widening = score < 0; } } return pair(best.get(), widening); } if (o == null) return null; _MethodCache cache = callOpt_getCache(o.getClass()); List methods = cache.cache.get(method); if (methods != null) for (Method m : methods) { int score = methodApplicabilityScore_withPrimitiveWidening_onTypes(m, argTypes); if (abs(score) < Integer.MAX_VALUE) { best.put(m, abs(score)); widening = score < 0; } } return pair(best.get(), widening); } catch (Exception __e) { throw rethrow(__e); } } static public Method findSingleInterfaceMethodOrFail(Class intrface) { Method m = findSingleInterfaceMethod(intrface); if (m == null) throw fail(intrface + " is not a single method interface"); return m; } static public A proxyFromInvocationHandler(Class intrface, InvocationHandler handler) { return (A) java.lang.reflect.Proxy.newProxyInstance(intrface.getClassLoader(), new Class[] { intrface }, handler); } static public Object handleObjectMethodsInProxyInvocationHandler(Object invocationHandler, Method implementedMethod, Method method, Object proxy, Object[] actualArgs) { String name = method.getName(); if (name.equals("hashCode")) return invocationHandler.hashCode(); if (name.equals("equals")) return proxy == actualArgs[0]; if (name.equals("toString")) return invocationHandler.toString(); throw fail("No handler for method " + method + " (only have " + implementedMethod + ")"); } static public Object[] concatMethodArgs(Object[] args1, Object[] args2) { int n1, n2; if (args1 == null || (n1 = args1.length) == 0) return args2; if (args2 == null || (n2 = args2.length) == 0) return args1; Object[] args = new Object[n1 + n2]; for (int i = 0; i < n1; i++) args[i] = args1[i]; for (int i = 0; i < n2; i++) args[n1 + i] = args2[i]; return args; } static public Object invokeMethodWithWidening(Method m, Object o, Object... args) { try { try { Class[] types = m.getParameterTypes(); int n = types.length; Object[] args2 = new Object[n]; for (int i = 0; i < n; i++) args2[i] = convertPrimitiveIfNecessary(args[i], types[i]); return m.invoke(o, args2); } catch (InvocationTargetException e) { throw rethrow(getExceptionCause(e)); } catch (IllegalArgumentException e) { throw new IllegalArgumentException(e.getMessage() + " - was calling: " + m + ", args: " + joinWithSpace(classNames(args))); } } catch (Exception __e) { throw rethrow(__e); } } static public Iterator iterator_gen(Object o) { if (o == null) return emptyItIt(); if (o instanceof Iterator) return ((Iterator) o); if (o instanceof Iterable) return ((Iterable) o).iterator(); if (o instanceof Object[]) return arrayIterator((Object[]) o); throw fail("Not iterable: " + className(o)); } static public class mapI_It extends IterableIterator { public Object f; public Iterator i; public mapI_It() { } public mapI_It(Object f, Iterator i) { this.i = i; this.f = f; } public boolean hasNext() { return i.hasNext(); } public Object next() { return callF(f, i.next()); } public String toString() { return formatFunctionCall("mapI", f, i); } } static public IterableIterator mapI(final Object f, final Iterator i) { return new mapI_It(f, i); } static public IterableIterator mapI(IterableIterator i, Object f) { return mapI((Iterator) i, f); } static public IterableIterator mapI(Object f, IterableIterator i) { return mapI((Iterator) i, f); } static public IterableIterator mapI(Iterator i, Object f) { return mapI(f, i); } static public IterableIterator mapI(Iterable i, IF1 f) { return new MapI(f, iterator(i)); } static public IterableIterator mapI(Iterator i, IF1 f) { return new MapI(f, i); } static public IterableIterator mapI(IterableIterator i, IF1 f) { return new MapI(f, i); } static public IterableIterator mapI(IF1 f, Iterable i) { return new MapI(f, iterator(i)); } static public IterableIterator mapI(Iterable i, Object f) { return mapI(f, i.iterator()); } static public IterableIterator mapI(Object f, Iterable i) { return mapI(i, f); } static public > IterableIterator nestedIterator(Iterable c, final F1 makeInnerIterator) { return nestedIterator(iterator(c), makeInnerIterator); } static public > IterableIterator nestedIterator(Iterable c, IF1 makeInnerIterator) { return nestedIterator(iterator(c), makeInnerIterator); } static public > IterableIterator nestedIterator(IterableIterator c, IF1 makeInnerIterator) { return nestedIterator((Iterator) c, makeInnerIterator); } static public > IterableIterator nestedIterator(Iterator it1, IF1 makeInnerIterator) { if (it1 == null || !it1.hasNext()) return emptyItIt(); return iff(new F0() { public A a; public Iterator innerIterator; { nextOuter(); } public void nextOuter() { a = it1.next(); innerIterator = makeInnerIterator.get(a); } public Object get() { while (true) { ping(); if (innerIterator != null && innerIterator.hasNext()) return innerIterator.next(); if (!it1.hasNext()) return endMarker(); nextOuter(); } } }); } static public > IterableIterator nestedIterator(final Iterator it1, F1 makeInnerIterator) { if (it1 == null || !it1.hasNext()) return emptyItIt(); return iff(new F0() { public A a; public Iterator innerIterator; { nextOuter(); } public void nextOuter() { a = it1.next(); innerIterator = makeInnerIterator.get(a); } public Object get() { while (true) { ping(); if (innerIterator != null && innerIterator.hasNext()) return innerIterator.next(); if (!it1.hasNext()) return endMarker(); nextOuter(); } } }); } static public > IterableIterator nestedIterator(IF1 makeInnerIterator, Iterator it1) { return nestedIterator(it1, makeInnerIterator); } static public > IterableIterator nestedIterator(IF1 makeInnerIterator, Collection l) { return nestedIterator(l, makeInnerIterator); } static public String struct(Object o) { return structure(o); } static public String struct(Object o, structure_Data data) { return structure(o, data); } static public List structTok(String s) { return javaTok_noMLS(s); } static public String indentStructureString(String s) { return indentStructureString(100, s); } static public String indentStructureString(int levels, String s) { if (s == null) return null; return new StructureStringIndenter().levels(levels).get(s); } static public Constructor findConstructor_precise_onTypes(Class c, Class... argTypes) { try { List ctors = constructorsWithNumberOfArguments(c, l(argTypes)); Lowest best = new Lowest(); if (ctors != null) for (Constructor ctor : ctors) { int score = methodApplicabilityScore_onTypes(ctor, argTypes); if (score < Integer.MAX_VALUE) best.put(ctor, score); } return best.get(); } catch (Exception __e) { throw rethrow(__e); } } static public Method findNonStaticMethod_precise_onTypes(Object o, String method, Class... argTypes) { try { Class c = _getClass(o); if (c == null) return null; _MethodCache cache = callOpt_getCache(c); List methods = cache.cache.get(method); Lowest best = new Lowest(); if (methods != null) for (Method m : methods) { { if (isStaticMethod(m)) continue; } int score = methodApplicabilityScore_onTypes(m, argTypes); if (score < Integer.MAX_VALUE) best.put(m, score); } return best.get(); } catch (Exception __e) { throw rethrow(__e); } } static public Method mostApplicableMethod_onTypes(Iterable methods, Class... argTypes) { Lowest best = new Lowest(); if (methods != null) for (Method m : methods) { int score = methodApplicabilityScore_onTypes(m, argTypes); if (score < Integer.MAX_VALUE) best.put(m, score); } return best.get(); } static public Map nonDefaultInterfaceMethods_cache = newDangerousWeakHashMap(); static public Method[] nonDefaultInterfaceMethods(Class c) { Method[] methods; synchronized (nonDefaultInterfaceMethods_cache) { methods = nonDefaultInterfaceMethods_cache.get(c); if (methods == null) nonDefaultInterfaceMethods_cache.put(c, methods = toTypedArray(Method.class, findNonDefaultInterfaceMethods(c))); } return methods; } static public Method findMethod_precise_onTypes(Object o, String method, Class... argTypes) { try { if (o instanceof Class) { _MethodCache cache = callOpt_getCache((Class) o); List methods = cache.cache.get(method); Lowest best = new Lowest(); if (methods != null) for (Method m : methods) { { if (!(isStaticMethod(m))) continue; } int score = methodApplicabilityScore_onTypes(m, argTypes); if (score < Integer.MAX_VALUE) best.put(m, score); } return best.get(); } if (o == null) return null; _MethodCache cache = callOpt_getCache(o.getClass()); List methods = cache.cache.get(method); Lowest best = new Lowest(); if (methods != null) for (Method m : methods) { int score = methodApplicabilityScore_onTypes(m, argTypes); if (score < Integer.MAX_VALUE) best.put(m, score); } return best.get(); } catch (Exception __e) { throw rethrow(__e); } } static public AutoCloseable tempSet(Object o, final String field, Object value) { return tempSetField(o, field, value); } static public Map putOrCreateSyncMap(Map map, A key, B value) { if (map == null) map = syncHashMap(); map.put(key, value); return map; } static public AutoCloseable tempPut(Map map, A key, B value) { if (map != null) { boolean wasContained = map.containsKey(key); B old = map.put(key, value); return () -> { if (wasContained) map.put(key, old); else map.remove(key); }; } return null; } static public A pnl(A l) { return pnl("", l); } static public A pnl(String prefix, A l) { printNumberedLines(prefix, l); return l; } static public A[] pnl(A[] l) { return pnl("", l); } static public A[] pnl(String prefix, A[] l) { printNumberedLines(prefix, l); return l; } static public A pnl(A map) { printNumberedLines(map); return map; } static public A pnl(String prefix, A map) { printNumberedLines(prefix, map); return map; } static public String pnl(String s) { printNumberedLines(lines(s)); return s; } static public MultiSet pnl(MultiSet ms) { pnl(ms == null ? null : ms.asMap()); return ms; } static public MultiMap pnl(MultiMap mm) { pnl(mm == null ? null : mm.asMap()); return mm; } static public String nlLogic_text(Exp e) { return e == null ? null : e.text(); } static public String nlLogic_text(IfThen r) { return r == null ? null : r.text(); } static public AtomicLong randomClassName_counter = new AtomicLong(); static public String randomClassName() { return "UserCode" + inc(randomClassName_counter); } static public A print_tabToSingleSpace(A o) { print(tabToSingleSpace(str(o))); return o; } static public ClassLoader myClassLoader() { return _getClass(mc()).getClassLoader(); } static public A newInstance(Class c, Object... args) { return nuObject(c, args); } static public Object newInstance(String className, Object... args) { return nuObject(className, args); } static public List syncMap(Object f, Map map) { return syncMap(map, f); } static public List syncMap(Map map, Object f) { return map(cloneLinkedHashMap(map), f); } static public Map syncMap() { return synchroHashMap(); } static public Map syncMap(Map map) { return synchronizedMap(map); } static public boolean canCallWithVarargs(Object o, String method, Object... args) { if (o == null) return false; if (o instanceof Class) { Class c = (Class) o; _MethodCache cache = callOpt_getCache(c); if (cache.findStaticMethod(method, args) != null) return true; List methods = cache.cache.get(method); if (methods != null) methodSearch: for (Method m : methods) { { if (!(m.isVarArgs() && isStaticMethod(m))) continue; } if (massageArgsForVarArgsCall(m, args) != null) return true; } } else { Class c = o.getClass(); _MethodCache cache = callOpt_getCache(c); if (cache.findMethod(method, args) != null) return true; List methods = cache.cache.get(method); if (methods != null) methodSearch: for (Method m : methods) { { if (!(m.isVarArgs())) continue; } if (massageArgsForVarArgsCall(m, args) != null) return true; } } return false; } static public String replaceDollarVars_js(String s, Object... __) { Map vars = paramsToMap_withNulls(__); if (empty(vars)) return s; var vars2 = mapKeys(__83 -> dropDollarPrefix(__83), vars); return replaceDollarVars_dyn(s, var -> { if (!vars2.containsKey(var)) return null; Object value = vars2.get(var); return jsonEncode_extended(value); }); } static public Set createOrAddToSet(Set set, A a) { if (set == null) set = new HashSet(); set.add(a); return set; } static public Set createOrAddToSet(Set set, A... l) { for (A a : unnullForIteration(l)) set = createOrAddToSet(set, a); return set; } static public void replaceLastElement(List l, A a) { if (nempty(l)) l.set(l(l) - 1, a); } static public String pnlToString(String prefix, Iterable l) { return hijackPrint(new Runnable() { public void run() { try { pnl(prefix, l); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "pnl(prefix, l)"; } }); } static public String pnlToString(final Iterable l) { return hijackPrint(new Runnable() { public void run() { try { pnl(l); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "pnl(l)"; } }); } static public String pnlToString(final A[] l) { return hijackPrint(new Runnable() { public void run() { try { pnl(l); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "pnl(l)"; } }); } static public String pnlToString(final Map map) { return hijackPrint(new Runnable() { public void run() { try { pnl(map); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "pnl(map)"; } }); } static public String pnlToString(MultiMap map) { return pnlToString(multiMapToMap(map)); } static public String renderRecordVars(String recordName, Object... params) { List l = new ArrayList(); int i = 0; for (; i + 1 < l(params); i += 2) l.add(params[i] + "=" + params[i + 1]); return formatFunctionCall(recordName, l); } static public String strUnnull(Object o) { return o == null ? "" : str(o); } static public String jlabel_textAsHTML_center_ifNeeded(String text) { if (swic(text, "") && ewic(text, "")) return text; if (!containsNewLines(text)) return text; return jlabel_textAsHTML_center(text); } static public void copyMap(Map a, Map b) { if (a == null || b == null) return; b.clear(); b.putAll(a); } static public void printShortenedFunctionCall(Object fname, Object... args) { printShortenedFunctionCall(100, fname, args); } static public void printShortenedFunctionCall(int len, Object fname, Object... args) { print(shorten(len, formatFunctionCall(fname, args))); } static public int hexToInt(String s) { return Integer.parseInt(s, 16); } static public _MethodCache getMethodCache(Class c) { return callOpt_getCache(c); } static public void removeFromParent(final Component c) { if (c != null) { swing(() -> { Container cc = c.getParent(); if (cc != null) { cc.remove(c); revalidate(cc); } }); } } static public String longestPrefixInNavigableSet(String s, NavigableSet set) { if (set == null || s == null) return null; while (licensed()) { String key = set.floor(s); if (key == null) break; int n = lCommonPrefix(key, s); if (n == l(key)) return key; s = takeFirst(s, n); } return null; } static public double frac_nonNeg(double d) { return mod(d, 1); } static public boolean checkFields(Object x, Object... data) { for (int i = 0; i < l(data); i += 2) if (neq(getOpt(x, (String) data[i]), data[i + 1])) return false; return true; } static public Set newWeakHashSet() { return synchroWeakHashSet(); } static public void cancelTimers(Collection timers) { for (Object timer : timers) cancelTimer(timer); } static public List getAndClearList(Collection l) { if (l == null) return emptyList(); synchronized (collectionMutex(l)) { List out = cloneList(l); l.clear(); return out; } } static public int identityHash(Object o) { return identityHashCode(o); } static public String hostToIP(String host) { try { for (InetAddress a : InetAddress.getAllByName(host)) { String ip = a.getHostAddress(); if (isIPv4(ip)) return ip; } throw fail("No IP address found for " + host); } catch (Exception __e) { throw rethrow(__e); } } static public ClassLoader getClassLoader(Object o) { return o == null ? null : _getClass(o).getClassLoader(); } static public boolean dirOrZipContainsPath(File location, String subPath) { try { if (location.isDirectory()) { return new File(location, subPath).exists(); } else if (location.isFile()) { return zipFileContains_falseOnError(location, subPath); } return false; } catch (Exception __e) { throw rethrow(__e); } } static public List loadedJigsawModuleNames() { var moduleLayer = ModuleLayer.boot(); var modules = moduleLayer.modules(); return map(modules, mod -> mod.getName()); } static public List classNamesInJigsawModule(String moduleName) { return classNamesInJigsawModule(moduleName, javaHome()); } static public List classNamesInJigsawModule(String moduleName, File javaHome) { return classNamesInJarOrDir(jigsawModuleFile(moduleName, javaHome), "classes/"); } static public boolean md5OfFile_verbose = false; static public String md5OfFile(String path) { return md5OfFile(newFile(path)); } static public String md5OfFile(File f) { try { if (!f.exists()) return "-"; if (md5OfFile_verbose) print("Getting MD5 of " + f); MessageDigest md5 = MessageDigest.getInstance("MD5"); FileInputStream in = new FileInputStream(f); try { byte[] buf = new byte[65536]; int l; while (true) { l = in.read(buf); if (l <= 0) break; md5.update(buf, 0, l); } return bytesToHex(md5.digest()); } finally { _close(in); } } catch (Exception __e) { throw rethrow(__e); } } static public Class getRawTypeClass(Type t) { if (t instanceof ParameterizedType) return (Class) ((ParameterizedType) t).getRawType(); return (Class) t; } static public String classNameToByteCodeFormat(String className) { return "L" + className.replace('.', '/'); } static public String classNameToByteCodeFormat(Class c) { return classNameToByteCodeFormat(className(c)); } static public boolean isPrimitiveType(Class c) { return c != null && c.isPrimitive(); } static public Object[] arrayrep(Object a, int n) { Object[] array = new Object[n]; for (int i = 0; i < n; i++) array[i] = a; return array; } static public A[] arrayrep(Class type, A a, int n) { A[] array = newArray(type, n); for (int i = 0; i < n; i++) array[i] = a; return array; } static public int methodApplicabilityScore_withPrimitiveWidening(Executable m, Object[] args) { Class[] types = m.getParameterTypes(); if (types.length != l(args)) return Integer.MAX_VALUE; int score = 0; boolean widenings = false; for (int i = 0; i < types.length; i++) { Object a = args[i]; Class c = types[i]; if (a == null) { if (c.isPrimitive()) return Integer.MAX_VALUE; } else { Class t = a.getClass(); int s = typeConversionScoreWithUnboxing(t, c); if (s == Integer.MAX_VALUE) return Integer.MAX_VALUE; if (s < 0) widenings = true; score += abs(s); } } return widenings ? -score : score; } static public Object invokeConstructorWithWidening(Constructor m, Object... args) { try { try { Class[] types = m.getParameterTypes(); int n = types.length; Object[] args2 = new Object[n]; for (int i = 0; i < n; i++) args2[i] = convertPrimitiveIfNecessary(args[i], types[i]); return m.newInstance(args2); } catch (IllegalArgumentException e) { throw new IllegalArgumentException(e.getMessage() + " - was calling: " + m + ", args: " + joinWithSpace(classNames(args))); } } catch (Exception __e) { throw rethrow(__e); } } static public Object callWithVarargs(Object o, String method, Object... args) { return call_withVarargs(o, method, args); } static public int methodApplicabilityScore_withPrimitiveWidening_onTypes(Executable m, Class[] argTypes) { Class[] types = m.getParameterTypes(); if (types.length != l(argTypes)) return Integer.MAX_VALUE; int score = 0; boolean widenings = false; for (int i = 0; i < types.length; i++) { Class t = argTypes[i]; Class c = types[i]; int s = typeConversionScoreWithUnboxing(t, c); if (s == Integer.MAX_VALUE) return Integer.MAX_VALUE; if (s < 0) widenings = true; score += abs(s); } return widenings ? -score : score; } static public Method findSingleInterfaceMethod(Class intrface) { return singletonOpt(findNonDefaultInterfaceMethods(intrface)); } static public Object convertPrimitiveIfNecessary(Object o, Class b) { if (b.isPrimitive()) { if (o instanceof Character) { char x = (char) (((Character) o)); if (b == int.class) return Integer.valueOf(x); if (b == long.class) return Long.valueOf(x); if (b == float.class) return Float.valueOf(x); if (b == double.class) return Double.valueOf(x); } else if (o instanceof Number) { if (b == char.class) return Character.valueOf((char) ((Number) o).intValue()); if (b == short.class) return ((Number) o).shortValue(); if (b == int.class) return ((Number) o).intValue(); if (b == long.class) return ((Number) o).longValue(); if (b == float.class) return ((Number) o).floatValue(); } } return o; } static public IterableIterator emptyItIt() { return emptyIterableIterator(); } static public IterableIterator arrayIterator(A[] l) { return l == null ? null : new IterableIterator() { public int i = 0; public boolean hasNext() { return i < l.length; } public A next() { return l[i++]; } }; } static public IterableIterator iff(Object f) { return iteratorFromFunction_withEndMarker(f); } static public IterableIterator iff(F0 f) { return iteratorFromFunction_withEndMarker(f); } static public IterableIterator iff(IF0 f) { return iteratorFromFunction_withEndMarker(f); } static public Object endMarker() { return iteratorFromFunction_endMarker; } static public int methodApplicabilityScore_onTypes(Method m, Class[] argTypes) { return methodApplicabilityScore_onTypes((Executable) m, argTypes); } static public int methodApplicabilityScore_onTypes(Executable m, Class[] argTypes) { Class[] types = m.getParameterTypes(); if (types.length != argTypes.length) return Integer.MAX_VALUE; int score = 0; for (int i = 0; i < types.length; i++) { Class a = argTypes[i]; Class c = types[i]; if (c == a) { } else if (isSubclassOf(a, c)) ++score; else return Integer.MAX_VALUE; } return score; } static public List findNonDefaultInterfaceMethods(Class intrface) { if (!isInterface(intrface)) return null; List l = new ArrayList(); _MethodCache cache = getMethodCache(intrface); Class c = intrface; do { for (Method m : c.getDeclaredMethods()) if (m.getDeclaringClass() != Object.class && !m.isDefault() && !isStaticMethod(m)) l.add(m); c = c.getSuperclass(); } while (c != null); return l; } static public AutoCloseable tempSetField(Object o, String field, Object value) { final Object oldValue = get(o, field); set(o, field, value); return () -> set(o, field, oldValue); } static public AutoCloseable tempSetField(ISetAndGet gs, A value) { if (gs == null) return null; A oldValue = gs.get(); gs.set(value); return () -> gs.set(oldValue); } static public AutoCloseable tempSetField(A value, ISetAndGet gs) { return tempSetField(gs, value); } static public void printNumberedLines(Map map) { printNumberedLines(mapToLines(map)); } static public void printNumberedLines(String prefix, Map map) { printNumberedLines(prefix, mapToLines(map)); } static public A printNumberedLines(A l) { int i = 0; if (l != null) for (Object a : cloneList(l)) print((++i) + ". " + str(a)); return l; } static public A printNumberedLines(String prefix, A l) { int i = 0; if (l != null) for (Object a : cloneList(l)) print(prefix + (++i) + ". " + str(a)); return l; } static public void printNumberedLines(Object[] l) { printNumberedLines("", l); } static public void printNumberedLines(String prefix, Object[] l) { printNumberedLines(prefix, wrapAsList(l)); } static public void printNumberedLines(Object o) { printNumberedLines(lines(str(o))); } static public int inc(AtomicInteger i) { return incAtomicInt(i); } static public int inc(AtomicInteger i, int delta) { return incAtomicInt(i, delta); } static public long inc(AtomicLong l) { return incAtomicLong(l); } static public long inc(AtomicLong l, long b) { return l.addAndGet(b); } static public int inc(IntVar v) { synchronized (v) { int val = v.get() + 1; v.set(val); return val; } } static public int inc(int i) { return i + 1; } static public long inc(long l) { return l + 1; } static public String tabToSingleSpace(String s) { return replace(s, '\t', ' '); } static public Object iteratorFromFunction_endMarker = new Object(); static public IterableIterator iteratorFromFunction_withEndMarker(final Object f) { class IFF extends IterableIterator { public A a; public boolean have, done; public boolean hasNext() { getNext(); return !done; } public A next() { getNext(); if (done) throw fail(); A _a = a; a = null; have = false; return _a; } public void getNext() { if (done || have) return; Object o = callF(f); if (o == iteratorFromFunction_endMarker) { done = true; return; } a = (A) o; have = true; } } ; return new IFF(); } static public IterableIterator iteratorFromFunction_withEndMarker(final F0 f) { return iteratorFromFunction_withEndMarker_f0(f); } static public Map paramsToMap_withNulls(Object... params) { int n = l(params); if (l(params) == 1 && params[0] instanceof Map) return (Map) params[0]; LinkedHashMap map = new LinkedHashMap(); for (int i = 0; i + 1 < n; i += 2) map.put(params[i], params[i + 1]); return map; } static public String jsonEncode_extended(Object o) { StringBuilder buf = new StringBuilder(); jsonEncode_extended(o, buf); return str(buf); } static public void jsonEncode_extended(Object o, StringBuilder buf) { if (o == null) buf.append("null"); else if (o instanceof JS) buf.append(((JS) o).get()); else if (o instanceof String) buf.append(quote((String) o)); else if (o instanceof Number || o instanceof Boolean) buf.append(o); else if (o instanceof Map) { Map map = (Map) o; buf.append("{"); boolean first = true; for (Object key : keys(map)) { if (first) first = false; else buf.append(","); buf.append(quote((String) key)); buf.append(":"); jsonEncode_extended(map.get(key), buf); } buf.append("}"); } else if (o instanceof Collection) { Collection l = (Collection) o; buf.append("["); boolean first = true; for (Object element : l) { if (first) first = false; else buf.append(","); jsonEncode_extended(element, buf); } buf.append("]"); } else throw fail("Unknown object for JSON encoding: " + className(o)); } static public String hijackPrint(Runnable r) { StringBuilder buf = new StringBuilder(); Object old = interceptPrintInThisThread(new F1() { public Boolean get(String s) { buf.append(s); return false; } }); try { { if (r != null) r.run(); } return str(buf); } finally { interceptPrintInThisThread(old); } } static public boolean containsNewLines(String s) { return containsNewLine(s); } static public String jlabel_textAsHTML_center(String text) { return "
" + replace(htmlencode2(text), "\n", "
") + "
"; } static public int lCommonPrefix(String a, String b) { int i = 0, n = Math.min(l(a), l(b)); while (i < n && a.charAt(i) == b.charAt(i)) ++i; return i; } static public int mod(int n, int m) { return (n % m + m) % m; } static public long mod(long n, long m) { return (n % m + m) % m; } static public BigInteger mod(BigInteger n, int m) { return n.mod(bigint(m)); } static public double mod(double n, double m) { return (n % m + m) % m; } static public
Set synchroWeakHashSet() { return Collections.newSetFromMap((Map) newWeakHashMap()); } static public boolean isIPv4(String s) { return s != null && l(javaTokC(s)) == 7 && jfind(javaTok(s), "...") == 1; } static public boolean zipFileContains_falseOnError(File inZip, String fileName) { try { return zipFileContains(inZip, fileName); } catch (Throwable e) { return false; } } static public File javaHome() { return envJavaHome(); } static public File javaHome(String sub) { return newFile(envJavaHome(), sub); } static public File jigsawModuleFile(String moduleName) { return jigsawModuleFile(moduleName, javaHome()); } static public File jigsawModuleFile(String moduleName, File javaHome) { return new File(javaHome, "jmods/" + moduleName + ".jmod"); } static public A[] newArray(Class c, int n) { return typedArray(c, n); } static public int typeConversionScoreWithUnboxing(Class a, Class b) { int score = typeConversionScore(a, b); if (score == 0 || score == 1) return score; Class aPrim = boxedToPrimitiveType(a); if (aPrim != null) { int score2 = typeConversionScore(aPrim, b); if (score2 == 0) return 1; else if (score2 != Integer.MAX_VALUE) return score2; } return score; } static public A singletonOpt(Collection l) { return l(l) == 1 ? first(l) : null; } static public A singletonOpt(A[] l) { return l(l) == 1 ? first(l) : null; } static public IterableIterator emptyIterableIterator_instance = new IterableIterator() { public Object next() { throw fail(); } public boolean hasNext() { return false; } }; static public IterableIterator emptyIterableIterator() { return emptyIterableIterator_instance; } static public boolean isSubclassOf(Class a, Class b) { return isSubclass(a, b); } static public List wrapAsList(A[] a) { return wrapArrayAsList(a); } static public int incAtomicInt(AtomicInteger i) { return i.incrementAndGet(); } static public int incAtomicInt(AtomicInteger i, int delta) { return i.addAndGet(delta); } static public IterableIterator iteratorFromFunction_withEndMarker_f0(final F0 f) { class IFF2 extends IterableIterator { public A a; public boolean have, done; public boolean hasNext() { getNext(); return !done; } public A next() { getNext(); if (done) throw fail(); A _a = a; a = null; have = false; return _a; } public void getNext() { if (done || have) return; Object o = f.get(); if (o == iteratorFromFunction_endMarker) { done = true; return; } a = (A) o; have = true; } } ; return new IFF2(); } static public Object interceptPrintInThisThread(Object f) { Object old = print_byThread().get(); print_byThread().set(f); return old; } static public boolean zipFileContains(File inZip, String fileName) { try { ZipFile zip = new ZipFile(inZip); try { return zipFileContains(zip, fileName); } finally { zip.close(); } } catch (Exception __e) { throw rethrow(__e); } } static public boolean zipFileContains(ZipFile zip, String fileName) { try { return zip.getEntry(fileName) != null; } catch (Exception __e) { throw rethrow(__e); } } static public File envJavaHome() { return newFile(System.getProperty("java.home")); } static public A[] typedArray(Class c, int n) { return (A[]) Array.newInstance(c, n); } static public int typeConversionScore(Class a, Class b) { if (a == b) return 0; if (b.isPrimitive()) { if (a.isPrimitive()) { if (b == boolean.class) return Integer.MAX_VALUE; if (b == byte.class) return Integer.MAX_VALUE; if (b == char.class) return a == byte.class ? -2 : Integer.MAX_VALUE; if (b == short.class) return a == byte.class ? -2 : Integer.MAX_VALUE; if (b == int.class) return a == byte.class || a == char.class || a == short.class ? -2 : Integer.MAX_VALUE; if (b == long.class) return a == byte.class || a == char.class || a == short.class || a == int.class ? -2 : Integer.MAX_VALUE; if (b == float.class) return a == byte.class || a == char.class || a == short.class || a == int.class ? -2 : Integer.MAX_VALUE; return a != boolean.class ? -2 : Integer.MAX_VALUE; } else { return primitiveToBoxedType(b) == a ? 1 : Integer.MAX_VALUE; } } else { if (a.isPrimitive()) return primitiveToBoxedType(a) == b ? 1 : Integer.MAX_VALUE; if (!b.isAssignableFrom(a)) return Integer.MAX_VALUE; if (a.isInterface() || b.isInterface()) return 1; return subclassDistance(a, b); } } static public Class boxedToPrimitiveType(Class type) { if (type == Boolean.class) return boolean.class; if (type == Integer.class) return int.class; if (type == Long.class) return long.class; if (type == Float.class) return float.class; if (type == Short.class) return short.class; if (type == Character.class) return char.class; if (type == Byte.class) return byte.class; if (type == Double.class) return double.class; return null; } static public boolean isSubclass(Class a, Class b) { return a != null && b != null && b.isAssignableFrom(a); } static public List wrapArrayAsList(A[] a) { return a == null ? null : Arrays.asList(a); } static public int subclassDistance(Class a, Class b) { int n = 0; while (a != b) { a = a.getSuperclass(); if (a == null) return Integer.MAX_VALUE; ++n; } return n; } static public class StructureStringIndenter { final public StructureStringIndenter setLevels(int levels) { return levels(levels); } public StructureStringIndenter levels(int levels) { this.levels = levels; return this; } final public int getLevels() { return levels(); } public int levels() { return levels; } public int levels = 100; final public StructureStringIndenter setInlineChars(int inlineChars) { return inlineChars(inlineChars); } public StructureStringIndenter inlineChars(int inlineChars) { this.inlineChars = inlineChars; return this; } final public int getInlineChars() { return inlineChars(); } public int inlineChars() { return inlineChars; } public int inlineChars = 40; final public StructureStringIndenter setVerbose(boolean verbose) { return verbose(verbose); } public StructureStringIndenter verbose(boolean verbose) { this.verbose = verbose; return this; } final public boolean getVerbose() { return verbose(); } public boolean verbose() { return verbose; } public boolean verbose = false; public List tok; public Map bracketMap; public String get(String s) { if (s == null) return null; tok = javaTokForStructure(s); int n = l(tok); bracketMap = getBracketMap(tok, __1 -> isOpeningBracket(__1), __2 -> isClosingBracket(__2)); int levels = clampToInt(this.levels * 2L); StringBuilder buf = new StringBuilder(); int indent = 0; for (int i = 0; i < n; i++) { String t = tok.get(i); if (isOpeningBracket(t)) { Integer j = or(bracketMap.get(i), n); if (j != null && !tokenRangeLongerThanNChars(tok, i + 1, j + 1, inlineChars)) { buf.append(joinSubList(tok, i, j + 1)); i = j; } else { if (verbose) print("Bracket part longer than " + inlineChars + " chars: " + quote(shortenJoinSubList(inlineChars, tok, i, j + 1))); indent += 2; buf.append(t); if (indent <= levels) buf.append("\n").append(spaces(indent)); } } else if (isClosingBracket(t)) { indent -= 2; if (indent < levels) buf.append("\n").append(spaces(indent)); buf.append(t); } else if (indent <= levels && eq(t, ",")) { buf.append(t).append("\n").append(spaces(indent)); i++; } else buf.append(t); } return str(buf); } } static public class Value implements IF0, IFieldsToList { public A value; public Value() { } public Value(A value) { this.value = value; } public boolean equals(Object o) { if (!(o instanceof Value)) return false; Value __1 = (Value) o; return eq(value, __1.value); } public int hashCode() { int h = 82420049; h = boostHashCombine(h, _hashCode(value)); return h; } public Object[] _fieldsToList() { return new Object[] { value }; } public A get() { return value; } public String toString() { return str(get()); } } static public class MapI extends IterableIterator { public IF1 f; public Iterator it; public MapI(IF1 f, Iterator it) { this.it = it; this.f = f; } public boolean hasNext() { return it.hasNext(); } public B next() { return f.get(it.next()); } } static public interface ISetAndGet extends ISetter, IF0 { } static public class IntVar { public int a; public synchronized void set(int v) { if (v != a) { a = v; notifyAll(); } } public synchronized int get() { return a; } synchronized public int waitForValue(int x) { try { while (a != x) wait(); return a; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return str(this.get()); } } static public Map getBracketMap(List tok) { return getBracketMap(tok, getBracketMap_opening, getBracketMap_closing); } static public Map getBracketMap(List tok, Collection opening, Collection closing) { return getBracketMap(tok, opening, closing, 0, l(tok)); } static public Map getBracketMap(List tok, Collection opening, Collection closing, int from, int to) { TreeMap map = new TreeMap(); List stack = new ArrayList(); for (int i = from | 1; i < to; i += 2) { Object t = tok.get(i); if (opening.contains(t)) stack.add(i); else if (closing.contains(t)) if (!empty(stack)) map.put(liftLast(stack), i); } return map; } static public Map getBracketMap(List tok, IF1 opening, IF1 closing) { return getBracketMap(tok, opening, closing, 0, l(tok)); } static public Map getBracketMap(List tok, IF1 opening, IF1 closing, int from, int to) { TreeMap map = new TreeMap(); List stack = new ArrayList(); for (int i = from | 1; i < to; i += 2) { String t = tok.get(i); if (opening.get(t)) stack.add(i); else if (closing.get(t)) if (!empty(stack)) map.put(liftLast(stack), i); } return map; } static public Set getBracketMap_opening = lithashset("{", "("); static public Set getBracketMap_closing = lithashset("}", ")"); static public boolean isOpeningBracket(String s) { return eqOneOf(s, "(", "{", "["); } static public boolean isClosingBracket(String s) { return eqOneOf(s, ")", "}", "]"); } static public int clampToInt(long l) { return (int) clamp(l, Integer.MIN_VALUE, Integer.MAX_VALUE); } static public boolean tokenRangeLongerThanNChars(List tok, int iStart, int iEnd, int maxChars) { int nChars = 0, n = l(tok); iStart = Math.max(0, iStart); iEnd = Math.min(n, iEnd); for (int i = iStart; i < iEnd; i++) { nChars += l(tok.get(i)); if (nChars > maxChars) return true; } return false; } static public String shortenJoinSubList(int max, List l, int i, int j) { return shortenJoin(max, subList(l, i, j)); } static public String shortenJoinSubList(int max, List l, int i) { return shortenJoin(max, subList(l, i)); } static public String spaces(int n) { return rep(' ', n); } static public String shortenJoin(int max, Iterable l) { StringBuilder buf = new StringBuilder(); for (String s : unnullForIteration(l)) { buf.append(s); if (l(buf) > max) break; } return shorten(max, str(buf)); } }