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 javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.table.*;
import java.io.*;
import java.net.*;
import java.lang.reflect.*;
import java.lang.ref.*;
import java.lang.management.*;
import java.security.*;
import java.security.spec.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.imageio.*;
import java.math.*;
import x30_pkg.x30_util;
import static x30_pkg.x30_util.VF1;
import static x30_pkg.x30_util.l;
import static x30_pkg.x30_util.fail;
import static x30_pkg.x30_util.indexOf;
import static x30_pkg.x30_util.getOpt;
import static x30_pkg.x30_util.setOpt;
import static x30_pkg.x30_util.callOpt;
import static x30_pkg.x30_util.newWeakHashMap;
import static x30_pkg.x30_util.newDangerousWeakHashMap;
import static x30_pkg.x30_util.get;
import static x30_pkg.x30_util.get_raw;
import static x30_pkg.x30_util.assertTrue;
import static x30_pkg.x30_util.isHeadless;
import static x30_pkg.x30_util.isAndroid;
import static x30_pkg.x30_util.isTrue;
import static x30_pkg.x30_util.asList;
import x30_pkg.x30_util.DynamicObject;
import loadableUtils.utils;
import static loadableUtils.utils._threadInfo;
import static loadableUtils.utils._threadInheritInfo;
import static loadableUtils.utils._threadInfo_addMakerAndRetriever;
import static loadableUtils.utils.dm_currentModule;
import static loadableUtils.utils.dm_current_mandatory;
import static loadableUtils.utils.match;
import static loadableUtils.utils.getOpt_raw;
import static loadableUtils.utils.setOpt_raw;
import static loadableUtils.utils.getField;
import static loadableUtils.utils.fieldType;
import static loadableUtils.utils.format3;
import static loadableUtils.utils.vm_generalIdentityHashSet;
import static loadableUtils.utils.vm_generalHashMap;
import static loadableUtils.utils.vm_generalWeakSubMap;
import static loadableUtils.utils.bindToComponent;
import static loadableUtils.utils.struct;
import static loadableUtils.utils.structure;
import static loadableUtils.utils.loadPage;
import static loadableUtils.utils.loadPage_utf8;
import static loadableUtils.utils.loadPageSilentlyWithTimeout;
import static loadableUtils.utils.loadPageSilently;
import static loadableUtils.utils.loadSnippet;
import static loadableUtils.utils.loadSnippetQuietly;
import static loadableUtils.utils.sendToLocalBot;
import static loadableUtils.utils.componentPopupMenu;
import static loadableUtils.utils.componentPopupMenu_top;
import static loadableUtils.utils.componentPopupMenu_getEvent;
import static loadableUtils.utils.componentPopupMenu_initForComponent;
import static loadableUtils.utils.listPopupMenu;
import static loadableUtils.utils.tablePopupMenu;
import static loadableUtils.utils.sexyTableWithoutDrag;
import static loadableUtils.utils.dm_current_generic;
import static loadableUtils.utils.dm_current_mandatory_generic;
import static loadableUtils.utils.cset;
import static loadableUtils.utils.DynamicObject_loading;
import static loadableUtils.utils.concepts_unlisted;
import static loadableUtils.utils.makePopupMenuConditional;
import static loadableUtils.utils.makeConceptsTable_idWidth;
import static loadableUtils.utils.showConceptsTable_afterUpdate;
import static loadableUtils.utils.dynamicObjectIsLoading;
import loadableUtils.utils.F0;
import loadableUtils.utils.F1;
import loadableUtils.utils.Matches;
import loadableUtils.utils.BetterLabel;
import loadableUtils.utils.SingleComponentPanel;
import loadableUtils.utils.Snippet;
import loadableUtils.utils.Q;
import loadableUtils.utils.ImageSurface;
import loadableUtils.utils.structure_Data;
import loadableUtils.utils.RGBImage;
import loadableUtils.utils.RGB;
import loadableUtils.utils.BWImage;
import loadableUtils.utils.MakesBufferedImage;
import loadableUtils.utils.Concept;
import loadableUtils.utils.Concepts;
import loadableUtils.utils.IConceptIndex;
import loadableUtils.utils.IFieldIndex;
import loadableUtils.utils.Derefable;
import loadableUtils.utils.ImageSurfaceSelector;
import loadableUtils.utils.SimpleCRUD;
import loadableUtils.utils.PersistableThrowable;
import loadableUtils.utils.DynModule;
import loadableUtils.utils.DynPrintLog;
import loadableUtils.utils.DynObjectTable;
import loadableUtils.utils.DynImageSurface;
import loadableUtils.utils.DynCalculatedList;
import loadableUtils.utils.Rect;
import loadableUtils.utils.Pt;
import javax.swing.event.AncestorListener;
import javax.swing.event.AncestorEvent;
import javax.swing.Timer;
import javax.swing.undo.UndoManager;

class main {

  public static class ScreenFillingText extends DynModule {

    public String text = "TEST";

    public float fontSize;

    public transient JTextPane textPane;

    public transient ReliableSingleThread rstAdjust = dm_rst(this, new Runnable() {

      public void run() {
        try {
          jTextPane_adjustTextSizeToFillParentHeight_wait(textPane);
          dm_setFieldUnlessNull("fontSize", fontSize(textPane));
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "jTextPane_adjustTextSizeToFillParentHeight_wait(textPane);\r\n    dm_setFieldUn...";
      }
    });

    public JComponent visualize() {
      return onResize(rstAdjust, jscroll(textPane = fontSize(fontSize, dm_centeredTextPane("text"))));
    }

    public void start() {
      super.start();
      dm_watchField("text", rstAdjust);
    }
  }

  public static boolean _moduleClass_ScreenFillingText;

  public static Object callF(Object f, Object... args) {
    try {
      if (f instanceof String)
        return callMC((String) f, args);
      return x30_util.callF(f, args);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public static <A> A callF(F0<A> f) {
    return f == null ? null : f.get();
  }

  public static <A, B> B callF(F1<A, B> f, A a) {
    return f == null ? null : f.get(a);
  }

  public static <A> void callF(VF1<A> f, A a) {
    if (f != null)
      f.get(a);
  }

  public static Object callMC(String method, Object... args) {
    return call(mc(), method, args);
  }

  public static Object call(Object o) {
    return callF(o);
  }

  public static Object call(Object o, String method, Object... args) {
    return call_withVarargs(o, method, args);
  }

  public static void _onLoad_initUtils() {
    utils.__javax = javax();
  }

  public static void _onLoad_defaultClassFinder() {
    setDefaultClassFinder(new F1<String, Class>() {

      public Class get(String name) {
        try {
          Class c = findClass_fullName(name);
          if (c != null)
            return c;
          if (startsWith(name, "main$"))
            return loadableUtils.utils.findClass_fullName("loadableUtils.utils" + substring(name, 4));
          return null;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "Class c = findClass_fullName(name);\r\n    if (c != null) ret c;\r\n    if (start...";
      }
    });
  }

  public static String programID() {
    return getProgramID();
  }

  public static String programID(Object o) {
    return getProgramID(o);
  }

  public static volatile StringBuffer local_log = new StringBuffer();

  public static volatile Appendable print_log = local_log;

  public static volatile int print_log_max = 1024 * 1024;

  public static volatile int local_log_max = 100 * 1024;

  public static boolean print_silent;

  public static Object print_byThread_lock = new Object();

  public static volatile ThreadLocal<Object> print_byThread;

  public static volatile Object print_allThreads;

  public static volatile Object print_preprocess;

  public static void print() {
    print("");
  }

  public static <A> A print(String s, A o) {
    print((endsWithLetterOrDigit(s) ? s + ": " : s) + o);
    return o;
  }

  public static <A> A print(A o) {
    ping_okInCleanUp();
    if (print_silent)
      return o;
    String s = String.valueOf(o) + "\n";
    print_noNewLine(s);
    return o;
  }

  public static void print_noNewLine(String s) {
    Object f = getThreadLocal(print_byThread_dontCreate());
    if (f == null)
      f = print_allThreads;
    if (f != null)
      if (isFalse(f instanceof F1 ? ((F1) f).get(s) : callF(f, s)))
        return;
    print_raw(s);
  }

  public static void print_raw(String s) {
    if (print_preprocess != null)
      s = (String) callF(print_preprocess, s);
    s = fixNewLines(s);
    Appendable loc = local_log;
    Appendable buf = print_log;
    int loc_max = print_log_max;
    if (buf != loc && buf != null) {
      print_append(buf, s, print_log_max);
      loc_max = local_log_max;
    }
    if (loc != null)
      print_append(loc, s, loc_max);
    System.out.print(s);
  }

  public static ReliableSingleThread dm_rst(DynModule mod, Runnable r) {
    return dm_rst(mod, new ReliableSingleThread(r));
  }

  public static ReliableSingleThread dm_rst(DynModule mod, ReliableSingleThread rst) {
    rst.enter = dm_rEnter(mod);
    return rst;
  }

  public static void jTextPane_adjustTextSizeToFillParentHeight_wait(JTextPane pane, Object... __) {
    assertNotOnAWTThread();
    Flag done = new Flag();
    jTextPane_adjustTextSizeToFillParentHeight(pane, paramsPlus(__, "onDone", done));
    waitForFlag(done);
  }

  public static void dm_setFieldUnlessNull(String field, Object value) {
    if (value != null)
      dm_current_mandatory().setField(field, value);
  }

  public static <A extends JComponent> A fontSize(float size, A a) {
    return setFontSize(size, a);
  }

  public static <A extends JComponent> A fontSize(A a, float size) {
    return setFontSize(size, a);
  }

  public static Float fontSize(JComponent c) {
    Font f = getFont(c);
    return f == null ? null : f.getSize2D();
  }

  public static RuntimeException rethrow(Throwable t) {
    if (t instanceof Error)
      _handleError((Error) t);
    throw t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t);
  }

  public static RuntimeException rethrow(String msg, Throwable t) {
    throw new RuntimeException(msg, t);
  }

  public static <A extends Component> A onResize(A c, final Object r) {
    if (c != null && r != null) {
      swing(new Runnable() {

        public void run() {
          try {
            c.addComponentListener(new ComponentAdapter() {

              public void componentResized(ComponentEvent e) {
                pcallF(r);
              }
            });
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "c.addComponentListener(new ComponentAdapter {\r\n      public void componentRes...";
        }
      });
    }
    return c;
  }

  public static <A extends Component> A onResize(Object r, A c) {
    return onResize(c, r);
  }

  public static JScrollPane jscroll(final Component c) {
    return swing(new F0<JScrollPane>() {

      public JScrollPane get() {
        try {
          return new JScrollPane(c);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret new JScrollPane(c);";
      }
    });
  }

  public static JTextPane dm_centeredTextPane(String field) {
    return jCenteredLiveValueTextPane_bothWays(dm_fieldLiveValue(field));
  }

  public static void dm_watchField(String field, Runnable onChange) {
    new Dyn_FieldWatcher(dm_current_mandatory(), field, onChange);
  }

  public static Class mc() {
    return main.class;
  }

  public static Object call_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.findStaticMethod(method, args);
        if (me != null)
          return invokeMethod(me, null, args);
        List<Method> methods = cache.cache.get(method);
        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() + "." + method + "(" + joinWithComma(classNames(args)) + ") not found");
      } else {
        Class c = o.getClass();
        _MethodCache cache = callOpt_getCache(c);
        Method me = cache.findMethod(method, args);
        if (me != null)
          return invokeMethod(me, o, args);
        List<Method> 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);
          }
        throw fail("Method " + c.getName() + "." + method + "(" + joinWithComma(classNames(args)) + ") not found");
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public static Class javax() {
    return getJavaX();
  }

  public static void setDefaultClassFinder(Object cf) {
    _defaultClassFinder_value = cf;
  }

  public static HashMap<String, Class> findClass_fullName_cache = new HashMap();

  public static Class findClass_fullName(String name) {
    synchronized (findClass_fullName_cache) {
      if (findClass_fullName_cache.containsKey(name))
        return findClass_fullName_cache.get(name);
      Class c;
      try {
        c = Class.forName(name);
      } catch (ClassNotFoundException e) {
        c = null;
      }
      findClass_fullName_cache.put(name, c);
      return c;
    }
  }

  public static boolean startsWith(String a, String b) {
    return a != null && a.startsWith(b);
  }

  public static boolean startsWith(String a, char c) {
    return nemptyString(a) && a.charAt(0) == c;
  }

  public static boolean startsWith(String a, String b, Matches m) {
    if (!startsWith(a, b))
      return false;
    m.m = new String[] { substring(a, strL(b)) };
    return true;
  }

  public 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;
  }

