isLinux_cache = new Cache<>(() -> isLinux_load());
static boolean isLinux() { return isLinux_cache.get(); }
static Boolean isLinux_load() {
return !isWindows() && !isMac() && !isAndroid();
}
static A setFont(final Font font, final A a) {
if (a != null) { swing(() -> { a.setFont(font); }); }
return a;
}
static A setFont(A a, Font font) {
return setFont(font, a);
}
static A setFont(final String fontID, float fontSize, final A a) {
return setFont(loadFont_cached(fontID, fontSize), a);
}
static A makeUneditableWithTextColor(A a, Color color) {
if (a != null) { swing(() -> {
a.setEditable(false);
a.setDisabledTextColor(color);
}); }
return a;
}
static A makeUneditableWithTextColor(Color color, A a) {
return makeUneditableWithTextColor(a, color);
}
static JTextArea jTextArea_noUndo() {
return jTextArea_noUndo("");
}
static JTextArea jTextArea_noUndo(final String text) {
return swingNu(JTextArea.class, text);
}
static List synchroList() {
return synchroList(new ArrayList ());
}
static List synchroList(List l) {
return Collections.synchronizedList(l);
}
static boolean empty(Collection c) { return c == null || c.isEmpty(); }
static boolean empty(Iterable c) { return c == null || !c.iterator().hasNext(); }
static boolean empty(CharSequence s) { return s == null || s.length() == 0; }
static boolean empty(Map map) { return map == null || map.isEmpty(); }
static boolean empty(Object[] o) { return o == null || o.length == 0; }
static boolean empty(BitSet bs) { return bs == null || bs.isEmpty(); }
static boolean empty(Object o) {
if (o instanceof Collection) return empty((Collection) o);
if (o instanceof String) return empty((String) o);
if (o instanceof Map) return empty((Map) o);
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 boolean empty(Iterator i) { return i == null || !i.hasNext(); }
static boolean empty(double[] a) { return a == null || a.length == 0; }
static boolean empty(float[] a) { return a == null || a.length == 0; }
static boolean empty(int[] a) { return a == null || a.length == 0; }
static boolean empty(long[] a) { return a == null || a.length == 0; }
static boolean empty(byte[] a) { return a == null || a.length == 0; }
static boolean empty(short[] a) { return a == null || a.length == 0; }
static boolean empty(IMultiMap mm) { return mm == null || mm.size() == 0; }
static boolean empty(File f) { return getFileSize(f) == 0; }
static boolean empty(Rect r) { return !(r != null && r.w != 0 && r.h != 0); }
static boolean empty(Chain c) { return c == null; }
static boolean empty(AppendableChain c) { return c == null; }
static void pcallFAll(Collection l, Object... args) {
if (l != null) for (Object f : cloneList(l)) pcallF(f, args);
}
static void pcallFAll(Iterator it, Object... args) {
while (it.hasNext()) pcallF(it.next(), args);
}
static Map newWeakHashMap() {
return _registerWeakMap(synchroMap(new WeakHashMap()));
}
static void newPing() {
var tl = newPing_actionTL();
Runnable action = tl == null ? null : tl.get();
{ if (action != null) action.run(); }
}
// TODO: test if android complains about this
static boolean isAWTThread() {
if (isAndroid()) return false;
if (isHeadless()) return false;
return isAWTThread_awt();
}
static boolean isAWTThread_awt() {
return SwingUtilities.isEventDispatchThread();
}
static boolean isTrue(Object o) {
if (o instanceof Boolean)
return ((Boolean) o).booleanValue();
if (o == null) return false;
if (o instanceof ThreadLocal) // TODO: remove this
return isTrue(((ThreadLocal) o).get());
throw fail(getClassName(o));
}
static boolean isTrue(Boolean b) {
return b != null && b.booleanValue();
}
static void failIfUnlicensed() {
assertTrue("license off", licensed());
}
static Thread currentThread() {
return Thread.currentThread();
}
static boolean eq(Object a, Object b) {
return a == b || a != null && b != null && a.equals(b);
}
// a little kludge for stuff like eq(symbol, "$X")
static boolean eq(Symbol a, String b) {
return eq(str(a), b);
}
static RuntimeException fail() { throw new RuntimeException("fail"); }
static RuntimeException fail(Throwable e) { throw asRuntimeException(e); }
static RuntimeException fail(Object msg) { throw new RuntimeException(String.valueOf(msg)); }
static RuntimeException fail(Object... objects) { throw new Fail(objects); }
static RuntimeException fail(String msg) { throw new RuntimeException(msg == null ? "" : msg); }
static RuntimeException fail(String msg, Throwable innerException) { throw new RuntimeException(msg, innerException); }
static void _handleError(Error e) {
//call(javax(), '_handleError, e);
}
static Object pcallF(Object f, Object... args) {
return pcallFunction(f, args);
}
static A pcallF(F0 f) {
try { return f == null ? null : f.get(); } catch (Throwable __e) { printStackTrace(__e); } return null;
}
static B pcallF(F1 f, A a) {
try { return f == null ? null : f.get(a); } catch (Throwable __e) { printStackTrace(__e); } return null;
}
static void pcallF(VF1 f, A a) {
try {
{ if (f != null) f.get(a); }
} catch (Throwable __e) { printStackTrace(__e); }
}
static Object pcallF(Runnable r) {
try { { if (r != null) r.run(); } } catch (Throwable __e) { printStackTrace(__e); } return null;
}
static A pcallF(IF0 f) {
try { return f == null ? null : f.get(); } catch (Throwable __e) { printStackTrace(__e); } return null;
}
static B pcallF(IF1 f, A a) {
try { return f == null ? null : f.get(a); } catch (Throwable __e) { printStackTrace(__e); } return null;
}
static String str(Object o) {
return o == null ? "null" : o.toString();
}
static String str(char[] c) {
return new String(c);
}
static String str(char[] c, int offset, int count) {
return new String(c, offset, count);
}
static void swingAndWait(Runnable r) { try {
if (isAWTThread())
r.run();
else
EventQueue.invokeAndWait(addThreadInfoToRunnable(r));
} catch (Exception __e) { throw rethrow(__e); } }
static 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 boolean swic(String a, String b) {
return startsWithIgnoreCase(a, b);
}
static 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 boolean ewic(String a, String b) {
return endsWithIgnoreCase(a, b);
}
static boolean ewic(String a, String b, Matches m) {
return endsWithIgnoreCase(a, b, m);
}
static boolean containsNewLines(String s) {
return containsNewLine(s);
}
static String jlabel_textAsHTML_center(String text) {
return ""
+ replace(htmlencode2(text), "\n", " ")
+ "
";
}
static Map> callF_cache = newDangerousWeakHashMap();
static A callF(F0 f) {
return f == null ? null : f.get();
}
static B callF(F1 f, A a) {
return f == null ? null : f.get(a);
}
static A callF(IF0 f) {
return f == null ? null : f.get();
}
static B callF(IF1 f, A a) {
return f == null ? null : f.get(a);
}
static B callF(A a, IF1 f) {
return f == null ? null : f.get(a);
}
static C callF(IF2 f, A a, B b) {
return f == null ? null : f.get(a, b);
}
static void callF(VF1 f, A a) {
if (f != null) f.get(a);
}
static void callF(A a, IVF1 f) {
if (f != null) f.get(a);
}
static void callF(IVF1 f, A a) {
if (f != null) f.get(a);
}
static Object callF(Runnable r) { { if (r != null) r.run(); } return null; }
static Object callF(Object f, Object... args) {
return safeCallF(f, args);
}
static 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));
}
// used internally
static 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 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) {
// TODO: varargs
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);
// try varargs
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 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);
// try varargs
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);
// try varargs
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 String nemptyLines(Iterable l) {
return lines(nempties(allToStrOrNull(l)));
}
static String nemptyLines(Object... l) {
return nemptyLinesLL(l);
}
static 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 List ll(A... a) {
ArrayList l = new ArrayList(a.length);
if (a != null) for (A x : a) l.add(x);
return l;
}
static String combinePrintParameters(String s, Object o) {
return (endsWithLetterOrDigit(s) ? s + ": " : s) + o;
}
static void ping_okInCleanUp() {
if (ping_pauseAll || ping_anyActions)
ping_impl(true);
}
// this syntax should be removed...
static Object getThreadLocal(Object o, String name) {
ThreadLocal t = (ThreadLocal) (getOpt(o, name));
return t != null ? t.get() : null;
}
static A getThreadLocal(ThreadLocal tl) {
return tl == null ? null : tl.get();
}
static A getThreadLocal(ThreadLocal tl, A defaultValue) {
return or(getThreadLocal(tl), defaultValue);
}
static ThreadLocal print_byThread_dontCreate() {
return print_byThread;
}
static boolean isFalse(Object o) {
return eq(false, o);
}
static 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 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 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 void vmBus_send(String msg) {
vmBus_send(msg, (Object) null);
}
static Class mc() {
return main.class;
}
static PersistableThrowable persistableThrowable(Throwable e) {
return e == null ? null : new PersistableThrowable(e);
}
static Throwable getException(Runnable r) {
try {
callF(r);
return null;
} catch (Throwable e) {
return e;
}
}
static boolean startsWithOneOf(String s, String... l) {
for (String x : l) if (startsWith(s, x)) return true; return false;
}
static boolean startsWithOneOf(String s, Matches m, String... l) {
for (String x : l) if (startsWith(s, x, m)) return true; return false;
}
static boolean isAGIBlueDomain(String domain) {
return domainIsUnder(domain, theAGIBlueDomain());
}
static String hostNameFromURL(String url) { try {
return empty(url) ? null : new URL(url).getHost();
} catch (Exception __e) { throw rethrow(__e); } }
static ArrayList emptyList() {
return new ArrayList();
//ret Collections.emptyList();
}
static ArrayList emptyList(int capacity) {
return new ArrayList(max(0, capacity));
}
// Try to match capacity
static ArrayList emptyList(Iterable l) {
return l instanceof Collection ? emptyList(((Collection) l).size()) : emptyList();
}
static ArrayList emptyList(Object[] l) {
return emptyList(l(l));
}
// get correct type at once
static ArrayList emptyList(Class c) {
return new ArrayList();
}
static int[] emptyIntArray_a = new int[0];
static int[] emptyIntArray() { return emptyIntArray_a; }
static char[] emptyCharArray = new char[0];
static char[] emptyCharArray() { return emptyCharArray; }
static double[] emptyDoubleArray = new double[0];
static double[] emptyDoubleArray() { return emptyDoubleArray; }
static Map emptyMap() {
return new HashMap();
}
static Object[] emptyObjectArray_a = new Object[0];
static Object[] emptyObjectArray() { return emptyObjectArray_a; }
static Symbol emptySymbol_value;
static Symbol emptySymbol() {
if (emptySymbol_value == null) emptySymbol_value = symbol("");
return emptySymbol_value;
}
static String substring(String s, int x) {
return substring(s, x, strL(s));
}
static 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);
}
// convenience method for quickly dropping a prefix
static String substring(String s, CharSequence l) {
return substring(s, lCharSequence(l));
}
static String getClassName(Object o) {
return o == null ? "null" : o instanceof Class ? ((Class) o).getName() : o.getClass().getName();
}
static Object sleepQuietly_monitor = new Object();
static void sleepQuietly() { try {
assertFalse(isAWTThread());
synchronized(sleepQuietly_monitor) { sleepQuietly_monitor.wait(); }
} catch (Exception __e) { throw rethrow(__e); } }
static String roundBracket(String s) {
return "(" + s + ")";
}
static String roundBracket(Object s) {
return roundBracket(str(s));
}
static Object first(Object list) {
return first((Iterable) list);
}
static A first(List list) {
return empty(list) ? null : list.get(0);
}
static A first(A[] bla) {
return bla == null || bla.length == 0 ? null : bla[0];
}
static Pair first(Map map) {
return mapEntryToPair(first(entrySet(map)));
}
static 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 A first(IterableIterator i) {
return first((Iterator ) i);
}
static A first(Iterator i) {
return i == null || !i.hasNext() ? null : i.next();
}
static A first(Iterable i) {
if (i == null) return null;
Iterator it = i.iterator();
return it.hasNext() ? it.next() : null;
}
static Character first(String s) { return empty(s) ? null : s.charAt(0); }
static Character first(CharSequence s) { return empty(s) ? null : s.charAt(0); }
static A first(Pair p) {
return p == null ? null : p.a;
}
static Byte first(byte[] l) {
return empty(l) ? null : l[0];
}
static A first(A[] l, IF1 pred) {
return firstThat(l, pred);
}
static A first(Iterable l, IF1 pred) {
return firstThat(l, pred);
}
static A first(IF1 pred, Iterable l) {
return firstThat(pred, l);
}
static A first(AppendableChain a) {
return a == null ? null : a.element;
}
static List childrenOfType(Component c, Class theClass) {
List l = new ArrayList();
scanForComponents(c, theClass, l);
return l;
}
static List childrenOfType(Class theClass, Component c) {
return childrenOfType(c, theClass);
}
static void onFirstResize(Component c, Object r) {
onFirstResize(c, toRunnable(r));
}
static void onFirstResize(Component c, Runnable r) {
if (c != null && r != null) { swing(() -> {
c.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
c.removeComponentListener(this);
pcallF(r);
}
});
}); }
}
// independent timer
static void awtLater(int delay, final Object r) {
swingLater(delay, r);
}
static void awtLater(int delay, Runnable r) {
swingLater(delay, r);
}
static void awtLater(Object r) {
swingLater(r);
}
static void awtLater(double delaySeconds, Runnable r) {
swingLater(toMS(delaySeconds), r);
}
// dependent timer (runs only when component is visible)
static void awtLater(JComponent component, int delay, Object r) {
installTimer(component, r, delay, delay, false);
}
static void awtLater(JFrame frame, int delay, Object r) {
awtLater(frame.getRootPane(), delay, r);
}
static A swingConstruct(final Class c, final Object... args) {
return swing(new F0 () { public A get() { try { return nuObject(c, args); } catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "return nuObject(c, args);"; }});
}
static A _recordNewSwingComponent(A c) {
if (c != null)
callF((Object) vm_generalMap_get("newSwingComponentRegistry"), (Object) c);
return c;
}
static JComponent componentToJComponent(Component c) {
if (c instanceof JComponent) return (JComponent) c;
if (c instanceof JFrame) return ((JFrame) c).getRootPane();
if (c == null) return null;
throw fail("boohoo " + getClassName(c));
}
static JScrollPane jscroll(Component c) { return swing(() -> {
return c instanceof JScrollPane ? ((JScrollPane) c) : new JScrollPane(c);
}); }
static JLabel jlabel(final String text) {
return swingConstruct(BetterLabel.class, text);
}
static JLabel jlabel() {
return jlabel(" ");
}
static JScrollPane borderlessScrollPane(JScrollPane sp) {
return setBorder(null, withoutViewportBorder(sp));
}
static JScrollPane jscroll_centered(Component c) {
return c instanceof JScrollPane ? ((JScrollPane) c) : jscroll(jFullCenter(c));
}
static ThreadLocal print_byThread() {
synchronized(print_byThread_lock) {
if (print_byThread == null)
print_byThread = new ThreadLocal();
}
return print_byThread;
}
// f can return false to suppress regular printing
// call print_raw within f to actually print something
static AutoCloseable tempInterceptPrint(F1 f) {
return tempSetThreadLocal(print_byThread(), f);
}
static double parseDouble(String s) {
return empty(s) ? 0.0 : Double.parseDouble(s);
}
static Map vm_generalMap_map;
static Map vm_generalMap() {
if (vm_generalMap_map == null)
vm_generalMap_map = (Map) get(javax(), "generalMap");
return vm_generalMap_map;
}
public static boolean isWindows() {
return System.getProperty("os.name").contains("Windows");
}
static boolean isMac() {
return System.getProperty("os.name").toLowerCase().contains("mac");
}
static int isAndroid_flag;
static boolean isAndroid() {
if (isAndroid_flag == 0)
isAndroid_flag = System.getProperty("java.vendor").toLowerCase().indexOf("android") >= 0 ? 1 : -1;
return isAndroid_flag > 0;
}
static Map loadFont_cached_cache = new HashMap();
static synchronized Font loadFont_cached(String snippetID) { try {
snippetID = formatSnippetID(snippetID);
Font f = loadFont_cached_cache.get(snippetID);
if (f == null)
loadFont_cached_cache.put(snippetID, f = loadFont(snippetID, 12f));
return f;
} catch (Exception __e) { throw rethrow(__e); } }
static synchronized Font loadFont_cached(String snippetID, float size) { try {
return loadFont_cached(snippetID).deriveFont(size);
} catch (Exception __e) { throw rethrow(__e); } }
static String getType(Object o) {
return getClassName(o);
}
static long getFileSize(String path) {
return path == null ? 0 : new File(path).length();
}
static long getFileSize(File f) {
return f == null ? 0 : f.length();
}
static ArrayList cloneList(Iterable l) {
return l instanceof Collection ? cloneList((Collection) l) : asList(l);
}
static ArrayList cloneList(Collection l) {
if (l == null) return new ArrayList();
synchronized(collectionMutex(l)) {
return new ArrayList (l);
}
}
static List _registerWeakMap_preList;
static A _registerWeakMap(A map) {
if (javax() == null) {
// We're in class init
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 void _onLoad_registerWeakMap() {
assertNotNull(javax());
if (_registerWeakMap_preList == null) return;
for (Object o : _registerWeakMap_preList)
_registerWeakMap(o);
_registerWeakMap_preList = null;
}
static Map synchroMap() {
return synchroHashMap();
}
static Map synchroMap(Map map) {
return Collections.synchronizedMap(map);
}
static x30_pkg.x30_util.BetterThreadLocal newPing_actionTL;
static 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 Boolean isHeadless_cache;
static boolean isHeadless() {
if (isHeadless_cache != null) return isHeadless_cache;
if (isAndroid()) return isHeadless_cache = true;
if (GraphicsEnvironment.isHeadless()) return isHeadless_cache = true;
// Also check if AWT actually works.
// If DISPLAY variable is set but no X server up, this will notice.
try {
SwingUtilities.isEventDispatchThread();
return isHeadless_cache = false;
} catch (Throwable e) { return isHeadless_cache = true; }
}
static void assertTrue(Object o) {
if (!(eq(o, true) /*|| isTrue(pcallF(o))*/))
throw fail(str(o));
}
static boolean assertTrue(String msg, boolean b) {
if (!b)
throw fail(msg);
return b;
}
static boolean assertTrue(boolean b) {
if (!b)
throw fail("oops");
return b;
}
static volatile boolean licensed_yes = true;
static boolean licensed() {
if (!licensed_yes) return false;
ping_okInCleanUp();
return true;
}
static void licensed_off() {
licensed_yes = false;
}
static RuntimeException asRuntimeException(Throwable t) {
if (t instanceof Error)
_handleError((Error) t);
return t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t);
}
static Object pcallFunction(Object f, Object... args) {
try { return callFunction(f, args); } catch (Throwable __e) { printStackTrace(__e); }
return null;
}
static 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 boolean startsWithIgnoreCase(String a, String b) {
return regionMatchesIC(a, 0, b, 0, b.length());
}
static int l(Object[] a) { return a == null ? 0 : a.length; }
static int l(boolean[] a) { return a == null ? 0 : a.length; }
static int l(byte[] a) { return a == null ? 0 : a.length; }
static int l(short[] a) { return a == null ? 0 : a.length; }
static int l(long[] a) { return a == null ? 0 : a.length; }
static int l(int[] a) { return a == null ? 0 : a.length; }
static int l(float[] a) { return a == null ? 0 : a.length; }
static int l(double[] a) { return a == null ? 0 : a.length; }
static int l(char[] a) { return a == null ? 0 : a.length; }
static int l(Collection c) { return c == null ? 0 : c.size(); }
static int l(Iterator i) { return iteratorCount_int_close(i); } // consumes the iterator && closes it if possible
static int l(Map m) { return m == null ? 0 : m.size(); }
static int l(CharSequence s) { return s == null ? 0 : s.length(); }
static long l(File f) { return f == null ? 0 : f.length(); }
static int l(IMultiMap mm) { return mm == null ? 0 : mm.size(); }
static int l(IntSize o) { return o == null ? 0 : o.size(); }
static boolean endsWithIgnoreCase(String a, String b) {
int la = l(a), lb = l(b);
return la >= lb && regionMatchesIC(a, la-lb, b, 0, lb);
}
static 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 boolean containsNewLine(String s) {
return contains(s, '\n'); // screw \r, nobody needs it
}
static 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 List replace(A a, A b, List l) {
return replace(l, a, b);
}
// replace all occurrences of a in s with b
static String replace(String s, String a, String b) {
return s == null ? null : a == null || b == null ? s : s.replace(a, b);
}
static String replace(String s, char a, char b) {
return s == null ? null : s.replace(a, b);
}
static String htmlencode2(String s) {
return htmlencode_noQuotes(s);
}
static Map newDangerousWeakHashMap() {
return _registerDangerousWeakMap(synchroMap(new WeakHashMap()));
}
// initFunction: voidfunc(Map) - is called initially, and after clearing the map
static Map newDangerousWeakHashMap(Object initFunction) {
return _registerDangerousWeakMap(synchroMap(new WeakHashMap()), initFunction);
}
static 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 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 Field makeAccessible(Field f) {
try {
f.setAccessible(true);
} catch (Throwable e) {
// Note: The error reporting only works with Java VM option --illegal-access=deny
vmBus_send("makeAccessible_error", e, f);
}
return f;
}
static Method makeAccessible(Method m) {
try {
m.setAccessible(true);
} catch (Throwable e) {
vmBus_send("makeAccessible_error", e, m);
}
return m;
}
static Constructor makeAccessible(Constructor c) {
try {
c.setAccessible(true);
} catch (Throwable e) {
vmBus_send("makeAccessible_error", e, c);
}
return c;
}
static final Map callOpt_cache = newDangerousWeakHashMap();
static 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);
// TODO: (super-rare) case where method exists static and non-static
// with different args
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); } }
// no longer synchronizes! (see #1102990)
static _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 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);
// TODO: optimize
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 boolean isStaticMethod(Method m) {
return methodIsStatic(m);
}
static String joinWithComma(Collection c) {
return join(", ", c);
}
static String joinWithComma(Object... c) {
return join(", ", c);
}
static String joinWithComma(String... c) {
return join(", ", c);
}
static String joinWithComma(Pair p) {
return p == null ? "" : joinWithComma(str(p.a), str(p.b));
}
static List classNames(Collection l) {
return getClassNames(l);
}
static List classNames(Object[] l) {
return getClassNames(asList(l));
}
static String lines(Iterable lines) { return fromLines(lines); }
static String lines(Object[] lines) { return fromLines(asList(lines)); }
static List lines(String s) { return toLines(s); }
// convenience map call
static String lines(Iterable l, IF1 f) {
return mapToLines(l, f);
}
static List nempties(Collection c) {
return filterNempty(c);
}
static List allToStrOrNull(Iterable c) {
return lmap(__24 -> strOrNull(__24), c);
}
static List allToStrOrNull(Object... c) {
return lmap(__25 -> strOrNull(__25), c);
}
static String nemptyLinesLL(Object... l) {
return nemptyLines(ll(l));
}
// unclear semantics as to whether return null on null
static ArrayList asList(A[] a) {
return a == null ? new ArrayList () : new ArrayList (Arrays.asList(a));
}
static ArrayList asList(int[] a) {
if (a == null) return null;
ArrayList l = emptyList(a.length);
for (int i : a) l.add(i);
return l;
}
static ArrayList asList(long[] a) {
if (a == null) return null;
ArrayList l = emptyList(a.length);
for (long i : a) l.add(i);
return l;
}
static ArrayList asList(float[] a) {
if (a == null) return null;
ArrayList l = emptyList(a.length);
for (float i : a) l.add(i);
return l;
}
static ArrayList asList(double[] a) {
if (a == null) return null;
ArrayList l = emptyList(a.length);
for (double i : a) l.add(i);
return l;
}
static ArrayList asList(short[] a) {
if (a == null) return null;
ArrayList l = emptyList(a.length);
for (short i : a) l.add(i);
return l;
}
static ArrayList asList(Iterator it) {
ArrayList l = new ArrayList();
if (it != null)
while (it.hasNext())
l.add(it.next());
return l;
}
// disambiguation
static ArrayList asList(IterableIterator s) {
return asList((Iterator) s);
}
static ArrayList asList(Iterable s) {
if (s instanceof ArrayList) return (ArrayList) s;
ArrayList l = new ArrayList();
if (s != null)
for (A a : s)
l.add(a);
return l;
}
static ArrayList asList(Enumeration e) {
ArrayList l = new ArrayList();
if (e != null)
while (e.hasMoreElements())
l.add(e.nextElement());
return l;
}
static ArrayList asList(ReverseChain c) {
return c == null ? emptyList() : c.toList();
}
static List asList(Pair p) {
return p == null ? null : ll(p.a, p.b);
}
static boolean endsWithLetterOrDigit(String s) {
return s != null && s.length() > 0 && Character.isLetterOrDigit(s.charAt(s.length()-1));
}
static Object getOpt(Object o, String field) {
return getOpt_cached(o, field);
}
static Object getOpt(String field, Object o) {
return getOpt_cached(o, field);
}
static 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); } }
// access of static fields is not yet optimized
static 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 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 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 int indexOf(List l, int startIndex, A a) {
return indexOf(l, a, startIndex);
}
static int indexOf(List l, A a) {
if (l == null) return -1;
return l.indexOf(a);
}
static int indexOf(String a, String b) {
return a == null || b == null ? -1 : a.indexOf(b);
}
static int indexOf(String a, String b, int i) {
return a == null || b == null ? -1 : a.indexOf(b, i);
}
static int indexOf(String a, char b) {
return a == null ? -1 : a.indexOf(b);
}
static int indexOf(String a, int i, char b) {
return indexOf(a, b, i);
}
static int indexOf(String a, char b, int i) {
return a == null ? -1 : a.indexOf(b, i);
}
static int indexOf(String a, int i, String b) {
return a == null || b == null ? -1 : a.indexOf(b, i);
}
static 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 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 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 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 Object vmBus_wrapArgs(Object... args) {
return empty(args) ? null
: l(args) == 1 ? args[0]
: args;
}
static void pcallFAll_minimalExceptionHandling(Collection l, Object... args) {
if (l != null) for (Object f : cloneList(l)) { ping(); pcallF_minimalExceptionHandling(f, args); }
}
static void pcallFAll_minimalExceptionHandling(Iterator it, Object... args) {
while (it.hasNext()) { ping(); pcallF_minimalExceptionHandling(it.next(), args); }
}
static Set vm_busListeners_live_cache;
static Set vm_busListeners_live() { if (vm_busListeners_live_cache == null) vm_busListeners_live_cache = vm_busListeners_live_load(); return vm_busListeners_live_cache;}
static Set vm_busListeners_live_load() {
return vm_generalIdentityHashSet("busListeners");
}
static Map vm_busListenersByMessage_live_cache;
static Map vm_busListenersByMessage_live() { if (vm_busListenersByMessage_live_cache == null) vm_busListenersByMessage_live_cache = vm_busListenersByMessage_live_load(); return vm_busListenersByMessage_live_cache;}
static Map vm_busListenersByMessage_live_load() {
return vm_generalHashMap("busListenersByMessage");
}
static boolean startsWith(String a, String b) {
return a != null && a.startsWith(unnull(b));
}
static boolean startsWith(String a, char c) {
return nemptyString(a) && a.charAt(0) == c;
}
static 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 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 boolean domainIsUnder(String domain, String mainDomain) {
return eqic(domain, mainDomain) || ewic(domain, "." + mainDomain);
}
static String theAGIBlueDomain() {
return "agi.blue";
}
static int max(int a, int b) { return Math.max(a, b); }
static int max(int a, int b, int c) { return max(max(a, b), c); }
static long max(int a, long b) { return Math.max((long) a, b); }
static long max(long a, long b) { return Math.max(a, b); }
static double max(int a, double b) { return Math.max((double) a, b); }
static float max(float a, float b) { return Math.max(a, b); }
static double max(double a, double b) { return Math.max(a, b); }
static > 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;
}
/*Nah.
static int max(Collection c) {
int x = Integer.MIN_VALUE;
for (int i : c) x = max(x, i);
ret x;
}*/
static double max(double[] c) {
if (c.length == 0) return Double.MIN_VALUE;
double x = c[0];
for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]);
return x;
}
static 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 byte max(byte[] c) {
byte x = -128;
for (byte d : c) if (d > x) x = d;
return x;
}
static short max(short[] c) {
short x = -0x8000;
for (short d : c) if (d > x) x = d;
return x;
}
static int max(int[] c) {
int x = Integer.MIN_VALUE;
for (int d : c) if (d > x) x = d;
return x;
}
static > A max(A a, A b) {
return cmp(a, b) >= 0 ? a : b;
}
static 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 Symbol symbol(String s) {
if (s == null) return null;
synchronized(symbol_map) {
// TODO: avoid object creation by passing the string to findKey
Symbol symbol = new Symbol(s, true);
Symbol existingSymbol = symbol_map.findKey(symbol);
if (existingSymbol == null)
symbol_map.put(existingSymbol = symbol, true);
return existingSymbol;
}
}
static 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 Symbol symbol(Object o) {
return symbol((CharSequence) o);
}
static int strL(String s) {
return s == null ? 0 : s.length();
}
static int lCharSequence(CharSequence s) {
return s == null ? 0 : s.length();
}
static void assertFalse(Object o) {
if (!(eq(o, false) /*|| isFalse(pcallF(o))*/))
throw fail(str(o));
}
static boolean assertFalse(boolean b) {
if (b) throw fail("oops");
return b;
}
static boolean assertFalse(String msg, boolean b) {
if (b) throw fail(msg);
return b;
}
static Pair mapEntryToPair(Map.Entry e) {
return e == null ? null : pair(e.getKey(), e.getValue());
}
static Set> entrySet(Map map) {
return _entrySet(map);
}
static Pair pair(A a, B b) {
return new Pair(a, b);
}
static Pair pair(A a) {
return new Pair(a, a);
}
static A firstThat(Iterable l, IF1 pred) {
for (A a : unnullForIteration(l))
if (pred.get(a))
return a;
return null;
}
static A firstThat(A[] l, IF1 pred) {
for (A a : unnullForIteration(l))
if (pred.get(a))
return a;
return null;
}
static A firstThat(IF1 pred, Iterable l) {
return firstThat(l, pred);
}
static A firstThat(IF1 pred, A[] l) {
return firstThat(l, pred);
}
static void scanForComponents(final Component c, final Class theClass, final List l) {
if (theClass.isInstance(c))
l.add((A) c);
if (c instanceof Container) { swing(() -> {
for (Component comp : ((Container) c).getComponents())
scanForComponents(comp, theClass, l);
}); }
}
static 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 void swingLater(long delay, final Object r) {
javax.swing.Timer timer = new javax.swing.Timer(toInt(delay), actionListener(wrapAsActivity(r)));
timer.setRepeats(false);
timer.start();
}
static void swingLater(Object r) {
SwingUtilities.invokeLater(toRunnable(r));
}
static long toMS(double seconds) {
return (long) (seconds*1000);
}
// first delay = delay
static Timer installTimer(JComponent component, Object r, long delay) {
return installTimer(component, r, delay, delay);
}
// first delay = delay
static Timer installTimer(RootPaneContainer frame, long delay, Object r) {
return installTimer(frame.getRootPane(), r, delay, delay);
}
// first delay = delay
static Timer installTimer(JComponent component, long delay, Object r) {
return installTimer(component, r, delay, delay);
}
static Timer installTimer(JComponent component, long delay, long firstDelay, Object r) {
return installTimer(component, r, delay, firstDelay);
}
static Timer installTimer(final JComponent component, final Object r, final long delay, final long firstDelay) {
return installTimer(component, r, delay, firstDelay, true);
}
static Timer installTimer(final JComponent component, final Object r, final long delay, final long firstDelay, final boolean repeats) {
if (component == null) return null;
return (Timer) swingAndWait(new F0() { public Object get() { try {
final Var timer = new Var();
timer.set(new Timer(toInt(delay), new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent _evt) { try {
AutoCloseable __1 = tempActivity(r); try {
try {
if (!allPaused())
if (isFalse(callF(r)))
cancelTimer(timer.get());
} catch (Throwable __e) { printStackTrace(__e); }
} finally { _close(__1); }} catch (Throwable __e) { messageBox(__e); }}}));
timer.get().setInitialDelay(toInt(firstDelay));
timer.get().setRepeats(repeats);
bindTimerToComponent(timer.get(), component);
return timer.get();
} catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "final new Var timer;\r\n timer.set(new Timer(toInt(delay), actionList..."; }});
}
static Timer installTimer(RootPaneContainer frame, long delay, long firstDelay, Object r) {
return installTimer(frame.getRootPane(), delay, firstDelay, r);
}
static Object nuObject(String className, Object... args) { try {
return nuObject(classForName(className), args);
} catch (Exception __e) { throw rethrow(__e); } }
// too ambiguous - maybe need to fix some callers
/*static O nuObject(O realm, S className, O... args) {
ret nuObject(_getClass(realm, className), args);
}*/
static A nuObject(Class c, Object... args) { try {
if (args == null || args.length == 0) return nuObjectWithoutArguments(c); // cached!
Constructor m = nuObject_findConstructor(c, args);
makeAccessible(m);
return (A) m.newInstance(args);
} catch (Exception __e) { throw rethrow(__e); } }
static 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 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 A setBorder(Border border, A c) {
if (c != null) { swing(() -> { c.setBorder(border); }); }
return c;
}
static A setBorder(A c, Border border) {
return setBorder(border, c);
}
static JScrollPane withoutViewportBorder(JScrollPane sp) {
if (sp != null) { swing(() -> { sp.setViewportBorder(null); }); }
return sp;
}
static JPanel jFullCenter(final Component c) {
return swing(new F0() { public JPanel get() { try {
JPanel panel = new JPanel(new GridBagLayout());
panel.add(c);
return panel;
} catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "JPanel panel = new JPanel(new GridBagLayout);\r\n panel.add(c);\r\n ret panel;"; }});
}
static 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); }};
}
// get purpose 1: access a list/array/map (safer version of x.get(y))
static A get(List l, int idx) {
return l != null && idx >= 0 && idx < l(l) ? l.get(idx) : null;
}
// seems to conflict with other signatures
/*static B get(Map map, A key) {
ret map != null ? map.get(key) : null;
}*/
static A get(A[] l, int idx) {
return idx >= 0 && idx < l(l) ? l[idx] : null;
}
// default to false
static boolean get(boolean[] l, int idx) {
return idx >= 0 && idx < l(l) ? l[idx] : false;
}
// get purpose 2: access a field by reflection or a map
static 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 Object get_raw(String field, Object o) {
return get_raw(o, field);
}
static 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 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 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 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 Object get(String field, Object o) {
return get(o, field);
}
static boolean get(BitSet bs, int idx) {
return bs != null && bs.get(idx);
}
static Class javax() {
return getJavaX();
}
static String formatSnippetID(String id) {
return "#" + parseSnippetID(id);
}
static String formatSnippetID(long id) {
return "#" + id;
}
static Font loadFont(String snippetID) { try {
return loadFont(snippetID, 12f);
} catch (Exception __e) { throw rethrow(__e); } }
static Font loadFont(InputStream in) { try {
return Font.createFont(Font.TRUETYPE_FONT, in);
} catch (Exception __e) { throw rethrow(__e); } }
static Font loadFont(String snippetID, float fontSize) {
return loadFont(loadLibrary(snippetID), fontSize);
}
static Font loadFont(File f, float fontSize) { try {
return Font.createFont(Font.TRUETYPE_FONT, f).deriveFont(fontSize);
} catch (Exception __e) { throw rethrow(__e); } }
static Font loadFont(InputStream in, float fontSize) { try {
return Font.createFont(Font.TRUETYPE_FONT, in).deriveFont(fontSize);
} catch (Exception __e) { throw rethrow(__e); } }
// TODO: JDK 17!! ?? No! Yes? Yes!!
static Object collectionMutex(List l) {
return l;
}
static Object collectionMutex(Object o) {
if (o instanceof List) return o;
// TODO: actually use our own maps so we can get the mutex properly
String c = className(o);
return o;
}
static A printException(A e) {
printStackTrace(e);
return e;
}
static A assertNotNull(A a) {
assertTrue(a != null);
return a;
}
static A assertNotNull(String msg, A a) {
assertTrue(msg, a != null);
return a;
}
static Map synchroHashMap() {
return synchronizedMap(new HashMap());
}
static A vm_generalMap_getOrCreate(Object key, F0 create) {
return vm_generalMap_getOrCreate(key, f0ToIF0(create));
}
static A vm_generalMap_getOrCreate(Object key, IF0 create) {
Map generalMap = vm_generalMap();
if (generalMap == null) return null; // must be x30 init
synchronized(generalMap) { // should switch to locks here
A a = (A) (vm_generalMap_get(key));
if (a == null)
vm_generalMap_put(key, a = create == null ? null : create.get());
return a;
}
}
static A callF_gen(F0 f) {
return f == null ? null : f.get();
}
static B callF_gen(F1 f, A a) {
return f == null ? null : f.get(a);
}
static A callF_gen(IF0 f) {
return f == null ? null : f.get();
}
static B callF_gen(IF1 f, A a) {
return f == null ? null : f.get(a);
}
static B callF_gen(A a, IF1 f) {
return f == null ? null : f.get(a);
}
static C callF_gen(IF2 f, A a, B b) {
return f == null ? null : f.get(a, b);
}
static void callF_gen(VF1 f, A a) {
{ if (f != null) f.get(a); }
}
static void callF_gen(A a, IVF1 f) {
{ if (f != null) f.get(a); }
}
static void callF_gen(IVF1 f, A a) {
{ if (f != null) f.get(a); }
}
static Object callF_gen(Runnable r) { { if (r != null) r.run(); } return null; }
static Object callF_gen(Object f, Object... args) {
return callF(f, args);
}
static Object callFunction(Object f, Object... args) {
return callF(f, args);
}
static Runnable asRunnable(Object o) {
return toRunnable(o);
}
static void _inheritThreadInfo(Object info) {
_threadInheritInfo(info);
}
static boolean regionMatchesIC(String a, int offsetA, String b, int offsetB, int len) {
return a != null && a.regionMatches(true, offsetA, b, offsetB, len);
}
static 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 boolean contains(Collection c, Object o) {
return c != null && c.contains(o);
}
static boolean contains(Iterable it, Object a) {
if (it != null)
for (Object o : it)
if (eq(a, o))
return true;
return false;
}
static boolean contains(Object[] x, Object o) {
if (x != null)
for (Object a : x)
if (eq(a, o))
return true;
return false;
}
static boolean contains(String s, char c) {
return s != null && s.indexOf(c) >= 0;
}
static boolean contains(String s, String b) {
return s != null && s.indexOf(b) >= 0;
}
static boolean contains(BitSet bs, int i) {
return bs != null && bs.get(i);
}
static boolean contains(Rect r, Pt p) { return rectContains(r, p); }
static 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("");
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 List _registerDangerousWeakMap_preList;
static A _registerDangerousWeakMap(A map) {
return _registerDangerousWeakMap(map, null);
}
static 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) {
// We're in class init
if (_registerDangerousWeakMap_preList == null) _registerDangerousWeakMap_preList = synchroList();
_registerDangerousWeakMap_preList.add(pair(map, init));
return map;
}
call(javax(), "_registerDangerousWeakMap", map, init);
return map;
}
static void _onLoad_registerDangerousWeakMap() {
assertNotNull(javax());
if (_registerDangerousWeakMap_preList == null) return;
for (Pair p : _registerDangerousWeakMap_preList)
_registerDangerousWeakMap(p.a, p.b);
_registerDangerousWeakMap_preList = null;
}
static Throwable getExceptionCause(Throwable e) {
Throwable c = e.getCause();
return c != null ? c : e;
}
static String joinWithSpace(Iterable c) {
return join(" ", c);
}
static String joinWithSpace(Object... c) {
return join(" ", c);
}
static boolean isInstanceX(Class type, Object arg) {
if (type == boolean.class) return arg instanceof Boolean;
if (type == int.class) return arg instanceof Integer;
if (type == long.class) return arg instanceof Long;
if (type == float.class) return arg instanceof Float;
if (type == short.class) return arg instanceof Short;
if (type == char.class) return arg instanceof Character;
if (type == byte.class) return arg instanceof Byte;
if (type == double.class) return arg instanceof Double;
return type.isInstance(arg);
}
static boolean argumentCompatibleWithType(Object arg, Class type) {
return arg == null ? !type.isPrimitive() : isInstanceX(type, arg);
}
static void arraycopy(Object[] a, Object[] b) {
if (a != null && b != null)
arraycopy(a, 0, b, 0, Math.min(a.length, b.length));
}
static void arraycopy(Object src, int srcPos, int destPos, int n) { arraycopy(src, srcPos, src, destPos, n); }
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int n) {
if (n != 0)
System.arraycopy(src, srcPos, dest, destPos, n);
}
static boolean methodIsStatic(Method m) {
return (m.getModifiers() & Modifier.STATIC) != 0;
}
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 String join(Iterable strings) {
return join("", strings);
}
static String join(Iterable strings, String glue) {
return join(glue, strings);
}
public static String join(String[] strings) {
return join("", strings);
}
static String join(String glue, Pair p) {
return p == null ? "" : str(p.a) + glue + str(p.b);
}
static List getClassNames(Collection l) {
List out = new ArrayList();
if (l != null) for (Object o : l)
out.add(o == null ? null : getClassName(o));
return out;
}
// usually L
static 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 String fromLines(String... lines) {
return fromLines(asList(lines));
}
static IterableIterator toLines(File f) {
return linesFromFile(f);
}
static List toLines(String s) {
List lines = new ArrayList();
if (s == null) return lines;
int start = 0;
while (true) {
int i = toLines_nextLineBreak(s, start);
if (i < 0) {
if (s.length() > start) lines.add(s.substring(start));
break;
}
lines.add(s.substring(start, i));
if (s.charAt(i) == '\r' && i+1 < s.length() && s.charAt(i+1) == '\n')
i += 2;
else
++i;
start = i;
}
return lines;
}
static 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 List mapToLines(Map map) {
List l = new ArrayList();
for (Object key : keys(map))
l.add(str(key) + " = " + str(map.get(key)));
return l;
}
static String mapToLines(Map map, Object f) {
return lines(map(map, f));
}
static String mapToLines(Object f, Map map) {
return lines(map(map, f));
}
static String mapToLines(Object f, Iterable l) {
return lines(map(f, l));
}
static String mapToLines(Iterable l, IF1 f) {
return mapToLines((Object) f, l);
}
static String mapToLines(IF1 f, Iterable l) {
return mapToLines((Object) f, l);
}
static String mapToLines(Map map, IF2 f) {
return lines(map(map, f));
}
static String mapToLines(IF1 f, A data1, A... moreData) {
return lines(map(f, data1, moreData));
}
static List filterNempty(Collection c) {
List l = new ArrayList();
for (String x : unnull(c))
if (nempty(x))
l.add(x);
return l;
}
static List lmap(IF1 f, Iterable l) {
return lambdaMap(f, l);
}
static List lmap(IF1 f, A[] l) {
return lambdaMap(f, l);
}
static String strOrNull(Object o) {
return o == null ? null : str(o);
}
//static final Map> getOpt_cache = newDangerousWeakHashMap(f getOpt_special_init);
static class getOpt_Map extends WeakHashMap {
getOpt_Map() {
if (getOpt_special == null) getOpt_special = new HashMap();
clear();
}
public void clear() {
super.clear();
//print("getOpt clear");
put(Class.class, getOpt_special);
put(String.class, getOpt_special);
}
}
static final Map> getOpt_cache =
_registerDangerousWeakMap(synchroMap(new getOpt_Map()));
static HashMap getOpt_special; // just a marker
/*static void getOpt_special_init(Map map) {
map.put(Class.class, getOpt_special);
map.put(S.class, getOpt_special);
}*/
static 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 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 S)
ret getOpt(getBot((S) 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); } }
// used internally - we are in synchronized block
static 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 Field getOpt_findField(Class> c, String field) {
Class _c = c;
do {
for (Field f : _c.getDeclaredFields())
if (f.getName().equals(field))
return f;
_c = _c.getSuperclass();
} while (_c != null);
return null;
}
static 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 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 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 boolean nemptyString(String s) {
return s != null && s.length() > 0;
}
static int listL(Collection l) {
return l == null ? 0 : l.size();
}
static boolean eqic(String a, String b) {
if ((a == null) != (b == null)) return false;
if (a == null) return true;
return a.equalsIgnoreCase(b);
}
static boolean eqic(Symbol a, Symbol b) {
return eq(a, b);
}
static boolean eqic(Symbol a, String b) {
return eqic(asString(a), b);
}
static 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 Iterator iterator(Iterable c) {
return c == null ? emptyIterator() : c.iterator();
}
static int cmp(Number a, Number b) {
return a == null ? b == null ? 0 : -1 : cmp(a.doubleValue(), b.doubleValue());
}
static int cmp(double a, double b) {
return a < b ? -1 : a == b ? 0 : 1;
}
static int cmp(int a, int b) {
return a < b ? -1 : a == b ? 0 : 1;
}
static int cmp(long a, long b) {
return a < b ? -1 : a == b ? 0 : 1;
}
static 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 Set> _entrySet(Map map) {
return map == null ? Collections.EMPTY_SET : map.entrySet();
}
static String unnullForIteration(String s) {
return s == null ? "" : s;
}
static Collection unnullForIteration(Collection l) {
return l == null ? immutableEmptyList() : l;
}
static List unnullForIteration(List l) { return l == null ? immutableEmptyList() : l; }
static byte[] unnullForIteration(byte[] l) { return l == null ? emptyByteArray() : l; }
static int[] unnullForIteration(int[] l) { return l == null ? emptyIntArray() : l; }
static char[] unnullForIteration(char[] l) { return l == null ? emptyCharArray() : l; }
static double[] unnullForIteration(double[] l) { return l == null ? emptyDoubleArray() : l; }
static short[] unnullForIteration(short[] l) { return l == null ? emptyShortArray() : l; }
static Map unnullForIteration(Map l) {
return l == null ? immutableEmptyMap() : l;
}
static Iterable unnullForIteration(Iterable i) {
return i == null ? immutableEmptyList() : i;
}
static A[] unnullForIteration(A[] a) {
return a == null ? (A[]) emptyObjectArray() : a;
}
static BitSet unnullForIteration(BitSet b) {
return b == null ? new BitSet() : b;
}
static Pt unnullForIteration(Pt p) {
return p == null ? new Pt() : p;
}
//ifclass Symbol
static Symbol unnullForIteration(Symbol s) {
return s == null ? emptySymbol() : s;
}
//endif
static Pair unnullForIteration(Pair p) {
return p != null ? p : new Pair(null, null);
}
static long unnullForIteration(Long l) { return l == null ? 0L : l; }
static 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 int toInt(long l) {
if (l != (int) l) throw fail("Too large for int: " + l);
return (int) l;
}
static ActionListener actionListener(final Object runnable) {
return actionListener(runnable, null);
}
static ActionListener actionListener(final Object runnable, final Object instanceToHold) {
if (runnable instanceof ActionListener) return (ActionListener) runnable;
final Object info = _threadInfo();
return new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent _evt) { try {
_threadInheritInfo(info);
AutoCloseable __1 = holdInstance(instanceToHold); try {
pcallF(runnable);
} finally { _close(__1); }} catch (Throwable __e) { messageBox(__e); }}};
}
static 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 AutoCloseable tempActivity(Object r) {
return null;
}
static boolean allPaused() {
return ping_pauseAll;
}
static void cancelTimer(javax.swing.Timer timer) {
if (timer != null) timer.stop();
}
static void cancelTimer(java.util.Timer timer) {
if (timer != null) timer.cancel();
}
static 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 void _close(AutoCloseable c) {
if (c != null) try {
c.close();
} catch (Throwable e) {
// Some classes stupidly throw an exception on double-closing
if (c instanceof javax.imageio.stream.ImageOutputStream)
return;
else throw rethrow(e);
}
}
static void messageBox(final String msg) {
print(msg);
{ swing(() -> {
JOptionPane.showMessageDialog(null, msg, "JavaX", JOptionPane.INFORMATION_MESSAGE);
}); }
}
static void messageBox(Throwable e) {
//showConsole();
printStackTrace(e);
messageBox(hideCredentials(innerException2(e)));
}
static void bindTimerToComponent(final Timer timer, JFrame f) {
bindTimerToComponent(timer, f.getRootPane());
}
static void bindTimerToComponent(final Timer timer, JComponent c) {
if (c.isShowing())
timer.start();
c.addAncestorListener(new AncestorListener() {
public void ancestorAdded(AncestorEvent event) {
timer.start();
}
public void ancestorRemoved(AncestorEvent event) {
timer.stop();
}
public void ancestorMoved(AncestorEvent event) {
}
});
}
static Map classForName_cache = synchroHashMap();
static Class classForName(String name) { return classForName(name, null); }
static Class classForName(String name, Object classFinder) {
// first clause is when we're in class init
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 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 Map nuObjectWithoutArguments_cache = newDangerousWeakHashMap();
static Object nuObjectWithoutArguments(String className) { try {
return nuObjectWithoutArguments(classForName(className));
} catch (Exception __e) { throw rethrow(__e); } }
static A nuObjectWithoutArguments(Class c) { try {
if (nuObjectWithoutArguments_cache == null)
// in class init
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 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());
}
// TODO: convert to regularly cleared normal map
static Map getDeclaredConstructors_cached_cache = newDangerousWeakHashMap();
static 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 List getClasses(Object[] array) {
List l = emptyList(l(array));
for (Object o : array) l.add(_getClass(o));
return l;
}
static A setThreadLocal(ThreadLocal tl, A value) {
if (tl == null) return null;
A old = tl.get();
tl.set(value);
return old;
}
static Object getOptDynOnly(DynamicObject o, String field) {
if (o == null || o.fieldValues == null) return null;
return o.fieldValues.get(field);
}
static Class __javax;
static Class getJavaX() { try {
return __javax;
} catch (Exception __e) { throw rethrow(__e); } }
static void __setJavaX(Class j) {
__javax = j;
_onJavaXSet();
}
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 File loadLibrary(String snippetID) {
return loadBinarySnippet(snippetID);
}
static String className(Object o) {
return getClassName(o);
}
static Map synchronizedMap() {
return synchroMap();
}
static Map synchronizedMap(Map map) {
return synchroMap(map);
}
static IF0 f0ToIF0(F0 f) {
return f == null ? null : () -> f.get();
}
static Object vm_generalMap_put(Object key, Object value) {
return mapPutOrRemove(vm_generalMap(), key, value);
}
static 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 boolean rectContains(Rect a, Rect b) {
return b.x >= a.x && b.y >= a.y && b.x2() <= a.x2() && b.y2() <= a.y2();
}
static boolean rectContains(Rect a, Rectangle b) {
return rectContains(a, toRect(b));
}
static boolean rectContains(Rect a, int x, int y) {
return a != null && a.contains(x, y);
}
static boolean rectContains(Rect a, Pt p) {
return a != null && p != null && a.contains(p);
}
static List takeFirst(List l, int n) {
return l(l) <= n ? l : newSubListOrSame(l, 0, n);
}
static List takeFirst(int n, List l) {
return takeFirst(l, n);
}
static String takeFirst(int n, String s) { return substring(s, 0, n); }
static String takeFirst(String s, int n) { return substring(s, 0, n); }
static CharSequence takeFirst(int n, CharSequence s) { return subCharSequence(s, 0, n); }
static 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 List takeFirst(int n, Iterable i) {
if (i == null) return null;
return i == null ? null : takeFirst(n, i.iterator());
}
static List takeFirst(int n, IterableIterator i) {
return takeFirst(n, (Iterator ) i);
}
static int[] takeFirst(int n, int[] a) { return takeFirstOfIntArray(n, a); }
static short[] takeFirst(int n, short[] a) { return takeFirstOfShortArray(n, a); }
static byte[] takeFirst(int n, byte[] a) { return takeFirstOfByteArray(n, a); }
static byte[] takeFirst(byte[] a, int n) { return takeFirstOfByteArray(n, a); }
static double[] takeFirst(int n, double[] a) { return takeFirstOfDoubleArray(n, a); }
static double[] takeFirst(double[] a, int n) { return takeFirstOfDoubleArray(n, a); }
static String intToHex_flexLength(int i) {
return Integer.toHexString(i);
}
static HashMap> callMC_cache = new HashMap();
static String callMC_key;
static Method callMC_value;
// varargs assignment fixer for a single string array argument
static Object callMC(String method, String[] arg) {
return callMC(method, new Object[] {arg});
}
static Object callMC(String method, Object... args) { try {
Method me;
if (callMC_cache == null) callMC_cache = new HashMap(); // initializer time workaround
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 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 CloseableIterableIterator linesFromFile(File f) { return linesFromFile(f, null); }
static 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 CloseableIterableIterator linesFromFile(String path) { return linesFromFile(path, null); }
static CloseableIterableIterator linesFromFile(String path, IResourceHolder resourceHolder) {
return linesFromFile(newFile(path), resourceHolder);
}
static Set keys(Map map) {
return map == null ? new HashSet() : map.keySet();
}
// convenience shortcut for keys_gen
static Set keys(Object map) {
return keys((Map) map);
}
static Set keys(IMultiMap mm) {
return mm.keySet();
}
static List map(Iterable l, Object f) { return map(f, l); }
static 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;
}
// map: func(key, value) -> list element
static 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 List map(Object f, Object[] l) { return map(f, asList(l)); }
static List map(Object[] l, Object f) { return map(f, l); }
static List map(Object f, Map map) {
return map(map, f);
}
static List map(Iterable l, F1 f) { return map(f, l); }
static 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 List map(IF1 f, Iterable l) { return map(l, f); }
static 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 List map(IF1 f, A[] l) { return map(l, f); }
static 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 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;
}
// new magic alias for mapLL - does it conflict?
static 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 boolean nempty(Collection c) {
return !empty(c);
}
static boolean nempty(CharSequence s) {
return !empty(s);
}
static boolean nempty(Object[] o) { return !empty(o); }
static boolean nempty(byte[] o) { return !empty(o); }
static boolean nempty(int[] o) { return !empty(o); }
static boolean nempty(BitSet bs) { return !empty(bs); }
static boolean nempty(Map m) {
return !empty(m);
}
static boolean nempty(Iterator i) {
return i != null && i.hasNext();
}
static boolean nempty(IMultiMap mm) { return mm != null && mm.size() != 0; }
static boolean nempty(Object o) { return !empty(o); }
static boolean nempty(Rect r) { return r != null && r.w != 0 && r.h != 0; }
static List lambdaMap(IF1 f, Iterable l) {
return map(l, f);
}
static List lambdaMap(IF1 f, A[] l) {
return map(l, f);
}
static void clear(Collection c) {
if (c != null) c.clear();
}
static void clear(Map map) {
if (map != null) map.clear();
}
static void put(Map map, A a, B b) {
if (map != null) map.put(a, b);
}
static void put(List l, int i, A a) {
if (l != null && i >= 0 && i < l(l)) l.set(i, a);
}
static Class> _getClass(String name) {
try {
return Class.forName(name);
} catch (ClassNotFoundException e) {
return null; // could optimize this
}
}
static Class _getClass(Object o) {
return o == null ? null
: o instanceof Class ? (Class) o : o.getClass();
}
static Class _getClass(Object realm, String name) {
try {
return classLoaderForObject(realm).loadClass(classNameToVM(name));
} catch (ClassNotFoundException e) {
return null; // could optimize this
}
}
static B syncMapGet2(Map map, A a) {
if (map == null) return null;
synchronized(collectionMutex(map)) {
return map.get(a);
}
}
static B syncMapGet2(A a, Map map) {
return syncMapGet2(map, a);
}
static boolean isSubtypeOf(Class a, Class b) {
return a != null && b != null && b.isAssignableFrom(a); // << always hated that method, let's replace it!
}
static Set reflection_classesNotToScan_value = litset(
"jdk.internal.loader.URLClassPath"
);
static Set reflection_classesNotToScan() {
return reflection_classesNotToScan_value;
}
static Throwable _storeException_value;
static void _storeException(Throwable e) {
_storeException_value = e;
}
static Set syncIdentityHashSet() {
return (Set) synchronizedSet(identityHashSet());
}
static Map syncHashMap() {
return synchroHashMap();
}
static String asString(Object o) {
return o == null ? null : o.toString();
}
static Iterator emptyIterator() {
return Collections.emptyIterator();
}
static List immutableEmptyList() {
return Collections.emptyList();
}
static byte[] emptyByteArray_a = new byte[0];
static byte[] emptyByteArray() { return emptyByteArray_a; }
static short[] emptyShortArray = new short[0];
static short[] emptyShortArray() { return emptyShortArray; }
static Map immutableEmptyMap() {
return Collections.emptyMap();
}
static int parseInt(String s) {
return emptyString(s) ? 0 : Integer.parseInt(s);
}
static int parseInt(char c) {
return Integer.parseInt(str(c));
}
static int boolToInt(boolean b) {
return b ? 1 : 0;
}
static ThreadLocal> holdInstance_l = new ThreadLocal();
static AutoCloseable holdInstance(Object o) {
if (o == null) return null;
listThreadLocalAdd(holdInstance_l, o);
return new AutoCloseable() {
public void close() {
listThreadLocalPopLast(holdInstance_l);
}
};
}
static Object dm_current_generic() {
return getWeakRef(dm_current_generic_tl().get());
}
static Object rcall(String method, Object o, Object... args) {
return call_withVarargs(o, method, args);
}
static Throwable innerException2(Throwable e) {
if (e == null) return null;
while (empty(e.getMessage()) && e.getCause() != null)
e = e.getCause();
return e;
}
static void _onJavaXSet() {}
static String shortenSnippetID(String snippetID) {
if (snippetID.startsWith("#"))
snippetID = snippetID.substring(1);
String httpBlaBla = "http://tinybrain.de/";
if (snippetID.startsWith(httpBlaBla))
snippetID = snippetID.substring(httpBlaBla.length());
return "" + parseLong(snippetID);
}
static File loadBinarySnippet(String snippetID) {
IResourceLoader rl = vm_getResourceLoader();
if (rl != null)
return rl.loadLibrary(snippetID);
return loadBinarySnippet_noResourceLoader(snippetID);
}
static 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 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 Rect toRect(Rectangle r) {
return r == null ? null : new Rect(r);
}
static Rect toRect(RectangularShape r) {
return r == null ? null : toRect(r.getBounds());
}
static Rect toRect(Rect r) { return r; }
static List newSubListOrSame(List l, int startIndex) {
return newSubListOrSame(l, startIndex, l(l));
}
static 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 CharSequence subCharSequence(CharSequence s, int x) {
return subCharSequence(s, x, s == null ? 0 : s.length());
}
static 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 int[] takeFirstOfIntArray(int[] b, int n) {
return subIntArray(b, 0, n);
}
static int[] takeFirstOfIntArray(int n, int[] b) {
return takeFirstOfIntArray(b, n);
}
static short[] takeFirstOfShortArray(short[] b, int n) {
return subShortArray(b, 0, n);
}
static short[] takeFirstOfShortArray(int n, short[] b) {
return takeFirstOfShortArray(b, n);
}
static byte[] takeFirstOfByteArray(byte[] b, int n) {
return subByteArray(b, 0, n);
}
static byte[] takeFirstOfByteArray(int n, byte[] b) {
return takeFirstOfByteArray(b, n);
}
static double[] takeFirstOfDoubleArray(double[] b, int n) {
return subDoubleArray(b, 0, n);
}
static double[] takeFirstOfDoubleArray(int n, double[] b) {
return takeFirstOfDoubleArray(b, n);
}
static 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 void multiMapPut(MultiMap mm, A key, B value) {
if (mm != null && key != null && value != null) mm.put(key, value);
}
static CloseableIterableIterator emptyCloseableIterableIterator_instance = new CloseableIterableIterator() {
public Object next() { throw fail(); }
public boolean hasNext() { return false; }
};
static CloseableIterableIterator emptyCloseableIterableIterator() {
return emptyCloseableIterableIterator_instance;
}
static CloseableIterableIterator linesFromReader(Reader r) { return linesFromReader(r, null); }
static 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 BufferedReader utf8bufferedReader(InputStream in) { try {
return in == null ? null : bufferedReader(_registerIOWrap(new InputStreamReader(in, "UTF-8"), in));
} catch (Exception __e) { throw rethrow(__e); } }
static BufferedReader utf8bufferedReader(File f) { try {
return utf8bufferedReader(newFileInputStream(f));
} catch (Exception __e) { throw rethrow(__e); } }
static GZIPInputStream newGZIPInputStream(File f) {
return gzInputStream(f);
}
static GZIPInputStream newGZIPInputStream(InputStream in) {
return gzInputStream(in);
}
static File newFile(File base, String... names) {
for (String name : names) base = new File(base, name);
return base;
}
static File newFile(String name) {
return name == null ? null : new File(name);
}
static File newFile(String base, String... names) {
return newFile(newFile(base), names);
}
static ClassLoader classLoaderForObject(Object o) {
if (o instanceof ClassLoader) return ((ClassLoader) o);
if (o == null) return null;
return _getClass(o).getClassLoader();
}
// Note: This is actually broken. Inner classes must stay with a $ separator
static String classNameToVM(String name) {
return name.replace(".", "$");
}
static HashSet litset(A... items) {
return lithashset(items);
}
static Set synchronizedSet() {
return synchroHashSet();
}
static Set synchronizedSet(Set set) {
return Collections.synchronizedSet(set);
}
static Set identityHashSet() {
return Collections.newSetFromMap(new IdentityHashMap());
}
static boolean emptyString(String s) {
return s == null || s.length() == 0;
}
static void listThreadLocalAdd(ThreadLocal> tl, A a) {
List l = tl.get();
if (l == null) tl.set(l = new ArrayList());
l.add(a);
}
static A listThreadLocalPopLast(ThreadLocal> tl) {
List l = tl.get();
if (l == null) return null;
A a = popLast(l);
if (empty(l)) tl.set(null);
return a;
}
static A getWeakRef(Reference ref) {
return ref == null ? null : ref.get();
}
static x30_pkg.x30_util.BetterThreadLocal dm_current_generic_tl;
static 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 long parseLong(String s) {
if (empty(s)) return 0;
return Long.parseLong(dropSuffix("L", s));
}
static long parseLong(Object s) {
return Long.parseLong((String) s);
}
static IResourceLoader vm_getResourceLoader() {
return proxy(IResourceLoader.class, vm_generalMap_get("_officialResourceLoader"));
}
static boolean isImageServerSnippet(long id) {
return id >= 1100000 && id < 1200000;
}
static 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); } }
// If you change this, also change DiskSnippetCache_fileToLibID
static File DiskSnippetCache_file(long snippetID) {
return new File(getGlobalCache(), "data_" + snippetID + ".jar");
}
// Data files are immutable, use centralized cache
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 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 long fileSize(String path) { return getFileSize(path); }
static long fileSize(File f) { return getFileSize(f); }
static 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 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));
}
// TODO: check if we hit the "LOADING" message
if (fileSize(f) == 0) throw fail();
System.err.println("Bytes loaded: " + fileSize(f));
} catch (Throwable e) {
//printStackTrace(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 int min(int a, int b) {
return Math.min(a, b);
}
static long min(long a, long b) {
return Math.min(a, b);
}
static float min(float a, float b) { return Math.min(a, b); }
static float min(float a, float b, float c) { return min(min(a, b), c); }
static double min(double a, double b) {
return Math.min(a, b);
}
static double min(double[] c) {
double x = Double.MAX_VALUE;
for (double d : c) x = Math.min(x, d);
return x;
}
static float min(float[] c) {
float x = Float.MAX_VALUE;
for (float d : c) x = Math.min(x, d);
return x;
}
static byte min(byte[] c) {
byte x = 127;
for (byte d : c) if (d < x) x = d;
return x;
}
static short min(short[] c) {
short x = 0x7FFF;
for (short d : c) if (d < x) x = d;
return x;
}
static int min(int[] c) {
int x = Integer.MAX_VALUE;
for (int d : c) if (d < x) x = d;
return x;
}
static int[] subIntArray(int[] b, int start) {
return subIntArray(b, start, l(b));
}
static 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 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 byte[] subByteArray(byte[] b, int start) {
return subByteArray(b, start, l(b));
}
static 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 double[] subDoubleArray(double[] b, int start) { return subDoubleArray(b, start, l(b)); }
static 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 BufferedReader bufferedReader(Reader r) { return bufferedReader(r, 8192); }
static BufferedReader bufferedReader(Reader r, int bufSize) {
if (r == null) return null;
return r instanceof BufferedReader ? (BufferedReader) r : _registerIOWrap(new BufferedReader(r, bufSize), r);
}
static A holdResource(IResourceHolder holder, A a) {
{ if (holder != null) holder.add(a); }
return a;
}
static CloseableIterableIterator iteratorFromFunction_f0_autoCloseable(final F0 f, final AutoCloseable closeable) {
class IFF2 extends CloseableIterableIterator {
A a;
boolean done = false;
public boolean hasNext() {
getNext();
return !done;
}
public A next() {
getNext();
if (done) throw fail();
A _a = a;
a = null;
return _a;
}
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 String readLineFromReaderWithClose(BufferedReader r) { try {
String s = r.readLine();
if (s == null) r.close();
return s;
} catch (Exception __e) { throw rethrow(__e); } }
static 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 A _registerIOWrap(A wrapper, Object wrapped) {
return wrapper;
}
static FileInputStream newFileInputStream(File path) throws IOException {
return newFileInputStream(path.getPath());
}
static FileInputStream newFileInputStream(String path) throws IOException {
FileInputStream f = new FileInputStream(path);
_registerIO(f, path, true);
return f;
}
static int gzInputStream_defaultBufferSize = 65536;
static GZIPInputStream gzInputStream(File f) { try {
return gzInputStream(new FileInputStream(f));
} catch (Exception __e) { throw rethrow(__e); } }
static GZIPInputStream gzInputStream(File f, int bufferSize) { try {
return gzInputStream(new FileInputStream(f), bufferSize);
} catch (Exception __e) { throw rethrow(__e); } }
static GZIPInputStream gzInputStream(InputStream in) {
return gzInputStream(in, gzInputStream_defaultBufferSize);
}
static GZIPInputStream gzInputStream(InputStream in, int bufferSize) { try {
return _registerIOWrap(new GZIPInputStream(in, gzInputStream_defaultBufferSize), in);
} catch (Exception __e) { throw rethrow(__e); } }
static HashSet lithashset(A... items) {
HashSet set = new HashSet();
for (A a : items) set.add(a);
return set;
}
static Set synchroHashSet() {
return synchronizedSet(new HashSet ());
}
static A popLast(List l) {
return liftLast(l);
}
static List popLast(int n, List l) {
return liftLast(n, l);
}
static boolean loadBufferedImage_useImageCache = true;
static 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();
// fall back to loading from sourceforge
}
}
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"));
//Log.info("Cached image.");
}
//Log.info("Loaded image.");
return image;
} else
return loadBufferedImage(new File(snippetIDOrURLOrFile));
} catch (Exception __e) { throw rethrow(__e); } }
static BufferedImage loadBufferedImage(File file) {
return loadBufferedImageFile(file);
}
static String dropSuffix(String suffix, String s) {
return nempty(suffix) && endsWith(s, suffix) ? s.substring(0, l(s)-l(suffix)) : s;
}
static 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 A proxy(Object target, Class intrface) {
return proxy(intrface, target);
}
static boolean isURL(String s) {
return startsWithOneOf(s, "http://", "https://", "file:");
}
public static boolean isSnippetID(String s) {
try {
parseSnippetID(s);
return true;
} catch (RuntimeException e) {
return false;
}
}
static File imageSnippetCacheFile(String snippetID) {
File dir = imageSnippetsCacheDir();
if (!loadBufferedImage_useImageCache) return null;
return new File(dir, parseSnippetID(snippetID) + ".png");
}
static String snippetImageURL_noHttps(String snippetID) {
return snippetImageURL_noHttps(snippetID, "png");
}
static 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 ThreadLocal>> loadBinaryPage_responseHeaders = new ThreadLocal();
static ThreadLocal> loadBinaryPage_extraHeaders = new ThreadLocal();
static byte[] loadBinaryPage(String url) { try {
print("Loading " + url);
return loadBinaryPage(loadPage_openConnection(new URL(url)));
} catch (Exception __e) { throw rethrow(__e); } }
static 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 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/*Long*/(); } 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); } }
/** writes safely (to temp file, then rename) */
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 byte[] saveBinaryFile(File fileName, byte[] contents) {
return saveBinaryFile(fileName.getPath(), contents);
}
static File getGlobalCache() {
File file = new File(javaxCachesDir(), "Binary Snippets");
file.mkdirs();
return file;
}
static long psI(String snippetID) {
return parseSnippetID(snippetID);
}
static String dataSnippetLink(String snippetID) {
long id = parseSnippetID(snippetID);
if (id >= 1100000 && id < 1200000)
return imageServerURL() + id;
if (id >= 1200000 && id < 1300000) { // Woody files, actually
String pw = muricaPassword();
if (empty(pw)) throw fail("Please set 'murica password by running #1008829");
return "https://botcompany.de/files/" + id + "?_pass=" + pw; // XXX, although it typically gets hidden when printing
}
return fileServerURL() + "/" + id /*+ "?_pass=" + muricaPassword()*/;
}
static String tb_mainServer_default = "https://code.botcompany.de:9898";
static Object tb_mainServer_override; // func -> S
static String tb_mainServer() {
if (tb_mainServer_override != null) return (String) callF(tb_mainServer_override);
return trim(loadTextFile(tb_mainServer_file(),
tb_mainServer_default));
}
static File tb_mainServer_file() {
return getProgramFile("#1001638", "mainserver.txt");
}
static boolean tb_mainServer_isDefault() {
return eq(tb_mainServer(), tb_mainServer_default);
}
static String fsI(String id) {
return formatSnippetID(id);
}
static String fsI(long id) {
return formatSnippetID(id);
}
static A addAndReturn(Collection c, A a) {
if (c != null) c.add(a);
return a;
}
static A addAndReturn(List c, int idx, A a) {
if (c != null) c.add(idx, a);
return a;
}
static void loadBinaryPageToFile(String url, File file) { try {
print("Loading " + url);
loadBinaryPageToFile(openConnection(new URL(url)), file);
} catch (Exception __e) { throw rethrow(__e); } }
static void loadBinaryPageToFile(URLConnection con, File file) { try {
setHeaders(con);
loadBinaryPageToFile_noHeaders(con, file);
} catch (Exception __e) { throw rethrow(__e); } }
static 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/*Long*/(); } 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 URLConnection openConnection(String url) { try {
return openConnection(new URL(url));
} catch (Exception __e) { throw rethrow(__e); } }
static URLConnection openConnection(URL url) { try {
ping();
callOpt(javax(), "recordOpenURLConnection", str(url));
return url.openConnection();
} catch (Exception __e) { throw rethrow(__e); } }
static List allToString(Iterable c) {
List l = new ArrayList();
for (Object o : unnull(c)) l.add(str(o));
return l;
}
static List allToString(Object[] c) {
List l = new ArrayList();
for (Object o : unnull(c)) l.add(str(o));
return l;
}
static void _registerIO(Object object, String path, boolean opened) {
}
static 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 List liftLast(int n, List l) {
int i = l(l)-n;
List part = cloneSubList(l, i);
removeSubList(l, i);
return part;
}
static BufferedImage imageIO_readURL(String url) { try {
return ImageIO.read(new URL(url));
} catch (Exception __e) { throw rethrow(__e); } }
static File imageSnippetsCacheDir() {
return javaxCachesDir("Image-Snippets");
}
static String snippetImageURL_http(String snippetID) {
return snippetImageURL_http(snippetID, "png");
}
static String snippetImageURL_http(String snippetID, String contentType) {
return replacePrefix("https://", "http://", snippetImageURL(snippetID, contentType)).replace(":8443", ":8080");
}
static BufferedImage loadBufferedImageFile(File file) { try {
return isFile(file) ? ImageIO.read(file) : null;
} catch (Exception __e) { throw rethrow(__e); } }
static boolean endsWith(String a, String b) {
return a != null && a.endsWith(b);
}
static boolean endsWith(String a, char c) {
return nempty(a) && lastChar(a) == c;
}
static 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 boolean isInstance(Class type, Object arg) {
return type.isInstance(arg);
}
static String snippetImageURL(long snippetID) {
return snippetImageURL(fsI(snippetID));
}
static String snippetImageURL(String snippetID) {
return snippetImageURL(snippetID, "png");
}
static 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 = "http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_" + id + "&contentType=image/" + contentType;
url = "https://botcompany.de/img/" + id;
return url;
}
static int loadPage_defaultTimeout = 60000;
static ThreadLocal loadPage_charset = new ThreadLocal();
static boolean loadPage_allowGzip = true, loadPage_debug;
static boolean loadPage_anonymous = false; // don't send computer ID
static int loadPage_verboseness = 100000;
static int loadPage_retries = 1; //60; // seconds
static ThreadLocal loadPage_silent = new ThreadLocal();
static volatile int loadPage_forcedTimeout; // ms
static ThreadLocal loadPage_forcedTimeout_byThread = new ThreadLocal(); // ms
static ThreadLocal>> loadPage_responseHeaders = new ThreadLocal();
static ThreadLocal> loadPage_extraHeaders = new ThreadLocal();
static 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 String loadPage_preprocess(String url) {
if (url.startsWith("tb/")) // don't think we use this anymore
url = tb_mainServer() + "/" + url;
if (url.indexOf("://") < 0)
url = "http://" + url;
return url;
}
static 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 String loadPage(URL url) {
return loadPage(url.toExternalForm());
}
static String loadPage(URLConnection con, URL url) throws IOException {
return loadPage(con, url, true);
}
static String loadPage(URLConnection con, URL url, boolean addHeaders) { try {
Map extraHeaders = getAndClearThreadLocal(loadPage_extraHeaders);
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) {} // fails if within doPost
return loadPage(con);
} catch (Exception __e) { throw rethrow(__e); } }
// just download as string, no shenanigans or extra headers or ANYTHING
static String loadPage(URLConnection con) { try {
Long limit = optPar(loadPage_sizeLimit);
URL url = con.getURL();
vm_generalSubMap("URLConnection per thread").put(currentThread(), con);
loadPage_responseHeaders.set(con.getHeaderFields());
InputStream in = null;
try {
in = urlConnection_getInputStream(con);
//vm_generalSubMap("InputStream per thread").put(currentThread(), in);
if (loadPage_debug)
print("Put stream in map: " + currentThread());
String contentType = con.getContentType();
if (contentType == null) {
//printStruct("Headers: ", con.getHeaderFields());
throw new IOException("Page could not be read: " + hideCredentials(url));
}
//print("Content-Type: " + contentType);
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("InputStream per thread").remove(currentThread());
vm_generalSubMap("URLConnection per thread").remove(currentThread());
if (in != null) in.close();
}
} catch (Exception __e) { throw rethrow(__e); } }
static 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);
/* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */
//return or(match, "ISO-8859-1");
return or(match, "UTF-8");
}
static 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 A getAndClearThreadLocal(ThreadLocal tl) {
A a = tl.get();
tl.set(null);
return a;
}
static 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) {
//printShortException(e);
}
}
static A println(A a) {
return print(a);
}
static FileOutputStream newFileOutputStream(File path) throws IOException {
return newFileOutputStream(path.getPath());
}
static FileOutputStream newFileOutputStream(String path) throws IOException {
return newFileOutputStream(path, false);
}
static FileOutputStream newFileOutputStream(File path, boolean append) throws IOException {
return newFileOutputStream(path.getPath(), append);
}
static FileOutputStream newFileOutputStream(String path, boolean append) throws IOException {
mkdirsForFile(path);
FileOutputStream f = new FileOutputStream(path, append);
_registerIO(f, path, true);
return f;
}
static File javaxCachesDir_dir; // can be set to work on different base dir
static File javaxCachesDir() {
return javaxCachesDir_dir != null ? javaxCachesDir_dir : new File(userHome(), "JavaX-Caches");
}
static File javaxCachesDir(String sub) {
return newFile(javaxCachesDir(), sub);
}
static String imageServerURL() {
return or2(trim(loadTextFile(javaxDataDir("image-server-url.txt"))), "http://botcompany.de/images/raw/");
}
static volatile boolean muricaPassword_pretendNotAuthed = false;
static String muricaPassword() {
if (muricaPassword_pretendNotAuthed) return null;
return trim(loadTextFile(muricaPasswordFile()));
}
static String fileServerURL() {
return "https://botcompany.de/files";
}
static String trim(String s) { return s == null ? null : s.trim(); }
static String trim(StringBuilder buf) { return buf.toString().trim(); }
static String trim(StringBuffer buf) { return buf.toString().trim(); }
static String loadTextFile(String fileName) {
return loadTextFile(fileName, null);
}
static String loadTextFile(File f, String defaultContents) { return loadTextFile(f, defaultContents, "UTF-8"); }
static 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 String loadTextFile(String fileName, String defaultContents) {
return fileName == null ? defaultContents : loadTextFile(newFile(fileName), defaultContents);
}
static String loadTextFile(Reader reader) throws IOException {
StringBuilder builder = new StringBuilder();
try {
char[] buffer = new char[1024];
int n;
while (-1 != (n = reader.read(buffer)))
builder.append(buffer, 0, n);
} finally {
reader.close();
}
return str(builder);
}
static File getProgramFile(String progID, String fileName) {
if (new File(fileName).isAbsolute())
return new File(fileName);
return new File(getProgramDir(progID), fileName);
}
static File getProgramFile(String fileName) {
return getProgramFile(getProgramID(), fileName);
}
static String f2s(File f) {
return f == null ? null : f.getAbsolutePath();
}
static String f2s(String s) { return f2s(newFile(s)); }
static String f2s(java.nio.file.Path p) {
return p == null ? null : f2s(p.toFile());
}
public static File mkdirsFor(File file) {
return mkdirsForFile(file);
}
static 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 File renameFile_assertTrue(File a, File b) { try {
if (a.equals(b)) return b; // no rename necessary
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 List cloneSubList(List l, int startIndex, int endIndex) {
return newSubList(l, startIndex, endIndex);
}
static List cloneSubList(List l, int startIndex) {
return newSubList(l, startIndex);
}
static void removeSubList(List l, int from, int to) {
if (l != null) subList(l, from, to).clear();
}
static void removeSubList(List l, int from) {
if (l != null) subList(l, from).clear();
}
static String replacePrefix(String prefix, String replacement, String s) {
if (!startsWith(s, prefix)) return s;
return replacement + substring(s, l(prefix));
}
static boolean isFile(File f) {
return f != null && f.isFile();
}
static boolean isFile(String path) {
return isFile(newFile(path));
}
static char lastChar(String s) {
return empty(s) ? '\0' : s.charAt(l(s)-1);
}
static A[] dropLast(A[] a) { return dropLast(a, 1); }
static 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 List dropLast(List l) {
return subList(l, 0, l(l)-1);
}
static List dropLast(int n, List l) {
return subList(l, 0, l(l)-n);
}
static List dropLast(Iterable l) {
return dropLast(asList(l));
}
static String dropLast(String s) {
return substring(s, 0, l(s)-1);
}
static String dropLast(String s, int n) {
return substring(s, 0, l(s)-n);
}
static String dropLast(int n, String s) {
return dropLast(s, n);
}
static String imageServerLink(String md5OrID) {
if (possibleMD5(md5OrID))
return "https://botcompany.de/images/md5/" + md5OrID;
return imageServerLink(parseSnippetID(md5OrID));
}
static String imageServerLink(long id) {
return "https://botcompany.de/images/" + id;
}
static boolean networkAllowanceTest(String url) {
return isAllowed("networkAllowanceTest", url);
}
static A printWithTime(A a) {
return printWithTime("", a);
}
static A printWithTime(String s, A a) {
print(hmsWithColons() + ": " + s, a);
return a;
}
static A optPar(ThreadLocal tl, A defaultValue) {
A a = tl.get();
if (a != null) {
tl.set(null);
return a;
}
return defaultValue;
}
static A optPar(ThreadLocal tl) {
return optPar(tl, null);
}
static Object optPar(Object[] params, String name) {
return optParam(params, name);
}
static Object optPar(String name, Object[] params) {
return optParam(params, name);
}
static Object optPar(String name, Map params) {
return optParam(name, params);
}
static A optPar(Object[] params, String name, A defaultValue) {
return optParam(params, name, defaultValue);
}
static A optPar(String name, Object[] params, A defaultValue) {
return optParam(params, name, defaultValue);
}
static 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 InputStream urlConnection_getInputStream(URLConnection con) throws IOException {
return con.getInputStream();
}
static 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);
}
}
return unquoteSingleOrDoubleQuotes(s);
}
static String toHex(byte[] bytes) {
return bytesToHex(bytes);
}
static String toHex(byte[] bytes, int ofs, int len) {
return bytesToHex(bytes, ofs, len);
}
static byte[] utf8(String s) {
return toUtf8(s);
}
static Matcher regexpMatcher(String pat, String s) {
return compileRegexp(pat).matcher(unnull(s));
}
static Matcher regexpMatcher(java.util.regex.Pattern pat, String s) {
return pat.matcher(unnull(s));
}
static 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 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 String getComputerID_quick() {
return computerID();
}
public static File mkdirsForFile(File file) {
File dir = file.getParentFile();
if (dir != null) { // is null if file is in current dir
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 String _userHome;
static String userHome() {
if (_userHome == null)
return actualUserHome();
return _userHome;
}
static File userHome(String path) {
return new File(userDir(), path);
}
static String or2(String a, String b) {
return nempty(a) ? a : b;
}
static String or2(String a, String b, String c) {
return or2(or2(a, b), c);
}
static File javaxDataDir_dir; // can be set to work on different base dir
static File javaxDataDir() {
return javaxDataDir_dir != null ? javaxDataDir_dir : new File(userHome(), "JavaX-Data");
}
static File javaxDataDir(String... subs) {
return newFile(javaxDataDir(), subs);
}
static File muricaPasswordFile() {
return new File(javaxSecretDir(), "murica/muricaPasswordFile");
}
static ThreadLocal> checkFileNotTooBigToRead_tl = new ThreadLocal();
static void checkFileNotTooBigToRead(File f) {
callF(checkFileNotTooBigToRead_tl.get(), f);
}
static File getProgramDir() {
return programDir();
}
static File getProgramDir(String snippetID) {
return programDir(snippetID);
}
static String programID;
static String getProgramID() {
return nempty(programID) ? formatSnippetIDOpt(programID) : "?";
}
// TODO: ask JavaX instead
static String getProgramID(Class c) {
String id = (String) getOpt(c, "programID");
if (nempty(id))
return formatSnippetID(id);
return "?";
}
static String getProgramID(Object o) {
return getProgramID(getMainClass(o));
}
// TODO: optimize to x-(x%n) in case that's the same thing
// (or x-mod(x,n)?)
static int roundDownTo(int n, int x) {
return x/n*n;
}
static long roundDownTo(long n, long x) {
return x/n*n;
}
static List newSubList(List l, int startIndex, int endIndex) {
return cloneList(subList(l, startIndex, endIndex));
}
static List newSubList(List l, int startIndex) {
return cloneList(subList(l, startIndex));
}
static List subList(List l, int startIndex) {
return subList(l, startIndex, l(l));
}
static List subList(int startIndex, List l) {
return subList(l, startIndex);
}
static List subList(int startIndex, int endIndex, List l) {
return subList(l, startIndex, endIndex);
}
static 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 A[] arrayOfSameType(A[] a, int n) {
return newObjectArrayOfSameType(a, n);
}
static boolean possibleMD5(String s) { return isMD5(s); }
static volatile Object isAllowed_function; // func(S, O[]) -> bool
static volatile boolean isAllowed_all = true;
static boolean isAllowed(String askingMethod, Object... args) {
// check on VM level
Object f = vm_generalMap_get("isAllowed_function");
if (f != null && !isTrue(callF(f, askingMethod, args))) return false;
// check locally
return isAllowed_all || isTrue(callF(isAllowed_function, askingMethod, args));
}
static String hmsWithColons() {
return hmsWithColons(now());
}
static String hmsWithColons(long time) {
return new SimpleDateFormat("HH:mm:ss").format(time);
}
static A optParam(ThreadLocal tl, A defaultValue) {
return optPar(tl, defaultValue);
}
static A optParam(ThreadLocal tl) {
return optPar(tl);
}
static Object optParam(String name, Map params) {
return mapGet(params, name);
}
// now also takes a map as single array entry
static 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 Object optParam(Object[] opt, String name) {
return optParam(opt, name, null);
}
static Object optParam(String name, Object[] params) {
return optParam(params, name);
}
static String unquoteSingleOrDoubleQuotes(String s) {
if (s == null) return null;
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);
// Octal escape?
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;
// Hex Unicode: u????
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; // added by Stefan
}
i++;
}
sb.append(ch);
}
return sb.toString();
}
}
return s; // not quoted - return original
}
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 byte[] toUtf8(String s) { try {
return s.getBytes(utf8charset());
} catch (Exception __e) { throw rethrow(__e); } }
static Map compileRegexp_cache = syncMRUCache(10);
static 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 String _computerID;
static 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) {
// legacy load
_computerID = loadTextFile(userDir(".tinybrain/computer-id"));
if (_computerID == null)
_computerID = makeRandomID(12, new SecureRandom());
saveTextFile(file, _computerID);
}
} finally { unlock(__0); } }
return _computerID;
}
static String actualUserHome_value;
static String actualUserHome() {
if (actualUserHome_value == null) {
if (isAndroid())
actualUserHome_value = "/storage/emulated/0/";
else
actualUserHome_value = System.getProperty("user.home");
}
return actualUserHome_value;
}
static File actualUserHome(String sub) {
return newFile(new File(actualUserHome()), sub);
}
static File userDir() {
return new File(userHome());
}
static File userDir(String path) {
return new File(userHome(), path);
}
static File javaxSecretDir_dir; // can be set to work on different base dir
static File javaxSecretDir() {
return javaxSecretDir_dir != null ? javaxSecretDir_dir : new File(userHome(), "JavaX-Secret");
}
static File javaxSecretDir(String sub) {
return newFile(javaxSecretDir(), sub);
}
static File programDir_mine; // set this to relocate program's data
static File programDir() {
return programDir(getProgramID());
}
static 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 File programDir(String snippetID, String subPath) {
return new File(programDir(snippetID), subPath);
}
static String formatSnippetIDOpt(String s) {
return isSnippetID(s) ? formatSnippetID(s) : s;
}
static Class getMainClass() {
return mc();
}
static 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 A[] newObjectArrayOfSameType(A[] a) { return newObjectArrayOfSameType(a, a.length); }
static A[] newObjectArrayOfSameType(A[] a, int n) {
return (A[]) Array.newInstance(a.getClass().getComponentType(), n);
}
static boolean isMD5(String s) {
return l(s) == 32 && isLowerHexString(s);
}
static long now_virtualTime;
static long now() {
return now_virtualTime != 0 ? now_virtualTime : System.currentTimeMillis();
}
static B mapGet(Map map, A a) {
return map == null || a == null ? null : map.get(a);
}
static B mapGet(A a, Map map) {
return map == null || a == null ? null : map.get(a);
}
static boolean even(int i) {
return (i & 1) == 0;
}
static boolean even(long i) {
return (i & 1) == 0;
}
static boolean even(BigInteger n) {
return even(n.intValue());
}
static Charset utf8charset_cache;
static Charset utf8charset() { if (utf8charset_cache == null) utf8charset_cache = utf8charset_load(); return utf8charset_cache;}
static Charset utf8charset_load() {
return Charset.forName("UTF-8");
}
static Map syncMRUCache(int size) {
return synchroMap(new MRUCache(size));
}
static 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);
}
// NO call to ping here! Make sure lock is always released.
} catch (Exception __e) { throw rethrow(__e); } }
static void lock(Lock lock, String msg) {
print("Locking: " + msg);
lock(lock);
}
static void lock(Lock lock, String msg, long timeout) {
print("Locking: " + msg);
lockOrFail(lock, timeout);
}
static ReentrantLock lock() {
return fairLock();
}
static File computerIDFile() {
return javaxDataDir("Basic Info/computer-id.txt");
}
static String makeRandomID(int length) {
return makeRandomID(length, defaultRandomGenerator());
}
static 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 String makeRandomID(Random r, int length) {
return makeRandomID(length, r);
}
/** writes safely (to temp file, then rename) */
static File saveTextFile(String fileName, String contents) throws IOException {
/*ifdef CriticalActions
temp beginCriticalAction("Saving file " + fileName + " (" + l(contents) + " chars)");
endifdef*/
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 File saveTextFile(File fileName, String contents) { try {
saveTextFile(fileName.getPath(), contents);
return fileName;
} catch (Exception __e) { throw rethrow(__e); } }
static void unlock(Lock lock, String msg) {
if (lock == null) return;
lock.unlock();
vmBus_send("unlocked", lock, "thread" , currentThread());
print("Unlocked: " + msg); // print afterwards to make sure the lock is always unlocked
}
static void unlock(Lock lock) {
if (lock == null) return;
lock.unlock();
vmBus_send("unlocked", lock, "thread" , currentThread());
}
static boolean sameSnippetID(String a, String b) {
if (!isSnippetID(a) || !isSnippetID(b)) return false;
return parseSnippetID(a) == parseSnippetID(b);
}
static String programID() {
return getProgramID();
}
static String programID(Object o) {
return getProgramID(o);
}
static volatile String caseID_caseID;
static String caseID() { return caseID_caseID; }
static void caseID(String id) {
caseID_caseID = id;
}
static String mainClassNameForClassLoader(ClassLoader cl) {
return or((String) callOpt(cl, "mainClassName"), "main");
}
static Class loadClassFromClassLoader_orNull(ClassLoader cl, String name) {
try {
return cl == null ? null : cl.loadClass(name);
} catch (ClassNotFoundException e) {
return null;
}
}
static 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') {
// ok
} else
return false;
}
return true;
}
static Map vm_threadInterruptionReasonsMap() {
return vm_generalWeakSubMap("Thread interruption reasons");
}
static String strOr(Object o, String ifNull) {
return o == null ? ifNull : str(o);
}
static 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 ReentrantLock fairLock() {
return new ReentrantLock(true);
}
static Random defaultRandomGenerator() {
{ Random r = customRandomizerForThisThread(); if (r != null) return r; }
return ThreadLocalRandom.current();
}
static 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 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 Random customRandomizerForThisThread() {
return customRandomizerForThisThread_tl().get();
}
static 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 Map newWeakMap() {
return newWeakHashMap();
}
static ThreadLocal customRandomizerForThisThread_tl = new ThreadLocal();
static ThreadLocal customRandomizerForThisThread_tl() {
return customRandomizerForThisThread_tl;
}
static abstract class VF1 implements IVF1 {
public abstract void get(A a);
}
// immutable, has strong refs
// Do not run in a synchronized block - it goes wrong in the presence
// of elaborate classloaders (like in Gazelle BEA)
// see #1102990 and #1102991
final static class _MethodCache {
final Class c;
final HashMap> cache = new HashMap();
_MethodCache(Class c) {
this.c = c; _init(); }
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();
}
// add default methods - this might lead to a duplication
// because the overridden method is also added, but it's not
// a problem except for minimal performance loss.
// If any classes in the hierarchy were inaccessible, we add
// all interface methods (see test_callForbiddenMethodByReflection for a test)
for (Class intf : allInterfacesImplementedBy(c))
for (Method m : intf.getDeclaredMethods())
if ((anyHiddenClasses || m.isDefault()) && !reflection_isForbiddenMethod(m))
multiMapPut(cache, m.getName(), makeAccessible(m));
}
// Returns only matching methods
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); } }
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); } }
//Cl allMethods() { ret allValues(cache); }
}
static class Matches {
String[] m;
Matches() {}
Matches(String... m) {
this.m = m;}
String get(int i) { return i < m.length ? m[i] : null; }
String unq(int i) { return unquote(get(i)); }
String tlc(int i) { return unq(i).toLowerCase(); }
boolean bool(int i) { return "true".equals(unq(i)); }
String rest() { return m[m.length-1]; } // for matchStart
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 class SingleThread {
boolean running = false;
Thread thread;
void run(Object r) { go(r); }
synchronized boolean go(final Object runnable) {
if (running) return false;
running = true;
thread = startThread("Single Thread", new Runnable() { public void run() { try {
try {
callF(runnable);
} finally {
_done();
}
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "try {\r\n callF(runnable);\r\n } finally {\r\n _done();\r\n }"; }});
return true;
}
synchronized void _done() {
running = false;
thread = null;
}
synchronized boolean running() { return running; }
synchronized Thread getThread() { return thread; }
}
// for the version with MasterSymbol (used WAY back in "Smart Bot"!) see #1010608
static class Symbol implements CharSequence {
String text;
Symbol() {}
Symbol(String text, boolean dummy) {
this.text = text;} // weird signature to prevent accidental calling
public int hashCode() { return _hashCode(text); }
public String toString() { return text; }
public boolean equals(Object o) {
return this == o;
}
// implementation of CharSequence methods
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 class Var implements IVar , ISetter {
Var() {}
Var(A v) {
this.v = v;}
A v; // you can access this directly if you use one thread
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 synchronized A getAndSet(A a) {
var value = v;
set(a);
return value;
}
public IF0 getter() { return () -> get(); }
public IVF1 setter() { return __52 -> set(__52); }
public String toString() { return str(this.get()); }
}
static class ImageSurface extends Surface {
BufferedImage image;
double zoomX = 1, zoomY = 1, zoomFactor = 1.5;
private Rectangle selection;
List tools = new ArrayList();
// use overlays now
Object overlay; // voidfunc(Graphics2D)
List overlays = syncL();
Runnable onSelectionChange;
final public ImageSurface setVerbose(boolean verbose){ return verbose(verbose); }
public ImageSurface verbose(boolean verbose) { this.verbose = verbose; return this; } final public boolean getVerbose(){ return verbose(); }
public boolean verbose() { return verbose; }
boolean verbose = false;
boolean noMinimumSize = true;
String titleForUpload;
Object onZoom;
boolean specialPurposed = false; // true = don't show image changing commands in popup menu
final public ImageSurface setAllowPaste(boolean allowPaste){ return allowPaste(allowPaste); }
public ImageSurface allowPaste(boolean allowPaste) { this.allowPaste = allowPaste; return this; } final public boolean getAllowPaste(){ return allowPaste(); }
public boolean allowPaste() { return allowPaste; }
boolean allowPaste = false;
final public ImageSurface setZoomable(boolean zoomable){ return zoomable(zoomable); }
public ImageSurface zoomable(boolean zoomable) { this.zoomable = zoomable; return this; } final public boolean getZoomable(){ return zoomable(); }
public boolean zoomable() { return zoomable; }
boolean zoomable = true;
boolean noAlpha = false; // set to true to speed up drawing if you don't use alpha
Object interpolationMode = RenderingHints.VALUE_INTERPOLATION_BILINEAR;
Object onNewImage; // use imageChanged event instead
BufferedImage imageToDraw; // if you want to draw a different image
File file; // where image was loaded from
boolean autoZoomToDisplay = false; // only works 100% when not in scrollpane
final public ImageSurface setRepaintInThread(boolean repaintInThread){ return repaintInThread(repaintInThread); }
public ImageSurface repaintInThread(boolean repaintInThread) { this.repaintInThread = repaintInThread; return this; } final public boolean getRepaintInThread(){ return repaintInThread(); }
public boolean repaintInThread() { return repaintInThread; }
boolean repaintInThread = false; // after setImage, repaint in same thread
BoolVar showingVar;
Pt mousePosition;
transient Set onMousePositionChanged;
public ImageSurface onMousePositionChanged(Runnable r) { onMousePositionChanged = createOrAddToSyncLinkedHashSet(onMousePositionChanged, r); return this; }
public ImageSurface removeMousePositionChangedListener(Runnable r) { main.remove(onMousePositionChanged, r); return this; }
public void mousePositionChanged() { if (onMousePositionChanged != null) for (var listener : onMousePositionChanged) pcallF_typed(listener); }
transient Set onImageChanged;
public ImageSurface onImageChanged(Runnable r) { onImageChanged = createOrAddToSyncLinkedHashSet(onImageChanged, r); return this; }
public ImageSurface removeImageChangedListener(Runnable r) { main.remove(onImageChanged, r); return this; }
public void imageChanged() { if (onImageChanged != null) for (var listener : onImageChanged) pcallF_typed(listener); }
transient Set> onUserModifiedImage;
public ImageSurface onUserModifiedImage(IVF1 f) { onUserModifiedImage = createOrAddToSyncLinkedHashSet(onUserModifiedImage, f); return this; }
public ImageSurface removeUserModifiedImageListener(IVF1 f) { main.remove(onUserModifiedImage, f); return this; }
public void userModifiedImage(BufferedImage image) { if (onUserModifiedImage != null) for (var listener : onUserModifiedImage) pcallF_typed(listener, image); }
public ImageSurface() {
this(dummyImage());
}
static BufferedImage dummyImage() {
return whiteImage(1);
}
ImageSurface(MakesBufferedImage image) {
this(image != null ? image.getBufferedImage() : dummyImage());
}
ImageSurface(BufferedImage image) {
setImage(image);
clearSurface = false;
onResize(this, () -> performAutoZoom());
bindToComponent(this, () -> performAutoZoom(), null);
componentPopupMenu2(this, ImageSurface_popupMenuMaker());
new ImageSurfaceSelector(this);
jHandleFileDrop(this, new VF1() { public void get(File f) { try { setImage(loadBufferedImage(f)) ; } catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "setImage(loadBufferedImage(f))"; }});
imageSurfaceOnHover(this, p -> {
mousePosition = p;
mousePositionChanged();
});
}
public ImageSurface(RGBImage image, double zoom) {
this(image);
setZoom(zoom);
}
// point is already in image coordinates
protected void fillPopupMenu(JPopupMenu menu, final Point point) {
if (zoomable) {
JMenuItem miZoomReset = new JMenuItem("Zoom 100%");
miZoomReset.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
setZoom(1.0);
centerPoint(point);
}
});
menu.add(miZoomReset);
JMenuItem miZoomIn = new JMenuItem("Zoom in");
miZoomIn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
zoomIn(zoomFactor);
centerPoint(point);
}
});
menu.add(miZoomIn);
JMenuItem miZoomOut = new JMenuItem("Zoom out");
miZoomOut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
zoomOut(zoomFactor);
centerPoint(point);
}
});
menu.add(miZoomOut);
menu.add(jMenuItemStayCheckedOnClick("Zoom to window",
() -> autoZoomToDisplay,
() -> setAutoZoomToDisplay(true)));
addMenuItem(menu, "Show full screen", new Runnable() { public void run() { try { showFullScreen() ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "showFullScreen()"; }});
addMenuItem(menu, "Point: " + point.x + "," + point.y + " (image: " + w() + "*" + h() + ")", null);
menu.addSeparator();
}
if (!specialPurposed)
addMenuItem(menu, "Load image...", new Runnable() { public void run() { try { selectFile("Load image",
new VF1() { public void get(File f) { try { setImage(loadImage2(f)) ; } catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "setImage(loadImage2(f))"; }}) ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "selectFile(\"Load image\",\r\n new VF1() { public void get(File f) c..."; }});
addMenuItem(menu, "Save image...", new Runnable() { public void run() { try { saveImage() ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "saveImage()"; }});
addMenuItem(menu, "Copy image to clipboard", new Runnable() { public void run() { try { copyImageToClipboard(getImage()) ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "copyImageToClipboard(getImage())"; }});
if (!specialPurposed || allowPaste)
addMenuItem(menu, "Paste image from clipboard", new Runnable() { public void run() { try { loadFromClipboard() ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "loadFromClipboard()"; }});
if (!specialPurposed)
addMenuItem(menu, "Load image snippet...", new Runnable() { public void run() { try {
selectImageSnippet(new VF1() { public void get(String imageID) { try {
setImage(loadImage2(imageID))
; } catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "setImage(loadImage2(imageID))"; }});
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "selectImageSnippet(new VF1() { public void get(String imageID) ctex {..."; }});
if (selection != null)
addMenuItem(menu, "Crop", new Runnable() { public void run() { try { crop() ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "crop()"; }});
if (!specialPurposed)
addMenuItem(menu, "No image", new Runnable() { public void run() { try { noImage() ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "noImage()"; }});
}
void noImage() { setImage((BufferedImage) null); }
void crop() {
if (selection == null) return;
BufferedImage img = cloneClipBufferedImage(getImage(), selection);
selection = null;
setUserModifiedImage(img);
}
void setUserModifiedImage(BufferedImage img) {
setImage(img);
userModifiedImage(img);
}
void loadFromClipboard() {
BufferedImage img = getImageFromClipboard();
if (img != null)
setUserModifiedImage(img);
}
transient IF0 defaultImageDir;
File defaultImageDir() { return defaultImageDir != null ? defaultImageDir.get() : defaultImageDir_base(); }
final File defaultImageDir_fallback(IF0 _f) { return _f != null ? _f.get() : defaultImageDir_base(); }
File defaultImageDir_base() { return getProgramDir(); }
void saveImage() {
var image = getImage();
JFileChooser fileChooser = new JFileChooser(defaultImageDir());
if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
try {
main.saveImage(image, file = fileChooser.getSelectedFile());
} catch (Throwable e) {
popup(e);
}
}
}
void drawImageItself(int w, int h, Graphics2D g) {
int iw = getZoomedWidth(), ih = getZoomedHeight();
if (interpolationMode == RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR || zoomX >= 1 || zoomY >= 1) {
// faster
g.drawImage(image, 0, 0, iw, ih, null);
} else
g.drawImage(resizeImage(image, iw, ih), 0, 0, null); // smoother
}
public void render(int w, int h, Graphics2D g) {
if (verbose) _print("render");
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolationMode);
g.setColor(Color.white);
BufferedImage image = or(imageToDraw, this.image);
if (!hasImage())
g.fillRect(0, 0, w, h);
else {
boolean alpha = !noAlpha && hasTransparency(image);
if (alpha) g.fillRect(0, 0, w, h);
drawImageItself(w, h, g);
int iw = getZoomedWidth(), ih = getZoomedHeight();
if (!alpha) {
g.fillRect(iw, 0, w-iw, h);
g.fillRect(0, ih, iw, h-ih);
}
}
if (overlay != null) {
if (verbose) _print("render overlay");
pcallF(overlay, g);
}
for (var overlay : cloneList(overlays)) { try {
overlay.drawOn(g);
} catch (Throwable __e) { printStackTrace(__e); }}
if (selection != null) {
if (verbose) _print("render selection");
// drawRect is inclusive, selection is exclusive, so... whatever, tests show it's cool.
drawSelectionRect(g, selection, Color.green, Color.white);
}
}
public void drawSelectionRect(Graphics2D g, Rectangle selection, Color green, Color white) {
drawSelectionRect(g, selection, green, white, zoomX, zoomY);
}
public void drawSelectionRect(Graphics2D g, Rectangle selection, Color green, Color white, double zoomX, double zoomY) {
g.setColor(green);
int top = (int) (selection.y * zoomY);
int bottom = (int) ((selection.y+selection.height) * zoomY);
int left = (int) (selection.x * zoomX);
int right = (int) ((selection.x+selection.width) * zoomX);
g.drawRect(left-1, top-1, right-left+1, bottom-top+1);
g.setColor(white);
g.drawRect(left - 2, top - 2, right - left + 3, bottom - top + 3);
}
public ImageSurface setZoom(double zoom) {
setZoom(zoom, zoom);
return this;
}
public void setZoom(double zoomX, double zoomY) {
autoZoomToDisplay = false;
setZoom_dontChangeAutoZoom(zoomX, zoomY);
}
public void setZoom_dontChangeAutoZoom(double zoomX) { setZoom_dontChangeAutoZoom(zoomX, zoomX); }
public void setZoom_dontChangeAutoZoom(double zoomX, double zoomY) {
if (this.zoomX == zoomX && this.zoomY == zoomY) return;
if (verbose) _print("Setting zoom");
this.zoomX = zoomX;
this.zoomY = zoomY;
revalidateMe();
repaint();
centerPoint(new Point(getImage().getWidth()/2, getImage().getHeight()/2));
pcallF(onZoom);
}
public Dimension getMinimumSize() {
if (metaGet("scaffolding") != null) scaffoldCalled(this, "getMinimumSize");
if (noMinimumSize) return new Dimension(1, 1);
int w = getZoomedWidth();
int h = getZoomedHeight();
Dimension min = super.getMinimumSize();
return printIfScaffoldingEnabled(this, new Dimension(Math.max(w, min.width), Math.max(h, min.height)));
}
int getZoomedHeight() {
return (int) (h() * zoomY);
}
int getZoomedWidth() {
return (int) (w() * zoomX);
}
boolean isShowing_quick() {
if (showingVar == null) { swing(() -> {
if (showingVar == null) showingVar = componentShowingVar(ImageSurface.this);
}); }
return showingVar.get();
}
public void setImageIfShowing_thisThread(MakesBufferedImage image) { setImageIfShowing_thisThread(toBufferedImage(image)); }
public void setImageIfShowing_thisThread(BufferedImage image) {
if (isShowing_quick())
setImage_thisThread(image);
}
public void setImage(MakesBufferedImage image) { swing(() -> {
setImage_thisThread(image);
}); }
public void setImage(BufferedImage img) { swing(() -> {
setImage_thisThread(img);
}); }
public void setImage_thisThread(MakesBufferedImage img) { setImage_thisThread(toBufferedImage(img)); }
public void setImage_thisThread(BufferedImage img) {
BufferedImage newImage = img != null ? img : dummyImage();
BufferedImage oldImage = image;
image = newImage;
if (verbose) print("Old image size:" + imageSize(oldImage) + ", new image size: " + imageSize(newImage));
boolean sameSize = imagesHaveSameSize(oldImage, newImage);
if (!sameSize) {
if (verbose) _print("New image size");
revalidateMe();
}
quickRepaint();
pcallF(onNewImage);
if (!sameSize && autoZoomToDisplay) zoomToDisplaySize();
imageChanged();
}
void setImageAndZoomToDisplay(BufferedImage img) {
setImage(img);
zoomToDisplaySize();
}
public BufferedImage getImage() {
return image;
}
public double getZoomX() {
return zoomX;
}
public double getZoomY() {
return zoomY;
}
public Dimension getPreferredSize() {
if (metaGet("scaffolding") != null) scaffoldCalled(this, "getPreferredSize");
return printIfScaffoldingEnabled(this, new Dimension(getZoomedWidth(), getZoomedHeight()));
}
/** returns a scrollpane with the scroll-mode prevent-garbage-drawing fix applied */
public JScrollPane makeScrollPane() {
JScrollPane scrollPane = new JScrollPane(this);
scrollPane.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
return scrollPane;
}
public void zoomToWindow() { zoomToDisplaySize(); }
public void zoomToDisplaySize() { swing(() -> {
if (!hasImage()) return;
Dimension display = getDisplaySize();
if (display.width == 0 || display.height == 0) return;
int w = w(), h = h();
double xRatio = (display.width-5)/(double) w;
double yRatio = (display.height-5)/(double) h;
if (scaffoldingEnabled(this))
printVars("zoomToDisplaySize", "display", display, "w", w, "h", h, "xRatio", xRatio, "yRatio", yRatio);
setZoom_dontChangeAutoZoom(min(xRatio, yRatio));
revalidateMe();
}); }
/** tricky magic to get parent scroll pane */
private Dimension getDisplaySize() {
if (metaGet("scaffolding") != null) scaffoldCalled(this, "getDisplaySize");
Container c = getParent();
while (c != null) {
if (c instanceof JScrollPane)
return c.getSize();
c = c.getParent();
}
return getSize();
}
public void setSelection(Rect r) {
setSelection(toRectangle(r));
}
public void setSelection(Rectangle r) {
if (neq(selection, r)) {
selection = r;
pcallF(onSelectionChange);
quickRepaint();
}
}
public Rectangle getSelection() {
return selection;
}
public RGBImage getRGBImage() {
return new RGBImage(getImage());
}
// p is in image coordinates
void centerPoint(Point p) {
JScrollPane sp = enclosingScrollPane(this);
if (sp == null) return;
p = new Point((int) (p.x*getZoomX()), (int) (p.y*getZoomY()));
final JViewport viewport = sp.getViewport();
Dimension viewSize = viewport.getExtentSize();
//_print("centerPoint " + p);
int x = max(0, p.x-viewSize.width/2);
int y = max(0, p.y-viewSize.height/2);
//_print("centerPoint " + p + " => " + x + "/" + y);
p = new Point(x,y);
//_print("centerPoint " + p);
final Point _p = p;
awtLater(new Runnable() { public void run() { try {
viewport.setViewPosition(_p);
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "viewport.setViewPosition(_p);"; }});
}
Pt pointFromEvent(MouseEvent e) {
return pointFromComponentCoordinates(new Pt(e.getX(), e.getY()));
}
Pt pointFromComponentCoordinates(Pt p) {
return new Pt((int) (p.x/zoomX), (int) (p.y/zoomY));
}
Pt pointToComponentCoordinates(double x, double y) {
return new Pt((int) (x*zoomX), (int) (y*zoomY));
}
void uploadTheImage() {
//call(hotwire(/*#1007313*/#1016427), "go", getImage(), titleForUpload);
}
void showFullScreen() {
showFullScreenImageSurface(getImage());
}
void zoomIn(double f) { setZoom(getZoomX()*f, getZoomY()*f); }
void zoomOut(double f) { setZoom(getZoomX()/f, getZoomY()/f); }
ImageSurface setFile(File f) { file = f; return this; }
void setOverlay(IVF1 overlay) {
this.overlay = overlay;
}
boolean hasImage() { return image != null; }
public int w() { return image.getWidth(); }
public int h() { return image.getHeight(); }
final void pixelate(boolean b){ setPixelated(b); }
void setPixelated(boolean b) {
assertTrue(b);
imageSurface_pixelated(this);
}
final ImageSurface autoZoomToDisplay(boolean b){ return setAutoZoomToDisplay(b); }
ImageSurface setAutoZoomToDisplay(boolean b) {
if (autoZoomToDisplay = b)
zoomToDisplaySize();
return this;
}
void quickRepaint() {
if (repaintInThread)
paintImmediately(0, 0, getWidth(), getHeight());
else
repaint();
}
void setTool(ImageSurfaceMouseHandler tool) { swing(() -> {
removeAllTools();
addTool(tool);
}); }
boolean hasTool(AutoCloseable tool) {
return swing(() -> tools.contains(tool));
}
void addTool(ImageSurfaceMouseHandler tool) { swing(() -> {
if (!tools.contains(tool))
tool.register(this);
}); }
void removeTool(AutoCloseable tool) { swing(() -> {
if (tools.contains(tool)) {
close(tool);
tools.remove(tool);
}
}); }
void removeAllTools() {
closeAllAndClear(tools);
}
void performAutoZoom() {
if (autoZoomToDisplay) zoomToDisplaySize();
}
void revalidateMe() {
revalidateIncludingFullCenterContainer(this);
}
void addOverlay(G2Drawable overlay) {
overlays.add(overlay);
repaint();
}
void clearOverlays() {
if (nempty(overlays)) {
overlays.clear();
repaint();
}
}
void setOverlay(G2Drawable overlay) {
clearOverlays();
if (overlay != null) addOverlay(overlay);
}
void loadImage(File f) {
setImage(loadImage2(f));
}
JComponent visualize() {
return jscroll_center_borderless(this);
}
A print(A a) { return print("", a); }
A print(String msg, A a) { return _print(msg, a); }
} // end of ImageSurface
// static function allows garbage collection
static VF2 ImageSurface_popupMenuMaker() {
return new VF2() { public void get(ImageSurface is, JPopupMenu menu) { try {
Point p = is.pointFromEvent(componentPopupMenu_mouseEvent.get()).getPoint();
is.fillPopupMenu(menu, p);
} catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "Point p = is.pointFromEvent(componentPopupMenu_mouseEvent.get()).getPoint();\r..."; }};
}
// In the newest pinging system (with flag PingV3), a ping source
// is the object that "allows" some code to run.
// When that code calls ping(), the ping source's action (if defined)
// is triggered.
// This allows randomly interrupting code execution, for example.
static class PingSource {
// returns true if it slept
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 IF0 action;
// optional description of this ping source
String text;
// optional thread pool that this ping source likes to run in
ThreadPool threadPool;
PingSource() {}
PingSource(ThreadPool threadPool) {
this.threadPool = threadPool;}
PingSource(ThreadPool threadPool, String text) {
this.text = text;
this.threadPool = threadPool;}
PingSource(IF0 action) {
this.action = action;}
// returns true if it slept
final boolean get() {
var a = action;
return a != null && a.get();
}
final void ping() {
var a = action;
if (a != null) a.get();
}
void cancel() {
action = new Cancelled();
}
class Cancelled implements IF0 {
public Boolean get() { throw new PingSourceCancelledException(PingSource.this); }
}
class Encapsulated implements Runnable , IFieldsToList{
Runnable r;
Encapsulated() {}
Encapsulated(Runnable r) {
this.r = r;}public Object[] _fieldsToList() { return new Object[] {r}; }
public void run() { try {
//System.out.println("Encapsulated running: " + r);
try {
pingSource_tl().set(PingSource.this);
//System.out.println("Ping source set");
ping();
r.run();
//System.out.println("Done running");
} finally {
//System.out.println("Finally");
pingSource_tl().set(null);
}
} catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return PingSource.this + ": " + r; }
}
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(); }
ISleeper_v2 sleeper() { return threadPool.sleeper(); }
}
// records its full size (total value count) in a field now
static class MultiMap implements IMultiMap {
Map > data = new HashMap >();
int fullSize;
MultiMap() {}
MultiMap(boolean useTreeMap) { if (useTreeMap) data = new TreeMap(); }
MultiMap(MultiMap map) { putAll(map); }
MultiMap(Map > data) {
this.data = data;}
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;
}}
void add(A key, B value) { put(key, value); }
void addAll(A key, Collection values) { putAll(key, values); }
void addAllIfNotThere(A key, Collection values) { synchronized(data) {
for (B value : values)
setPut(key, value);
}}
void setPut(A key, B value) { synchronized(data) {
if (!containsPair(key, value))
put(key, value);
}}
boolean containsPair(A key, B value) { synchronized(data) {
return get(key).contains(value);
}}
void putAll(Collection keys, B value) { synchronized(data) {
for (A key : unnullForIteration(keys))
put(key, value);
}}
void putAll(A key, Collection values) { synchronized(data) {
if (nempty(values)) getActual(key).addAll(values);
}}
void putAll(Iterable> pairs) { synchronized(data) {
for (Pair p : unnullForIteration(pairs))
put(p.a, p.b);
}}
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;
}}
List getOpt(A key) { synchronized(data) {
return data.get(key);
}}
List getAndClear(A key) { synchronized(data) {
List l = cloneList(data.get(key));
remove(key);
return l;
}}
// returns actual mutable live list
// creates the list if not there
List getActual(A key) { synchronized(data) {
List list = data.get(key);
if (list == null)
data.put(key, list = _makeEmptyList());
return list;
}}
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();
}}
void remove(A key) { synchronized(data) {
fullSize -= l(this.getOpt(key));
data.remove(key);
}}
final void remove(Pair p){ removePair(p); }
void removePair(Pair p) {
if (p != null) remove(p.a, p.b);
}
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);
}
}}
void clear() { synchronized(data) {
data.clear();
}}
boolean containsKey(A key) { synchronized(data) {
return data.containsKey(key);
}}
B getFirst(A key) { synchronized(data) {
List list = get(key);
return list.isEmpty() ? null : list.get(0);
}}
void addAll(MultiMap map) { putAll(map); }
void putAll(MultiMap map) { synchronized(data) {
for (A key : map.keySet())
putAll(key, map.get(key));
}}
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;
}}
// expensive operation
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;
}}
Map > asMap() { synchronized(data) {
return cloneMap(data);
}}
boolean isEmpty() { synchronized(data) { return data.isEmpty(); }}
// override in subclasses
List _makeEmptyList() {
return new ArrayList();
}
// returns live lists
Collection> allLists() {
synchronized(data) {
return new ArrayList(data.values());
}
}
Collection> values() { return allLists(); }
List allValues() {
return concatLists(data.values());
}
Object mutex() { return data; }
public String toString() { return "mm" + str(data); }
}
static interface IResourceLoader {
String loadSnippet(String snippetID);
String getTranspiled(String snippetID); // with libs
int getSnippetType(String snippetID);
String getSnippetTitle(String snippetID);
File loadLibrary(String snippetID);
//ifndef NoJavaXJar
default File pathToJavaXJar() { return pathToJavaxJar_noResourceLoader(); }
//endifndef
// may return null, then caller compiles themselves
default File getSnippetJar(String snippetID, String transpiledSrc) { return null; }
}
/*
* @(#)WeakHashMap.java 1.5 98/09/30
*
* Copyright 1998 by Sun Microsystems, Inc.,
* 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
* All rights reserved.
*
* This software is the confidential and proprietary information
* of Sun Microsystems, Inc. ("Confidential Information"). You
* shall not disclose such Confidential Information and shall use
* it only in accordance with the terms of the license agreement
* you entered into with Sun.
*/
// From https://github.com/mernst/plume-lib/blob/df0bfafc3c16848d88f4ea0ef3c8bf3367ae085e/java/src/plume/WeakHasherMap.java
static final class WeakHasherMap extends AbstractMap implements Map {
private Hasher hasher = null;
/*@Pure*/
private boolean keyEquals(Object k1, Object k2) {
return (hasher==null ? k1.equals(k2)
: hasher.equals(k1, k2));
}
/*@Pure*/
private int keyHashCode(Object k1) {
return (hasher==null ? k1.hashCode()
: hasher.hashCode(k1));
}
// The WeakKey class can't be static because it depends on the hasher.
// That in turn means that its methods can't be static.
// However, I need to be able to call the methods such as create() that
// were static in the original version of this code.
// This finesses that.
private /*@Nullable*/ WeakKey WeakKeyCreate(K k) {
if (k == null) return null;
else return new WeakKey(k);
}
private /*@Nullable*/ WeakKey WeakKeyCreate(K k, ReferenceQueue super K> q) {
if (k == null) return null;
else return new WeakKey(k, q);
}
// Cannot be a static class: uses keyHashCode() and keyEquals()
private final class WeakKey extends WeakReference {
private int hash; /* Hashcode of key, stored here since the key
may be tossed by the GC */
private WeakKey(K k) {
super(k);
hash = keyHashCode(k);
}
private /*@Nullable*/ WeakKey create(K k) {
if (k == null) return null;
else return new WeakKey(k);
}
private WeakKey(K k, ReferenceQueue super K> q) {
super(k, q);
hash = keyHashCode(k);
}
private /*@Nullable*/ WeakKey create(K k, ReferenceQueue super K> q) {
if (k == null) return null;
else return new WeakKey(k, q);
}
/* A WeakKey is equal to another WeakKey iff they both refer to objects
that are, in turn, equal according to their own equals methods */
/*@Pure*/
@Override
public boolean equals(/*@Nullable*/ Object o) {
if (o == null) return false; // never happens
if (this == o) return true;
// This test is illegal because WeakKey is a generic type,
// so use the getClass hack below instead.
// if (!(o instanceof WeakKey)) return false;
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);
}
/*@Pure*/
@Override
public int hashCode() {
return hash;
}
}
/* Hash table mapping WeakKeys to values */
private HashMap hash;
/* Reference queue for cleared WeakKeys */
private ReferenceQueue super K> queue = new ReferenceQueue();
/* Remove all invalidated entries from the map, that is, remove all entries
whose keys have been discarded. This method should be invoked once by
each public mutator in this class. We don't invoke this method in
public accessors because that can lead to surprising
ConcurrentModificationExceptions. */
@SuppressWarnings("unchecked")
private void processQueue() {
WeakKey wk;
while ((wk = (WeakKey)queue.poll()) != null) { // unchecked cast
hash.remove(wk);
}
}
/* -- Constructors -- */
/**
* Constructs a new, empty WeakHashMap with the given
* initial capacity and the given load factor.
*
* @param initialCapacity the initial capacity of the
* WeakHashMap
*
* @param loadFactor the load factor of the WeakHashMap
*
* @throws IllegalArgumentException If the initial capacity is less than
* zero, or if the load factor is
* nonpositive
*/
public WeakHasherMap(int initialCapacity, float loadFactor) {
hash = new HashMap(initialCapacity, loadFactor);
}
/**
* Constructs a new, empty WeakHashMap with the given
* initial capacity and the default load factor, which is
* 0.75.
*
* @param initialCapacity the initial capacity of the
* WeakHashMap
*
* @throws IllegalArgumentException If the initial capacity is less than
* zero
*/
public WeakHasherMap(int initialCapacity) {
hash = new HashMap(initialCapacity);
}
/**
* Constructs a new, empty