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 java.text.NumberFormat;
class main {
static Set webSockets = synchroHashSet();
static long counter;

public static void main(final String[] args) throws Exception {
  replaceCollection(webSockets, subBot_getMyWebSockets());
  print("Have " + n2(webSockets, "web socket") + ".");
  doEvery(1000, "count");
}

static Object html(String uri, final Map<String, String> params) { try {

  return loadJQuery()
    + "Counting:"
    + hdiv("", "id" , "results")
    + hreconnectingWebSockets()
    + hjavascript("\n      var ws = new ReconnectingWebSocket(\"${URI}\");\n      ws.onmessage = function(event) {\n        var d = event.data;\n        $(\"#results\").html(d);\n      };\n    ".replace("${URI}", subBot_myWebSocketURI()));
} catch (Exception __e) { throw rethrow(__e); } }

static void count() {
  ++counter;
  if (empty(webSockets)) return;
  print("Sending " + counter + " to " + n2(webSockets, "socket"));
  for (Object ws : webSockets)
    pcall(ws, "send", str(counter));
}

static void onNewWebSocket(Object ws, String uri) {
  print("New web socket!");
  webSockets.add(ws);
}

static void onWebSocketMessage(Object ws, String msg) {
  print("Got message: " + msg);
}

static void onWebSocketClosed(Object ws) {
  print("Closed web socket");
  webSockets.remove(ws);
}
static RuntimeException rethrow(Throwable t) {
  
  if (t instanceof Error)
    _handleError((Error) t);
  
  throw t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t);
}
static String n2(long l, String singular, String plural) {
  return n_fancy2(l, singular, plural);
}

static String n2(long l, String singular) {
  return n_fancy2(l, singular, singular + "s");
}

static String n2(Collection l, String singular) {
  return n2(l(l), singular);
}

static String n2(Collection l, String singular, String plural) {
  return n_fancy2(l, singular, plural);
}

static String n2(Map m, String singular, String plural) {
  return n_fancy2(m, singular, plural);
}

static String n2(Object[] a, String singular, String plural) {
  return n_fancy2(a, singular, plural);
}


static Map<Thread, Boolean> _registerThread_threads = newWeakHashMap();

static Thread _registerThread(Thread t) {
  _registerThread_threads.put(t, true);
  return t;
}

static void _registerThread() { _registerThread(Thread.currentThread()); }
static <A> void replaceCollection(Collection<A> dest, Collection<A> src) {
  dest.clear();
  dest.addAll(src);
}
// firstDelay = delay
static FixedRateTimer doEvery(long delay, final Object r) {
  return doEvery(delay, delay, r);
}

static FixedRateTimer doEvery(long delay, long firstDelay, final Object r) {
  FixedRateTimer timer = new FixedRateTimer();
  timer.scheduleAtFixedRate(smartTimerTask(r, timer, toInt(delay)), toInt(firstDelay), toInt(delay));
  return timer;
}

// reversed argument order for fun
static FixedRateTimer doEvery(double initialSeconds, double delaySeconds, final Object r) {
  return doEvery(toMS(delaySeconds), toMS(initialSeconds), r);
}

static FixedRateTimer doEvery(double delaySeconds, final Object r) {
  return doEvery(toMS(delaySeconds), r);
}

static boolean empty(Collection c) { return c == null || c.isEmpty(); }
static boolean empty(String s) { return s == null || s.length() == 0; }
static boolean empty(Map map) { return map == null || map.isEmpty(); }
static boolean empty(Object[] o) { return o == null || o.length == 0; }
static boolean empty(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 == null) return true;
  throw fail("unknown type for 'empty': " + getType(o));
}

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


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

static String str(char[] c) {
  return new String(c);
}
static volatile StringBuffer local_log = new StringBuffer(); // not redirected
static volatile StringBuffer print_log = local_log; // might be redirected, e.g. to main bot

// in bytes - will cut to half that
static volatile int print_log_max = 1024*1024;
static volatile int local_log_max = 100*1024;
//static int print_maxLineLength = 0; // 0 = unset

static boolean print_silent; // total mute if set

static Object print_byThread_lock = new Object();
static volatile ThreadLocal<Object> print_byThread; // special handling by thread - prefers F1<S, Bool>
static volatile Object print_allThreads;

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

// slightly overblown signature to return original object...
static <A> A print(A o) {
  ping();
  if (print_silent) return o;
  String s = String.valueOf(o) + "\n";
  print_noNewLine(s);
  return o;
}

static void print_noNewLine(String s) {
  
  Object f = print_byThread == null ? null : print_byThread.get();
  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);
}

static void print_raw(String s) {
  s = fixNewLines(s);
  // TODO if (print_maxLineLength != 0)
  StringBuffer loc = local_log;
  StringBuffer buf = print_log;
  int loc_max = print_log_max;
  if (buf != loc && buf != null) {
    print_append(buf, s, print_log_max);
    loc_max = local_log_max;
  }
  if (loc != null) 
    print_append(loc, s, loc_max);
  System.out.print(s);
}

static void print(long l) {
  print(String.valueOf(l));
}

static void print(char c) {
  print(String.valueOf(c));
}

static void print_append(StringBuffer buf, String s, int max) {
  synchronized(buf) {
    buf.append(s);
    max /= 2;
    if (buf.length() > max) try {
      int newLength = max/2;
      int ofs = buf.length()-newLength;
      String newString = buf.substring(ofs);
      buf.setLength(0);
      buf.append("[...] ").append(newString);
    } catch (Exception e) {
      buf.setLength(0);
    }
  }
}
static String subBot_myWebSocketURI() {
  int port = subBot_currentPort();
  return (subBot_isHttps() ? "wss://" : "ws://") + domain() 
    + (port == 80 ? "" : ":" + port) + "/" + parsedProgramID();
}
static Collection subBot_getMyWebSockets() {
  Collection sockets = filterByField((Collection) get(mainBot(), "webSockets"), "botID" , formattedProgramID());
  WeakReference ref = new WeakReference(mc());
  for (Object ws : sockets)
    setOpt(ws, "bot" , ref);
  return sockets;
}
static Throwable pcall(Runnable r) {
  try {
    r.run();
    return null;
  } catch (Throwable e) {
    return e;
  }
}

static Object pcall(Object o, String method, Object... args) { try {
  return call(o, method, args);
} catch (Throwable __e) { return null; } }
static String hreconnectingWebSockets() {
  return hjavascript_src_snippet("#1013374" /*#1013375*/);
}
static <A> Set<A> synchroHashSet() {
  return Collections.synchronizedSet(new HashSet<A>());
}

static String hdiv(Object contents, Object... params) {
  return div(contents, params);
}
static String hjavascript(String script) {
  return tag("script", script, "type", "text/javascript");
}
static String loadJQuery() {
  return "<script src=\"https://code.jquery.com/jquery-1.10.2.js\"></script>";
}


