import java.util.*;
import java.util.zip.*;
import java.util.List;
import java.util.regex.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.concurrent.locks.*;
import java.util.function.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.table.*;
import java.io.*;
import java.net.*;
import java.lang.reflect.*;
import java.lang.ref.*;
import java.lang.management.*;
import java.security.*;
import java.security.spec.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.imageio.*;
import java.math.*;
import java.time.Duration;
import java.lang.invoke.VarHandle;
import java.lang.invoke.MethodHandles;
import java.awt.geom.*;
import static x30_pkg.x30_util.DynamicObject;
import java.text.*;
import java.text.NumberFormat;
import java.util.TimeZone;
class main {
static class StopLossJuicer extends AbstractJuicer {
StopLossJuicer() {}
// How much loss we will accept
// Can be positive (stop loss in profit) or negative (stop loss with actual loss)
final public StopLossJuicer setStopLossLimit(double stopLossLimit){ return stopLossLimit(stopLossLimit); }
public StopLossJuicer stopLossLimit(double stopLossLimit) { this.stopLossLimit = stopLossLimit; return this; } final public double getStopLossLimit(){ return stopLossLimit(); }
public double stopLossLimit() { return stopLossLimit; }
double stopLossLimit = -0.5;
final public StopLossJuicer setStopLossEnabled(boolean stopLossEnabled){ return stopLossEnabled(stopLossEnabled); }
public StopLossJuicer stopLossEnabled(boolean stopLossEnabled) { this.stopLossEnabled = stopLossEnabled; return this; } final public boolean getStopLossEnabled(){ return stopLossEnabled(); }
public boolean stopLossEnabled() { return stopLossEnabled; }
boolean stopLossEnabled = true;
// Reference threshold to calculate signal below 100%
// (doesn't impact closing behavior)
final public StopLossJuicer setStartStopLossSignalAt(double startStopLossSignalAt){ return startStopLossSignalAt(startStopLossSignalAt); }
public StopLossJuicer startStopLossSignalAt(double startStopLossSignalAt) { this.startStopLossSignalAt = startStopLossSignalAt; return this; } final public double getStartStopLossSignalAt(){ return startStopLossSignalAt(); }
public double startStopLossSignalAt() { return startStopLossSignalAt; }
double startStopLossSignalAt;
StopLossJuicer(double stopLossLimit) {
this.stopLossLimit = stopLossLimit;}
{
onCalculatingCloseSignals(signals -> {
// How close are we to our loss limit?
if (stopLossEnabled && stopLossLimit > -infinity()) {
var signal = new CloseSignal().createdBy(this).reason("Stop loss");
if (juiceValue <= stopLossLimit)
signal.strength(100);
else {
double startAt = max(startStopLossSignalAt, 0);
if (startAt > stopLossLimit)
signal.strength(doubleRatio(startAt-juiceValue, startAt-stopLossLimit)*100);
}
signals.add(signal);
}
});
}
}
static double infinity() {
return positiveInfinity();
}
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 double doubleRatio(double x, double y) {
return y == 0 ? 0 : x/y;
}
static double doubleRatio(Seconds x, Seconds y) {
return doubleRatio(x.get(), y.get());
}
static double positiveInfinity() {
return Double.POSITIVE_INFINITY;
}
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 Iterator emptyIterator() {
return Collections.emptyIterator();
}
static class CloseSignal extends SignalWithStrength {
CloseSignal() {}
{ type("Close"); }
}
abstract static class AbstractJuicer extends MetaWithChangeListeners {
AbstractJuicer() {}
// what we are monitoring & closing (a position or a strategy)
public transient FieldVar varJuiceable_cache;
public FieldVar varJuiceable() { if (varJuiceable_cache == null) varJuiceable_cache = varJuiceable_load(); return varJuiceable_cache;}
public FieldVar varJuiceable_load() {
return new FieldVar(this, "juiceable", () -> juiceable(), juiceable -> juiceable(juiceable)); }
final public AbstractJuicer setJuiceable(Juiceable juiceable){ return juiceable(juiceable); }
public AbstractJuicer juiceable(Juiceable juiceable) { if (!eq(this.juiceable, juiceable)) { this.juiceable = juiceable; change(); } return this; }
final public Juiceable getJuiceable(){ return juiceable(); }
public Juiceable juiceable() { return juiceable; }
Juiceable juiceable;
public transient FieldVar varJuiceValue_cache;
public FieldVar varJuiceValue() { if (varJuiceValue_cache == null) varJuiceValue_cache = varJuiceValue_load(); return varJuiceValue_cache;}
public FieldVar varJuiceValue_load() {
return new FieldVar(this, "juiceValue", () -> juiceValue(), juiceValue -> juiceValue(juiceValue)); }
final public AbstractJuicer setJuiceValue(double juiceValue){ return juiceValue(juiceValue); }
public AbstractJuicer juiceValue(double juiceValue) { if (!eq(this.juiceValue, juiceValue)) { this.juiceValue = juiceValue; change(); } return this; }
final public double getJuiceValue(){ return juiceValue(); }
public double juiceValue() { return juiceValue; }
double juiceValue;
public transient FieldVar varClosingAllowed_cache;
public FieldVar varClosingAllowed() { if (varClosingAllowed_cache == null) varClosingAllowed_cache = varClosingAllowed_load(); return varClosingAllowed_cache;}
public FieldVar varClosingAllowed_load() {
return new FieldVar(this, "closingAllowed", () -> closingAllowed(), closingAllowed -> closingAllowed(closingAllowed)); }
final public AbstractJuicer setClosingAllowed(boolean closingAllowed){ return closingAllowed(closingAllowed); }
public AbstractJuicer closingAllowed(boolean closingAllowed) { if (!eq(this.closingAllowed, closingAllowed)) { this.closingAllowed = closingAllowed; change(); } return this; }
final public boolean getClosingAllowed(){ return closingAllowed(); }
public boolean closingAllowed() { return closingAllowed; }
boolean closingAllowed = true;
// last calculated signals
public transient FieldVar> varCurrentSignals_cache;
public FieldVar> varCurrentSignals() { if (varCurrentSignals_cache == null) varCurrentSignals_cache = varCurrentSignals_load(); return varCurrentSignals_cache;}
public FieldVar> varCurrentSignals_load() {
return new FieldVar>(this, "currentSignals", () -> currentSignals(), currentSignals -> currentSignals(currentSignals)); }
final public AbstractJuicer setCurrentSignals(List currentSignals){ return currentSignals(currentSignals); }
public AbstractJuicer currentSignals(List currentSignals) { if (!eq(this.currentSignals, currentSignals)) { this.currentSignals = currentSignals; change(); } return this; }
final public List getCurrentSignals(){ return currentSignals(); }
public List currentSignals() { return currentSignals; }
List currentSignals;
public transient FieldVar> varSuppressedSignals_cache;
public FieldVar> varSuppressedSignals() { if (varSuppressedSignals_cache == null) varSuppressedSignals_cache = varSuppressedSignals_load(); return varSuppressedSignals_cache;}
public FieldVar> varSuppressedSignals_load() {
return new FieldVar>(this, "suppressedSignals", () -> suppressedSignals(), suppressedSignals -> suppressedSignals(suppressedSignals)); }
final public AbstractJuicer setSuppressedSignals(List suppressedSignals){ return suppressedSignals(suppressedSignals); }
public AbstractJuicer suppressedSignals(List suppressedSignals) { if (!eq(this.suppressedSignals, suppressedSignals)) { this.suppressedSignals = suppressedSignals; change(); } return this; }
final public List getSuppressedSignals(){ return suppressedSignals(); }
public List suppressedSignals() { return suppressedSignals; }
List suppressedSignals;
transient Set>> onCalculatingCloseSignals;
public AbstractJuicer onCalculatingCloseSignals(IVF1> f) { onCalculatingCloseSignals = createOrAddToSyncLinkedHashSet(onCalculatingCloseSignals, f); return this; }
public AbstractJuicer removeCalculatingCloseSignalsListener(IVF1> f) { main.remove(onCalculatingCloseSignals, f); return this; }
public void calculatingCloseSignals(List outList) { if (onCalculatingCloseSignals != null) for (var listener : onCalculatingCloseSignals) pcallF_typed(listener, outList); }
// must return a new list
transient IF0> calculateCloseSignals;
List calculateCloseSignals() { return calculateCloseSignals != null ? calculateCloseSignals.get() : calculateCloseSignals_base(); }
final List calculateCloseSignals_fallback(IF0> _f) { return _f != null ? _f.get() : calculateCloseSignals_base(); }
List calculateCloseSignals_base() {
grabJuiceValue();
List signals = new ArrayList();
calculatingCloseSignals(signals);
if (closingAllowed) {
suppressedSignals(emptyList());
currentSignals(signals);
} else {
suppressedSignals(signals);
currentSignals(emptyList());
}
return currentSignals;
}
void grabJuiceValue() {
juiceValue(juiceable.juiceValue());
}
AbstractJuicer configClone() {
return restructure(this);
}
void copyTransientValuesFrom(AbstractJuicer juicer) {}
}
public static interface IF0 {
A get();
}
interface Juiceable {
// e.g. a position's profit before leverage
double juiceValue();
}
static class FieldVar extends VarWithNotify {
IHasChangeListeners containingObject;
String fieldName;
IF0 getter;
IVF1 setter;
FieldVar(IHasChangeListeners containingObject,
String fieldName, IF0 getter, IVF1 setter) {
this.setter = setter;
this.getter = getter;
this.fieldName = fieldName;
this.containingObject = containingObject;
containingObject.onChangeAndNow(() -> _updateFromObject());
}
void _updateFromObject() {
set(getter.get());
}
public void fireChange() {
setter.get(get());
super.fireChange(); }
public FieldVar onChange(IVF1 r) {
if (r != null) onChange(() -> r.get(get()));
return this;
}
}
static class MetaWithChangeListeners extends Meta implements IHasChangeListeners, ChangeTriggerable {
transient Set onChange;
public MetaWithChangeListeners onChange(Runnable r) { onChange = createOrAddToSyncLinkedHashSet(onChange, r); return this; }
public MetaWithChangeListeners removeChangeListener(Runnable r) { main.remove(onChange, r); return this; }
public void change() { if (onChange != null) for (var listener : onChange) pcallF_typed(listener); }
}
static interface IVF1 {
void get(A a);
}
static class SignalWithStrength {
SignalWithStrength() {}
final public SignalWithStrength setType(String type){ return type(type); }
public SignalWithStrength type(String type) { this.type = type; return this; } final public String getType(){ return type(); }
public String type() { return type; }
String type;
final public SignalWithStrength setReason(String reason){ return reason(reason); }
public SignalWithStrength reason(String reason) { this.reason = reason; return this; } final public String getReason(){ return reason(); }
public String reason() { return reason; }
String reason;
// 0 = no signal, 100 = full signal
// can be outside of [0; 100] too
final public SignalWithStrength setStrength(double strength){ return strength(strength); }
public SignalWithStrength strength(double strength) { this.strength = strength; return this; } final public double getStrength(){ return strength(); }
public double strength() { return strength; }
double strength;
final public SignalWithStrength setCreatedBy(Object createdBy){ return createdBy(createdBy); }
public SignalWithStrength createdBy(Object createdBy) { this.createdBy = createdBy; return this; } final public Object getCreatedBy(){ return createdBy(); }
public Object createdBy() { return createdBy; }
Object createdBy;
public String toString() {
return (nempty(reason) ? reason : or2(type, "Unspecified ") + " signal")
+ appendRoundBracketed(
strength >= 100 ? null : iround(strength) + "%"
);
}
boolean isTrigger() { return strength >= 100; }
boolean nonNegative() { return strength >= 0; }
boolean positive() { return strength > 0; }
}
// Meta - a "minimal" approach to adding meta-level to Java objects
static class Meta implements IMeta {
// Meta - a "minimal" approach to adding meta-level to Java objects
// (implementing the interface IMeta)
// We allocate one extra field for each Java object to make it
// reasoning-compatible (reasoning-compatible = extensible with
// fields of any name at runtime).
//
// We couldn't go for 0 extra fields (meta values must be linked
// directly from the object) and there are no half fields in
// Java... so there you go.
//
// Also, if you don't use any meta data, you are probably not
// reasoning about anything. The point of reasoning in JavaX is
// to attach information to objects directly used in the program.
// Possible information contained in the meta field:
// Origin, destination, security level, sender, cost center,
// purpose, list of reifications, ...
// So here it is. THE FIELD YOU HAVE BEEN WAITING FOR!
// [We also have IMeta to retrofit foreign classes (rare but
// probably useful).]
//////////////////////
// The "meta" field //
//////////////////////
// Generic meta value of any kind, but the typical case is it's a
// Map with extra field values for the object etc.
// "meta" is volatile to avoid synchronization; but you can also synchronize on
// _tempMetaMutex() which is usually the object itself. Collections
// and maps are exempt from using the collections's monitor as the meta
// mutex because their monitor tends to be held for long operations
// (e.g. cloneList). For those we use a substantially more complex
// algorithm using a weakMap. Probably overkill. I may reconsider.
volatile Object meta;
// The meta field is not transient, thus by default it will be
// persisted like anything else unless you customize your object
// to suppress or modulate this.
// ...and the interface methods
public void _setMeta(Object meta) { this.meta = meta; }
public Object _getMeta() { return meta; }
// MOST functions are implemented in IMeta (default implementations)
// Scaffolding convenience functions
final boolean scaffolding(){ return scaffoldingEnabled(); }
final boolean scaffolded(){ return scaffoldingEnabled(); }
boolean scaffoldingEnabled() { return main.scaffoldingEnabled(this); }
boolean scaffoldingEnabled(Object o) { return main.scaffoldingEnabled(o); }
// Implementing setMetaToString
String toString_base() { return super.toString(); }
public String toString() {
Object o = metaGet("toString", this);
if (o instanceof String) return ((String) o);
if (o instanceof IF1) return str(((IF1) o).get(this));
return toString_base();
}
}
interface IHasChangeListeners {
IHasChangeListeners onChange(Runnable r);
IHasChangeListeners removeChangeListener(Runnable r);
default IHasChangeListeners onChangeAndNow(Runnable l) {
onChange(l);
callF(l);
return this;
}
}
static class VarWithNotify extends Var implements IVarWithNotify {
transient Set onChange;
public VarWithNotify onChange(Runnable r) { onChange = createOrAddToSyncLinkedHashSet(onChange, r); return this; }
public VarWithNotify removeChangeListener(Runnable r) { main.remove(onChange, r); return this; }
public void fireChange() { if (onChange != null) for (var listener : onChange) pcallF_typed(listener); }
VarWithNotify() {}
VarWithNotify(A a) { super(a); }
// clever way (I hope) to do eq() outside of synchronization block
public void set(A a) {
A v = get();
if (eq(v, a)) {
return;
}
synchronized(this) {
this.v = a;
notifyAll();
}
fireChange();
}
}
interface ChangeTriggerable {
public void change();
}
interface IVarWithNotify extends IVar, IF0WithChangeListeners {
default IVarWithNotify onChange(IVF1 r) {
if (r == null) return this;
onChange(() -> r.get(get()));
return this;
}
default IVarWithNotify onChangeAndNow(IVF1 r) {
if (r == null) return this;
onChangeAndNow(() -> r.get(get()));
return this;
}
}
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 __26 -> set(__26); }
public String toString() { return str(this.get()); }
}
static interface IMeta {
// see class "Meta" for the bla bla
public void _setMeta(Object meta);
public Object _getMeta();
default public IAutoCloseableF0 _tempMetaMutex() {
return new IAutoCloseableF0() {
public Object get() { return IMeta.this; }
public void close() {}
};
}
// actually query another object
default public Object getMeta(Object obj, Object key){ return metaGet(obj, key); }
default public Object metaGet(Object obj, Object key) {
// call global function
return metaMapGet(obj, key);
}
default public Object metaGet(String key, Object obj) {
// call global function
return metaMapGet(obj, key);
}
default public Object getMeta(Object key){ return metaGet(key); }
default public Object metaGet(Object key) {
if (key == null) return null;
Object meta = _getMeta();
if (meta instanceof Map) return ((Map) meta).get(key);
return null;
}
default public void metaSet(IMeta obj, Object key, Object value){ metaPut(obj, key, value); }
default public void metaPut(IMeta obj, Object key, Object value) {
// call global function
metaMapPut(obj, key, value);
}
default public void metaSet(Object key, Object value){ metaPut(key, value); }
default public void metaPut(Object key, Object value) {
if (key == null) return;
Map map = convertObjectMetaToMap(this);
syncMapPutOrRemove(map, key, value);
}
}
static interface ISetter {
void set(A a);
}
interface IF0WithChangeListeners extends IF0, IHasChangeListeners {}
static interface IAutoCloseableF0 extends IF0, AutoCloseable {}
static interface IVar extends IF0 {
void set(A a);
A get();
// reified type of value (if available)
default Class getType() { return null; }
default IF0 getter() { return () -> get(); }
default IVF1 setter() { return __1 -> set(__1); }
default boolean has() { return get() != null; }
default void clear() { set(null); }
}
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 void change() {
//mainConcepts.allChanged();
// safe version for now cause function is sometimes included unnecessarily (e.g. by EGDiff)
callOpt(getOptMC("mainConcepts"), "allChanged");
}
static Set createOrAddToSyncLinkedHashSet(Set set, A a) {
if (set == null) set = syncLinkedHashSet();
set.add(a);
return set;
}
static void remove(List l, int i) {
if (l != null && i >= 0 && i < l(l))
l.remove(i);
}
static void remove(Collection l, A a) {
if (l != null) l.remove(a);
}
static B remove(Map map, Object a) {
return map == null ? null : map.remove(a);
}
static void remove(BitSet bs, int i) {
bs.clear(i);
}
static A pcallF_typed(F0 f) {
try { return f == null ? null : f.get(); } catch (Throwable __e) { pcallFail(__e); } return null;
}
static B pcallF_typed(F1 f, A a) {
try { return f == null ? null : f.get(a); } catch (Throwable __e) { pcallFail(__e); } return null;
}
static void pcallF_typed(VF1 f, A a) {
try {
{ if (f != null) f.get(a); }
} catch (Throwable __e) { pcallFail(__e); }
}
static void pcallF_typed(IVF1 f, A a) {
try {
{ if (f != null) f.get(a); }
} catch (Throwable __e) { pcallFail(__e); }
}
static void pcallF_typed(IVF2 f, A a, B b) {
try {
{ if (f != null) f.get(a, b); }
} catch (Throwable __e) { pcallFail(__e); }
}
static Object pcallF_typed(Runnable r) {
try { { if (r != null) r.run(); } } catch (Throwable __e) { pcallFail(__e); } return null;
}
static A pcallF_typed(IF0 f) {
try { return f == null ? null : f.get(); } catch (Throwable __e) { pcallFail(__e); } return null;
}
static B pcallF_typed(IF1 f, A a) {
try { return f == null ? null : f.get(a); } catch (Throwable __e) { pcallFail(__e); } return null;
}
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 A restructure(A a) {
return (A) unstructure(structure(a));
}
static A set(A o, String field, Object value) {
if (o == null) return null;
if (o instanceof Class) set((Class) o, field, value);
else try {
Field f = set_findField(o.getClass(), field);
makeAccessible(f);
smartSet(f, o, value);
} catch (Exception e) {
throw new RuntimeException(e);
}
return o;
}
static void set(Class c, String field, Object value) {
if (c == null) return;
try {
Field f = set_findStaticField(c, field);
makeAccessible(f);
smartSet(f, null, value);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static Field set_findStaticField(Class> c, String field) {
Class _c = c;
do {
for (Field f : _c.getDeclaredFields())
if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0)
return f;
_c = _c.getSuperclass();
} while (_c != null);
throw new RuntimeException("Static field '" + field + "' not found in " + c.getName());
}
static Field set_findField(Class> c, String field) {
Class _c = c;
do {
for (Field f : _c.getDeclaredFields())
if (f.getName().equals(field))
return f;
_c = _c.getSuperclass();
} while (_c != null);
throw new RuntimeException("Field '" + field + "' not found in " + c.getName());
}
static void set(BitSet bs, int idx) {
{ if (bs != null) bs.set(idx); }
}
// 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 A onChange(A spinner, Object r) {
return onChange(spinner, toRunnable(r));
}
static A onChange(A spinner, Runnable r) {
if (r != null)
{ swing(() -> { spinner.addChangeListener(changeListener(r)); }); }
return spinner;
}
static A onChange(A b, Runnable r) {
{ swing(() -> { b.addItemListener(itemListener(r)); }); }
return b;
}
static void onChange(JTextComponent tc, Runnable r) {
onUpdate(tc, r);
}
static A onChange(A slider, Runnable r) {
{ swing(() -> { slider.addChangeListener(changeListener(r)); }); }
return slider;
}
static JComboBox onChange(JComboBox cb, ChangeTriggerable r) {
return onChange(cb, new ChangeTrigger(r));
}
static JComboBox onChange(JComboBox cb, IVF1 f) {
if (f != null) addActionListener(cb, () -> f.get(getSelectedItem_typed(cb)));
return cb;
}
// Note: JComboBox also supports addActionListener.
// Not sure if that would help us any.
static JComboBox onChange(JComboBox cb, Runnable r) {
if (isEditableComboBox(cb))
onChange(textFieldFromComboBox(cb), r);
else
onSelectedItem(cb, runnableToIVF1(r));
return cb;
}
static A onChange(A tabs, Runnable r) {
{ swing(() -> { tabs.addChangeListener(changeListener(r)); }); }
return tabs;
}
static A onChange(Runnable r, A cc) {
if (cc != null && r != null) { swing(() -> {
cc.getSelectionModel().addChangeListener(changeListener(r));
}); }
return cc;
}
static A onChange(A a, ChangeTriggerable b) {
if (a != null && b != null) a.onChange(new ChangeTrigger(b));
return a;
}
static A onChange(A a, Updateable b) {
if (a != null && b != null) a.onChange(new UpdateTrigger(b));
return a;
}
static A onChange(A a, Runnable r) {
if (a != null && r != null) a.onChange(r);
return a;
}
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 boolean nempty(IntSize l) { return l != null && l.size() != 0; }
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 String appendRoundBracketed(String b) {
return empty(b) ? "" : "" + " (" + b + ")";
}
static String appendRoundBracketed(String a, String b) {
return empty(b) ? a : a + appendRoundBracketed(b);
}
static int iround(double d) {
return (int) Math.round(d);
}
static int iround(Number n) {
return iround(toDouble(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;
}
// action = runnable or method name
static void onChangeAndNow(JComponent c, Object r) {
onUpdateAndNow(c, r);
}
static void onChangeAndNow(List extends JComponent> l, Object r) {
onUpdateAndNow(l, r);
}
static void onChangeAndNow(JTextComponent c, IVF1 r) {
onUpdateAndNow(c, r);
}
static JComboBox onChangeAndNow(JComboBox cb, IVF1 f) {
onChange(cb, f);
{ if (f != null) f.get(getSelectedItem_typed(cb)); }
return cb;
}
static A onChangeAndNow(A tabs, Runnable r) {
if (r != null) {
onChange(tabs, r);
r.run();
}
return tabs;
}
static JSlider onChangeAndNow(JSlider s, Runnable f) {
if (s != null && f != null) {
onChange(s, f);
f.run();
}
return s;
}
static Object metaGet(IMeta o, Object key) {
return metaMapGet(o, key);
}
static Object metaGet(Object o, Object key) {
return metaMapGet(o, key);
}
static Object metaGet(String key, IMeta o) {
return metaMapGet(o, key);
}
static Object metaGet(String key, Object o) {
return metaMapGet(o, key);
}
static Object metaMapGet(IMeta o, Object key) {
return o == null ? null : o.metaGet(key); // We now let the object itself do it (overridable!)
}
static Object metaMapGet(Object o, Object key) {
return metaMapGet(toIMeta(o), key);
}
static void metaPut(IMeta o, Object key, Object value) {
metaMapPut(o, key, value);
}
static void metaPut(Object o, Object key, Object value) {
metaMapPut(o, key, value);
}
static void metaMapPut(IMeta o, Object key, Object value) {
{ if (o != null) o.metaPut(key, value); }
}
static void metaMapPut(Object o, Object key, Object value) {
var meta = initIMeta(o);
{ if (meta != null) meta.metaPut(key, value); }
}
static Map convertObjectMetaToMap(IMeta o) { return convertObjectMetaToMap(o, () -> makeObjectMetaMap()); }
static Map convertObjectMetaToMap(IMeta o, IF0