  public static String substring(String s, int x) {
    return substring(s, x, strL(s));
  }

  public static String substring(String 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.substring(x, y);
  }

  public static Object _defaultClassFinder_value;

  public static Object _defaultClassFinder() {
    return _defaultClassFinder_value;
  }

  public static String programID;

  public static String getProgramID() {
    return nempty(programID) ? formatSnippetIDOpt(programID) : "?";
  }

  public static String getProgramID(Class c) {
    String id = (String) getOpt(c, "programID");
    if (nempty(id))
      return formatSnippetID(id);
    return "?";
  }

  public static String getProgramID(Object o) {
    return getProgramID(getMainClass(o));
  }

  public static boolean endsWithLetterOrDigit(String s) {
    return s != null && s.length() > 0 && Character.isLetterOrDigit(s.charAt(s.length() - 1));
  }

  public static void ping_okInCleanUp() {
    if (ping_pauseAll || ping_anyActions)
      ping_impl(true);
  }

  public static Object getThreadLocal(Object o, String name) {
    ThreadLocal t = (ThreadLocal) (getOpt(o, name));
    return t != null ? t.get() : null;
  }

  public static <A> A getThreadLocal(ThreadLocal<A> tl) {
    return tl == null ? null : tl.get();
  }

  public static ThreadLocal<Object> print_byThread_dontCreate() {
    return print_byThread;
  }

  public static boolean isFalse(Object o) {
    return eq(false, o);
  }

  public 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();
  }