static String fixNewLines(String s) {
  return s.replace("\r\n", "\n").replace("\r", "\n");
}
static long parsedProgramID() {
  return psI(programID());
}
// TODO: send hard errors to core

static AtomicLong _handleError_nonVMErrors = new AtomicLong();
static AtomicLong _handleError_vmErrors = new AtomicLong();
static AtomicLong _handleError_outOfMemoryErrors = new AtomicLong();
static volatile long _handleError_lastOutOfMemoryError;
static volatile Error _handleError_lastHardError;

static void _handleError(Error e) {
  if (!(e instanceof VirtualMachineError)) {
    incAtomicLong(_handleError_nonVMErrors);
    return;
  }
  
  print("\nHARD ERROR\n");
  printStackTrace2(e);
  print("\nHARD ERROR\n");
  _handleError_lastHardError = e;
  
  incAtomicLong(_handleError_vmErrors);
  if (e instanceof OutOfMemoryError) {
    incAtomicLong(_handleError_outOfMemoryErrors);
    _handleError_lastOutOfMemoryError = sysNow();
  }
}
static volatile boolean ping_pauseAll;
static int ping_sleep = 100; // poll pauseAll flag every 100

static volatile boolean ping_anyActions;
static Map<Thread, Object> ping_actions = newWeakHashMap();


// always returns true
static boolean ping() {
  if (ping_pauseAll  || ping_anyActions ) ping_impl();
  return true;
}

// returns true when it slept
static boolean ping_impl() { try {
  if (ping_pauseAll && !isAWTThread()) {
    do
      Thread.sleep(ping_sleep);
    while (ping_pauseAll);
    return true;
  }
  
  
  if (ping_anyActions) {
    Object action;
    synchronized(ping_actions) {
      action = ping_actions.get(currentThread());
      if (action instanceof Runnable)
        ping_actions.remove(currentThread());
      if (ping_actions.isEmpty()) ping_anyActions = false;
    }
    
    if (action instanceof Runnable)
      ((Runnable) action).run();
    else if (eq(action, "cancelled"))
      throw fail("Thread cancelled.");
  }
  
  
  return false;
} catch (Exception __e) { throw rethrow(__e); } }
static WeakHashMap<Class, ArrayList<Method>> callF_cache = new WeakHashMap();




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


static Object callF(Object f, Object... args) { try {
  if (f instanceof String)
    return callMC((String) f, args);
  if (f instanceof Runnable) {
    ((Runnable) f).run();
    return null;
  }
  if (f == null) return null;
  
  Class c = f.getClass();
  ArrayList<Method> methods;
  synchronized(callF_cache) {
    methods = callF_cache.get(c);
    if (methods == null)
      methods = callF_makeCache(c);
  }
  
  int n = l(methods);
  if (n == 0) throw fail("No get method in " + getClassName(c));
  if (n == 1) return invokeMethod(methods.get(0), f, args);
  for (int i = 0; i < n; i++) {
    Method m = methods.get(i);
    if (call_checkArgs(m, args, false))
      return invokeMethod(m, f, args);
  }
  throw fail("No matching get method in " + getClassName(c));
} catch (Exception __e) { throw rethrow(__e); } }

// used internally
static ArrayList<Method> callF_makeCache(Class c) {
  ArrayList<Method> l = new ArrayList();
  Class _c = c;
  do {
    for (Method m : _c.getDeclaredMethods())
      if (m.getName().equals("get")) {
        m.setAccessible(true);
        l.add(m);
      }
    if (!l.isEmpty()) break;
    _c = _c.getSuperclass();
  } while (_c != null);
  callF_cache.put(c, l);
  return l;
}
static Object mainBot() {
  return getMainBot();
}
static <A, B> Map<A, B> newWeakHashMap() {
  return _registerWeakMap(synchroMap(new WeakHashMap()));
}
static String div(Object contents, Object... params) {
  return hfulltag("div", contents, params);
}

static BigInteger div(BigInteger a, BigInteger b) {
  return a.divide(b);
}

static BigInteger div(BigInteger a, int b) {
  return a.divide(bigint(b));
}
static Class mc() {
  return main.class;
}
static long toMS(double seconds) {
  return (long) (seconds*1000);
}
// get purpose 1: access a list/array/map (safer version of x.get(y))

static <A> A get(List<A> l, int idx) {
  return l != null && idx >= 0 && idx < l(l) ? l.get(idx) : null;
}

// seems to conflict with other signatures
/*static <A, B> B get(Map<A, B> map, A key) {
  ret map != null ? map.get(key) : null;
}*/

static <A> A get(A[] l, int idx) {
  return idx >= 0 && idx < l(l) ? l[idx] : null;
}

// default to false
static boolean get(boolean[] l, int idx) {
  return idx >= 0 && idx < l(l) ? l[idx] : false;
}

// get purpose 2: access a field by reflection or a map

static Object get(Object o, String field) {
  try {
    if (o instanceof Class) return get((Class) o, field);
    
    if (o instanceof Map)
      return ((Map) o).get(field);
      
    Field f = getOpt_findField(o.getClass(), field);
    if (f != null) {
      f.setAccessible(true);
      return f.get(o);
    }
      
    
  } catch (Exception e) {
    throw asRuntimeException(e);
  }
  throw new RuntimeException("Field '" + field + "' not found in " + o.getClass().getName());
}

static Object get_raw(Object o, String field) {
  try {
    Field f = get_findField(o.getClass(), field);
    f.setAccessible(true);
    return f.get(o);
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}

static Object get(Class c, String field) {
  try {
    Field f = get_findStaticField(c, field);
    f.setAccessible(true);
    return f.get(null);
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}

static Field get_findStaticField(Class<?> c, String field) {
  Class _c = c;
  do {
    for (Field f : _c.getDeclaredFields())
      if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0)
        return f;
    _c = _c.getSuperclass();
  } while (_c != null);
  throw new RuntimeException("Static field '" + field + "' not found in " + c.getName());
}

static Field get_findField(Class<?> c, String field) {
  Class _c = c;
  do {
    for (Field f : _c.getDeclaredFields())
      if (f.getName().equals(field))
        return f;
    _c = _c.getSuperclass();
  } while (_c != null);
  throw new RuntimeException("Field '" + field + "' not found in " + c.getName());
}

// r may return false to cancel timer
static TimerTask smartTimerTask(Object r, java.util.Timer timer, long delay) {
  return new SmartTimerTask(r, timer, delay);
}

static  class SmartTimerTask extends TimerTask {
  Object r;
  java.util.Timer timer;
  long delay;
  SmartTimerTask() {}
  SmartTimerTask(Object r, java.util.Timer timer, long delay) {
  this.delay = delay;
  this.timer = timer;
  this.r = r;}
  public String toString() { return "SmartTimerTask(" + r + ", " + timer + ", " + delay + ")"; }
  long lastRun;
  
  public void run() {
    if (!licensed())
      timer.cancel();
    else {
      lastRun = fixTimestamp(lastRun);
      long now = now();
      if (now >= lastRun + delay*0.9) {
        lastRun = now;
        if (eq(false, pcallF(r)))
          timer.cancel();
      }
    }
  }
}
static String tag(String tag) {
  return htag(tag);
}

static String tag(String tag, Object contents, Object... params) {
  return htag(tag, str(contents), params);
}

static String tag(String tag, StringBuilder contents, Object... params) {
  return htag(tag, contents, params);
}

static String tag(String tag, StringBuffer contents, Object... params) {
  return htag(tag, contents, params);
}
static int subBot_currentPort() {
  return toInt(getOpt(subBot_httpd(), "myPort"));
}
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));
}

