sclass Thinker { L ranking = synchroList(); int listMakingTimeout = 2000; int maxListLength = 100; bool showExceptions, debug; volatile int load; O env; // must supply "makeGenerators" void startUp(O env, L log) { this.env = env; readLocally2(this, "ranking"); print("Ranking: " + structure(ranking)); } // also called from outside void recommendSolver(S solverID) { if (!isRecommendedSolver(solverID = fsi(solverID))) { print("Adding recommended solver: " + solverID); logQuoted("recommendations.txt", solverID); } else print("Solver already recommended: " + solverID); } bool isRecommendedSolver(S solverID) { ret contains(scanLog("recommendations.txt"), fsI(solverID)); } // log = what's in the chat // input = what user is typing void makeListData(L thelog, S input, L> otherLogs, L l) { long started = now(); try { long timeout = started + listMakingTimeout; new HashMap seen; // maps to the line // extended log including what user is typing L xlog = listPlus(thelog, input); // Make generators for both modes new L gens; for (bool completing : ll(false, true)) { new L gens_; try { genLog_set(completing ? xlog : thelog); gOtherLogs_set(otherLogs); gCompleting_set(completing); call(env, "makeGenerators", gens_); for (Gen g : gens_) gens.add(new Gen(g.name + gMode(), g.func)); } finally { genLog_clear(); gOtherLogs_clear(); gCompleting_set(null); } } // Rank all generators gens = rankGenerators(gens); // Produce list int i = -1; while (now() < timeout && l(l) < maxListLength && nempty(gens)) { i = (i+1) % l(gens); Gen gen = gens.get(i); bool completing = gen.name.endsWith("/i"); try { genLog_set(completing ? xlog : thelog); gOtherLogs_set(otherLogs); gCompleting_set(completing); bool remove = false; if (debug) print("Trying generator " + gen.name); try { S s = callGen(gen); if (empty(s) /*|| eq(input, s)*/) remove = true; else if (seen.containsKey(s)) { Map line = seen.get(s); setAdd((L) line.get("Suggesters"), gen.name); remove = true; } else { Map line = litorderedmap("Suggestion", s, "Suggesters", ll(gen.name)); l.add(line); seen.put(s, line); } } catch e { if (showExceptions) l.add(litorderedmap("Suggestion", "[error] " + exceptionToStringShort(e), "Suggesters", ll(gen.name))); remove = true; } if (remove) gens.remove(i--); } finally { genLog_clear(); gOtherLogs_clear(); gCompleting_set(null); } } } catch e { printStackTrace(e); l.add(e.toString()); } finally { load = (int) ((now()-started)*100/listMakingTimeout); } } L rankGenerators(L gens) { Map index = indexByField(gens, "name"); new L l; L rank = cloneList(ranking); for (S name : rank) { Gen g = index.get(name); if (g != null) { l.add(g); index.remove(name); } } l.addAll(values(index)); // add rest in unspecified order //print("Using ranking: " + struct(rank)); //print("Ranked generators: " + struct(l)); ret l; } void rankToTop(S name) { if (empty(name)) ret; if (eq(first(ranking), name)) ret; ranking.remove(name); ranking.add(0, name); saveLocally2(this, "ranking"); print("New ranking: " + structure(ranking)); } }