sclass NewWoody { transient Map rulesByName; transient new L badRules; Map ruleData = ciMap(); S lastOutput; BBRule activeRule; sclass RuleData { int answerIndex; } RuleData ruleData(BBRule rule) { ret getOrCreate(ruleData, rule.listName, RuleData); } *() { rulesByName = indexFieldAsCIMap('listName, bb_allRules()); } *(NewWoody w) { copyFields(w, this, 'rulesByName, 'badRules); } void processInput(S input) { temp tempSetTL(ctxContext_var(), nu(CtxContext, +input)); new L matching; for (BBRule r : valuesList(rulesByName)) if (ruleExpressionMatches(r)) matching.add(r); lastOutput = null; activeRule = first(matching); if (activeRule != null) if (cic(activeRule.answerMode, 'random)) lastOutput = random(activeRule.answers); else { RuleData rd = ruleData(activeRule); lastOutput = get(activeRule.answers, rd.answerIndex = (rd.answerIndex+1) % l(activeRule.answers)); } } bool ruleExpressionMatches(BBRule r) { if (empty(r.expression)) false; try { ret ctxEvalCondition(r.expression); } catch print e { badRules.add(r); rulesByName.remove(r.listName); false; } } L listsMatchingInput(S input) { temp tempSetTL(ctxContext_var(), nu(CtxContext, +input)); ret [BBRule r : valuesList(rulesByName) | ruleExpressionMatches(r)]; } }