static int toInt(long l) {
  if (l != (int) l) throw fail("Too large for int: " + l);
  return (int) l;
}
static boolean isFalse(Object o) {
  return eq(false, o);
}
static int l(Object[] a) { return a == null ? 0 : a.length; }
static int l(boolean[] a) { return a == null ? 0 : a.length; }
static int l(byte[] a) { return a == null ? 0 : a.length; }
static int l(int[] a) { return a == null ? 0 : a.length; }
static int l(float[] a) { return a == null ? 0 : a.length; }
static int l(char[] a) { return a == null ? 0 : a.length; }
static int l(Collection c) { return c == null ? 0 : c.size(); }
static int l(Map m) { return m == null ? 0 : m.size(); }
static int l(CharSequence s) { return s == null ? 0 : s.length(); } static long l(File f) { return f == null ? 0 : f.length(); }

static int l(Object o) {
  return o == null ? 0
    : o instanceof String ? l((String) o)
    : o instanceof Map ? l((Map) o)
    : o instanceof Collection ? l((Collection) o)
    : (Integer) call(o, "size");
}




static String formattedProgramID() {
  return fsI(programID());
}
static String hjavascript_src_snippet(String snippetID) {
  return tag("script", "", "src" , snippetRawURL(snippetID));
}
static <A> List<A> filterByField(Collection<A> c, String field, Object value) {
  List<A> l = new ArrayList();
  for (A x : c)
    if (eq(getOpt(x, field), value))
      l.add(x);
  return l;
}
static Object call(Object o) {
  return callFunction(o);
}

// varargs assignment fixer for a single string array argument
static Object call(Object o, String method, String[] arg) {
  return call(o, method, new Object[] {arg});
}

static Object call(Object o, String method, Object... args) {
  try {
    if (o instanceof Class) {
      Method m = call_findStaticMethod((Class) o, method, args, false);
      m.setAccessible(true);
      return invokeMethod(m, null, args);
    } else {
      Method m = call_findMethod(o, method, args, false);
      m.setAccessible(true);
      return invokeMethod(m, o, args);
    }
  } catch (Exception e) {
    throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
  }
}

static Method call_findStaticMethod(Class c, String method, Object[] args, boolean debug) {
  Class _c = c;
  while (c != null) {
    for (Method m : c.getDeclaredMethods()) {
      if (debug)
        System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
      if (!m.getName().equals(method)) {
        if (debug) System.out.println("Method name mismatch: " + method);
        continue;
      }

      if ((m.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0 || !call_checkArgs(m, args, debug))
        continue;

      return m;
    }
    c = c.getSuperclass();
  }
  throw new RuntimeException("Method '" + method + "' (static) with " + args.length + " parameter(s) not found in " + _c.getName());
}

static Method call_findMethod(Object o, String method, Object[] args, boolean debug) {
  Class c = o.getClass();
  while (c != null) {
    for (Method m : c.getDeclaredMethods()) {
      if (debug)
        System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
      if (m.getName().equals(method) && call_checkArgs(m, args, debug))
        return m;
    }
    c = c.getSuperclass();
  }
  throw new RuntimeException("Method '" + method + "' (non-static) with " + args.length + " parameter(s) not found in " + o.getClass().getName());
}

private static boolean call_checkArgs(Method m, Object[] args, boolean debug) {
  Class<?>[] types = m.getParameterTypes();
  if (types.length != args.length) {
    if (debug)
      System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
    return false;
  }
  for (int i = 0; i < types.length; i++)
    if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
      if (debug)
        System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
      return false;
    }
  return true;
}
static RuntimeException fail() { throw new RuntimeException("fail"); }
static RuntimeException fail(Throwable e) { throw asRuntimeException(e); }
static RuntimeException fail(Object msg) { throw new RuntimeException(String.valueOf(msg)); }
static RuntimeException fail(String msg) { throw new RuntimeException(msg == null ? "" : msg); }
static RuntimeException fail(String msg, Throwable innerException) { throw new RuntimeException(msg, innerException); }

static String n_fancy2(long l, String singular, String plural) {
  return formatWithThousandsSeparator(l) + " " + trim(l == 1 ? singular : plural);
}

static String n_fancy2(Collection l, String singular, String plural) {
  return n_fancy2(l(l), singular, plural);
}

static String n_fancy2(Map m, String singular, String plural) {
  return n_fancy2(l(m), singular, plural);
}

static String n_fancy2(Object[] a, String singular, String plural) {
  return n_fancy2(l(a), singular, plural);
}


static Field setOpt_findField(Class c, String field) {
  HashMap<String, Field> map;
  synchronized(getOpt_cache) {
    map = getOpt_cache.get(c);
    if (map == null)
      map = getOpt_makeCache(c);
  }
  return map.get(field);
}

static void setOpt(Object o, String field, Object value) { try {
  if (o == null) return;
  
  
  
  Class c = o.getClass();
  HashMap<String, Field> map;
  
  synchronized(getOpt_cache) {
    map = getOpt_cache.get(c);
    if (map == null)
      map = getOpt_makeCache(c);
  }
  
  if (map == getOpt_special) {
    if (o instanceof Class) {
      setOpt((Class) o, field, value);
      return;
    }
    
    // It's probably a subclass of Map. Use raw method
    setOpt_raw(o, field, value);
    return;
  }
  
  Field f = map.get(field);
  if (f != null)
    smartSet(f, o, value); // possible improvement: skip setAccessible
} catch (Exception __e) { throw rethrow(__e); } }

static void setOpt(Class c, String field, Object value) {
  if (c == null) return;
  try {
    Field f = setOpt_findStaticField(c, field);
    if (f != null)
      smartSet(f, null, value);
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}
  
static Field setOpt_findStaticField(Class<?> c, String field) {
  Class _c = c;
  do {
    for (Field f : _c.getDeclaredFields())
      if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0)
        return f;
    _c = _c.getSuperclass();
  } while (_c != null);
  return null;
}
static boolean subBot_isHttps() {
  return eq(subBot_httpd(), getOpt(mainBot(), "serveHttps_server"));
}
static String getType(Object o) {
  return getClassName(o);
}
static String domain() {
  return domainName();
}


