!7 sclass Node { S id, name; *() {} *(S *id, S *name) {} } sS meID = 'liahcrxesjjuwuur; sS functionsCollectionID = 'dudnfsbhcgoeudhs; static new L functions; static Canvas canvas; p { functions = persistentList("Functions"); canvas = showCAL(diagram(), 600, 400)); doFrameTitle(); calcOnConceptChanges(1000, r { canvas = showCAL(diagram(), canvas); doFrameTitle() }, false); bot("Soul Bot."); } svoid doFrameTitle { setFrameTitle("Happiness level " + happiness(), canvas); } static CirclesAndLines diagram() { new CirclesAndLines cal; // Static circles Circle me = cal.circle("Me\n\n" + meID, halfSizeImage(quickVisualize("Voice assistant")), 0.2, 0.2); int size = l(functions)*20+4; Circle f = cal.circle(whiteImage(size, size), 0.7, 0.65, n(functions, "function") + "\n(collection)\n\n" + functionsCollectionID); cal.arrow(me, "has", f); // Dynamically changing circles for (Node n : functions) { Circle fn = cal.circle(whiteImage(20, 20), random(0.5)+0.5, random(0.5)+0.5, n.name); cal.arrow(f, "contains", fn); } ret cal; } static int happiness() { ret 1+l(functions); } answer { if "add function *" { functions.add(new Node(aGlobalID(), $1)); ret "OK"; } if "remove function *" { removeWhereParams(functions, id := $1); removeWhereParams(functions, name := $1); ret "OK"; } }