gt: 			ESLVal[] vals = new ESLVal[t.getArity()];
context: package esl.lib;
  
  import java.io.Serializable;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.InvocationTargetException;
  import java.util.Hashtable;
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors;
  import java.util.concurrent.locks.ReentrantLock;
  import java.util.function.Consumer;
  import java.util.function.Supplier;
  
  import ast.general.AST;
  import ast.modules.Module;
  import edb.frame.EDBFrame;
  import runtime.data.Term;
  
  public class Lib {
  
  	public static abstract class SerializableFunction<T, R> implements java.util.function.Function<T, R>, Serializable {
  		public SerializableFunction() {
  		}
  	}
  
  	public static abstract class SerializableSupplier<T> implements java.util.function.Supplier<T>, Serializable {
  		public SerializableSupplier() {
  		}
  	}
  
  	static Actor														actor				= new DummyActor();
  	static Object														lock				= new Object();
  	final static int												THREADS			= 500;
  	static ExecutorService									threadPool	= Executors.newFixedThreadPool(THREADS);
  	static boolean													timerActive	= true;
  	static long															time0				= System.currentTimeMillis();
  	static Hashtable<Object, ReentrantLock>	locks				= new Hashtable<Object, ReentrantLock>();
  	public static ESLVal										edb					= new ESLVal(EDBFrame.FRAME);
  	public static ESLVal										$zero				= new ESLVal(0);
  	public static ESLVal										$one				= new ESLVal(1);
  	public static ESLVal										$true				= new ESLVal(true);
  	public static ESLVal										$false			= new ESLVal(false);
  	public static ESLVal										$null				= new Null();
  	public static ESLVal										$nil				= new Nil();
  	public static ESLVal										$emptyset		= new EmptySet();
  	public static ESLVal										$emptybag		= new EmptyBag();
  
  	public static ESLVal										wait				= new ESLVal(new Function(new ESLVal("wait"), null) {
  
  																												public ESLVal apply(ESLVal... args) {
  																													try {
  																														synchronized (Thread.currentThread()) {
  																															Thread.currentThread().wait(args[0].intVal);
  																														}
  																													} catch (InterruptedException e) {
  																														// Might happen if the system stops during a wait.
  																													}
  																													return Lib.$null;
  																												}
  																											});
  
  	public static ESLVal replaceNth(ESLVal list, ESLVal index, ESLVal v) {
  		int i = index.intVal;
  		while (i > 0 && list.state == ValState.CONS) {
  			i--;
  			list = list.tailVal;
  		}
  		if (list.state == ValState.CONS) {
  			list.headVal = v;
  			return list;
  		} else
  			throw new Error("replaceNth: ran out of list " + list);
  	}
  
  	public static ESLVal replaceNth = new ESLVal(new Function(new ESLVal("replaceNth"), null) {
  		public ESLVal apply(ESLVal... args) {
  			return replaceNth(args[0], args[1], args[2]);
  		}
  	});
  
  	public static ESLVal member(ESLVal x, ESLVal l) {
  		return l.member(x);
  	}
  
  	public static ESLVal member = new ESLVal(new Function(new ESLVal("member"), null) {
  		public ESLVal apply(ESLVal... args) {
  			return args[1].member(args[0]);
  		}
  	});
  
  	public static ESLVal sum(ESLVal l) {
  		int i = 0;
  		while(!l.isNil()) {
  			i += l.head().intVal;
  			l = l.tail();
  		}
  		return new ESLVal(i);
  	}
  	
  	public static ESLVal occurrences(ESLVal x, ESLVal l) {
  		return l.ocurrences(x);
  	}
  
  	public static ESLVal occurrences = new ESLVal(new Function(new ESLVal("occurrences"), null) {
  		public ESLVal apply(ESLVal... args) {
  			return args[1].ocurrences(args[0]);
  		}
  	});
  
  	public static ESLVal remove(ESLVal x, ESLVal l) {
  		return l.remove(x);
  	}
  
  	public static ESLVal remove = new ESLVal(new Function(new ESLVal("remove"), null) {
  		public ESLVal apply(ESLVal... args) {
  			return args[1].remove(args[0]);
  		}
  	});
  
  	public static ESLVal removeAll(ESLVal removables, ESLVal l) {
  		while (!removables.isNil()) {
  			ESLVal v = removables.headVal;
  			removables = removables.tailVal;
  			l = remove.apply(v, l);
  		}
  		return l;
  	}
  
  	public static ESLVal removeAll = new ESLVal(new Function(new ESLVal("removeAll"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal removables = args[0];
  			ESLVal l = args[1];
  			return removeAll(removables, l);
  		}
  	});
  
  	public static ESLVal exists(ESLVal p, ESLVal l) {
  		switch (l.state) {
  		case NIL:
  			return $false;
  		case CONS:
  			if (p.funVal.apply(l.headVal).boolVal)
  				return $true;
  			else
  				return exists.funVal.apply(p, l.tailVal);
  		default:
  			throw new Error("expecting a list: " + l);
  		}
  	}
  
  	public static ESLVal exists = new ESLVal(new Function(new ESLVal("exists"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal p = args[0];
  			ESLVal l = args[1];
  			return exists(p, l);
  		}
  	});
  
  	public static ESLVal filter(ESLVal p, ESLVal lin) {
  		ESLVal lout = $nil;
  		while (!lin.isNil()) {
  			ESLVal v = lin.headVal;
  			lin = lin.tailVal;
  			if (p.apply(v).boolVal) lout = lout.append(new ESLVal(v, $nil));
  		}
  		return lout;
  	}
  
  	public static ESLVal filter = new ESLVal(new Function(new ESLVal("filter"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal p = args[0];
  			ESLVal lin = args[1];
  			return filter(p, lin);
  		}
  	});
  
  	public static ESLVal forall(ESLVal p, ESLVal l) {
  
  		while (!l.isNil()) {
  			ESLVal v = l.headVal;
  			if (!p.apply(v).boolVal) return $false;
  			l = l.tailVal;
  		}
  		return $true;
  	}
  
  	public static ESLVal	forall	= new ESLVal(new Function(new ESLVal("forall"), null) {
  																	public ESLVal apply(ESLVal... args) {
  																		ESLVal p = args[0];
  																		ESLVal l = args[1];
  																		return forall(p, l);
  																	}
  																});
  
  	public static ESLVal	$ndCase	= new ESLVal(new Function(new ESLVal("$ndCase"), null) {
  
  																	public ESLVal apply(ESLVal... args) {
  																		ESLVal set = args[0];
  																		ESLVal arms = args[1];
  																		ESLVal fail = args[2];
  																		return ndCase(set, arms, fail);
  																	}
  																});
  
  	public static ESLVal reject(ESLVal p, ESLVal l) {
  		switch (l.state) {
  		case CONS:
  			if (p.apply(l.headVal).boolVal)
  				return reject.apply(p, l.tailVal);
  			else
  				return new ESLVal(l.headVal, reject.apply(p, l.tailVal));
  		case NIL:
  			return l;
  		default:
  			throw new Error("reject expects a list " + l);
  		}
  	}
  
  	public static ESLVal reject = new ESLVal(new Function(new ESLVal("reject"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal pred = args[0];
  			ESLVal l = args[1];
  			return reject(pred, l);
  		}
  	});
  
  	public static ESLVal map(ESLVal pred, ESLVal l) {
  		switch (l.state) {
  		case CONS:
  			return new ESLVal(pred.apply(l.headVal), map.apply(pred, l.tailVal));
  		case NIL:
  			return l;
  		default:
  			throw new Error("map expects a list " + l);
  		}
  	}
  
  	public static ESLVal map = new ESLVal(new Function(new ESLVal("map"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal pred = args[0];
  			ESLVal l = args[1];
  			return map(pred, l);
  		}
  	});
  
  	public static ESLVal nth(ESLVal list, ESLVal index) {
  		int i = index.intVal;
  		while (i != 0 && list.state == ValState.CONS) {
  			i--;
  			list = list.tailVal;
  		}
  		if (list.state == ValState.CONS) {
  			return list.headVal;
  		} else
  			throw new Error("nth ran out of elements: " + list);
  	}
  
  	public static ESLVal nth = new ESLVal(new Function(new ESLVal("nth"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal list = args[0];
  			ESLVal i = args[1];
  			return nth(list, i);
  		}
  	});
  
  	public static ESLVal take(ESLVal list, ESLVal index) {
  		int i = index.intVal;
  		return list.take(i);
  	}
  
  	public static ESLVal take = new ESLVal(new Function(new ESLVal("take"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal list = args[0];
  			ESLVal index = args[1];
  			return take(list, index);
  		}
  	});
  
  	public static ESLVal drop(ESLVal list, ESLVal index) {
  		int i = index.intVal;
  		return list.drop(i);
  	}
  
  	public static ESLVal drop = new ESLVal(new Function(new ESLVal("drop"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal list = args[0];
  			ESLVal index = args[1];
  			return drop(list, index);
  		}
  	});
  
  	public static ESLVal dropWhile(ESLVal pred, ESLVal list) {
  		if (list.isNil()) {
  			return list;
  		} else {
  			if (pred.apply(list.headVal).boolVal) {
  				return dropWhile.apply(pred, list.tailVal);
  			} else
  				return list;
  		}
  	}
  
  	public static ESLVal dropWhile = new ESLVal(new Function(new ESLVal("dropWhile"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal pred = args[0];
  			ESLVal list = args[1];
  			return dropWhile(pred, list);
  		}
  	});
  
  	public static ESLVal subst(ESLVal new_, ESLVal old, ESLVal list) {
  		if (list.isNil()) {
  			return list;
  		} else {
  			if (list.headVal.equals(old))
  				return new ESLVal(new_, subst.apply(new_, old, list.tailVal));
  			else
  				return new ESLVal(list.headVal, subst.apply(new_, old, list.tailVal));
  		}
  	}
  
  	public static ESLVal subst = new ESLVal(new Function(new ESLVal("subst"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal new_ = args[0];
  			ESLVal old = args[1];
  			ESLVal list = args[2];
  			return subst(new_, old, list);
  		}
  	});
  
  	public static ESLVal takeWhile(ESLVal pred, ESLVal list) {
  		if (list.isNil()) {
  			return list;
  		} else {
  			if (pred.apply(list.headVal).boolVal) {
  				return new ESLVal(list.headVal, takeWhile.apply(pred, list.tailVal));
  			} else
  				return $nil;
  		}
  	}
  
  	public static ESLVal	takeWhile	= new ESLVal(new Function(new ESLVal("takeWhile"), null) {
  																		public ESLVal apply(ESLVal... args) {
  																			ESLVal pred = args[0];
  																			ESLVal list = args[1];
  																			return takeWhile(pred, list);
  																		}
  																	});
  
  	public static ESLVal	builtin		= new ESLVal(new Function(new ESLVal("builtin"), null) {
  
  																		public ESLVal apply(ESLVal... args) {
  																			switch (args[1].strVal) {
  																			case "intToFloat":
  																				return intToFloat;
  																			case "round":
  																				return round;
  																			case "readWorkbook":
  																				return readWorkbook;
  																			case "writeWorkbook":
  																				return writeWorkbook;
  																			default:
  																				throw new Error("unknown builtin: " + args[1]);
  																			}
  																		}
  																	});
  
  	public static ESLVal removeDups(ESLVal lin) {
  		ESLVal lout = $nil;
  		while (!lin.isNil()) {
  			lout = lout.append(new ESLVal(lin.head(), $nil));
  			lin = remove.apply(lin.headVal, lin);
  		}
  		return lout;
  	}
  
  	public static ESLVal	removeDups		= new ESLVal(new Function(new ESLVal("removeDups"), null) {
  																				public ESLVal apply(ESLVal... args) {
  																					ESLVal lin = args[0];
  																					return removeDups(lin);
  																				}
  																			});
  
  	public static ESLVal	foldr					= new ESLVal(new Function(new ESLVal("foldr"), null) {
  
  																				public ESLVal apply(ESLVal... args) {
  																					ESLVal map = args[0];
  																					ESLVal bin = args[1];
  																					ESLVal unit = args[2];
  																					ESLVal list = args[3];
  																					return foldr(map, bin, unit, list);
  																				}
  																			});
  
  	public static ESLVal	round					= new ESLVal(new Function(new ESLVal("round"), null) {
  
  																				public ESLVal apply(ESLVal... args) {
  																					switch (args[0].state) {
  																					case INT:
  																						return args[0];
  																					case DOUBLE:
  																						return new ESLVal((int) Math.round(args[0].doubleVal));
  																					default:
  																						throw new Error("unknown type for round: " + args[0]);
  																					}
  																				}
  																			});
  
  	private static ESLVal	readWorkbook	= new ESLVal(new Function(new ESLVal("readWorkbook"), null) {
  
  																				public ESLVal apply(ESLVal... args) {
  																					String path = args[0].strVal;
  																					return ExcelReader.readWorkbook(path);
  																				}
  																			});
  
  	private static ESLVal	writeWorkbook	= new ESLVal(new Function(new ESLVal("writeWorkbook"), null) {
  
  																				public ESLVal apply(ESLVal... args) {
  																					String path = args[0].strVal;
  																					ESLVal term = args[1];
  																					return ExcelReader.writeWorkbook(path, term);
  																				}
  																			});
  
  	public static ESLVal	isqrt					= new ESLVal(new Function(new ESLVal("isqrt"), null) {
  
  																				public ESLVal apply(ESLVal... args) {
  																					return new ESLVal(Math.sqrt(args[0].intVal));
  																				}
  																			});
  
  	public static ESLVal	parse					= new ESLVal(new Function(new ESLVal("parse"), null) {
  
  																				public ESLVal apply(ESLVal... args) {
  																					String path = args[0].strVal;
  																					Module module = Module.parseModule(path, parser.ESL.readFile(path));
  																					runtime.data.Term term = (runtime.data.Term) AST.asESLValue(module);
  																					return asESLVal(term);
  																				}
  																			});
  
  	public static ESLVal	intToFloat		= new ESLVal(new Function(new ESLVal("intToFloat"), null) {
  
  																				public ESLVal apply(ESLVal... args) {
  																					return new ESLVal(1.0 * args[0].intVal);
  																				}
  																			});
  
  	public static ESLVal indexOf(ESLVal element, ESLVal list) {
  		int i = 0;
  		while (!list.isNil()) {
  			if (list.headVal.equals(element)) {
  				return new ESLVal(i);
  			} else {
  				i++;
  				list = list.tailVal;
  			}
  		}
  		throw new Error("cannot find index of " + element);
  	}
  
  	public static ESLVal indexOf = new ESLVal(new Function(new ESLVal("IndexOf"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal element = args[0];
  			ESLVal list = args[1];
  			return indexOf(element, list);
  		}
  	});
  
  	public static ESLVal lengthFun(ESLVal l) {
  		int i = 0;
  		while (l.state == ValState.CONS) {
  			i++;
  			l = l.tailVal;
  		}
  		return new ESLVal(i);
  	}
  
  	public static ESLVal length = new ESLVal(new Function(new ESLVal("length"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal l = args[0];
  			return lengthFun(l);
  		}
  	});
  
  	public static ESLVal last(ESLVal l) {
  		while (l.state == ValState.CONS) {
  			ESLVal v = l.headVal;
  			l = l.tailVal;
  			if (l.state == ValState.NIL) return v;
  		}
  		throw new Error("cannot find last value.");
  	}
  
  	public static ESLVal last = new ESLVal(new Function(new ESLVal("last"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal l = args[0];
  			return last(l);
  		}
  	});
  
  	public static ESLVal butlast(ESLVal l) {
  		if (l.isNil())
  			return l;
  		else if (l.tailVal.isNil())
  			return $nil;
  		else {
  			return new ESLVal(l.head(), butlast.apply(l.tailVal));
  		}
  	}
  
  	public static ESLVal butlast = new ESLVal(new Function(new ESLVal("butlast"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal l = args[0];
  			return butlast(l);
  		}
  	});
  
  	public static ESLVal select1(ESLVal l, ESLVal d, ESLVal p) {
  		while (l.state == ValState.CONS) {
  			if (p.apply(l.headVal).boolVal)
  				return l.headVal;
  			else {
  				l = l.tailVal;
  			}
  		}
  		return d;
  	}
  
  	public static ESLVal select1 = new ESLVal(new Function(new ESLVal("select1"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal l = args[0];
  			ESLVal d = args[1];
  			ESLVal p = args[2];
  			return select1(l, d, p);
  		}
  	});
  
  	public static ESLVal select(ESLVal pred, ESLVal lIn) {
  		ESLVal lOut = $nil;
  		while (!lIn.isNil()) {
  			if (pred.apply(lIn.headVal).boolVal) lOut = lOut.append(new ESLVal(lIn.headVal, $nil));
  			lIn = lIn.tailVal;
  		}
  		return lOut;
  	}
  
  	public static ESLVal select = new ESLVal(new Function(new ESLVal("select"), null) {
  		public ESLVal apply(ESLVal... args) {
  			ESLVal pred = args[0];
  			ESLVal lIn = args[1];
  			return select(pred, lIn);
  		}
  	});
  
  	public static ESLVal reverse(ESLVal l) {
  		return l.reverse();
  	}
  
  	public static ESLVal reverse = new ESLVal(new Function(new ESLVal("reverse"), null) {
  
  		public ESLVal apply(ESLVal... args) {
  			return args[0].reverse();
  		}
  	});
  
  	public static ESLVal flatten(ESLVal l) {
  		return l.flatten();
  	}
  
  	public static ESLVal flatten = new ESLVal(new Function(new ESLVal("flatten"), null) {
  		public ESLVal apply(ESLVal... args) {
  			return args[0].flatten();
  		}
  	});
  
  	public static ESLVal id(ESLVal x) {
  		return x;
  	}
  
  	public static ESLVal id = new ESLVal(new Function(new ESLVal("id"), null) {
  
  		public ESLVal apply(ESLVal... args) {
  			return args[0];
  		}
  	});
  
  	public static ESLVal head(ESLVal l) {
  		return l.head();
  	}
  
  	public static ESLVal head = new ESLVal(new Function(new ESLVal("head"), null) {
  
  		public ESLVal apply(ESLVal... args) {
  			return args[0].headVal;
  		}
  	});
  
  	public static ESLVal tail(ESLVal l) {
  		return l.tail();
  	}
  
  	public static ESLVal	tail		= new ESLVal(new Function(new ESLVal("tail"), null) {
  
  																	public ESLVal apply(ESLVal... args) {
  																		return args[0].tailVal;
  																	}
  																});
  
  	public static ESLVal	print		= new ESLVal(new Function(new ESLVal("print"), null) {
  
  																	public ESLVal apply(ESLVal... args) {
  																		System.out.println(args[0]);
  																		return Lib.$null;
  																	}
  																});
  
  	public static ESLVal	stopAll	= new ESLVal(new Function(new ESLVal("stopAll"), null) {
  
  																	public ESLVal apply(ESLVal... args) {
  																		stopAll();
  																		return Lib.$null;
  																	}
  																});
  
  	public static ESLVal	random	= new ESLVal(new Function(new ESLVal("random"), null) {
  
  																	public ESLVal apply(ESLVal... args) {
  																		return new ESLVal((int) (Math.random() * args[0].intVal));
  																	}
  																});
  
  	public static ESLVal	kill		= new ESLVal(new Function(new ESLVal("kill"), null) {
  
  																	public ESLVal apply(ESLVal... args) {
  																		switch (args[0].state) {
  																		case ACTOR:
  																			args[0].actor.stop();
  																			break;
  																		case JAVA_ACTOR:
  																			args[0].javaActor.stop();
  																			break;
  																		default:
  																			throw new Error("cannot stop " + args[0]);
  																		}
  																		return args[0];
  																	}
  																});
  
  	public static ESLVal asESLVal(Object o) {
  		if (o == null) return $null;
  		if (o instanceof Integer) return new ESLVal((int) o);
  		if (o instanceof String) return new ESLVal((String) o);
  		if (o instanceof Double) return new ESLVal((double) o);
  		if (o instanceof Boolean) return new ESLVal((boolean) o);
  		if (o instanceof list.Nil<?>) return $nil;
  		if (o instanceof list.List<?>) {
  			list.List<Object> l = (list.List<Object>) o;
  			return new ESLVal(asESLVal(l.getHead()), asESLVal(l.getTail()));
  		}
  		if (o instanceof Term) {
  			Term t = (Term) o;
  