static String htag(String tag) {
  return htag(tag, "");
}

static String htag(String tag, Object contents, Object... params) {
  String openingTag = hopeningTag(tag, params);
  String s = str(contents);
  if (empty(s) && neqic(tag, "script"))
    return dropLast(openingTag) + "/>";
  return openingTag + s + "</" + tag + ">";
}
static Object pcallF(Object f, Object... args) {
  return pcallFunction(f, args);
}


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

static Object callFunction(Object f, Object... args) {
  return callF(f, args);
}
static HashMap<String, List<Method>> callMC_cache = new HashMap();
static String callMC_key;
static Method callMC_value;

// varargs assignment fixer for a single string array argument
static Object callMC(String method, String[] arg) {
  return callMC(method, new Object[] {arg});
}

static Object callMC(String method, Object... args) { try {
  Method me;
  if (callMC_cache == null) callMC_cache = new HashMap(); // initializer time workaround
  synchronized(callMC_cache) {
    me = method == callMC_key ? callMC_value : null;
  }
  if (me != null) try {
    return invokeMethod(me, null, args);
  } catch (IllegalArgumentException e) {
    throw new RuntimeException("Can't call " + me + " with arguments " + classNames(args), e);
  }

  List<Method> m;
  synchronized(callMC_cache) {
    m = callMC_cache.get(method);
  }
  if (m == null) {
    if (callMC_cache.isEmpty()) {
      callMC_makeCache();
      m = callMC_cache.get(method);
    }
    if (m == null) throw fail("Method named " + method + " not found in main");
  }
  int n = m.size();
  if (n == 1) {
    me = m.get(0);
    synchronized(callMC_cache) {
      callMC_key = method;
      callMC_value = me;
    }
    try {
      return invokeMethod(me, null, args);
    } catch (IllegalArgumentException e) {
      throw new RuntimeException("Can't call " + me + " with arguments " + classNames(args), e);
    }
  }
  for (int i = 0; i < n; i++) {
    me = m.get(i);
    if (call_checkArgs(me, args, false))
      return invokeMethod(me, null, args);
  }
  throw fail("No method called " + method + " with matching arguments found in main");
} catch (Exception __e) { throw rethrow(__e); } }

static void callMC_makeCache() {
  synchronized(callMC_cache) {
    callMC_cache.clear();
    Class _c = (Class) mc(), c = _c;
    while (c != null) {
      for (Method m : c.getDeclaredMethods())
        if ((m.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0) {
          m.setAccessible(true);
          multiMapPut(callMC_cache, m.getName(), m);
        }
      c = c.getSuperclass();
    }
  }
}
static String snippetRawURL(String snippetID) {
  return "https://www.botcompany.de:8443/serve/" + psI(snippetID);
  //ret tb_mainServer() + "/getraw.php?id=" + psI(snippetID) + "&utf8=1";
}
static Object subBot_httpd() {
  Object httpd = getThreadLocal((ThreadLocal) getOpt(mainBot(), "MyHTTPD_current"));
  if (httpd == null)
    httpd = getThreadLocal((ThreadLocal) getOpt(mainBot(), "WebSocketHTTPD_current"));
  return httpd;
}
static RuntimeException asRuntimeException(Throwable t) {
  
  if (t instanceof Error)
    _handleError((Error) t);
  
  return t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t);
}
static String trim(String s) { return s == null ? null : s.trim(); }
static String trim(StringBuilder buf) { return buf.toString().trim(); }
static String trim(StringBuffer buf) { return buf.toString().trim(); }
static void setOpt_raw(Object o, String field, Object value) { try {
  if (o == null) return;
  if (o instanceof Class) setOpt_raw((Class) o, field, value);
  else {
    Field f = setOpt_raw_findField(o.getClass(), field);
    if (f != null)
      smartSet(f, o, value);
  }
} catch (Exception __e) { throw rethrow(__e); } }

static void setOpt_raw(Class c, String field, Object value) { try {
  if (c == null) return;
  Field f = setOpt_raw_findStaticField(c, field);
  if (f != null)
    smartSet(f, null, value);
} catch (Exception __e) { throw rethrow(__e); } }
  
static Field setOpt_raw_findStaticField(Class<?> c, String field) {
  Class _c = c;
  do {
    for (Field f : _c.getDeclaredFields())
      if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0)
        return f;
    _c = _c.getSuperclass();
  } while (_c != null);
  return null;
}

static Field setOpt_raw_findField(Class<?> c, String field) {
  Class _c = c;
  do {
    for (Field f : _c.getDeclaredFields())
      if (f.getName().equals(field))
        return f;
    _c = _c.getSuperclass();
  } while (_c != null);
  return null;
}
// TODO: test if android complains about this
static boolean isAWTThread() {
  if (isAndroid()) return false;
  if (isHeadless()) return false;
  return isAWTThread_awt();
}

static boolean isAWTThread_awt() {
  return SwingUtilities.isEventDispatchThread();
}
static String fsI(String id) {
  return formatSnippetID(id);
}

static String fsI(long id) {
  return formatSnippetID(id);
}
// extended over Class.isInstance() to handle primitive types
static boolean isInstanceX(Class type, Object arg) {
  if (type == boolean.class) return arg instanceof Boolean;
  if (type == int.class) return arg instanceof Integer;
  if (type == long.class) return arg instanceof Long;
  if (type == float.class) return arg instanceof Float;
  if (type == short.class) return arg instanceof Short;
  if (type == char.class) return arg instanceof Character;
  if (type == byte.class) return arg instanceof Byte;
  if (type == double.class) return arg instanceof Double;
  return type.isInstance(arg);
}
static Thread currentThread() {
  return Thread.currentThread();
}
static long psI(String snippetID) {
  return parseSnippetID(snippetID);
}
static boolean eq(Object a, Object b) {
  return a == null ? b == null : a == b || a.equals(b);
}


static List _registerWeakMap_preList;

static <A> A _registerWeakMap(A map) {
  if (javax() == null) {
    // We're in class init
    if (_registerWeakMap_preList == null) _registerWeakMap_preList = synchroList();
    _registerWeakMap_preList.add(map);
    return map;
  }
  
  try {
    call(javax(), "_registerWeakMap", map);
  } catch (Throwable e) {
    printException(e);
    print("Upgrade JavaX!!");
  }
  return map;
}

