Warning: session_start(): open(/var/lib/php/sessions/sess_l8i0qvdnb3fnketu6erqa6se8l, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
// TODO: prevent non-master users from setting createdBy field manually
mainPackage gazelle
mainClassName main
set flag needToKnowMainLib.
!include early #1031277 // BEA general includes
!include once #1030833 // BEACalculations
//set flag defaultDefaultClassFinder_debug.
set flag CleanImports.
set flag DynModule.
set flag NoNanoHTTPD.
set flag AllPublic. // for dynamic BEA objects
rewrite BEA with BEAObject.
abstract static class GazelleBEA > DynGazelleRocks {
switchable bool mirrorBEAObjects; // don't do it for now
switchable bool enableAutoRuns = true;
switchable bool enableNewBEAObjectNotis = true;
switchable bool printAllConceptChanges;
switchable bool useShadowLogger = true;
switchable bool autoActivateDynamicObjects = true;
switchable bool reloadWhenMainLibUpdates;
switchable S baseSystemVersion = "1"; // increase this when all dynamic objects need a recompile
S activateOnlyTheseIDs;
S dontActivateTheseIDs;
transient ReliableSingleThread_Multi rstAutoRuns = dm_rstMulti(this, 1000, lambda1 performAutoRuns);
transient Q notificationQ;
transient ReliableSingleThread_Multi rstDistributeNewObject = dm_rstMulti(this, 1000, lambda1 distributeNewObject_impl);
transient Set newObjectsDistributed = weakSet();
transient ReliableSingleThread_Multi rstUpdateBEAMirrors = dm_rstMulti(this, 100, c -> c.updateMirrorPost());
transient ReliableSingleThread_Multi rstAutoActivateDynamicObjects = dm_rstMulti(this, 100, lambda1 autoActivateDynamicObject);
transient BEACalculations calculations = new(this);
transient BEACalculations calc = calculations;
transient int newFieldsToShow = 3;
transient bool allowAnonymousInputUpload = true; // TODO
switchable int maxInputLength = 50000;
switchable S mainDomainWithProtocol = "https://bea.gazelle.rocks";
switchable bool verboseQStartsAndStops;
transient ConceptClassesDependentValue inputsWithoutRewrites;
transient ConceptClassesDependentValue inputsWithoutMatches;
transient ConceptClassesDependentValue syntacticPatternsWithoutRewrites;
transient Set deadClassPaths = syncLinkedHashSet();
transient new x30_pkg.x30_util.BetterThreadLocal beaThreadOwner;
// add more fields for GazelleBEA here
!include #1030883 // DB quickImport mix-in
void init {
super.init();
//set quickDBReloadEnabled;
botName = heading = adminName = "Gazelle BEA";
set enableVars;
unset showTalkToBotLink;
unset phoneNumberSpecialInputField;
unset showMetaBotOnEveryPage;
}
Class lookForClass(ClassLoader cl, S name) {
pcall {
// first thing - filter
if (!name.startsWith(DynClassName_mainPrefixForVM())) null;
print("Looking for class " + name);
DynClassName dcn = DynClassName_parse(name);
if (dcn == null) dcn = DynClassName_parseOther(name);
if (dcn == null) {
vmBus_send lookingForClass_noDCNParse(name);
null;
}
S subPath = vmClassNameToSubPath(dcn.fullClassNameForVM());
File byteCode = dcn.byteCodeFile();
vmBus_send lookingForClass_haveByteCodeFile(byteCode);
// jar already added? done.
if (classLoaderContainsByteCodePath(cl, byteCode)) {
vmBus_send lookingForClass_haveByteCodePath(byteCode);
null;
}
// class file not found? bad.
bool exists = fileExistsInInDirOrZip(byteCode, subPath);
printVars(+exists, +subPath, +byteCode);
if (!exists) {
vmBus_send lookingForClass_subPathNotInByteCode(byteCode, subPath);
fail("Class not found: " + subPath + " in " + byteCode);
}
// register byte code path
addByteCodePathToClassLoader(cl, byteCode);
assertTrue("Byte code added", classLoaderContainsByteCodePath(cl, byteCode));
vmBus_send lookingForClass_byteCodePathAdded(byteCode);
ret (Class) call(cl, "super_findClass", name);
// null; // just let the class loader do its thing
// recursive call
//ctex { ret cl.loadClass(name); }
}
null;
}
void startDB {
ClassLoader cl = dm_moduleClassLoader();
setOpt(cl, verbose := true);
setFieldToIF1Proxy(cl, findClass_extension := (IF1) name -> {
vmBus_send lookingForClass(cl, name);
Class c = lookForClass(cl, name);
vmBus_send lookingForClass_result(cl, name, c);
ret c;
});
O classFinder = _defaultClassFinder();
db_mainConcepts().classFinder = func(S name) -> Class enter {
print("Deserializing class " + name);
try {
S name2 = dropPrefix(mcName() + "$", name);
S mainPrefix = dotToDollar(DynClassName_mainPrefix());
//printVars(+mainPrefix, +name2);
if (name2.startsWith(mainPrefix)) {
S vmName = DynClassName_parse(name2).fullClassNameForVM();
print("Loading dynamic class " + vmName);
Class c = classLoader_loadClass(module(), vmName);
//print(+c);
ret c;
}
Class c = cast callF(classFinder, name);
print(+c);
ret c;
} on fail e {
printStackTrace(e);
}
};
db();
Concepts concepts = db_mainConcepts();
concepts.useBackRefsForSearches = true;
concepts.makeStructureData = () ->
concepts.finishStructureData(new structure_Data {
void writeObject(O o, S shortName, MapSO fv) {
if (o instanceof Concept && conceptID(o/Concept) == 136925)
print("writeProblemObject " + shortName + " " + fv);
super.writeObject(o, shortName, fv);
}
});
inputsWithoutRewrites = ConceptClassesDependentValue(litset(BEA), () -> countPred(beaList("Input"), c -> empty(beaBackRefs(c, "Rewrite"))));
inputsWithoutMatches = ConceptClassesDependentValue(litset(BEA), () -> countPred(beaList("Input"), c -> empty(beaBackRefs(c, "Match"))));
syntacticPatternsWithoutRewrites = ConceptClassesDependentValue(litset(BEA), () -> countPred(beaList("Syntactic Pattern"), c -> empty(beaBackRefs(c, "Rewrite"))));
if (useShadowLogger) {
ConceptsShadowLogger shadowLogger = new(db_mainConcepts());
shadowLogger.install();
//shadowLogger.writer = printWriter(deflaterOutputStream_syncFlush_append(programFile("shadow.log.deflated")));
shadowLogger.writer = filePrintWriter_append(programFile("shadow.log"));
dm_doEvery(10.0, r { shadowLogger.flush(); });
ownResource(shadowLogger);
}
if (printAllConceptChanges) printAllConceptChanges();
}
MapSO emergencyFlags() {
ret (Map) parseEqualsProperties(
joinNemptiesWithEmptyLines(
loadTextFile(programFile("gazelle-emergency-options.txt")),
loadTextFile(javaxDataDir("gazelle-emergency-options.txt")),
));
}
void start {
print("Module ID: " + dm_moduleID());
set !useBotNameAsModuleName;
setOptAllDyn_pcall(module(), pnl(+emergencyFlags());
change();
S name = actualMCDollar() + "BEAObject";
print(+name);
assertEquals(BEAObject, callF(defaultDefaultClassFinder(), name));
assertEquals(ConceptWithGlobalID, callF(defaultDefaultClassFinder(), mcDollar() + "ConceptWithGlobalID"));
//seedDBFrom(#1030602);
set botDisabled;
set storeBaseClassesInStructure;
super.start();
print("main concepts: " + db_mainConcepts() + ", count: " + db_mainConcepts().countConcepts());
print(renderConceptClassesWithCount(db_mainConcepts()));
print("Inputs: " + n2(beaCount("Input")));
set showCRUDToEveryone;
//set showOnlySelectedObject;
// reload module when lib changes
dm_onSnippetTranspiled(mainLibID, r {
if (reloadWhenMainLibUpdates)
dm_reloadModule();
});
if (!enabled) ret;
// mirror all objects to be sure
rstUpdateBEAMirrors.addAll(list(BEAObject));
newObjectsDistributed.addAll(list(BEAObject));
/*onIndividualConceptChange_notOnAllChanged(BEAObject,
p -> { calculations.makeSyntacticPattern(p); });*/
onIndividualConceptChange_notOnAllChanged(BEAObject,
o -> {
if (enableAutoRuns) rstAutoRuns.add(o);
if (enableNewBEAObjectNotis && newObjectsDistributed.add(o))
rstDistributeNewObject.add(o);
});
notificationQ = dm_startQ();
// fix refs occasionally
dm_doEvery(5*60.0, r-enter {
print(ConceptsRefChecker(db_mainConcepts()).runAndFixAll());
});
// call _activate on all objects
setField(activateOnlyTheseIDs := nemptyLinesLL(
loadTextFile(programDir("gazelle-activate-only")),
loadTextFile(javaxDataDir("gazelle-activate-only"))));
Set ids = activateOnlyTheseIDs();
Set antiIDs = dontActivateTheseIDs();
print("Object IDs to activate: " + (ids == null ? "ALL" : ids));
if (nempty(antiIDs)) print("Object IDs not to activate: " + (ids == null ? "ALL" : ids));
for (BEA bea)
if ((ids == null || contains(ids, bea.id)) && !contains(antiIDs, bea.id)) {
//print("Activating: " + bea);
callActivate(bea);
}
// clean old websockets
for (BEA o : cloneList(beaList("Live WebSocket")))
cdelete(o);
print("All objects activated");
}
void makeIndices :: after {
indexConceptClass(BSettings);
indexConceptFieldDesc(BEAObject, "_modified");
indexConceptFieldCIWithTopTen(BEAObject, "type");
indexConceptFieldIC(BEAObject, "text");
indexConceptFieldIC(BEAObject, "purpose");
}
L crudClasses(Req req) {
ret listPlus(super.crudClasses(req), BEAObject, /*BEAPatternList*/);
}
Set hiddenCrudClasses() {
Set set = super.hiddenCrudClasses();
addAll(set, Conversation, ExecutedStep, InputHandled);
ret set;
}
S authFormHeading() {
ret h3("Gazelle BEA");
}
void makeFramer(Req req) {
super.makeFramer(req);
req.framer.addInHead(hjs_autoExpandingTextAreas());
}
HCRUD_Concepts crudData(Class c, Req req) {
HCRUD_Concepts cc = super.crudData(c, req);
if (c == BEAObject) {
cc.humanizeFieldNames = false;
cc.convertConceptValuesToRefs = true;
cc.itemName = () -> "BEA Object";
cc.addRenderer("meta_code", new HCRUD_Data.AceEditor(80, 20));
cc.isEditableValue = o ->
cc.isEditableValue_base(o)
&& !eq(shortClassName(o), "MultiSet");
cc.conceptClassForComboBoxSearch = (info, query) -> {
if (endsWith(info, "_nativeValue"))
ret Concept;
ret cc.conceptClassForComboBoxSearch_base(info, query);
};
cc.comboBoxSearchBaseItems = (info, query) -> {
new Matches m;
printVars comboBoxSearchBaseItems(+info);
if (jMatchStart("type=", info, m)) {
var l = beaList($1);
print("Got " + nItems(l));
ret cc.comboBoxItems(l);
}
ret cc.comboBoxSearchBaseItems_base(info, query);
};
cc.onCreate.add(o ->
cset(o, createdBy := currentUser()));
cc.getObjectForDuplication = id -> {
BEA o = beaGet(toLong(id));
MapSO item = cc.getObjectForDuplication_base(id);
item.put(createdBy := req.auth.user!); // set default creator to current user
item.put(createdFrom := o);
// call enhancer object
item = (MapSO) pcallOpt(cget cleanObjectForDuplication(websiteEnhancersObject()), "cleanObjectForDuplication", o, item);
ret item;
};
cc.emptyObject = () -> {
MapSO item = cc.emptyObject_base();
item.put(type := "");
ret item;
};
Set deletableRefs = litciset("Match");
cc.objectCanBeDeleted = id -> {
BEA o = cast cc.conceptForID(id);
ret userCanEditObject(user(req), o)
&& all(findBackRefs(BEAObject, o), x -> contains(deletableRefs, x.type()));
};
cc.actuallyDeleteConcept = o -> {
deleteConcepts(filter(findBackRefs(BEAObject, o),
o2 -> contains(deletableRefs, o2.type())));
cdelete(o);
};
}
ret cc;
}
HCRUD makeCRUD(Class c, Req req, HTMLFramer1 framer) {
HCRUD crud = super.makeCRUD(c, req, framer);
HCRUD_Concepts data = cast crud.data;
crud.showOnlySelected = true;
crud.showSearchField = true;
if (data.customFilter == null)
crud.descending = true; // show latest objects first by default except when searching
crud.cleanItemIDs = true;
if (c == BEAObject) {
crud.allowFieldRenaming = true;
var renderValue_old = crud.renderValue;
crud.renderValue = (field, value) -> {
S html = crud.renderValue_fallback(renderValue_old, field, value);
ret addShowMoreButton(html);
};
crud.cellColumnToolTips = true;
crud.unshownFields = litset("mirrorPost", "globalID");
crud.showTextFieldsAsAutoExpandingTextAreas = true;
crud.duplicateInNewTab = true;
crud.customizeACEEditor = ace -> {
ace.onKeyDown = "function(event) { " + jquery_submitFormOnCtrlEnter() + " }";
};
HCRUD_Concepts cc = cast crud.data;
S typeFilter = req.get("type");
if (nempty(typeFilter))
cc.addCIFilter(type := typeFilter);
crud.renderCmds = map -> {
BEA o = getConcept BEA(crud.itemIDAsLong(map));
new LS cmds;
// ask the object itself for commands
addAll(cmds, allToString(optCast Cl(pcall(o, "cmds"))));
// special commands for BEA types or objects with certain fields
if (fileNotEmpty(javaSourceFileForObject(o)))
cmds.add(targetBlank(baseLink + "/javaSource?id=" + o.id, "Show Java source"));
for (S field : ll("text", "what", "type")) {
S text = getStringOpt(o, field);
if (nempty(text))
cmds.add(
targetBlank(addParamsToURL(baseLink + "/query",
q := text, algorithm := "process input"),
"Use field " + quote(field) + " as query"));
}
if (o.typeIs("Input")) {
cmds.add(ahref(addParamsToURL(crudLink(BEAObject),
cmd := "new",
title := "Add Pattern For Input",
f_type := "Pattern",
f_text := getStringOpt text(o),
f_shouldMatch := o.id, metaInfo_shouldMatch := "concept",
), "Add pattern"));
cmds.add(ahref(appendParamsToURL(baseLink + "/query", q := o.text(), algorithm := "Apply all text functions"),
"Apply all text functions"));
}
if (o.typeIs("Pattern"))
cmds.add(ahref(appendParamsToURL(baseLink + "/query", q := o.id, algorithm := "Run pattern"),
"Try-run pattern against all inputs"));
if (o.typeIsOneOf("Pattern", "Syntactic Pattern")) {
cmds.add(ahref(appendParamsToURL(baseLink + "/reactAllInputsWithPattern", patternID := o.id),
"React pattern with all inputs"));
cmds.add(ahref(appendParamsToURL(baseLink + "/convertSyntacticToSemanticMatchesForWholePattern", patternID := o.id),
"Convert all syntactic matches to semantic matches"));
}
if (o.typeIs("Match")) {
cmds.add(ahref(appendParamsToURL(baseLink + "/query", q := o.id, algorithm := "Find rewrites for match"),
"Find rewrites"));
if (beaTypeIs(beaGet pattern(o), "Syntactic Pattern"))
cmds.add(ahref(appendParamsToURL(baseLink + "/convertSyntacticToSemanticMatches", matchID := o.id),
"Convert to semantic matches"));
}
cmds.add(
targetBlank(addParamsToURL(crudLink(BEA),
cmd := "new",
newField1_name := "inReferenceTo",
newField1_type := "BEAObject",
newField1_conceptValue := o.id),
"Reference this"));
cmds.add(
ahref(addParamsToURL(baseLink + "/markUseful",
redirect := beaShortURL(o),
objectID := o.id),
"Mark useful"));
cmds.add(
ahref(addParamsToURL(baseLink + "/markBad",
redirect := beaShortURL(o),
objectID := o.id),
"Mark bad"));
cmds.add(addCommentHTML(o));
if (o.typeIsOneOf("Script", "Step in script") || eqic(beforeVerticalBar(o.type()), "Instruction"))
cmds.add(
ahref(addParamsToURL(baseLink + "/runInstruction",
instruction := o.id),
"Run"));
if (o.typeIs("Function Result")) {
if (eqic(cget resultType(o), "string"))
cmds.add(
ahref(addParamsToURL(baseLink + "/convertResultToInput",
result := o.id),
"Convert to input"));
}
if (o.typeIs("Auto Run"))
cmds.add(
ahref(addParamsToURL(baseLink + "/performAutoRunOnAllObjects", autoRun := o.id), "Run on all objects"));
if (o.getClass() != BEA)
cmds.add(
ahref(addParamsToURL(baseLink + "/migrateToBase", id := o.id), "Migrate to BEAObject"));
cmds.add(
ahref(addParamsToURL(baseLink + "/performAutoRuns",
onObject := o.id),
"Perform auto runs on this object"));
framer.addInHead(hjs_copyToClipboard());
cmds.add(ahref_onClick(formatFunctionCall copyToClipboard(jsQuote(o.globalIDStr())), "Copy global ID [" + o.globalIDStr() + "]"));
LS items = llNempties(
crud.renderCmds_base(map),
!o.typeIsOneOf("Input", "Pattern", "Syntactic Pattern")
? null : addRewriteHTML(o),
!canAutoMigrate(o) ? null
: ahref(addParamsToURL(baseLink + "/autoMigrate", id := o.id), "Auto-migrate to " + shortClassName(defaultCustomClass(o))));
if (isObjectWithCode(o) && isMasterAuthed(req)) {
S link = baseLink + "/activateDynamicObject?id=" + o.id;
if (!codeHashUpToDate(o))
if (cget meta_codeHash(o) == null)
items.add(ahref(link, "Compile new code", title := "Object has not been compiled yet"));
else
items.add(ahref(link, "Compile changed code", title := "Code has changed afer last compilation"));
else if (compileErrorInObject(o))
items.add("Code error. " + ahref(link, "Compile again", title := "Object has code errors - maybe recompiling fixes them?"));
else if (o.customCodeLoaded())
items.add(ahref(link, "Compile again", title := "Custom code is loaded. Click if you want to recompile anyway"));
else
items.add(ahref(link, "Compile & load"));
}
// add more commands here
pcall { addAll(items, o.directCmds()); }
pcall {
addAll(items, (LS) callOpt(getWebsiteEnhancer("commandsForObject"), 'commandsFor, o));
}
items.add(hPopDownButton(cmds));
ret joinNemptiesWithVBar(items);
};
cc.massageItemMapForList = (item, map) -> {
BEAObject o = cast item;
if (o.typeIs("Input")) {
Cl matches = objectsWhereNotIC(objectsWhereCI(findBackRefs(o, BEAObject), type := "match"),
label := "bad");
map/Map.put("Best Matches", HTML(hparagraphs(
lmap matchDescHTML(takeFirst(3, matches)))));
}
S idField = crud.idField();
O id = map/Map.get(idField);
if (id instanceof S)
map/Map.put(idField, HTML(ahref(beaShortURL(o), id)));
if (o.typeIs("Function Result")) {
O value = o~.result;
map/Map.put("result", HTML(javaValueToHTML(value)));
}
if (o.typeIs("Match")) {
SS mapping = o.mapping();
if (mapping != null)
map/Map.put("mapping", HTML(
joinWithBR(map(mapping, (k, v) ->
htmlEncode2(k) + "=" + calculations.bestInputHTML(v)))));
}
if (o.getClass() != BEA)
map/Map.put("Java Class", dropPrefix(actualMCDollar(), className(o)));
if (eq(req.get("showSimpleObjectScore"), "1"))
map/Map.put("Simple object score" := calculations.simpleObjectScore(o));
}; // end of massageItemMapForList
crud.massageFormMatrix = (map, matrix) -> {
for (int i = 1; i <= newFieldsToShow; i++) {
S nf = "newField" + i;
S key = "\*nf*/_conceptValue";
BEA refValue = beaGet(req.get(key));
S refSelector =
crud.renderInput(key,
cc.makeConceptsComboBox(key, BEAObject), refValue)
+ hjs([[$("[name=]] + key + [[]").hide()]]);
S nativeSelector =
crud.renderInput("\*nf*/_nativeValue",
cc.makeConceptsComboBox("\*nf*/_nativeValue", Concept), null)
+ hjs([[$("[name=]] + nf + [[_nativeValue]").hide()]]);
LS types = ll("String", "BEAObject", "Bool", "Native");
S toggleVis = [[
$("[name=]] + nf + [[_value]").toggle(value == "String" || value == "Bool");
$("#]] + nf + [[_refBox").toggle(value == "BEAObject");
$("#]] + nf + [[_nativeSel").toggle(value == "Native");
]];
S type = req.get("\*nf*/_type");
S typeSelector = hselect_list(types, type, name := "\*nf*/_type",
onchange := "var value = this.value;" + toggleVis);
if (nempty(type))
typeSelector += hscript("(function(value) {" + toggleVis + "})(" + jsQuote(type) + ")");
matrix.add(ll("Add field:
" + htextfield("\*nf*/_name", req.get("\*nf*/_name"), title := "New field name"),
htmlTable2_noHtmlEncode(ll(ll(
// string input
//htextfield("\*nf*/_value"),
crud.renderTextField("\*nf*/_value", "", 40)
/*htextarea("",
name := nf + "_value",
class := "auto-expand",
style := "width: 300px",
)*/ +
span(refSelector, id := "\*nf*/_refBox", style := "display: none"),
span(nativeSelector, id := "\*nf*/_nativeSel", style := "display: none"),
"Type", typeSelector
)),
noHeader := true,
tableParams := litobjectarray(style := "width: 100%"))));
}
};
crud.preprocessUpdateParams = params -> {
params = cloneMap(params);
// drop empty strings
//removeFromMapWhereValue(params, v -> eq(v, ""));
params = mapValues(params, v -> eq(v, "") ? null : v);
for (int i = 1; i <= max(newFieldsToShow, 10); i++) {
S nf = "newField" + i;
S name = trim(params.get("\*nf*/_name")),
type = params.get("\*nf*/_type"),
refValue = params.get("\*nf*/_conceptValue"),
nativeValue = params.get("\*nf*/_nativeValue"),
value = params.get("\*nf*/_value");
if (eqic(type, "BEAObject")) {
value = refValue;
params.put("metaInfo_" + name, "concept");
} else if (eqic(type, "Native")) {
value = nativeValue;
params.put("metaInfo_" + name, "concept");
} else if (eqic(type, "Bool"))
params.put("metaInfo_" + name, "bool");
if (eq(value, "")) value = null;
if (nempty(name) /*&& neqOneOf(value, null, "")*/)
params.put(crud.fieldPrefix + name, value);
}
ret params;
};
// regular users can only edit their own objects
if (!isMasterAuthed(req))
cc.objectCanBeEdited = id -> userCanEditObject(user(req), (BEA) cc.conceptForID(id));
} // end of CRUD customization for BEAObject
ret crud;
}
bool userCanEditObject(User user, BEA o) {
ret user != null && (user.isMaster || cget createdBy(o) == user);
}
O serveBotFunction(Req req, S function, Map data, User user) {
if (eq(function, "beaList")) {
long changedAfter = toLong(data.get("changedAfter"));
double pollFor = min(bot_maxPollSeconds, toLong(data.get("pollFor"))); // how long to poll (seconds)
long startTime = sysNow();
// We're super-anal about catching all changes. This will probably never trigger
if (changedAfter > 0 && changedAfter == now()) sleep(1);
Cl objects;
while true {
objects = changedAfter == 0 ? list(BEAObject)
: conceptsWithFieldGreaterThan_sorted(BEAObject, _modified := changedAfter);
// return when there are results, no polling or poll expired
if (nempty(objects) || pollFor == 0 || elapsedSeconds_sysNow(startTime) >= pollFor)
ret serveJSON_breakAtLevels(2, result := map(objects, obj ->
litorderedmap(gid := str(obj.globalID()), struct := obj.structureString())
));
// sleep and try again
sleep(bot_pollInterval);
}
}
ret super.serveBotFunction(req, function, data, user);
}
O serveOtherPage2(Req req) null {
//printVars_str serveOtherPage2(uri := req.uri);
try object super.serveOtherPage2(req);
S uri = dropTrailingSlashIfNemptyAfterwards(req.uri);
new Matches m;
if (swic_notSame(uri, "/beaCRUD/", m))
ret renderBEAObjectTable(req, urldecode(m.rest()));
if (eq(uri, "/inputs"))
ret renderBEAObjectTable(req, "input");
if (eq(uri, "/syntacticMatchesTable"))
ret hrefresh(baseLink + "/matchesTable?syntacticOnly=1");
if (eq(uri, "/matchesTable")) {
bool syntacticOnly = eq("1", req.get("syntacticOnly"));
new L list;
for (BEA match : beaList("Match")) {
BEA input = cgetOpt BEA(match, "input");
BEA pat = cgetOpt BEA(match, "pattern");
if (syntacticOnly && !calculations.isSyntacticPattern(pat)) continue;
continue if calculations.patternAlwaysMatches(pat);
SS mapping = match.mapping();
if (input == null || pat == null || mapping == null) continue;
list.add(match);
}
list = sortedByCalculatedFieldDesc(list,
match -> conceptID(cgetBEA input(match)));
new HTMLPaginator paginator;
paginator.processParams(req.params());
paginator.baseLink = addParamsToURL(baseLink,
filterKeys(req.params(), p -> eq(p, "syntacticOnly")));
paginator.max = l(list);
req.framer.add(divUnlessEmpty(paginator.renderNav()));
list = subList(list, paginator.visibleRange());
new L