  public static void print_append(Appendable _buf, String s, int max) {
    try {
      synchronized (_buf) {
        _buf.append(s);
        if (!(_buf instanceof StringBuilder))
          return;
        StringBuilder buf = (StringBuilder) _buf;
        max /= 2;
        if (buf.length() > max)
          try {
            int newLength = max / 2;
            int ofs = buf.length() - newLength;
            String newString = buf.substring(ofs);
            buf.setLength(0);
            buf.append("[...] ").append(newString);
          } catch (Exception e) {
            buf.setLength(0);
          }
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public static F0<AutoCloseable> dm_rEnter(final DynModule mod) {
    return mod == null ? null : new F0<AutoCloseable>() {

      public AutoCloseable get() {
        try {
          return mod.enter();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret mod.enter();";
      }
    };
  }

  public static void assertNotOnAWTThread() {
    assertFalse("Can't do this in AWT thread", isAWTThread());
  }

  public static void jTextPane_adjustTextSizeToFillParentHeight(JTextPane pane, Object... __) {
    if (pane == null || getParent(pane) == null || empty(getText(pane))) {
      callF(optPar("onDone", __));
      return;
    }
    if (jTextPane_shouldDecreaseFontSizeToFillParentHeight(pane))
      jTextPane_shrinkTextSizeToFillParentHeight(pane, __);
    else if (jTextPane_shouldIncreaseFontSizeToFillParentHeight(pane)) {
      swing(new Runnable() {

        public void run() {
          try {
            float size = pane.getFont().getSize2D();
            float newSize = size + 1;
            if (boolPar("debug", __))
              print("new font size: " + newSize);
            setFontSize(pane, newSize);
            awtLater(optPar("delay", __, 50), new Runnable() {

              public void run() {
                try {
                  jTextPane_adjustTextSizeToFillParentHeight(pane, __);
                } catch (Exception __e) {
                  throw rethrow(__e);
                }
              }

              public String toString() {
                return "jTextPane_adjustTextSizeToFillParentHeight(pane, __);";
              }
            });
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "float size = pane.getFont().getSize2D();\r\n    float newSize = size+1;\r\n    if...";
        }
      });
    } else
      callF(optPar("onDone", __));
  }

  public static Object[] paramsPlus(Object[] a1, Object... a2) {
    if (a2 == null)
      return a1;
    if (a1 == null)
      return a2;
    if (l(a1) == 1 && a1[0] instanceof Map)
      return new Object[] { mapPlus((Map) a1[0], a2) };
    assertEvenLength(a1);
    assertEvenLength(a2);
    Map map = paramsToOrderedMap(a1);
    int n = l(a2);
    for (int i = 0; i < n; i += 2) {
      Object key = a2[i];
      if (key != null)
        map.put(key, a2[i + 1]);
    }
    return mapToParams(map);
  }

  public static void waitForFlag(Flag flag) {
    if (flag != null)
      flag.waitUntilUp();
  }

  public static <A extends JComponent> A setFontSize(final float size, final A a) {
    if (a == null)
      return a;
    {
      swing(new Runnable() {

        public void run() {
          try {
            Component _a = a;
            if (a instanceof JComboBox)
              _a = ((JComboBox) a).getEditor().getEditorComponent();
            _a.setFont(_a.getFont().deriveFont((float) size));
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "Component _a = a;\r\n    if (a instanceof JComboBox)\r\n      _a = ((JComboBox) a...";
        }
      });
    }
    return a;
  }

  public static <A extends JComponent> A setFontSize(A a, float size) {
    return setFontSize(size, a);
  }

  public static Font getFont(JComponent c) {
    return c == null ? null : swing(new F0<Font>() {

      public Font get() {
        try {
          return c.getFont();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret c.getFont();";
      }
    });
  }

  public static void _handleError(Error e) {
    call(javax(), "_handleError", e);
  }

  public static Object swing(Object f) {
    return swingAndWait(f);
  }

  public static <A> A swing(F0<A> f) {
    return (A) swingAndWait(f);
  }

  public static Object pcallF(Object f, Object... args) {
    return pcallFunction(f, args);
  }

  public static <A> A pcallF(F0<A> f) {
    try {
      return f == null ? null : f.get();
    } catch (Throwable __e) {
      return null;
    }
  }

  public static <A, B> B pcallF(F1<A, B> f, A a) {
    try {
      return f == null ? null : f.get(a);
    } catch (Throwable __e) {
      return null;
    }
  }

  public static JTextPane jCenteredLiveValueTextPane_bothWays(final SimpleLiveValue<String> lv) {
    final JTextPane ta = jCenteredTextPane();
    bindTextComponentToLiveValue_bothWays(ta, lv);
    return ta;
  }

  public static SimpleLiveValue dm_fieldLiveValue(String fieldName) {
    return dm_fieldLiveValue(dm_current_mandatory(), fieldName);
  }

  public static SimpleLiveValue dm_fieldLiveValue(final DynModule module, final String fieldName) {
    Lock __217 = module.lock;
    lock(__217);
    try {
      Class type = getFieldType(module, fieldName);
      final SimpleLiveValue value = new SimpleLiveValue(type, get(module, fieldName));
      module.onChange(new Runnable() {

        public void run() {
          try {
            Object o = get(module, fieldName);
            value.set(o);
            ;
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "ifdef dm_fieldLiveValue_debug\r\n      print(\"dm_fieldLiveValue: setting \" + fi...";
        }
      });
      value.onChange(new Runnable() {

        public void run() {
          try {
            module.setField(fieldName, value.get());
            ;
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "ifdef dm_fieldLiveValue_debug\r\n      print(\"dm_fieldLiveValue: setting 2 \" + ...";
        }
      });
      return value;
    } finally {
      unlock(__217);
    }
  }

  public static final Map<Class, _MethodCache> callOpt_cache = newDangerousWeakHashMap();

  public 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);
        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);
    }
  }

  public static _MethodCache callOpt_getCache(Class c) {
    synchronized (callOpt_cache) {
      _MethodCache cache = callOpt_cache.get(c);
      if (cache == null)
        callOpt_cache.put(c, cache = new _MethodCache(c));
      return cache;
    }
  }

  public 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);
    }
  }

  public static boolean isStaticMethod(Method m) {
    return methodIsStatic(m);
  }

  public static Object[] massageArgsForVarArgsCall(Method m, Object[] args) {
    Class<?>[] types = m.getParameterTypes();
    int n = types.length - 1, nArgs = args.length;
    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);
    Object[] varArgs = arrayOfType(varArgType, nArgs - n);
    arraycopy(args, n, varArgs, 0, nArgs - n);
    newArgs[n] = varArgs;
    return newArgs;
  }

  public static <A> String joinWithComma(Collection<A> c) {
    return join(", ", c);
  }

  public static String joinWithComma(String... c) {
    return join(", ", c);
  }

  public static List<String> classNames(Collection l) {
    return getClassNames(l);
  }

  public static List<String> classNames(Object[] l) {
    return getClassNames(Arrays.asList(l));
  }

  public static Class __javax;

  public static Class getJavaX() {
    try {
      return __javax;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public static boolean nemptyString(String s) {
    return s != null && s.length() > 0;
  }

  public static int strL(String s) {
    return s == null ? 0 : s.length();
  }

  public static int listL(Collection l) {
    return l == null ? 0 : l.size();
  }

  public static boolean neq(Object a, Object b) {
    return !eq(a, b);
  }

  public static boolean nempty(Collection c) {
    return !empty(c);
  }

  public static boolean nempty(CharSequence s) {
    return !empty(s);
  }

  public static boolean nempty(Object[] o) {
    return !empty(o);
  }

  public static boolean nempty(byte[] o) {
    return !empty(o);
  }

  public static boolean nempty(int[] o) {
    return !empty(o);
  }

  public static boolean nempty(Map m) {
    return !empty(m);
  }

  public static boolean nempty(Iterator i) {
    return i != null && i.hasNext();
  }

  public static boolean nempty(Object o) {
    return !empty(o);
  }

  public static String formatSnippetIDOpt(String s) {
    return isSnippetID(s) ? formatSnippetID(s) : s;
  }

  public static String formatSnippetID(String id) {
    return "#" + parseSnippetID(id);
  }

  public static String formatSnippetID(long id) {
    return "#" + id;
  }

  public static Class getMainClass() {
    return mc();
  }

  public static Class getMainClass(Object o) {
    try {
      if (o == null)
        return null;
      if (o instanceof Class && eq(((Class) o).getName(), "x30"))
        return (Class) o;
      return (o instanceof Class ? (Class) o : o.getClass()).getClassLoader().loadClass("main");
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public static volatile boolean ping_pauseAll;

  public static int ping_sleep = 100;

  public static volatile boolean ping_anyActions;

  public static Map<Thread, Object> ping_actions = newWeakHashMap();

  public static ThreadLocal<Boolean> ping_isCleanUpThread = new ThreadLocal();

  public static boolean ping() {
    if (ping_pauseAll || ping_anyActions)
      ping_impl(true);
    return true;
  }

  public static boolean ping_impl(boolean okInCleanUp) {
    try {
      if (ping_pauseAll && !isAWTThread()) {
        do Thread.sleep(ping_sleep); while (ping_pauseAll);
        return true;
      }
      if (ping_anyActions) {
        if (!okInCleanUp && !isTrue(ping_isCleanUpThread.get()))
          failIfUnlicensed();
        Object action = null;
        synchronized (ping_actions) {
          if (!ping_actions.isEmpty()) {
            action = ping_actions.get(currentThread());
            if (action instanceof Runnable)
              ping_actions.remove(currentThread());
            if (ping_actions.isEmpty())
              ping_anyActions = false;
          }
        }
        if (action instanceof Runnable)
          ((Runnable) action).run();
        else if (eq(action, "cancelled"))
          throw fail("Thread cancelled.");
      }
      return false;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public static boolean eq(Object a, Object b) {
    return a == null ? b == null : a == b || b != null && a.equals(b);
  }

  public static void assertFalse(Object o) {
    if (!(eq(o, false)))
      throw fail(str(o));
  }

  public static boolean assertFalse(boolean b) {
    if (b)
      throw fail("oops");
    return b;
  }

  public static boolean assertFalse(String msg, boolean b) {
    if (b)
      throw fail(msg);
    return b;
  }

  public static boolean isAWTThread() {
    if (isAndroid())
      return false;
    if (isHeadless())
      return false;
    return isAWTThread_awt();
  }

  public static boolean isAWTThread_awt() {
    return SwingUtilities.isEventDispatchThread();
  }

  public static Container getParent(final Component c) {
    return c == null ? null : swing(new F0<Container>() {

      public Container get() {
        try {
          return c.getParent();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret c.getParent();";
      }
    });
  }

  public static boolean empty(Collection c) {
    return c == null || c.isEmpty();
  }

  public static boolean empty(CharSequence s) {
    return s == null || s.length() == 0;
  }

  public static boolean empty(Map map) {
    return map == null || map.isEmpty();
  }

  public static boolean empty(Object[] o) {
    return o == null || o.length == 0;
  }

  public 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));
  }

  public static boolean empty(float[] a) {
    return a == null || a.length == 0;
  }

  public static boolean empty(int[] a) {
    return a == null || a.length == 0;
  }

  public static boolean empty(long[] a) {
    return a == null || a.length == 0;
  }

  public static boolean empty(byte[] a) {
    return a == null || a.length == 0;
  }

  public static boolean empty(File f) {
    return getFileSize(f) == 0;
  }

  public static String getText(final AbstractButton c) {
    return c == null ? "" : (String) swingAndWait(new F0<Object>() {

      public Object get() {
        try {
          return c.getText();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret c.getText();";
      }
    });
  }

  public static String getText(final JTextComponent c) {
    return c == null ? "" : (String) swingAndWait(new F0<Object>() {

      public Object get() {
        try {
          return c.getText();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret c.getText();";
      }
    });
  }

  public static String getText(final JLabel l) {
    return l == null ? "" : (String) swingAndWait(new F0<Object>() {

      public Object get() {
        try {
          return l.getText();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret l.getText();";
      }
    });
  }

  public static String getText(final JComboBox cb) {
    if (cb == null)
      return null;
    if (isEditableComboBox(cb))
      return unnull((String) cb.getEditor().getItem());
    else
      return str(cb.getSelectedItem());
  }

  public static <A> A optPar(ThreadLocal<A> tl, A defaultValue) {
    A a = tl.get();
    if (a != null) {
      tl.set(null);
      return a;
    }
    return defaultValue;
  }

  public static <A> A optPar(ThreadLocal<A> tl) {
    return optPar(tl, null);
  }

  public static Object optPar(Object[] params, String name) {
    return optParam(params, name);
  }

  public static Object optPar(String name, Object[] params) {
    return optParam(params, name);
  }

  public static Object optPar(String name, Map params) {
    return optParam(name, params);
  }

  public static <A> A optPar(Object[] params, String name, A defaultValue) {
    return optParam(params, name, defaultValue);
  }

  public static <A> A optPar(String name, Object[] params, A defaultValue) {
    return optParam(params, name, defaultValue);
  }

  public static boolean jTextPane_shouldDecreaseFontSizeToFillParentHeight(JTextPane pane) {
    return preferredHeight(pane) > getParentHeight(pane);
  }

  public static void jTextPane_shrinkTextSizeToFillParentHeight(JTextPane pane, Object... __) {
    if (pane == null || getParent(pane) == null) {
      callF(optPar("onDone", __));
      return;
    }
    {
      swing(new Runnable() {

        public void run() {
          try {
            int pref = preferredHeight(pane);
            int h = getParentHeight(pane);
            double ratio = doubleRatio(h, pref);
            if (ratio >= 1) {
              callF(optPar("onDone", __));
              return;
            }
            float size = pane.getFont().getSize2D();
            float newSize = size - 1;
            if (boolPar("debug", __))
              print("pref=" + pref + ", h=" + h + ", new font size: " + newSize);
            setFontSize(pane, newSize);
            awtLater(optPar("delay", __, 50), new Runnable() {

              public void run() {
                try {
                  jTextPane_shrinkTextSizeToFillParentHeight(pane, __);
                } catch (Exception __e) {
                  throw rethrow(__e);
                }
              }

              public String toString() {
                return "jTextPane_shrinkTextSizeToFillParentHeight(pane, __);";
              }
            });
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "int pref = preferredHeight(pane);\r\n    int h = getParentHeight(pane);\r\n    do...";
        }
      });
    }
  }

  public static boolean jTextPane_shouldIncreaseFontSizeToFillParentHeight(JTextPane pane) {
    return preferredHeight(pane) < getParentHeight(pane);
  }

  public static boolean boolPar(ThreadLocal<Boolean> tl) {
    return boolOptParam(tl);
  }

  public static boolean boolPar(Object[] __, String name) {
    return boolOptParam(__, name);
  }

  public static boolean boolPar(String name, Object[] __) {
    return boolOptParam(__, name);
  }

  public static boolean boolPar(String name, Map __) {
    return boolOptParam(name, __);
  }

  public static boolean boolPar(String name, Object[] params, boolean defaultValue) {
    return optParam(params, name, defaultValue);
  }

  public static void awtLater(int delay, final Object r) {
    swingLater(delay, r);
  }

  public static void awtLater(Object r) {
    swingLater(r);
  }

  public static void awtLater(JComponent component, int delay, Object r) {
    installTimer(component, r, delay, delay, false);
  }

  public static void awtLater(JFrame frame, int delay, Object r) {
    awtLater(frame.getRootPane(), delay, r);
  }

  public static <A, B> Map<A, B> mapPlus(Map<A, B> m, Object... data) {
    m = cloneMap(m);
    litmap_impl(m, data);
    return m;
  }

  public static Object[] assertEvenLength(Object[] a) {
    assertTrue(even(l(a)));
    return a;
  }

  public static LinkedHashMap paramsToOrderedMap(Object... params) {
    return asLinkedHashMap(paramsToMap(params));
  }

  public static Object[] mapToParams(Map map) {
    return mapToObjectArray(map);
  }

  public static void swingAndWait(Runnable r) {
    try {
      if (isAWTThread())
        r.run();
      else
        EventQueue.invokeAndWait(addThreadInfoToRunnable(r));
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public 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();
    }
  }

  public static Object pcallFunction(Object f, Object... args) {
    try {
      return callFunction(f, args);
    } catch (Throwable __e) {
      _handleException(__e);
    }
    return null;
  }

  public static JTextPane jCenteredTextPane() {
    return jcenteredtextpane();
  }

  public static JTextPane jCenteredTextPane(String text, AttributeSet attributes) {
    return jcenteredtextpane(text, attributes);
  }

  public static JTextPane jCenteredTextPane(String text) {
    return jcenteredtextpane(text);
  }

  public static <A extends JTextComponent> A bindTextComponentToLiveValue_bothWays(final A tc, final SimpleLiveValue<String> lv) {
    bindLiveValueListenerToComponent(tc, lv, new Runnable() {

      public void run() {
        try {
          setTextKeepCaret(tc, lv.get());
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "setTextKeepCaret(tc, lv.get())";
      }
    });
    onChange(tc, new Runnable() {

      public void run() {
        try {
          lv.set(getText(tc));
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "lv.set(getText(tc))";
      }
    });
    return tc;
  }

  public static void lock(Lock lock) {
    try {
      ping();
      if (lock == null)
        return;
      try {
        lock.lockInterruptibly();
      } catch (InterruptedException e) {
        print("Locking interrupted! I probably deadlocked, oops.");
        printStackTrace(e);
        rethrow(e);
      }
      ping();
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public static void lock(Lock lock, String msg) {
    print("Locking: " + msg);
    lock(lock);
  }

  public static void lock(Lock lock, String msg, long timeout) {
    print("Locking: " + msg);
    lockOrFail(lock, timeout);
  }

  public static ReentrantLock lock() {
    return fairLock();
  }

  public static Class getFieldType(Object o, String field) {
    return fieldType(o, field);
  }

  public static void unlock(Lock lock, String msg) {
    if (lock == null)
      return;
    print("Unlocking: " + msg);
    lock.unlock();
  }

  public static void unlock(Lock lock) {
    if (lock == null)
      return;
    lock.unlock();
  }

  public static Throwable getExceptionCause(Throwable e) {
    Throwable c = e.getCause();
    return c != null ? c : e;
  }

  public static String joinWithSpace(Collection<String> c) {
    return join(" ", c);
  }

  public static String joinWithSpace(String... c) {
    return join(" ", c);
  }

  public static boolean methodIsStatic(Method m) {
    return (m.getModifiers() & Modifier.STATIC) != 0;
  }

  public static boolean argumentCompatibleWithType(Object arg, Class type) {
    return arg == null ? !type.isPrimitive() : isInstanceX(type, arg);
  }

  public static void arraycopy(Object[] a, Object[] b) {
    int n = min(a.length, b.length);
    for (int i = 0; i < n; i++) b[i] = a[i];
  }

  public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int n) {
    System.arraycopy(src, srcPos, dest, destPos, n);
  }

  public static <A> A[] arrayOfType(Class<A> type, int n) {
    return makeArray(type, n);
  }

  public static <A> A[] arrayOfType(int n, Class<A> type) {
    return arrayOfType(type, n);
  }

  public static <A> String join(String glue, Iterable<A> strings) {
    if (strings == null)
      return "";
    if (strings instanceof Collection) {
      if (((Collection) strings).size() == 1)
        return str(first(((Collection) strings)));
    }
    StringBuilder buf = new StringBuilder();
    Iterator<A> 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 <A> String join(Iterable<A> strings) {
    return join("", strings);
  }

  public static <A> String join(Iterable<A> strings, String glue) {
    return join(glue, strings);
  }

  public static String join(String[] strings) {
    return join("", strings);
  }

  public static String str(Object o) {
    return o == null ? "null" : o.toString();
  }

  public static String str(char[] c) {
    return new String(c);
  }

  public static List<String> getClassNames(Collection l) {
    List<String> out = new ArrayList();
    if (l != null)
      for (Object o : l) out.add(o == null ? null : getClassName(o));
    return out;
  }

  public static boolean isSnippetID(String s) {
    try {
      parseSnippetID(s);
      return true;
    } catch (RuntimeException e) {
      return false;
    }
  }

  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;
  }

  public static void failIfUnlicensed() {
    assertTrue("license off", licensed());
  }

  public static Thread currentThread() {
    return Thread.currentThread();
  }

  public static String getType(Object o) {
    return getClassName(o);
  }

  public static long getFileSize(String path) {
    return path == null ? 0 : new File(path).length();
  }

  public static long getFileSize(File f) {
    return f == null ? 0 : f.length();
  }

  public static boolean isEditableComboBox(final JComboBox cb) {
    return cb != null && swing(new F0<Boolean>() {

      public Boolean get() {
        try {
          return cb.isEditable();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret cb.isEditable();";
      }
    });
  }

  public static String unnull(String s) {
    return s == null ? "" : s;
  }

  public static <A> Collection<A> unnull(Collection<A> l) {
    return l == null ? emptyList() : l;
  }

  public static <A> List<A> unnull(List<A> l) {
    return l == null ? emptyList() : l;
  }

  public static <A, B> Map<A, B> unnull(Map<A, B> l) {
    return l == null ? emptyMap() : l;
  }

  public static <A> Iterable<A> unnull(Iterable<A> i) {
    return i == null ? emptyList() : i;
  }

  public static <A> A[] unnull(A[] a) {
    return a == null ? (A[]) new Object[0] : a;
  }

  public static BitSet unnull(BitSet b) {
    return b == null ? new BitSet() : b;
  }

  public static Pt unnull(Pt p) {
    return p == null ? new Pt() : p;
  }

  public static <A> A optParam(ThreadLocal<A> tl, A defaultValue) {
    return optPar(tl, defaultValue);
  }

  public static <A> A optParam(ThreadLocal<A> tl) {
    return optPar(tl);
  }

  public static Object optParam(String name, Map params) {
    return mapGet(params, name);
  }

  public static <A> 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;
  }

  public static Object optParam(Object[] opt, String name) {
    return optParam(opt, name, null);
  }

  public static int preferredHeight(Component c) {
    return c == null ? 0 : getPreferredSize(c).height;
  }

  public static int getParentHeight(Component c) {
    return getHeight(getParent(c));
  }

  public static double doubleRatio(double x, double y) {
    return y == 0 ? 0 : x / y;
  }

  public static boolean boolOptParam(ThreadLocal<Boolean> tl) {
    return isTrue(optPar(tl));
  }

  public static boolean boolOptParam(Object[] __, String name) {
    return isTrue(optParam(__, name));
  }

  public static boolean boolOptParam(String name, Object[] __) {
    return boolOptParam(__, name);
  }

  public static boolean boolOptParam(String name, Map __) {
    return isTrue(optPar(name, __));
  }

  public 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();
  }

  public static void swingLater(Object r) {
    SwingUtilities.invokeLater(toRunnable(r));
  }

  public static Timer installTimer(JComponent component, Object r, long delay) {
    return installTimer(component, r, delay, delay);
  }

  public static Timer installTimer(RootPaneContainer frame, long delay, Object r) {
    return installTimer(frame.getRootPane(), r, delay, delay);
  }

  public static Timer installTimer(JComponent component, long delay, Object r) {
    return installTimer(component, r, delay, delay);
  }

  public static Timer installTimer(JComponent component, long delay, long firstDelay, Object r) {
    return installTimer(component, r, delay, firstDelay);
  }

  public static Timer installTimer(final JComponent component, final Object r, final long delay, final long firstDelay) {
    return installTimer(component, r, delay, firstDelay, true);
  }

  public 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<Object>() {

      public Object get() {
        try {
          final Var<Timer> timer = new Var();
          timer.set(new Timer(toInt(delay), new java.awt.event.ActionListener() {

            public void actionPerformed(java.awt.event.ActionEvent _evt) {
              try {
                AutoCloseable __1566 = tempActivity(r);
                try {
                  try {
                    if (!allPaused())
                      if (isFalse(callF(r)))
                        cancelTimer(timer.get());
                  } catch (Throwable __e) {
                    _handleException(__e);
                  }
                } finally {
                  _close(__1566);
                }
              } 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> timer;\r\n    timer.set(new Timer(toInt(delay), actionList...";
      }
    });
  }

  public static Timer installTimer(RootPaneContainer frame, long delay, long firstDelay, Object r) {
    return installTimer(frame.getRootPane(), delay, firstDelay, r);
  }

  public static <A, B> Map<A, B> cloneMap(Map<A, B> map) {
    if (map == null)
      return new HashMap();
    synchronized (map) {
      return map instanceof TreeMap ? new TreeMap((TreeMap) map) : map instanceof LinkedHashMap ? new LinkedHashMap(map) : new HashMap(map);
    }
  }

  public static HashMap litmap(Object... x) {
    HashMap map = new HashMap();
    litmap_impl(map, x);
    return map;
  }

  public static void litmap_impl(Map map, Object... x) {
    for (int i = 0; i < x.length - 1; i += 2) if (x[i + 1] != null)
      map.put(x[i], x[i + 1]);
  }

  public static boolean even(int i) {
    return (i & 1) == 0;
  }

  public static boolean even(long i) {
    return (i & 1) == 0;
  }

  public static <A, B> LinkedHashMap<A, B> asLinkedHashMap(Map<A, B> map) {
    if (map instanceof LinkedHashMap)
      return (LinkedHashMap) map;
    LinkedHashMap<A, B> m = new LinkedHashMap();
    if (map != null)
      synchronized (collectionMutex(map)) {
        m.putAll(map);
      }
    return m;
  }

  public static Map paramsToMap(Object... params) {
    int n = l(params);
    if (l(params) == 1 && params[0] instanceof Map)
      return (Map) params[0];
    LinkedHashMap map = new LinkedHashMap();
    for (int i = 0; i + 1 < n; i += 2) mapPut(map, params[i], params[i + 1]);
    return map;
  }

  public static Object[] mapToObjectArray(Map map) {
    List l = new ArrayList();
    for (Object o : keys(map)) {
      l.add(o);
      l.add(map.get(o));
    }
    return toObjectArray(l);
  }

  public 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);";
      }
    };
  }

  public static Object callFunction(Object f, Object... args) {
    return callF(f, args);
  }

  public static volatile PersistableThrowable _handleException_lastException;

  public static List _handleException_onException = synchroList(ll("printStackTrace2"));

  public static void _handleException(Throwable e) {
    _handleException_lastException = persistableThrowable(e);
    Throwable e2 = innerException(e);
    if (e2.getClass() == RuntimeException.class && eq(e2.getMessage(), "Thread cancelled.") || e2 instanceof InterruptedException)
      return;
    for (Object f : cloneList(_handleException_onException)) try {
      callF(f, e);
    } catch (Throwable e3) {
      printStackTrace2(e3);
    }
  }

  public static JTextPane jcenteredtextpane() {
    return centerTextPane(jtextpane());
  }

  public static JTextPane jcenteredtextpane(String text, AttributeSet attributes) {
    return centerTextPane(jtextpane(text, attributes));
  }

  public static JTextPane jcenteredtextpane(String text) {
    return centerTextPane(jtextpane(text));
  }

  public static <A extends JComponent> A bindLiveValueListenerToComponent(A component, final LiveValue lv, final Runnable listener) {
    if (lv != null)
      bindToComponent(component, new Runnable() {

        public void run() {
          try {
            lv.onChangeAndNow(listener);
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "ifdef bindLiveValueListenerToComponent_debug\r\n          print(\"bindLiveValueL...";
        }
      }, new Runnable() {

        public void run() {
          try {
            lv.removeOnChangeListener(listener);
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "lv.removeOnChangeListener(listener)";
        }
      });
    return component;
  }

  public static <A extends JTextComponent> A setTextKeepCaret(final String text, final A c) {
    if (c != null) {
      swing(new Runnable() {

        public void run() {
          try {
            int caret = c.getCaretPosition();
            setText(c, text);
            setCaretPosition(c, caret);
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "int caret = c.getCaretPosition();\r\n    setText(c, text);\r\n    setCaretPositio...";
        }
      });
    }
    return c;
  }

  public static <A extends JTextComponent> A setTextKeepCaret(A c, String text) {
    return setTextKeepCaret(text, c);
  }

  public static void onChange(JSpinner spinner, Object r) {
    spinner.addChangeListener(changeListener(r));
  }

  public static <A extends AbstractButton> A onChange(A b, Object r) {
    b.addItemListener(itemListener(r));
    return b;
  }

  public static void onChange(JTextComponent tc, Object r) {
    onUpdate(tc, r);
  }

  public static void onChange(final JSlider slider, final Object r) {
    {
      swing(new Runnable() {

        public void run() {
          try {
            slider.addChangeListener(changeListener(r));
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "slider.addChangeListener(changeListener(r));";
        }
      });
    }
  }

  public static void onChange(JComboBox cb, final Object r) {
    if (isEditableComboBox(cb))
      onChange(textFieldFromComboBox(cb), r);
    else
      onSelectedItem(cb, new VF1<String>() {

        public void get(String s) {
          try {
            callF(r);
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "callF(r)";
        }
      });
  }

  public static Throwable printStackTrace(Throwable e) {
    print(getStackTrace(e));
    return e;
  }

  public static void printStackTrace() {
    printStackTrace(new Throwable());
  }

  public static void printStackTrace(String msg) {
    printStackTrace(new Throwable(msg));
  }

  public static void printStackTrace(String msg, Throwable e) {
    printStackTrace(new Throwable(msg, e));
  }

  public static void lockOrFail(Lock lock, long timeout) {
    try {
      ping();
      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);
      }
      ping();
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public static ReentrantLock fairLock() {
    return new ReentrantLock(true);
  }

  public 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);
  }

  public static int min(int a, int b) {
    return Math.min(a, b);
  }

  public static long min(long a, long b) {
    return Math.min(a, b);
  }

  public static float min(float a, float b) {
    return Math.min(a, b);
  }

  public static float min(float a, float b, float c) {
    return min(min(a, b), c);
  }

  public static double min(double a, double b) {
    return Math.min(a, b);
  }

  public static double min(double[] c) {
    double x = Double.MAX_VALUE;
    for (double d : c) x = Math.min(x, d);
    return x;
  }

  public static float min(float[] c) {
    float x = Float.MAX_VALUE;
    for (float d : c) x = Math.min(x, d);
    return x;
  }

  public static byte min(byte[] c) {
    byte x = 127;
    for (byte d : c) if (d < x)
      x = d;
    return x;
  }

  public static short min(short[] c) {
    short x = 0x7FFF;
    for (short d : c) if (d < x)
      x = d;
    return x;
  }

  public static int min(int[] c) {
    int x = Integer.MAX_VALUE;
    for (int d : c) if (d < x)
      x = d;
    return x;
  }

  public static <A> A[] makeArray(Class<A> type, int n) {
    return (A[]) Array.newInstance(type, n);
  }

  public static Object first(Object list) {
    return first((Iterable) list);
  }

  public static <A> A first(List<A> list) {
    return empty(list) ? null : list.get(0);
  }

  public static <A> A first(A[] bla) {
    return bla == null || bla.length == 0 ? null : bla[0];
  }

  public static <A> A first(Iterator<A> i) {
    return i == null || !i.hasNext() ? null : i.next();
  }

  public static <A> A first(Iterable<A> i) {
    if (i == null)
      return null;
    Iterator<A> it = i.iterator();
    return it.hasNext() ? it.next() : null;
  }

  public static Character first(String s) {
    return empty(s) ? null : s.charAt(0);
  }

  public static String getClassName(Object o) {
    return o == null ? "null" : o instanceof Class ? ((Class) o).getName() : o.getClass().getName();
  }

  public static Throwable printStackTrace2(Throwable e) {
    print(getStackTrace2(e));
    return e;
  }

  public static void printStackTrace2() {
    printStackTrace2(new Throwable());
  }

  public static void printStackTrace2(String msg) {
    printStackTrace2(new Throwable(msg));
  }

  public 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);
  }

  public static volatile boolean licensed_yes = true;

  public static boolean licensed() {
    if (!licensed_yes)
      return false;
    ping_okInCleanUp();
    return true;
  }

  public static void licensed_off() {
    licensed_yes = false;
  }

  public static ArrayList emptyList() {
    return new ArrayList();
  }

  public static ArrayList emptyList(int capacity) {
    return new ArrayList(max(0, capacity));
  }

  public static ArrayList emptyList(Iterable l) {
    return l instanceof Collection ? emptyList(((Collection) l).size()) : emptyList();
  }

  public static ArrayList emptyList(Object[] l) {
    return emptyList(l(l));
  }

  public static <A> ArrayList<A> emptyList(Class<A> c) {
    return new ArrayList();
  }

  public static Map emptyMap() {
    return new HashMap();
  }

  public static <A, B> B mapGet(Map<A, B> map, A a) {
    return map == null || a == null ? null : map.get(a);
  }

  public static <A, B> B mapGet(A a, Map<A, B> map) {
    return map == null || a == null ? null : map.get(a);
  }

  public static Dimension getPreferredSize(final Component c) {
    return c == null ? null : swing(new F0<Dimension>() {

      public Dimension get() {
        try {
          return c.getPreferredSize();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret c.getPreferredSize();";
      }
    });
  }

  public static int getHeight(Component c) {
    return c == null ? 0 : (int) swingCall(c, "getHeight");
  }

  public 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);
    throw fail("woot not int: " + getClassName(o));
  }

  public static int toInt(long l) {
    if (l != (int) l)
      throw fail("Too large for int: " + l);
    return (int) l;
  }

  public static ActionListener actionListener(final Object runnable) {
    return actionListener(runnable, null);
  }

  public 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 __371 = holdInstance(instanceToHold);
          try {
            callF(runnable);
          } finally {
            _close(__371);
          }
        } catch (Throwable __e) {
          messageBox(__e);
        }
      }
    };
  }

  public static Runnable wrapAsActivity(Object r) {
    return toRunnable(r);
  }

  public static Runnable toRunnable(final Object o) {
    if (o instanceof Runnable)
      return (Runnable) o;
    return new Runnable() {

      public void run() {
        try {
          callF(o);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "callF(o)";
      }
    };
  }

  public static AutoCloseable tempActivity(Object r) {
    return null;
  }

  public static boolean allPaused() {
    return ping_pauseAll;
  }

  public static void cancelTimer(javax.swing.Timer timer) {
    if (timer != null)
      timer.stop();
  }

  public static void cancelTimer(java.util.Timer timer) {
    if (timer != null)
      timer.cancel();
  }

  public 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) {
        _handleException(__e);
      }
    }
  }

  public static void _close(AutoCloseable c) {
    if (c != null)
      try {
        c.close();
      } catch (Throwable e) {
        if (c instanceof javax.imageio.stream.ImageOutputStream)
          return;
        else
          throw rethrow(e);
      }
  }

  public static void messageBox(final String msg) {
    if (headless())
      print(msg);
    else {
      swing(new Runnable() {

        public void run() {
          try {
            JOptionPane.showMessageDialog(null, msg, "JavaX", JOptionPane.INFORMATION_MESSAGE);
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "JOptionPane.showMessageDialog(null, msg, \"JavaX\", JOptionPane.INFORMATION_MES...";
        }
      });
    }
  }

  public static void messageBox(Throwable e) {
    printStackTrace(e);
    messageBox(hideCredentials(innerException2(e)));
  }

  public static void bindTimerToComponent(final Timer timer, JFrame f) {
    bindTimerToComponent(timer, f.getRootPane());
  }

  public 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) {
      }
    });
  }

  public static Object collectionMutex(Object o) {
    String c = className(o);
    if (eq(c, "java.util.TreeMap$KeySet"))
      c = className(o = getOpt(o, "m"));
    else if (eq(c, "java.util.HashMap$KeySet"))
      c = className(o = get_raw(o, "this$0"));
    if (eqOneOf(c, "java.util.TreeMap$AscendingSubMap", "java.util.TreeMap$DescendingSubMap"))
      c = className(o = get_raw(o, "m"));
    return o;
  }

  public static <A, B> void mapPut(Map<A, B> map, A key, B value) {
    if (map != null && key != null && value != null)
      map.put(key, value);
  }

  public static <A, B> Set<A> keys(Map<A, B> map) {
    return map == null ? new HashSet() : map.keySet();
  }

  public static Set keys(Object map) {
    return keys((Map) map);
  }

  public static Object[] toObjectArray(Collection c) {
    List l = asList(c);
    return l.toArray(new Object[l.size()]);
  }

  public static Runnable asRunnable(Object o) {
    return toRunnable(o);
  }

  public static void _inheritThreadInfo(Object info) {
    _threadInheritInfo(info);
  }

  public static <A> List<A> synchroList() {
    return Collections.synchronizedList(new ArrayList<A>());
  }

  public static <A> List<A> synchroList(List<A> l) {
    return Collections.synchronizedList(l);
  }

  public static <A> List<A> ll(A... a) {
    ArrayList l = new ArrayList(a.length);
    for (A x : a) l.add(x);
    return l;
  }

  public static PersistableThrowable persistableThrowable(Throwable e) {
    return e == null ? null : new PersistableThrowable(e);
  }

  public static Throwable innerException(Throwable e) {
    return getInnerException(e);
  }

  public static <A> ArrayList<A> cloneList(Iterable<A> l) {
    return l instanceof Collection ? cloneList((Collection) l) : asList(l);
  }

  public static <A> ArrayList<A> cloneList(Collection<A> l) {
    if (l == null)
      return new ArrayList();
    synchronized (collectionMutex(l)) {
      return new ArrayList<A>(l);
    }
  }

  public static JTextPane centerTextPane(JTextPane p) {
    textPane_paragraphAttributes(p, style_center());
    return p;
  }

  public static JTextPane jtextpane() {
    return jenableUndoRedo(swing(new F0<JTextPane>() {

      public JTextPane get() {
        try {
          return new JTextPane();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret new JTextPane;";
      }
    }));
  }

  public static JTextPane jtextpane(String text, AttributeSet attributes) {
    JTextPane pane = jtextpane();
    pane.setCharacterAttributes(attributes, true);
    pane.setText(text);
    return pane;
  }

  public static JTextPane jtextpane(String text) {
    return jtextpane(text, style_normal());
  }

  public static boolean setText_opt = true;

  public static <A extends JTextComponent> A setText(A c, Object text) {
    setText((JComponent) c, text);
    return c;
  }

  public static <A extends JComboBox> A setText(final A c, Object text) {
    final String s = strUnnull(text);
    {
      swing(new Runnable() {

        public void run() {
          try {
            c.getEditor().setItem(s);
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "c.getEditor().setItem(s);";
        }
      });
    }
    return c;
  }

  public static void setText(JLabel c, Object text) {
    setText((JComponent) c, text);
  }

  public static JButton setText(JButton c, Object text) {
    setText((JComponent) c, jlabel_textAsHTML_center_ifNeeded(strUnnull(text)));
    return c;
  }

  public static <A extends JComponent> A setText(final A c, Object text) {
    if (c == null)
      return null;
    final String s = strUnnull(text);
    {
      swing(new Runnable() {

        public void run() {
          try {
            if (!setText_opt || neq(callOpt(c, "getText"), s))
              call(c, "setText", s);
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "if (!setText_opt || neq(callOpt(c, \"getText\"), s))\r\n      call(c, \"setText\", s);";
        }
      });
    }
    return c;
  }

  public static void setCaretPosition(final JTextComponent c, final int pos) {
    if (c != null) {
      swing(new Runnable() {

        public void run() {
          try {
            try {
              int _pos = max(0, min(l(c.getText()), pos));
              c.setCaretPosition(_pos);
            } catch (Throwable __e) {
              _handleException(__e);
            }
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "pcall {\r\n      int _pos = max(0, min(l(c.getText()), pos));\r\n      c.setCaret...";
        }
      });
    }
  }

  public static ChangeListener changeListener(final Object r) {
    return new ChangeListener() {

      public void stateChanged(ChangeEvent e) {
        pcallF(r);
      }
    };
  }

  public static ItemListener itemListener(final Object r) {
    return new ItemListener() {

      public void itemStateChanged(ItemEvent e) {
        pcallF(r);
      }
    };
  }

  public static void onUpdate(JComponent c, final Object r) {
    if (c instanceof JTextComponent)
      ((JTextComponent) c).getDocument().addDocumentListener(new DocumentListener() {

        public void insertUpdate(DocumentEvent e) {
          call(r);
        }

        public void removeUpdate(DocumentEvent e) {
          call(r);
        }

        public void changedUpdate(DocumentEvent e) {
          call(r);
        }
      });
    else if (c instanceof ItemSelectable)
      ((ItemSelectable) c).addItemListener(new ItemListener() {

        public void itemStateChanged(ItemEvent e) {
          call(r);
        }
      });
    else
      print("Warning: onUpdate doesn't know " + getClassName(c));
  }

  public static void onUpdate(List<? extends JComponent> l, Object r) {
    for (JComponent c : l) onUpdate(c, r);
  }

  public static JTextField textFieldFromComboBox(JComboBox cb) {
    return (JTextField) cb.getEditor().getEditorComponent();
  }

  public static JComboBox onSelectedItem(final JComboBox cb, final VF1<String> f) {
    addActionListener(cb, new Runnable() {

      public void run() {
        try {
          pcallF(f, selectedItem(cb));
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "pcallF(f, selectedItem(cb))";
      }
    });
    return cb;
  }

  public static String getStackTrace(Throwable throwable) {
    lastException(throwable);
    return getStackTrace_noRecord(throwable);
  }

  public static String getStackTrace_noRecord(Throwable throwable) {
    StringWriter writer = new StringWriter();
    throwable.printStackTrace(new PrintWriter(writer));
    return hideCredentials(writer.toString());
  }

  public static String getStackTrace() {
    return getStackTrace_noRecord(new Throwable());
  }

  public static String getStackTrace2(Throwable e) {
    return hideCredentials(getStackTrace(unwrapTrivialExceptionWraps(e)) + replacePrefix("java.lang.RuntimeException: ", "FAIL: ", hideCredentials(str(innerException2(e)))) + "\n");
  }

  public static long parseLong(String s) {
    if (s == null)
      return 0;
    return Long.parseLong(dropSuffix("L", s));
  }

  public static long parseLong(Object s) {
    return Long.parseLong((String) s);
  }

  public static int max(int a, int b) {
    return Math.max(a, b);
  }

  public static int max(int a, int b, int c) {
    return max(max(a, b), c);
  }

  public static long max(int a, long b) {
    return Math.max((long) a, b);
  }

  public static long max(long a, long b) {
    return Math.max(a, b);
  }

  public static double max(int a, double b) {
    return Math.max((double) a, b);
  }

  public static float max(float a, float b) {
    return Math.max(a, b);
  }

  public static double max(double a, double b) {
    return Math.max(a, b);
  }

  public static int max(Collection<Integer> c) {
    int x = Integer.MIN_VALUE;
    for (int i : c) x = max(x, i);
    return x;
  }

  public 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;
  }

  public 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;
  }

  public static byte max(byte[] c) {
    byte x = -128;
    for (byte d : c) if (d > x)
      x = d;
    return x;
  }

  public static short max(short[] c) {
    short x = -0x8000;
    for (short d : c) if (d > x)
      x = d;
    return x;
  }

  public static int max(int[] c) {
    int x = Integer.MIN_VALUE;
    for (int d : c) if (d > x)
      x = d;
    return x;
  }

  public static Object swingCall(final Object o, final String method, final Object... args) {
    return swing(new F0<Object>() {

      public Object get() {
        try {
          return call(o, method, args);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret call(o, method, args);";
      }
    });
  }

  public static int parseInt(String s) {
    return empty(s) ? 0 : Integer.parseInt(s);
  }

  public static int parseInt(char c) {
    return Integer.parseInt(str(c));
  }

  public static ThreadLocal<List<Object>> holdInstance_l = new ThreadLocal();

  public static AutoCloseable holdInstance(Object o) {
    if (o == null)
      return null;
    listThreadLocalAdd(holdInstance_l, o);
    return new AutoCloseable() {

      public void close() {
        listThreadLocalPopLast(holdInstance_l);
      }
    };
  }

  public static boolean headless() {
    return isHeadless();
  }

  public static String hideCredentials(URL url) {
    return url == null ? null : hideCredentials(str(url));
  }

  public static String hideCredentials(String url) {
    return url.replaceAll("([&?])(_pass|key)=[^&\\s\"]*", "$1$2=<hidden>");
  }

  public static String hideCredentials(Object o) {
    return hideCredentials(str(o));
  }

  public static Throwable innerException2(Throwable e) {
    if (e == null)
      return null;
    while (empty(e.getMessage()) && e.getCause() != null) e = e.getCause();
    return e;
  }

  public static String className(Object o) {
    return getClassName(o);
  }

  public static boolean eqOneOf(Object o, Object... l) {
    for (Object x : l) if (eq(o, x))
      return true;
    return false;
  }

  public static Throwable getInnerException(Throwable e) {
    if (e == null)
      return null;
    while (e.getCause() != null) e = e.getCause();
    return e;
  }

  public static Throwable getInnerException(Runnable r) {
    return getInnerException(getException(r));
  }

  public static void textPane_paragraphAttributes(JTextPane p, AttributeSet attributes) {
    try {
      StyledDocument doc = p.getStyledDocument();
      doc.setParagraphAttributes(0, doc.getLength(), attributes, false);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public static SimpleAttributeSet style_center() {
    return style_center(new SimpleAttributeSet());
  }

  public static SimpleAttributeSet style_center(SimpleAttributeSet a) {
    StyleConstants.setAlignment(a, StyleConstants.ALIGN_CENTER);
    return a;
  }

  public static <A extends JTextComponent> A jenableUndoRedo(final A textcomp) {
    {
      swing(new Runnable() {

        public void run() {
          try {
            final UndoManager undo = new UndoManager();
            vm_generalWeakSet("Undo Managers").add(undo);
            textcomp.getDocument().addUndoableEditListener(new UndoableEditListener() {

              public void undoableEditHappened(UndoableEditEvent evt) {
                undo.addEdit(evt.getEdit());
              }
            });
            textcomp.getActionMap().put("Undo", abstractAction("Undo", new Runnable() {

              public void run() {
                try {
                  if (undo.canUndo())
                    undo.undo();
                } catch (Exception __e) {
                  throw rethrow(__e);
                }
              }

              public String toString() {
                return "if (undo.canUndo()) undo.undo()";
              }
            }));
            textcomp.getActionMap().put("Redo", abstractAction("Redo", new Runnable() {

              public void run() {
                try {
                  if (undo.canRedo())
                    undo.redo();
                } catch (Exception __e) {
                  throw rethrow(__e);
                }
              }

              public String toString() {
                return "if (undo.canRedo()) undo.redo()";
              }
            }));
            textcomp.getInputMap().put(KeyStroke.getKeyStroke("control Z"), "Undo");
            textcomp.getInputMap().put(KeyStroke.getKeyStroke("control Y"), "Redo");
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "final new UndoManager undo;\r\n    vm_generalWeakSet(\"Undo Managers\").add(undo)...";
        }
      });
    }
    return textcomp;
  }

  public static SimpleAttributeSet style_normal() {
    return new SimpleAttributeSet();
  }

  public static String strUnnull(Object o) {
    return o == null ? "" : str(o);
  }

  public static String jlabel_textAsHTML_center_ifNeeded(String text) {
    if (swic(text, "<html>") && ewic(text, "</html>"))
      return text;
    if (!containsNewLines(text))
      return text;
    return jlabel_textAsHTML_center(text);
  }

  public static void addActionListener(JTextField tf, final Runnable action) {
    onEnter(tf, action);
  }

  public static void addActionListener(final JComboBox cb, final Runnable action) {
    if (cb != null) {
      swing(new Runnable() {

        public void run() {
          try {
            cb.addActionListener(actionListener(action));
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "cb.addActionListener(actionListener(action));";
        }
      });
    }
  }

  public static void addActionListener(final AbstractButton b, final Runnable action) {
    if (b != null) {
      swing(new Runnable() {

        public void run() {
          try {
            b.addActionListener(actionListener(action));
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "b.addActionListener(actionListener(action));";
        }
      });
    }
  }

  public static String selectedItem(JList l) {
    return getSelectedItem(l);
  }

  public static String selectedItem(JComboBox cb) {
    return getSelectedItem(cb);
  }

  public static volatile PersistableThrowable lastException_lastException;

  public static PersistableThrowable lastException() {
    return lastException_lastException;
  }

  public static void lastException(Throwable e) {
    lastException_lastException = persistableThrowable(e);
  }

  public static Throwable unwrapTrivialExceptionWraps(Throwable e) {
    if (e == null)
      return e;
    while (e.getClass() == RuntimeException.class && e.getCause() != null && eq(e.getMessage(), str(e.getCause()))) e = e.getCause();
    return e;
  }

  public static String replacePrefix(String prefix, String replacement, String s) {
    if (!startsWith(s, prefix))
      return s;
    return replacement + substring(s, l(prefix));
  }

  public static String dropSuffix(String suffix, String s) {
    return s.endsWith(suffix) ? s.substring(0, l(s) - l(suffix)) : s;
  }

  public static <A> void listThreadLocalAdd(ThreadLocal<List<A>> tl, A a) {
    List<A> l = tl.get();
    if (l == null)
      tl.set(l = new ArrayList());
    l.add(a);
  }

  public static <A> A listThreadLocalPopLast(ThreadLocal<List<A>> tl) {
    List<A> l = tl.get();
    if (l == null)
      return null;
    A a = popLast(l);
    if (empty(l))
      tl.set(null);
    return a;
  }

  public static Throwable getException(Runnable r) {
    try {
      callF(r);
      return null;
    } catch (Throwable e) {
      return e;
    }
  }

  public static Set vm_generalWeakSet(Object name) {
    synchronized (get(javax(), "generalMap")) {
      Set set = (Set) (vm_generalMap_get(name));
      if (set == null)
        vm_generalMap_put(name, set = newWeakHashSet());
      return set;
    }
  }

  public static AbstractAction abstractAction(String name, final Object runnable) {
    return new AbstractAction(name) {

      public void actionPerformed(ActionEvent evt) {
        pcallF(runnable);
      }
    };
  }

  public static boolean swic(String a, String b) {
    return startsWithIgnoreCase(a, b);
  }

  public 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;
  }

  public static boolean ewic(String a, String b) {
    return endsWithIgnoreCase(a, b);
  }

  public static boolean ewic(String a, String b, Matches m) {
    return endsWithIgnoreCase(a, b, m);
  }

  public static boolean containsNewLines(String s) {
    return containsNewLine(s);
  }

  public static String jlabel_textAsHTML_center(String text) {
    return "<html><div style=\"text-align: center;\">" + replace(htmlencode(text), "\n", "<br>") + "</div></html>";
  }

  public static JTextField onEnter(final JTextField tf, final Object action) {
    if (action == null || tf == null)
      return tf;
    tf.addActionListener(new java.awt.event.ActionListener() {

      public void actionPerformed(java.awt.event.ActionEvent _evt) {
        try {
          tf.selectAll();
          callF(action);
        } catch (Throwable __e) {
          messageBox(__e);
        }
      }
    });
    return tf;
  }

  public static JButton onEnter(JButton btn, final Object action) {
    if (action == null || btn == null)
      return btn;
    btn.addActionListener(actionListener(action));
    return btn;
  }

  public static JList onEnter(JList list, Object action) {
    list.addKeyListener(enterKeyListener(rCallOnSelectedListItem(list, action)));
    return list;
  }

  public static JComboBox onEnter(final JComboBox cb, final Object action) {
    {
      swing(new Runnable() {

        public void run() {
          try {
            if (cb.isEditable()) {
              JTextField text = (JTextField) cb.getEditor().getEditorComponent();
              onEnter(text, action);
            } else {
              cb.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "enter");
              cb.getActionMap().put("enter", abstractAction("", new Runnable() {

                public void run() {
                  try {
                    cb.hidePopup();
                    callF(action);
                  } catch (Exception __e) {
                    throw rethrow(__e);
                  }
                }

                public String toString() {
                  return "cb.hidePopup(); callF(action);";
                }
              }));
            }
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "if (cb.isEditable()) {\r\n      JTextField text = (JTextField) cb.getEditor().g...";
        }
      });
    }
    return cb;
  }

  public static JTable onEnter(final JTable table, final Object action) {
    table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Enter");
    table.getActionMap().put("Enter", new AbstractAction() {

      public void actionPerformed(ActionEvent e) {
        callF(action, table.getSelectedRow());
      }
    });
    return table;
  }

  public static JTextField onEnter(Object action, JTextField tf) {
    return onEnter(tf, action);
  }

  public static String getSelectedItem(JList l) {
    return (String) l.getSelectedValue();
  }

  public static String getSelectedItem(JComboBox cb) {
    return strOrNull(cb.getSelectedItem());
  }

  public static <A> A popLast(List<A> l) {
    return liftLast(l);
  }

  public static Object vm_generalMap_get(Object key) {
    return vm_generalMap().get(key);
  }

  public static Object vm_generalMap_put(Object key, Object value) {
    return mapPutOrRemove(vm_generalMap(), key, value);
  }

  public static <A> Set<A> newWeakHashSet() {
    return synchroWeakHashSet();
  }

  public static boolean startsWithIgnoreCase(String a, String b) {
    return regionMatchesIC(a, 0, b, 0, b.length());
  }

  public static boolean endsWithIgnoreCase(String a, String b) {
    int la = l(a), lb = l(b);
    return la >= lb && regionMatchesIC(a, la - lb, b, 0, lb);
  }

  public static boolean endsWithIgnoreCase(String a, String b, Matches m) {
    if (!endsWithIgnoreCase(a, b))
      return false;
    m.m = new String[] { substring(a, 0, l(a) - l(b)) };
    return true;
  }

  public static boolean containsNewLine(String s) {
    return contains(s, '\n');
  }

  public static <A> List<A> replace(List<A> 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;
  }

  public static String replace(String s, String a, String b) {
    return s == null ? null : a == null || b == null ? s : s.replace(a, b);
  }

  public static String replace(String s, char a, char b) {
    return s == null ? null : s.replace(a, b);
  }

  public static String htmlencode(Object o) {
    return htmlencode(str(o));
  }

  public static String htmlencode(String s) {
    if (s == null)
      return "";
    StringBuilder out = new StringBuilder(Math.max(16, s.length()));
    for (int i = 0; i < s.length(); i++) {
      char c = s.charAt(i);
      if (c > 127 || c == '"' || c == '<' || c == '>' || c == '&')
        out.append("&#").append((int) c).append(';');
      else
        out.append(c);
    }
    return out.toString();
  }

  public static KeyListener enterKeyListener(final Object action) {
    return new KeyAdapter() {

      public void keyPressed(KeyEvent ke) {
        if (ke.getKeyCode() == KeyEvent.VK_ENTER)
          pcallF(action);
      }
    };
  }

  public static Runnable rCallOnSelectedListItem(final JList list, final Object action) {
    return new Runnable() {

      public void run() {
        try {
          pcallF(action, getSelectedItem(list));
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "pcallF(action, getSelectedItem(list))";
      }
    };
  }

  public static String strOrNull(Object o) {
    return o == null ? null : str(o);
  }

  public static <A> A liftLast(List<A> l) {
    if (l.isEmpty())
      return null;
    int i = l(l) - 1;
    A a = l.get(i);
    l.remove(i);
    return a;
  }

  public static Map vm_generalMap_map;

  public static Map vm_generalMap() {
    if (vm_generalMap_map == null)
      vm_generalMap_map = (Map) get(javax(), "generalMap");
    return vm_generalMap_map;
  }

  public static <A, B> B mapPutOrRemove(Map<A, B> 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;
  }

  public static <A> Set<A> synchroWeakHashSet() {
    return Collections.newSetFromMap((Map) newWeakHashMap());
  }

  public static boolean regionMatchesIC(String a, int offsetA, String b, int offsetB, int len) {
    return a != null && a.regionMatches(true, offsetA, b, offsetB, len);
  }

  public static boolean contains(Collection c, Object o) {
    return c != null && c.contains(o);
  }

  public static boolean contains(Object[] x, Object o) {
    if (x != null)
      for (Object a : x) if (eq(a, o))
        return true;
    return false;
  }

  public static boolean contains(String s, char c) {
    return s != null && s.indexOf(c) >= 0;
  }

  public static boolean contains(String s, String b) {
    return s != null && s.indexOf(b) >= 0;
  }

  public static boolean contains(BitSet bs, int i) {
    return bs != null && bs.get(i);
  }

  public static final class _MethodCache {

    public final Class c;

    public final HashMap<String, List<Method>> cache = new HashMap();

    public _MethodCache(Class c) {
      this.c = c;
      _init();
    }

    public void _init() {
      Class _c = c;
      while (_c != null) {
        for (Method m : _c.getDeclaredMethods()) if (!reflection_isForbiddenMethod(m))
          multiMapPut(cache, m.getName(), makeAccessible(m));
        _c = _c.getSuperclass();
      }
      for (Class intf : allInterfacesImplementedBy(c)) for (Method m : intf.getDeclaredMethods()) if (m.isDefault() && !reflection_isForbiddenMethod(m))
        multiMapPut(cache, m.getName(), makeAccessible(m));
    }

    public Method findMethod(String method, Object[] args) {
      try {
        List<Method> m = cache.get(method);
        if (m == null)
          return null;
        int n = m.size();
        for (int i = 0; i < n; i++) {
          Method me = m.get(i);
          if (call_checkArgs(me, args, false))
            return me;
        }
        return null;
      } catch (Exception __e) {
        throw rethrow(__e);
      }
    }

    public Method findStaticMethod(String method, Object[] args) {
      try {
        List<Method> 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);
      }
    }
  }

  public static class SimpleLiveValue<A> extends LiveValue<A> {

    public Class<A> type;

    public volatile A value;

    public transient List onChange = synchroList();

    public SimpleLiveValue(Class<A> type) {
      this.type = type;
    }

    public SimpleLiveValue(Class<A> type, A value) {
      this.value = value;
      this.type = type;
    }

    public Class<A> getType() {
      return type;
    }

    public A get() {
      return value;
    }

    public void onChange(Runnable l) {
      onChange.add(l);
    }

    public void onChangeAndNow(Runnable l) {
      onChange(l);
      callF(l);
    }

    public void removeOnChangeListener(Runnable l) {
      onChange.remove(l);
    }

    public void fireChanged() {
      pcallFAll(onChange);
    }

    public void set(A a) {
      if (neq(value, a)) {
        value = a;
        fireChanged();
      }
    }
  }

  public static class Var<A> implements IVar<A> {

    public A v;

    public Var() {
    }

    public Var(A v) {
      this.v = v;
    }

    public synchronized void set(A a) {
      if (v != a) {
        v = a;
        notifyAll();
      }
    }

    public synchronized A get() {
      return v;
    }

    public synchronized boolean has() {
      return v != null;
    }

    public synchronized void clear() {
      v = null;
    }

    public String toString() {
      return str(get());
    }
  }

  public static class ReliableSingleThread implements Runnable {

    public Object runnable;

    public boolean trigger;

    public Thread thread;

    public String name = "Single Thread";

    public F0<AutoCloseable> enter;

    public ReliableSingleThread(Object runnable) {
      this.runnable = runnable;
    }

    public void trigger() {
      go();
    }

    public synchronized void go() {
      trigger = true;
      if (!running()) {
        AutoCloseable __1353 = callF(enter);
        try {
          thread = startThread(name, new Runnable() {

            public void run() {
              try {
                AutoCloseable __1354 = callF(enter);
                try {
                  _run();
                } finally {
                  _close(__1354);
                }
              } catch (Exception __e) {
                throw rethrow(__e);
              }
            }

            public String toString() {
              return "AutoCloseable __1354 = callF(enter); try {\r\n        _run();\r\n      } finally ...";
            }
          });
        } finally {
          _close(__1353);
        }
      }
    }

    public void run() {
      go();
    }

    public void get() {
      go();
    }

    public synchronized boolean running() {
      return thread != null;
    }

    public void triggerAndWait() {
      trigger();
      while (running()) sleep(1);
    }

    public void _run() {
      while (licensed()) {
        synchronized (this) {
          if (!trigger) {
            thread = null;
            break;
          }
          trigger = false;
        }
        pcallF(runnable);
      }
    }

    public synchronized void cancel() {
      cancelAndInterruptThread(thread);
      thread = null;
    }
  }

  public abstract static class LiveValue<A> {

    public abstract Class<A> getType();

    public abstract A get();

    public abstract void onChange(Runnable l);

    public abstract void removeOnChangeListener(Runnable l);

    public void onChangeAndNow(Runnable l) {
      onChange(l);
      callF(l);
    }
  }

  public static class Dyn_FieldWatcher {

    public DynModule module;

    public String field;

    public Object value;

    public Runnable action;

    public Dyn_FieldWatcher(DynModule module, String field, Runnable action) {
      this.action = action;
      this.field = field;
      this.module = module;
      value = get(module, field);
      module.onChange(new Runnable() {

        public void run() {
          try {
            check();
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "check();";
        }
      });
    }

    public void check() {
      Object newValue = get(module, field);
      if (eq(value, newValue))
        return;
      value = newValue;
      dm_q(module, action);
    }
  }

  public static class Flag implements Runnable {

    public boolean up;

    public synchronized boolean raise() {
      if (!up) {
        up = true;
        notifyAll();
        return true;
      } else
        return false;
    }

    public synchronized void waitUntilUp() {
      while (!up) {
        try {
          wait();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }

    public synchronized void waitUntilUp(long timeout) {
      if (!up) {
        try {
          wait(timeout);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }

    public synchronized boolean isUp() {
      return up;
    }

    public boolean get() {
      return isUp();
    }

    public String toString() {
      return isUp() ? "up" : "down";
    }

    public void waitForThisOr(Flag otherFlag) {
      try {
        while (!isUp() && !otherFlag.isUp()) Thread.sleep(50);
      } catch (Exception __e) {
        throw rethrow(__e);
      }
    }

    public void run() {
      raise();
    }
  }

  public static interface IVar<A> {

    public void set(A a);

    public A get();

    public boolean has();

    public void clear();
  }

  public static boolean reflection_isForbiddenMethod(Method m) {
    return m.getDeclaringClass() == Object.class && eqOneOf(m.getName(), "finalize", "clone", "registerNatives");
  }

  public static <A, B> void multiMapPut(Map<A, List<B>> map, A a, B b) {
    List<B> l = map.get(a);
    if (l == null)
      map.put(a, l = new ArrayList());
    l.add(b);
  }

  public static Field makeAccessible(Field f) {
    f.setAccessible(true);
    return f;
  }

  public static Method makeAccessible(Method m) {
    m.setAccessible(true);
    return m;
  }

  public static Set<Class> allInterfacesImplementedBy(Class c) {
    if (c == null)
      return null;
    HashSet<Class> set = new HashSet();
    allInterfacesImplementedBy_find(c, set);
    return set;
  }

  public static void allInterfacesImplementedBy_find(Class c, Set<Class> set) {
    if (c.isInterface() && !set.add(c))
      return;
    do {
      for (Class intf : c.getInterfaces()) allInterfacesImplementedBy_find(intf, set);
    } while ((c = c.getSuperclass()) != null);
  }

  public static Method findMethod(Object o, String method, Object... args) {
    return findMethod_cached(o, method, args);
  }

  public static boolean findMethod_checkArgs(Method m, Object[] args, boolean debug) {
    Class<?>[] types = m.getParameterTypes();
    if (types.length != args.length) {
      if (debug)
        System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
      return false;
    }
    for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
      if (debug)
        System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
      return false;
    }
    return true;
  }

  public static boolean call_checkArgs(Method m, Object[] args, boolean debug) {
    Class<?>[] types = m.getParameterTypes();
    if (types.length != args.length) {
      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;
  }

  public static Method findStaticMethod(Class c, String method, Object... args) {
    Class _c = c;
    while (c != null) {
      for (Method m : c.getDeclaredMethods()) {
        if (!m.getName().equals(method))
          continue;
        if ((m.getModifiers() & Modifier.STATIC) == 0 || !findStaticMethod_checkArgs(m, args))
          continue;
        return m;
      }
      c = c.getSuperclass();
    }
    return null;
  }

  public static boolean findStaticMethod_checkArgs(Method m, Object[] args) {
    Class<?>[] types = m.getParameterTypes();
    if (types.length != args.length)
      return false;
    for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i])))
      return false;
    return true;
  }

  public static void pcallFAll(Collection l, Object... args) {
    if (l != null)
      for (Object f : cloneList(l)) pcallF(f, args);
  }

  public static void pcallFAll(Iterator it, Object... args) {
    while (it.hasNext()) pcallF(it.next(), args);
  }

  public static Thread startThread(Object runnable) {
    return startThread(defaultThreadName(), runnable);
  }

  public static Thread startThread(String name, Object runnable) {
    runnable = wrapAsActivity(runnable);
    return startThread(newThread(toRunnable(runnable), name));
  }

  public static Thread startThread(Thread t) {
    _registerThread(t);
    t.start();
    return t;
  }

  public static Class _run(String progID, String... args) {
    Class main = hotwire(progID);
    callMain(main, args);
    return main;
  }

  public static volatile boolean sleep_noSleep;

  public static void sleep(long ms) {
    ping();
    if (ms < 0)
      return;
    if (isAWTThread() && ms > 100)
      throw fail("Should not sleep on AWT thread");
    try {
      Thread.sleep(ms);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  public static void sleep() {
    try {
      if (sleep_noSleep)
        throw fail("nosleep");
      print("Sleeping.");
      sleepQuietly();
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public static void cancelAndInterruptThread(Thread t) {
    if (t == null)
      return;
    cancelThread(t);
    t.interrupt();
  }

  public static Q dm_q() {
    return dm_current_mandatory().q();
  }

  public static void dm_q(Runnable r) {
    dm_inQ(r);
  }

  public static void dm_q(DynModule module, Runnable r) {
    module.q().add(r);
  }

  public static Method findMethod_cached(Object o, String method, Object... args) {
    try {
      if (o == null)
        return null;
      if (o instanceof Class) {
        _MethodCache cache = callOpt_getCache(((Class) o));
        List<Method> methods = cache.cache.get(method);
        if (methods != null)
          for (Method m : methods) if (isStaticMethod(m) && findMethod_checkArgs(m, args, false))
            return m;
        return null;
      } else {
        _MethodCache cache = callOpt_getCache(o.getClass());
        List<Method> methods = cache.cache.get(method);
        if (methods != null)
          for (Method m : methods) if (findMethod_checkArgs(m, args, false))
            return m;
        return null;
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public static String defaultThreadName_name;

  public static String defaultThreadName() {
    if (defaultThreadName_name == null)
      defaultThreadName_name = "A thread by " + programID();
    return defaultThreadName_name;
  }

  public static Thread newThread(Object runnable) {
    return new Thread(_topLevelErrorHandling(toRunnable(runnable)));
  }

  public static Thread newThread(Object runnable, String name) {
    if (name == null)
      name = defaultThreadName();
    return new Thread(_topLevelErrorHandling(toRunnable(runnable)), name);
  }

  public static Thread newThread(String name, Object runnable) {
    return newThread(runnable, name);
  }

  public static Map<Thread, Boolean> _registerThread_threads;

  public static Object _onRegisterThread;

  public static Thread _registerThread(Thread t) {
    if (_registerThread_threads == null)
      _registerThread_threads = newWeakHashMap();
    _registerThread_threads.put(t, true);
    vm_generalWeakSubMap("thread2mc").put(t, weakRef(mc()));
    callF(_onRegisterThread, t);
    return t;
  }

  public static void _registerThread() {
    _registerThread(Thread.currentThread());
  }

  public static Class<?> hotwire(String src) {
    assertFalse(_inCore());
    Class j = getJavaX();
    if (isAndroid()) {
      synchronized (j) {
        List<File> libraries = new ArrayList<File>();
        File srcDir = (File) call(j, "transpileMain", src, libraries);
        if (srcDir == null)
          throw fail("transpileMain returned null (src=" + quote(src) + ")");
        Object androidContext = get(j, "androidContext");
        return (Class) call(j, "loadx2android", srcDir, src);
      }
    } else {
      Class c = (Class) (call(j, "hotwire", src));
      hotwire_copyOver(c);
      return c;
    }
  }

  public static <A> A callMain(A c, String... args) {
    callOpt(c, "main", new Object[] { args });
    return c;
  }

  public static void callMain() {
    callMain(mc());
  }

  public static Object sleepQuietly_monitor = new Object();

  public static void sleepQuietly() {
    try {
      assertFalse(isAWTThread());
      synchronized (sleepQuietly_monitor) {
        sleepQuietly_monitor.wait();
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public static void cancelThread(Thread t) {
    if (t == null)
      return;
    ping();
    synchronized (ping_actions) {
      ping_actions.put(t, "cancelled");
      ping_anyActions = true;
    }
  }

  public static void dm_inQ(Runnable r) {
    dm_q().add(r);
  }

  public static Runnable _topLevelErrorHandling(final Runnable runnable) {
    final Object info = _threadInfo();
    return new Runnable() {

      public void run() {
        try {
          try {
            _threadInheritInfo(info);
            runnable.run();
          } catch (Throwable __e) {
            _handleException(__e);
          }
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "pcall {\r\n      _threadInheritInfo(info);\r\n      runnable.run();\r\n    }";
      }
    };
  }

  public static <A> WeakReference<A> weakRef(A a) {
    return newWeakReference(a);
  }

  public static boolean _inCore() {
    return false;
  }

  public static String quote(Object o) {
    if (o == null)
      return "null";
    return quote(str(o));
  }

  public static String quote(String s) {
    if (s == null)
      return "null";
    StringBuilder out = new StringBuilder((int) (l(s) * 1.5 + 2));
    quote_impl(s, out);
    return out.toString();
  }

  public static void quote_impl(String s, StringBuilder out) {
    out.append('"');
    int l = s.length();
    for (int i = 0; i < l; i++) {
      char c = s.charAt(i);
      if (c == '\\' || c == '"')
        out.append('\\').append(c);
      else if (c == '\r')
        out.append("\\r");
      else if (c == '\n')
        out.append("\\n");
      else if (c == '\0')
        out.append("\\0");
      else
        out.append(c);
    }
    out.append('"');
  }

  public static List hotwire_copyOver_after = synchroList();

  public static void hotwire_copyOver(Class c) {
    for (String field : ll("print_log", "print_silent", "androidContext", "_userHome")) setOptIfNotNull(c, field, getOpt(mc(), field));
    setOptIfNotNull(c, "mainBot", getMainBot());
    setOpt(c, "creator_class", new WeakReference(mc()));
    pcallFAll(hotwire_copyOver_after, c);
  }

  public static <A> WeakReference<A> newWeakReference(A a) {
    return a == null ? null : new WeakReference(a);
  }

  public static void setOptIfNotNull(Object o, String field, Object value) {
    if (value != null)
      setOpt(o, field, value);
  }

  public static Object mainBot;

  public static Object getMainBot() {
    return mainBot;
  }
}