static void _onLoad_registerWeakMap() {
  assertNotNull(javax());
  if (_registerWeakMap_preList == null) return;
  for (Object o : _registerWeakMap_preList)
    _registerWeakMap(o);
  _registerWeakMap_preList = null;
}
static String domainName() {
  Object session = call(getMainBot(), "getSession");
  Map headers = (Map) ( call(session, "getHeaders"));
  String host = (String) ( headers.get("host"));
  if (host == null) return null;
  return dropFrom(host, ":");
}
static String getClassName(Object o) {
  return o == null ? "null" : o instanceof Class ? ((Class) o).getName() : o.getClass().getName();
}
static Object invokeMethod(Method m, Object o, Object... args) { try {
  try {
    return m.invoke(o, args);
  } catch (InvocationTargetException e) {
    throw rethrow(getExceptionCause(e));
  } catch (IllegalArgumentException e) {
    throw new IllegalArgumentException(e.getMessage() + " - was calling: " + m + ", args: " + joinWithSpace(classNames(args)));
  }
} catch (Exception __e) { throw rethrow(__e); } }
static long fixTimestamp(long timestamp) {
  return timestamp > now() ? 0 : timestamp;
}
static Map synchroMap() {
  return synchroHashMap();
}

static <A, B> Map<A, B> synchroMap(Map<A, B> map) {
  return Collections.synchronizedMap(map);
}
static String hfulltag(String tag) {
  return hfulltag(tag, "");
}

static String hfulltag(String tag, Object contents, Object... params) {
  return hopeningTag(tag, params) + str(contents) + "</" + tag + ">";
}
static Object mainBot;

static Object getMainBot() {
  return mainBot;
}
//static final Map<Class, HashMap<S, Field>> getOpt_cache = newDangerousWeakHashMap(f getOpt_special_init);

static class getOpt_Map extends WeakHashMap {
  getOpt_Map() {
    if (getOpt_special == null) getOpt_special = new HashMap();
    clear();
  }
  
  public void clear() {
    super.clear();
    //print("getOpt clear");
    put(Class.class, getOpt_special);
    put(String.class, getOpt_special);
  }
}

static final Map<Class, HashMap<String, Field>> getOpt_cache = _registerDangerousWeakMap(synchroMap(new getOpt_Map()));
//static final Map<Class, HashMap<S, Field>> getOpt_cache = _registerWeakMap(synchroMap(new getOpt_Map));
static HashMap getOpt_special; // just a marker

/*static void getOpt_special_init(Map map) {
  map.put(Class.class, getOpt_special);
  map.put(S.class, getOpt_special);
}*/

static Object getOpt_cached(Object o, String field) { try {
  if (o == null) return null;

  Class c = o.getClass();
  HashMap<String, Field> map;
  synchronized(getOpt_cache) {
    map = getOpt_cache.get(c);
    if (map == null)
      map = getOpt_makeCache(c);
  }
  
  if (map == getOpt_special) {
    if (o instanceof Class)
      return getOpt((Class) o, field);
    /*if (o instanceof S)
      ret getOpt(getBot((S) o), field);*/
    if (o instanceof Map)
      return ((Map) o).get(field);
  }
    
  Field f = map.get(field);
  if (f != null) return f.get(o);
  
  return null;
} catch (Exception __e) { throw rethrow(__e); } }

// used internally - we are in synchronized block
static HashMap<String, Field> getOpt_makeCache(Class c) {
  HashMap<String, Field> map;
  if (isSubtypeOf(c, Map.class))
    map = getOpt_special;
  else {
    map = new HashMap();
    Class _c = c;
    do {
      for (Field f : _c.getDeclaredFields()) {
        f.setAccessible(true);
        String name = f.getName();
        if (!map.containsKey(name))
          map.put(name, f);
      }
      _c = _c.getSuperclass();
    } while (_c != null);
  }
  getOpt_cache.put(c, map);
  return map;
}
static long sysNow() {
  return System.nanoTime()/1000000;
}
static long now_virtualTime;
static long now() {
  return now_virtualTime != 0 ? now_virtualTime : System.currentTimeMillis();
}

static void incAtomicLong(AtomicLong l) {
  l.incrementAndGet();
}
static BigInteger bigint(String s) {
  return new BigInteger(s);
}

static BigInteger bigint(long l) {
  return BigInteger.valueOf(l);
}
static String programID() {
  return getProgramID();
}
static volatile boolean licensed_yes = true;

static boolean licensed() {
  ping();
  return licensed_yes;
}

static void licensed_off() {
  licensed_yes = false;
}


static String formatWithThousandsSeparator(long l) {
  return NumberFormat.getInstance(new Locale("en_US")).format(l);
}
static void smartSet(Field f, Object o, Object value) throws Exception {
  f.setAccessible(true);
  
  // take care of common case (long to int)
  if (f.getType() == int.class && value instanceof Long)
    value = ((Long) value).intValue();
    
  try {
    f.set(o, value);
  } catch (Exception e) {
    
    throw e;
  }
}
static int parseInt(String s) {
  return empty(s) ? 0 : Integer.parseInt(s);
}

static int parseInt(char c) {
  return Integer.parseInt(str(c));
}
static Object getOpt(Object o, String field) {
  return getOpt_cached(o, field);
}

