parent root object user_db var root name 'user_db var user_db user_names #[] var user_db users [] var user_db connected_users [] eval .initialize(); . method user_created var user; if (caller() != $user) throw(~perm, "Caller is not $user."); user = sender(); users = [@users, user]; user_names = dict_add(user_names, user.vr_name(), user); . method user_changed_name arg old_name; var user; if (caller() != $user) throw(~perm, "Caller is not $user."); user = sender(); user_names = dict_del(user_names, old_name); user_names = dict_add(user_names, user.vr_name(), user); . method user_going_away var user; if (caller() != $user) throw(~perm, "Caller is not $user."); user = sender(); user_names = dict_del(user_names, user.vr_name()); users = setremove(users, user); connected_users = setremove(connected_users, user); . method user_connected if (caller() != $user) throw(~perm, "Caller is not $user."); connected_users = [@connected_users, sender()]; . method user_disconnected if (caller() != $user) throw(~perm, "Caller is not $user."); connected_users = setremove(connected_users, sender()); . method users return users; . method connected_users return connected_users; . method find_user arg name; catch ~keynf { return user_names[name]; } with handler { throw(~usernf, "User name " + toliteral(name) + " not found."); } .