!747 m { static new Map states; static int nMaxHistory = 2; static class State { S id; S machineID; S dataID; long since; S status; State previous; } p { readLocally("states"); makeAndroid3("Identity Manager."); } static synchronized S answer(S s, L history) { new Matches m; if (match3("* is now on machine * with data *", s, m)) { S programID = formatSnippetID(unquote(m.m[0])); S machineID = unquote(m.m[1]); S dataID = formatSnippetID(unquote(m.m[2])); new State state; state.since = now(); state.machineID = machineID; state.dataID = dataID; state.status = "residing"; setState(programID, state); return "OK"; } if (match3("* is now in state *", s, m)) { S programID = formatSnippetID(unquote(m.m[0])); new State state; state.since = now(); State last = states.get(programID); if (last != null) { state.machineID = last.machineID; state.dataID = last.dataID; } state.status = unquote(m.m[1]); setState(programID, state); return "OK"; } if (match3("* is now in state * with data * to machine *", s, m)) { S programID = formatSnippetID(unquote(m.m[0])); new State state; state.since = now(); State last = states.get(programID); state.machineID = unquote(m.m[3]); state.status = unquote(m.m[1]); state.dataID = formatSnippetID(unquote(m.m[2])); setState(programID, state); return "OK"; } if (match3("get state of *", s, m)) return structure(states.get(formatSnippetID(unquote(m.m[0])))); if (match3("what machine is * supposed to be on ", s, m)) { State state = states.get(formatSnippetID(unquote(m.m[0]))); ret state == null ? "Sorry, no information on bot" : format3("this one: *", state.machineID); } if (match3("list programs", s, m)) return structure(states.keySet()); if (match3("who is moving to *?", s, m)) { S machineID = unquote(m.m[0]); return structure(ids(forStateAndMachine("moving", machineID))); } if (match3("who is moving to * (full state)?", s, m)) { S machineID = unquote(m.m[0]); return structure(forStateAndMachine("moving", machineID)); } ret standardQuery(s, "states"); } static L forStateAndMachine(S status, S machineID) { new L l; for (State state : states.values()) { if (eq(state.status, status) && eq(state.machineID, machineID)) l.add(state); } ret l; } static L ids(L states) { new L ids; for (State state : states) ids.add(state.id); ret ids; } static void clearHistory(State state) { for (int n = 0; n < nMaxHistory; n++) { state = state.previous; if (state == null) return; } state.previous = null; } static synchronized void setState(S programID, State state) { state.id = programID; state.previous = states.get(programID); clearHistory(state); states.put(programID, state); saveLocally("states"); } }