static Object getOpt_raw(Object o, String field) {
  try {
    Field f = getOpt_findField(o.getClass(), field);
    if (f == null) return null;
    f.setAccessible(true);
    return f.get(o);
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}

// access of static fields is not yet optimized
static Object getOpt(Class c, String field) {
  try {
    if (c == null) return null;
    Field f = getOpt_findStaticField(c, field);
    if (f == null) return null;
    f.setAccessible(true);
    return f.get(null);
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}

static Field getOpt_findStaticField(Class<?> c, String field) {
  Class _c = c;
  do {
    for (Field f : _c.getDeclaredFields())
      if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0)
        return f;
    _c = _c.getSuperclass();
  } while (_c != null);
  return null;
}

static Throwable printStackTrace2(Throwable e) {
  // we go to system.out now - system.err is nonsense
  print(getStackTrace2(e));
  return e;
}

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

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

/*static void printStackTrace2(S indent, Throwable e) {
  if (endsWithLetter(indent)) indent += " ";
  printIndent(indent, getStackTrace2(e));
}*/
static Field getOpt_findField(Class<?> c, String field) {
  Class _c = c;
  do {
    for (Field f : _c.getDeclaredFields())
      if (f.getName().equals(field))
        return f;
    _c = _c.getSuperclass();
  } while (_c != null);
  return null;
}


static Throwable getExceptionCause(Throwable e) {
  Throwable c = e.getCause();
  return c != null ? c : e;
}
static String joinWithSpace(Collection<String> c) {
  return join(" ", c);
}

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

static String dropFrom(String s, String x) {
  if (s == null) return null;
  int i = s.indexOf(x);
  if (i < 0) return s;
  return substring(s, 0, i);
}
static boolean neqic(String a, String b) {
  return !eqic(a, b);
}
static List<String> classNames(Collection l) {
  return getClassNames(l);
}

static List<String> classNames(Object[] l) {
  return getClassNames(Arrays.asList(l));
}
static <A, B> void put(Map<A, B> map, A a, B b) {
  if (map != null) map.put(a, b);
}
static String[] dropLast(String[] a, int n) {
  n = Math.min(n, a.length);
  String[] b = new String[a.length-n];
  System.arraycopy(a, 0, b, 0, b.length);
  return b;
}

static <A> List<A> dropLast(List<A> l) {
  return subList(l, 0, l(l)-1);
}

static <A> List<A> dropLast(int n, List<A> l) {
  return subList(l, 0, l(l)-n);
}

static <A> List<A> dropLast(Iterable<A> l) {
  return dropLast(asList(l));
}

static String dropLast(String s) {
  return substring(s, 0, l(s)-1);
}

static String dropLast(String s, int n) {
  return substring(s, 0, l(s)-n);
}

static String dropLast(int n, String s) {
  return dropLast(s, n);
}

static <A> A assertNotNull(A a) {
  assertTrue(a != null);
  return a;
}

static <A> A assertNotNull(String msg, A a) {
  assertTrue(msg, a != null);
  return a;
}
static String getStackTrace2(Throwable throwable) {
  return hideCredentials(getStackTrace(throwable) + replacePrefix("java.lang.RuntimeException: ", "FAIL: ",
    hideCredentials(str(getInnerException(throwable)))) + "\n");
}
static boolean isSubtypeOf(Class a, Class b) {
  return b.isAssignableFrom(a); // << always hated that method, let's replace it!
}
static List<Pair> _registerDangerousWeakMap_preList;

static <A> A _registerDangerousWeakMap(A map) {
  return _registerDangerousWeakMap(map, null);
}

static <A> A _registerDangerousWeakMap(A map, Object init) {
  callF(init, map);
  
  if (init instanceof String) {
    final String f = (String) ( init);
    init = new VF1<Map>() { void get(Map map) { try {  callMC(f, map) ; } catch (Exception __e) { throw rethrow(__e); } }
  public String toString() { return "callMC(f, map)"; }};
  }
    
  if (javax() == null) {
    // We're in class init
    if (_registerDangerousWeakMap_preList == null) _registerDangerousWeakMap_preList = synchroList();
    _registerDangerousWeakMap_preList.add(pair(map, init));
    return map;
  }
  
  try {
    call(javax(), "_registerDangerousWeakMap", map, init);
  } catch (Throwable e) { printException(e);
    upgradeJavaXAndRestart();
  }
  return map;
}

static void _onLoad_registerDangerousWeakMap() {
  assertNotNull(javax());
  if (_registerDangerousWeakMap_preList == null) return;
  for (Pair p : _registerDangerousWeakMap_preList)
    _registerDangerousWeakMap(p.a, p.b);
  _registerDangerousWeakMap_preList = null;
}
static String programID;

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


// TODO: ask JavaX instead
static String getProgramID(Class c) {
  String id = (String) getOpt(c, "programID");
  if (nempty(id))
    return formatSnippetID(id);
  return "?";
}


static String getProgramID(Object o) {
  return getProgramID(getMainClass(o));
}
static String hopeningTag(String tag, Object... params) {
  StringBuilder buf = new StringBuilder();
  buf.append("<" + tag);
  for (int i = 0; i < l(params); i += 2) {
    String name = (String) get(params, i);
    Object val = get(params, i+1);
    if (nempty(name) && val != null) {
      String s = str(val);
      if (!empty(s))
        buf.append(" " + name + "=" + htmlQuote(s));
    }
  }
  buf.append(">");
  return str(buf);
}
static Object pcallFunction(Object f, Object... args) {
  try { return callFunction(f, args); } catch (Throwable __e) { printStackTrace2(__e); }
  return null;
}
static Boolean isHeadless_cache;

static boolean isHeadless() {
  if (isHeadless_cache != null) return isHeadless_cache;
  if (GraphicsEnvironment.isHeadless()) return isHeadless_cache = true;
  
  // Also check if AWT actually works.
  // If DISPLAY variable is set but no X server up, this will notice.
  
  try {
    SwingUtilities.isEventDispatchThread();
    return isHeadless_cache = false;
  } catch (Throwable e) { return isHeadless_cache = true; }
}
static Class javax() {
  return getJavaX();
}
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);
}
static String formatSnippetID(String id) {
  return "#" + parseSnippetID(id);
}

static String formatSnippetID(long id) {
  return "#" + id;
}
static void printException(Throwable e) {
  printStackTrace(e);
}
static Object getThreadLocal(Object o, String name) {
  ThreadLocal t = (ThreadLocal) ( getOpt(o, name));
  return t != null ? t.get() : null;
}

static <A> A getThreadLocal(ThreadLocal<A> tl) {
  return tl == null ? null : tl.get();
}
public static long parseSnippetID(String snippetID) {
  long id = Long.parseLong(shortenSnippetID(snippetID));
  if (id == 0) throw fail("0 is not a snippet ID");
  return id;
}
static <A> List<A> synchroList() {
  return Collections.synchronizedList(new ArrayList<A>());
}

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

static void clear(Collection c) {
  if (c != null) c.clear();
}
static Map synchroHashMap() {
  return Collections.synchronizedMap(new HashMap());
}

static int isAndroid_flag;

static boolean isAndroid() {
  if (isAndroid_flag == 0)
    isAndroid_flag = System.getProperty("java.vendor").toLowerCase().indexOf("android") >= 0 ? 1 : -1;
  return isAndroid_flag > 0;
}



static <A> ArrayList<A> asList(A[] a) {
  return a == null ? new ArrayList<A>() : new ArrayList<A>(Arrays.asList(a));
}

static ArrayList<Integer> asList(int[] a) {
  ArrayList<Integer> l = new ArrayList();
  for (int i : a) l.add(i);
  return l;
}

static <A> ArrayList<A> asList(Iterable<A> s) {
  if (s instanceof ArrayList) return (ArrayList) s;
  ArrayList l = new ArrayList();
  if (s != null)
    for (A a : s)
      l.add(a);
  return l;
}

static <A> ArrayList<A> asList(Enumeration<A> e) {
  ArrayList l = new ArrayList();
  if (e != null)
    while (e.hasMoreElements())
      l.add(e.nextElement());
  return l;
}
public static String join(String glue, Iterable<String> strings) {
  if (strings == null) return "";
  StringBuilder buf = new StringBuilder();
  Iterator<String> 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));
}

static String join(Iterable<String> strings) {
  return join("", strings);
}

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

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


static String join(String glue, Pair p) {
  return p == null ? "" : str(p.a) + glue + str(p.b);
}

