abstract sclass DynSayAndInputBot > DynPrintLog { S input, dialogText; transient AbstractSayAndInputBot2 bot; void submitInput { setField(input := trim(input)); addToDialog("User: " + input); if (bot != null) bot.addInput(input); } visual jtabs("Dialog" := northCenterAndSouthWithMargins( rightAlignedButtons( "New dialog", rThread startDialog, "Clear window", rThread clearDialogText), dm_textArea_scrollDown_readOnly('dialogText), dm_textFieldAndSubmit_q('input, 'submitInput, focusOnShow := true)), "Log" := super); void runBot(AbstractSayAndInputBot2 bot) { this.bot = bot; runBot(); } void addToDialog(S s) { setField(dialogText := appendWithNewLine(dialogText, print(s))); } void runBot { bot.say = voidfunc(S s) { addToDialog("Bot: " + s) }; thread "Bot" { bot.run_public(); print("\n[end]"); } } void clearDialogText { setField(dialogText := ""); } abstract AbstractSayAndInputBot2 makeBot(); void startDialog { clearDialogText(); runBot(makeBot()); } start { logModuleOutput(); startDialog(); } }