static String shortenSnippetID(String snippetID) {
  if (snippetID.startsWith("#"))
    snippetID = snippetID.substring(1);
  String httpBlaBla = "http://tinybrain.de/";
  if (snippetID.startsWith(httpBlaBla))
    snippetID = snippetID.substring(httpBlaBla.length());
  return "" + parseLong(snippetID);
}
static Throwable printStackTrace(Throwable e) {
  // we go to system.out now - system.err is nonsense
  print(getStackTrace(e));
  return e;
}

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

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

/*static void printStackTrace(S indent, Throwable e) {
  if (endsWithLetter(indent)) indent += " ";
  printIndent(indent, getStackTrace(e));
}*/
static String replacePrefix(String prefix, String replacement, String s) {
  if (!startsWith(s, prefix)) return s;
  return replacement + substring(s, l(prefix));
}
static void upgradeJavaXAndRestart() {
  run("#1001639");
  restart();
  sleep();
}
static String htmlQuote(String s) {
  return "\"" + htmlencode_forParams(s) + "\"";
}
static void assertTrue(Object o) {
  if (!(eq(o, true) /*|| isTrue(pcallF(o))*/))
    throw fail(str(o));
}
  
static boolean assertTrue(String msg, boolean b) {
  if (!b)
    throw fail(msg);
  return b;
}

static boolean assertTrue(boolean b) {
  if (!b)
    throw fail("oops");
  return b;
}
static String hideCredentials(URL url) { return url == null ? null : hideCredentials(str(url)); }

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

static String hideCredentials(Object o) {
  return hideCredentials(str(o));
}
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;
}
static Class getMainClass() {
  return main.class;
}

static Class getMainClass(Object o) { try {
  return (o instanceof Class ? (Class) o : o.getClass()).getClassLoader().loadClass("main");
} catch (Exception __e) { throw rethrow(__e); } }
static Class __javax;

static Class getJavaX() {
  return __javax;
}
static <A> List<A> subList(List<A> l, int startIndex) {
  return subList(l, startIndex, l(l));
}

static <A> List<A> subList(List<A> l, int startIndex, int endIndex) {
  startIndex = max(0, min(l(l), startIndex));
  endIndex = max(0, min(l(l), endIndex));
  if (startIndex > endIndex) return litlist();
  return l.subList(startIndex, endIndex);
}


static Throwable getInnerException(Throwable e) {
  while (e.getCause() != null)
    e = e.getCause();
  return e;
}
static String getStackTrace(Throwable throwable) {
  lastException(throwable);
  return getStackTrace_noRecord(throwable);
}

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

static String getStackTrace() {
  return getStackTrace_noRecord(new Throwable());
}
static String substring(String s, int x) {
  return substring(s, x, l(s));
}

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


static String formatSnippetIDOpt(String s) {
  return isSnippetID(s) ? formatSnippetID(s) : s;
}
static boolean nempty(Collection c) {
  return !isEmpty(c);
}

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

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

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

static boolean nempty(Iterator i) {
  return i != null && i.hasNext();
}
static boolean eqic(String a, String b) {
  
  
    if ((a == null) != (b == null)) return false;
    if (a == null) return true;
    return a.equalsIgnoreCase(b);
  
}



static boolean eqic(char a, char b) {
  if (a == b) return true;
  
    char u1 = Character.toUpperCase(a);
    char u2 = Character.toUpperCase(b);
    if (u1 == u2) return true;
  
  return Character.toLowerCase(u1) == Character.toLowerCase(u2);
}
static <A, B> Pair<A, B> pair(A a, B b) {
  return new Pair(a, b);
}

static <A> Pair<A, A> pair(A a) {
  return new Pair(a, a);
}


static volatile Throwable lastException_lastException;

static Throwable lastException() {
  return lastException_lastException;
}

static void lastException(Throwable e) {
  lastException_lastException = e;
}
static String asString(Object o) {
  return o == null ? null : o.toString();
}
  public static boolean isSnippetID(String s) {
    try {
      parseSnippetID(s);
      return true;
    } catch (RuntimeException e) {
      return false;
    }
  }
static volatile boolean sleep_noSleep;

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

static void sleep() { try {
  if (sleep_noSleep) throw fail("nosleep");
  print("Sleeping.");
  sleepQuietly();
} catch (Exception __e) { throw rethrow(__e); } }
static int min(int a, int b) {
  return Math.min(a, b);
}

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

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

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

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

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

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

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

static int min(int[] c) {
  int x = Integer.MAX_VALUE;
  for (int d : c) if (d < x) x = d;
  return x;
}
static <A> ArrayList<A> litlist(A... a) {
  ArrayList l = new ArrayList(a.length);
  for (A x : a) l.add(x);
  return l;
}
static void restart() {
  Object j = getJavaX();
  call(j, "cleanRestart", get(j, "fullArgs"));
}
static int max(int a, int b) { return Math.max(a, b); }
static int max(int a, int b, int c) { return max(max(a, b), c); }
static long max(int a, long b) { return Math.max((long) a, b); }
static long max(long a, long b) { return Math.max(a, b); }
static double max(int a, double b) { return Math.max((double) a, b); }
static float max(float a, float b) { return Math.max(a, b); }
static double max(double a, double b) { return Math.max(a, b); }

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

static double max(double[] c) {
  if (c.length == 0) return Double.MIN_VALUE;
  double x = c[0];
  for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]);
  return x;
}

static float max(float[] c) {
  if (c.length == 0) return Float.MAX_VALUE;
  float x = c[0];
  for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]);
  return x;
}

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

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

static int max(int[] c) {
  int x = Integer.MIN_VALUE;
  for (int d : c) if (d > x) x = d;
  return x;
}
static long parseLong(String s) {
  if (s == null) return 0;
  return Long.parseLong(dropSuffix("L", s));
}

static long parseLong(Object s) {
  return Long.parseLong((String) s);
}
static Class run(String progID, String... args) {
  Class main = hotwire(progID);
  callMain(main, args);
  return main;
}
static boolean isEmpty(Collection c) {
  return c == null || c.isEmpty();
}

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

static boolean isEmpty(Object[] a) {
  return a == null || a.length == 0;
}

static boolean isEmpty(Map map) {
  return map == null || map.isEmpty();
}
static String htmlencode_forParams(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 >= 0x100)
        out.append("&#x").append(charToHex(c)).append(';');
      else*/ if (c > 127 || c == '"' || c == '<' || c == '>') {
          out.append("&#");
          out.append((int) c);
          out.append(';');
      } else
          out.append(c);
  }
  return out.toString();
}
static boolean startsWith(String a, String b) {
  return a != null && a.startsWith(b);
}

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



static boolean startsWith(List a, List b) {
  if (a == null || l(b) > l(a)) return false;
  for (int i = 0; i < l(b); i++)
    if (neq(a.get(i), b.get(i)))
      return false;
  return true;
}




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

static void callMain() {
  callMain(mc());
}
static boolean neq(Object a, Object b) {
  return !eq(a, b);
}
static Object sleepQuietly_monitor = new Object();

static void sleepQuietly() { try {
  assertFalse(isAWTThread());
  synchronized(sleepQuietly_monitor) { sleepQuietly_monitor.wait(); }
} catch (Exception __e) { throw rethrow(__e); } }
static Class<?> hotwire(String src) {
  assertFalse(_inCore());
  Class j = getJavaX();
  if (isAndroid()) {
    synchronized(j) { // hopefully this goes well...
      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;
    
  }
}
static String dropSuffix(String suffix, String s) {
  return s.endsWith(suffix) ? s.substring(0, l(s)-l(suffix)) : s;
}


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

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();
}
  
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
      out.append(c);
  }
  out.append('"');
}
static boolean _inCore() {
  return false;
}
static void hotwire_copyOver(Class c) {
  synchronized(StringBuffer.class) {
    for (String field : litlist("print_log", "print_silent", "androidContext")) {
      Object o = getOpt(mc(), field);
      if (o != null)
        setOpt(c, field, o);
    }
      
    Object mainBot = getMainBot();
    if (mainBot != null)
      setOpt(c, "mainBot", mainBot);

    setOpt(c, "creator_class", new WeakReference(mc()));
  }
}
static Object callOpt(Object o) {
  if (o == null) return null;
  return callF(o);
}

static Object callOpt(Object o, String method, Object... args) {
  try {
    if (o == null) return null;
    if (o instanceof Class) {
      Method m = callOpt_findStaticMethod((Class) o, method, args, false);
      if (m == null) return null;
      m.setAccessible(true);
      return invokeMethod(m, null, args);
    } else {
      Method m = callOpt_findMethod(o, method, args, false);
      if (m == null) return null;
      m.setAccessible(true);
      return invokeMethod(m, o, args);
    }
  } catch (Exception e) {
    //fail(e.getMessage() + " | Method: " + method + ", receiver: " + className(o) + ", args: (" + join(", ", map(f className, args) + ")");
    throw rethrow(e);
  }
}

static Method callOpt_findStaticMethod(Class c, String method, Object[] args, boolean debug) {
  Class _c = c;
  while (c != null) {
    for (Method m : c.getDeclaredMethods()) {
      if (debug)
        System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
      if (!m.getName().equals(method)) {
        if (debug) System.out.println("Method name mismatch: " + method);
        continue;
      }

      if ((m.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0 || !callOpt_checkArgs(m, args, debug))
        continue;

      return m;
    }
    c = c.getSuperclass();
  }
  return null;
}

static Method callOpt_findMethod(Object o, String method, Object[] args, boolean debug) {
  Class c = o.getClass();
  while (c != null) {
    for (Method m : c.getDeclaredMethods()) {
      if (debug)
        System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
      if (m.getName().equals(method) && callOpt_checkArgs(m, args, debug))
        return m;
    }
    c = c.getSuperclass();
  }
  return null;
}

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


static void assertFalse(Object o) {
  if (!(eq(o, false) /*|| isFalse(pcallF(o))*/))
    throw fail(str(o));
}
  
static boolean assertFalse(boolean b) {
  if (b) throw fail("oops");
  return b;
}

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



static abstract class VF1<A> {
  abstract void get(A a);
}static abstract class F1<A, B> {
  abstract B get(A a);
}static class FixedRateTimer extends java.util.Timer {
  FixedRateTimer() { this(false); }
  FixedRateTimer(boolean daemon) {
    super(daemon);
    _registerTimer(this);
  }
  
  List<Entry> entries = synchroList();
  
  static  class Entry {
  TimerTask task;
  long firstTime;
  long period;
  Entry() {}
  Entry(TimerTask task, long firstTime, long period) {
  this.period = period;
  this.firstTime = firstTime;
  this.task = task;}
  public String toString() { return "Entry(" + task + ", " + firstTime + ", " + period + ")"; }}
  
  // Note: not all methods overridden; only use these once
  
  public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
    entries.add(new Entry(task, now()+delay, period));
    super.scheduleAtFixedRate(task, delay, period);
  }
  
  public void cancel() {
    entries.clear();
    super.cancel();
  }
  
  public int purge() {
    entries.clear();
    return super.purge();
  }
}static class Pair<A, B> implements Comparable<Pair<A, B>> {
  A a;
  B b;

  Pair() {}
  Pair(A a, B b) {
  this.b = b;
  this.a = a;}
  
  public int hashCode() {
    return hashCodeFor(a) + 2*hashCodeFor(b);
  }
  
  public boolean equals(Object o) {
    if (o == this) return true;
    if (!(o instanceof Pair)) return false;
    Pair t = (Pair) o;
    return eq(a, t.a) && eq(b, t.b);
  }
  
  public String toString() {
    return "<" + a + ", " + b + ">";
  }
  
  public int compareTo(Pair<A, B> p) {
    if (p == null) return 1;
    int i = ((Comparable<A>) a).compareTo(p.a);
    if (i != 0) return i;
    return ((Comparable<B>) b).compareTo(p.b);
  }
}

static Set<java.util.Timer> _registerTimer_list = newWeakHashSet();

static void _registerTimer(java.util.Timer timer) {
  _registerTimer_list.add(timer);
}
static int hashCodeFor(Object a) {
  return a == null ? 0 : a.hashCode();
}


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


static <A> Set<A> synchroWeakHashSet() {
  return new WeakHashSet();
}


static class WeakHashSet<A> extends AbstractSet<A> {
  Map<A, Boolean> map = newWeakHashMap();
  
  public int size() { return map.size(); }
  public Iterator<A> iterator() { return keys(map).iterator(); }
  public boolean contains(Object o) { return map.containsKey(o); }
  
  public boolean add(A a) {
    return map.put(a, Boolean.TRUE) != null;
  }
  public boolean remove(Object o) { return map.remove(o) != null; }
  
  Object mutex() { return collectionMutex(map); }
}

static <A> Iterator<A> iterator(Iterable<A> c) {
  return c == null ? emptyIterator() : c.iterator();
}
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"));
    
  
  if (o instanceof WeakHashSet)
    c = className(o = ((WeakHashSet) o).mutex());
  
    
  return o;
}
static <A, B> Set<A> keys(Map<A, B> map) {
  return map == null ? new HashSet() : map.keySet();
}

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








static String className(Object o) {
  return getClassName(o);
}
static Iterator emptyIterator() {
  return Collections.emptyIterator();
}
static boolean eqOneOf(Object o, Object... l) {
  for (Object x : l) if (eq(o, x)) return true; return false;
}

}