diff --git a/client/scripts/WebConsole.js b/client/scripts/WebConsole.js
index 8b46d88..a49e878 100644
--- a/client/scripts/WebConsole.js
+++ b/client/scripts/WebConsole.js
@@ -5,14 +5,14 @@
*/
/**
-* Global variables
-*/
-var persistenceManager = new WebConsolePersistenceManager();
-var connectionManager = new WebConsoleManager();
-var lang;
-var autoPasswordCompleted = false; //When true, saved password was used. If a 401 is received, then saved password is not correct
-var statusCommandsInterval = -1;
-var commandHistoryIndex = -1; //Saves current command history index. -1 when not browsing history.
+ * Global variables
+ */
+const persistenceManager = new WebConsolePersistenceManager();
+const connectionManager = new WebConsoleManager();
+let lang;
+let autoPasswordCompleted = false; //When true, saved password was used. If a 401 is received, then saved password is not correct
+let statusCommandsInterval = -1;
+let commandHistoryIndex = -1; //Saves current command history index. -1 when not browsing history.
/**
* Load list of servers in file servers.json
@@ -61,10 +61,10 @@ function openServer(serverName){
connectionManager.loadConnection(serverName);
//Load saved messages
- var i;
- var messages = connectionManager.activeConnection.messages;
+ let i;
+ const messages = connectionManager.activeConnection.messages;
for(i = 0; i < messages.length; i++){
- if(messages[i].status != 401){
+ if(messages[i].status !== 401){
onWebSocketsMessage(messages[i]);
}
}
@@ -88,7 +88,7 @@ function onWebSocketsMessage(message){
$("#loggedUserTypeLabel").text(message.as);
//Disable command bar if user is viewer
- if(message.as.toLowerCase() == "viewer"){
+ if(message.as.toLowerCase() === "viewer"){
$("#commandInput").prop("disabled", true);
$("#sendCommandButton").prop("disabled", true);
}
@@ -106,7 +106,7 @@ function onWebSocketsMessage(message){
break;
case 401:
//Waiting for login. Show password modal or retrieve password
- var savedPwd = persistenceManager.getServer(connectionManager.activeConnection.serverName).serverPassword;
+ const savedPwd = persistenceManager.getServer(connectionManager.activeConnection.serverName).serverPassword;
if(typeof savedPwd !== "undefined" && !autoPasswordCompleted){
connectionManager.sendPassword(savedPwd);
autoPasswordCompleted = true;
@@ -127,13 +127,17 @@ function onWebSocketsMessage(message){
//RAM Usage
writeRamInfo(message.free, message.used, message.max);
break;
+ case 1003:
+ //Server TPS
+ writeTpsInfo(message.tps, 20);
+ break;
default:
console.log('Unknown server response:');
}
console.log(message);
//Add interval for Players, CPU and RAM info, if not set
- if(statusCommandsInterval == -1 && message.status !== 401){
+ if(statusCommandsInterval === -1 && message.status !== 401){
statusCommandsInterval = setInterval(function(){
connectionManager.askForInfo();
}, 2500);
@@ -144,8 +148,8 @@ function onWebSocketsMessage(message){
* Write to console
*/
function writeToWebConsole(msg, time){
- var isScrolledDown = document.getElementById("consoleTextArea").scrollHeight - document.getElementById("consoleTextArea").scrollTop - 40 == $("#consoleTextArea").height();
-
+ const isScrolledDown = document.getElementById("consoleTextArea").scrollHeight - document.getElementById("consoleTextArea").scrollTop - 40 === $("#consoleTextArea").height();
+
//Write to div, replacing < to < (to avoid XSS) and replacing new line to br.
msg = msg.replace(/");
@@ -209,7 +213,7 @@ function writeToWebConsole(msg, time){
$("#consoleTextArea").append(msg + "
");
if(isScrolledDown){
- var textarea = document.getElementById('consoleTextArea');
+ const textarea = document.getElementById('consoleTextArea');
textarea.scrollTop = textarea.scrollHeight;
}
}
@@ -220,8 +224,8 @@ function writeToWebConsole(msg, time){
function writePlayerInfo(connected, maximum){
$("#connectedPlayers").text(connected);
$("#maxPlayers").text(maximum);
-
- var percent = (connected/maximum)*100;
+
+ const percent = (connected / maximum) * 100;
$("#playerProgressBar").width(percent + "%");
}
@@ -240,16 +244,30 @@ function writeCpuInfo(usage){
function writeRamInfo(free, used, total){
$("#usedRam").text(used);
$("#totalRam").text(total);
-
- var percent = (used/total)*100;
+
+ const percent = (used / total) * 100;
$("#RamProgressBar").width(percent + "%");
}
+/**
+ * Fill TPS info card
+ */
+function writeTpsInfo(tps, max){
+ if(tps > 20) {
+ tps = 20;
+ }
+ $("#tps").text(tps);
+ $("#maxTps").text(max);
+
+ const percent = (tps / max) * 100;
+ $("#TpsProgressBar").width(percent + "%");
+}
+
/**
* Called from WebConsoleConnector only.
*/
function closedConnection(serverName){
- if(connectionManager.activeConnection.serverName == serverName){
+ if(connectionManager.activeConnection.serverName === serverName){
//Disable command input and button
$("#commandInput").prop("disabled", true);
$("#sendCommandButton").prop("disabled", true);
@@ -288,13 +306,13 @@ function updateServerList(){
$('.servermenuitem').remove();
//Add all servers
- var servers = persistenceManager.getAllServers();
- for(var i = 0; i < servers.length; i++){
+ const servers = persistenceManager.getAllServers();
+ for(let i = 0; i < servers.length; i++){
$('#ServerListDropDown').append('');
}
//Show a "no servers" message when no servers are added
- if(servers.length == 0){
+ if(servers.length === 0){
$('#ServerListDropDown').append('');
}
}
diff --git a/client/scripts/WebConsoleManager.js b/client/scripts/WebConsoleManager.js
index a374f36..0872b8f 100644
--- a/client/scripts/WebConsoleManager.js
+++ b/client/scripts/WebConsoleManager.js
@@ -97,6 +97,11 @@ class WebConsoleManager {
command: "RAMUSAGE",
token: this.activeConnection.token,
});
+
+ this.activeConnection.sendToServer({
+ command: "TPS",
+ token: this.activeConnection.token,
+ });
}
/**
diff --git a/phrases.properties b/phrases.properties
index d74b9e6..59eea64 100644
--- a/phrases.properties
+++ b/phrases.properties
@@ -34,6 +34,9 @@ players-message = Connected {0} players for a maximum of {1}
# RamUsageCommand.java
ram-usage-message = {0} free, {1} used, {2} maximum memory
+# TpsCommand.java
+tps-message = {0} ticks from {1}
+
# WebConsoleCommand.java
webconsole-version = WebConsole version {0}.
webconsole-no-connections = There are no logged in WebConsole connections now.
diff --git a/phrases_cs.properties b/phrases_cs.properties
index 8cc1368..5171771 100644
--- a/phrases_cs.properties
+++ b/phrases_cs.properties
@@ -34,6 +34,9 @@ players-message = Je připojeno {0} hráčů z maxima {1}
# RamUsageCommand.java
ram-usage-message = {0} volné, {1} použité, {2} maximální paměti
+# TpsCommand.java
+tps-message = {0} ticks from {1}
+
# WebConsoleCommand.java
webconsole-version = WebConsole verze {0}.
webconsole-no-connections = Nejsou žádné WebConsole připojení.
diff --git a/phrases_de.properties b/phrases_de.properties
index 6bce551..b2b9ab4 100644
--- a/phrases_de.properties
+++ b/phrases_de.properties
@@ -34,6 +34,9 @@ players-message = {0} von {1} Spieler sind verbunden.
# RamUsageCommand.java
ram-usage-message = {0} frei, {1} benutzt, {2} maximal
+# TpsCommand.java
+tps-message = {0} ticks von {1}
+
# WebConsoleCommand.java
webconsole-version = Die WebConsole Version ist {0}.
webconsole-no-connections = Aktuell ist niemand mit der WebConsole verbunden
diff --git a/phrases_en.properties b/phrases_en.properties
index d74b9e6..59eea64 100644
--- a/phrases_en.properties
+++ b/phrases_en.properties
@@ -34,6 +34,9 @@ players-message = Connected {0} players for a maximum of {1}
# RamUsageCommand.java
ram-usage-message = {0} free, {1} used, {2} maximum memory
+# TpsCommand.java
+tps-message = {0} ticks from {1}
+
# WebConsoleCommand.java
webconsole-version = WebConsole version {0}.
webconsole-no-connections = There are no logged in WebConsole connections now.
diff --git a/phrases_es.properties b/phrases_es.properties
index 0d71ee6..654b6c8 100644
--- a/phrases_es.properties
+++ b/phrases_es.properties
@@ -34,6 +34,9 @@ players-message = Actualmente conectados {0} jugadores de un máximo de {1}
# RamUsageCommand.java
ram-usage-message = Memoria: {0} libre, {1} usada, {2} maxima
+# TpsCommand.java
+tps-message = {0} ticks from {1}
+
# WebConsoleCommand.java
webconsole-version = WebConsole version {0}.
webconsole-no-connections = No hay ninguna conexión activa a WebConsole en este momento.
diff --git a/phrases_fr.properties b/phrases_fr.properties
index 1556fb4..3991f63 100644
--- a/phrases_fr.properties
+++ b/phrases_fr.properties
@@ -34,6 +34,9 @@ players-message = Joueurs {0} connectés pour un maximum de {1}
# RamUsageCommand.java
ram-usage-message = {0} gratuit, {1} utilisé, {2} mémoire maximale
+# TpsCommand.java
+tps-message = {0} ticks from {1}
+
# WebConsoleCommand.java
webconsole-version = version WebConsole {0}.
webconsole-no-connections = Aucune connexion WebConsole n'est connectée maintenant.
diff --git a/phrases_it.properties b/phrases_it.properties
index 6a90a9f..22bde9d 100644
--- a/phrases_it.properties
+++ b/phrases_it.properties
@@ -34,6 +34,9 @@ players-message = Connessi {0} players su un massimo di {1}
# RamUsageCommand.java
ram-usage-message = {0} Libera, {1} Usata, {2} Memoria massima
+# TpsCommand.java
+tps-message = {0} ticks from {1}
+
# WebConsoleCommand.java
webconsole-version = Versione WebConsole {0}.
webconsole-no-connections = Non è stata effettuata ancora nessuna connessione tramite WebConsole.
diff --git a/phrases_ja.properties b/phrases_ja.properties
index 7ebc1fb..5b4122a 100644
--- a/phrases_ja.properties
+++ b/phrases_ja.properties
@@ -34,6 +34,9 @@ players-message = 接続数 | {0} ,最大接続数 | {1}
# RamUsageCommand.java
ram-usage-message = {0} 空き, {1} 使用済み, {2} 最大メモリ
+# TpsCommand.java
+tps-message = {0} ticks from {1}
+
# WebConsoleCommand.java
webconsole-version = WebConsoleのバージョン {0}.
webconsole-no-connections = 現在、WebConsoleのログイン接続はありません。
diff --git a/phrases_ko.properties b/phrases_ko.properties
index e84062d..696951f 100644
--- a/phrases_ko.properties
+++ b/phrases_ko.properties
@@ -34,6 +34,9 @@ players-message = {0}/{1}명의 플레이어를 연결하였습니다
# RamUsageCommand.java
ram-usage-message = {0} 여유, {1} 사용, {2} 최대
+# TpsCommand.java
+tps-message = {0} ticks from {1}
+
# WebConsoleCommand.java
webconsole-version = WebConsole 버전 {0}.
webconsole-no-connections = 현재 로그인된 사람이 없습니다.
diff --git a/phrases_nl.properties b/phrases_nl.properties
index c664614..001b4ad 100644
--- a/phrases_nl.properties
+++ b/phrases_nl.properties
@@ -34,6 +34,9 @@ players-message = {0} spelers verbonden voor een maximum van {1}
# RamUsageCommand.java
ram-usage-message = {0} ongebruikt, {1} gebruikt, {2} maximaal geheugen
+# TpsCommand.java
+tps-message = {0} ticks from {1}
+
# WebConsoleCommand.java
webconsole-version = WebConsole versie {0}.
webconsole-no-connections = Er zijn nu geen ingelogde Web Console-verbindingen.
diff --git a/phrases_pt.properties b/phrases_pt.properties
index 3e42347..2d8ae5f 100644
--- a/phrases_pt.properties
+++ b/phrases_pt.properties
@@ -34,6 +34,9 @@ players-message = Atualmente tem {0} jogador(es) de um total de {1}
# RamUsageCommand.java
ram-usage-message = Disponível: {0}, Consumo de RAM: {1} / {2}
+# TpsCommand.java
+tps-message = {0} ticks from {1}
+
# WebConsoleCommand.java
webconsole-version = WebConsole versão {0}.
webconsole-no-connections = Atualmente não tem nenhum usuário conectado.
diff --git a/phrases_ru.properties b/phrases_ru.properties
index 82b649c..13a59e6 100644
--- a/phrases_ru.properties
+++ b/phrases_ru.properties
@@ -34,6 +34,9 @@ players-message = Подключено {0} игроков из максимум
# RamUsageCommand.java
ram-usage-message = {0} свободно, {1} используется, {2} макс. памяти
+# TpsCommand.java
+tps-message = {0} ticks from {1}
+
# WebConsoleCommand.java
webconsole-version = Версия WebConsole {0}.
webconsole-no-connections = В настоящее время нет подключений к WebConsole.
diff --git a/phrases_tr.properties b/phrases_tr.properties
index 2d9cf69..cecb81b 100644
--- a/phrases_tr.properties
+++ b/phrases_tr.properties
@@ -34,6 +34,9 @@ players-message = {0} oyuncu bağlandı, toplam {1} oyuncu bağlanabilir.
# RamUsageCommand.java
ram-usage-message = {0} boş, {1} kullanılıyor, {2} maksimum bellek
+# TpsCommand.java
+tps-message = {0} ticks from {1}
+
# WebConsoleCommand.java
webconsole-version = WebConsole sürümü {0}.
webconsole-no-connections = Şuanda oturum açılmış WebSocket bağlantısı yok.
diff --git a/phrases_zh.properties b/phrases_zh.properties
index ab644db..ab4f5ab 100644
--- a/phrases_zh.properties
+++ b/phrases_zh.properties
@@ -34,6 +34,9 @@ players-message = {0}玩家連接,最多{1}
# RamUsageCommand.java
ram-usage-message = 空閒{0} , 已使用{1} , 最大內存{2}
+# TpsCommand.java
+tps-message = {0} ticks from {1}
+
# WebConsoleCommand.java
webconsole-version = 網站控制台版本 {0}.
webconsole-no-connections = 現在沒有連接登錄網站控制台。
diff --git a/src/es/mesacarlos/webconsole/websocket/WSServer.java b/src/es/mesacarlos/webconsole/websocket/WSServer.java
index a5cb666..8b73a56 100644
--- a/src/es/mesacarlos/webconsole/websocket/WSServer.java
+++ b/src/es/mesacarlos/webconsole/websocket/WSServer.java
@@ -23,7 +23,8 @@ import es.mesacarlos.webconsole.websocket.response.LoggedIn;
import es.mesacarlos.webconsole.websocket.response.UnknownCommand;
public class WSServer extends WebSocketServer {
- private HashMap commands = WSCommandFactory.getCommandsHashMap();
+
+ private final HashMap commands = WSCommandFactory.getCommandsHashMap();
public WSServer(InetSocketAddress address) {
super(address);
diff --git a/src/es/mesacarlos/webconsole/websocket/command/TpsCommand.java b/src/es/mesacarlos/webconsole/websocket/command/TpsCommand.java
new file mode 100644
index 0000000..8c5de25
--- /dev/null
+++ b/src/es/mesacarlos/webconsole/websocket/command/TpsCommand.java
@@ -0,0 +1,47 @@
+package es.mesacarlos.webconsole.websocket.command;
+
+//------------------------------
+//
+// This class was developed by Rafael K.
+// On 1/8/2022 at 10:22 PM
+// In the project WebConsole
+//
+//------------------------------
+
+import es.mesacarlos.webconsole.util.Internationalization;
+import es.mesacarlos.webconsole.websocket.WSServer;
+import es.mesacarlos.webconsole.websocket.response.Tps;
+import org.java_websocket.WebSocket;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class TpsCommand implements WSCommand {
+
+ @Override
+ public void execute(WSServer wsServer, WebSocket conn, String params) {
+ try {
+ double tps = getTps()[0];
+ wsServer.sendToClient(conn, new Tps(Internationalization.getPhrase("tps-message", tps), tps));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * @return Current server Tps
+ */
+ public double[] getTps() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
+ Class> minecraftServerClass = Class.forName("net.minecraft.server.MinecraftServer");
+ Method getServerMethod = minecraftServerClass.getDeclaredMethod("getServer");
+ Object serverInstance = getServerMethod.invoke(null);
+ Field recentTpsField = serverInstance.getClass().getField("recentTps");
+ double[] recentTps = (double[]) recentTpsField.get(serverInstance);
+ for (int i = 0; i < recentTps.length; i++) {
+ recentTps[i] = Math.round(recentTps[i]);
+ }
+ return recentTps;
+ }
+
+}
diff --git a/src/es/mesacarlos/webconsole/websocket/command/WSCommandFactory.java b/src/es/mesacarlos/webconsole/websocket/command/WSCommandFactory.java
index c10c7d5..a9147da 100644
--- a/src/es/mesacarlos/webconsole/websocket/command/WSCommandFactory.java
+++ b/src/es/mesacarlos/webconsole/websocket/command/WSCommandFactory.java
@@ -11,6 +11,7 @@ public class WSCommandFactory {
commands.put("PLAYERS", new PlayersCommand());
commands.put("CPUUSAGE", new CpuUsageCommand());
commands.put("RAMUSAGE", new RamUsageCommand());
+ commands.put("TPS", new TpsCommand());
commands.put("READLOGFILE", new ReadLogFileCommand());
return commands;
}
diff --git a/src/es/mesacarlos/webconsole/websocket/response/ConsoleOutput.java b/src/es/mesacarlos/webconsole/websocket/response/ConsoleOutput.java
index 2f371af..9cf1e2d 100644
--- a/src/es/mesacarlos/webconsole/websocket/response/ConsoleOutput.java
+++ b/src/es/mesacarlos/webconsole/websocket/response/ConsoleOutput.java
@@ -2,9 +2,10 @@ package es.mesacarlos.webconsole.websocket.response;
import com.google.gson.JsonObject;
-public class ConsoleOutput implements JSONOutput{
- private String message;
- private String time;
+public class ConsoleOutput implements JSONOutput {
+
+ private final String message;
+ private final String time;
public ConsoleOutput(String message, String time) {
this.message = message;
diff --git a/src/es/mesacarlos/webconsole/websocket/response/CpuUsage.java b/src/es/mesacarlos/webconsole/websocket/response/CpuUsage.java
index 53a6fd1..20a2580 100644
--- a/src/es/mesacarlos/webconsole/websocket/response/CpuUsage.java
+++ b/src/es/mesacarlos/webconsole/websocket/response/CpuUsage.java
@@ -2,9 +2,10 @@ package es.mesacarlos.webconsole.websocket.response;
import com.google.gson.JsonObject;
-public class CpuUsage implements JSONOutput{
- private String message;
- private double usage;
+public class CpuUsage implements JSONOutput {
+
+ private final String message;
+ private final double usage;
public CpuUsage(String message, double usage) {
this.message = message;
diff --git a/src/es/mesacarlos/webconsole/websocket/response/LoggedIn.java b/src/es/mesacarlos/webconsole/websocket/response/LoggedIn.java
index 9cd87f9..1917e75 100644
--- a/src/es/mesacarlos/webconsole/websocket/response/LoggedIn.java
+++ b/src/es/mesacarlos/webconsole/websocket/response/LoggedIn.java
@@ -4,8 +4,9 @@ import com.google.gson.JsonObject;
import es.mesacarlos.webconsole.config.UserType;
-public class LoggedIn implements JSONOutput{
- private String message;
+public class LoggedIn implements JSONOutput {
+
+ private final String message;
private String respondsTo;
private String username;
private UserType as;
diff --git a/src/es/mesacarlos/webconsole/websocket/response/LoginRequired.java b/src/es/mesacarlos/webconsole/websocket/response/LoginRequired.java
index cd7ba3a..27d3848 100644
--- a/src/es/mesacarlos/webconsole/websocket/response/LoginRequired.java
+++ b/src/es/mesacarlos/webconsole/websocket/response/LoginRequired.java
@@ -2,8 +2,9 @@ package es.mesacarlos.webconsole.websocket.response;
import com.google.gson.JsonObject;
-public class LoginRequired implements JSONOutput{
- private String message;
+public class LoginRequired implements JSONOutput {
+
+ private final String message;
public LoginRequired(String message) {
this.message = message;
diff --git a/src/es/mesacarlos/webconsole/websocket/response/Players.java b/src/es/mesacarlos/webconsole/websocket/response/Players.java
index 2985128..874eeb5 100644
--- a/src/es/mesacarlos/webconsole/websocket/response/Players.java
+++ b/src/es/mesacarlos/webconsole/websocket/response/Players.java
@@ -5,11 +5,12 @@ import java.util.List;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
-public class Players implements JSONOutput{
- private String message;
- private int connectedPlayers;
- private int maxPlayers;
- private List connectedPlayersList;
+public class Players implements JSONOutput {
+
+ private final String message;
+ private final int connectedPlayers;
+ private final int maxPlayers;
+ private final List connectedPlayersList;
public Players(String message, int connectedPlayers, int maxPlayers, List connectedPlayersList) {
this.message = message;
diff --git a/src/es/mesacarlos/webconsole/websocket/response/RamUsage.java b/src/es/mesacarlos/webconsole/websocket/response/RamUsage.java
index 336447b..45f00dd 100644
--- a/src/es/mesacarlos/webconsole/websocket/response/RamUsage.java
+++ b/src/es/mesacarlos/webconsole/websocket/response/RamUsage.java
@@ -3,10 +3,11 @@ package es.mesacarlos.webconsole.websocket.response;
import com.google.gson.JsonObject;
public class RamUsage implements JSONOutput {
- private String message;
- private long free;
- private long used;
- private long max;
+
+ private final String message;
+ private final long free;
+ private final long used;
+ private final long max;
public RamUsage(String message, long free, long used, long max) {
this.message = message;
diff --git a/src/es/mesacarlos/webconsole/websocket/response/Tps.java b/src/es/mesacarlos/webconsole/websocket/response/Tps.java
new file mode 100644
index 0000000..df15a18
--- /dev/null
+++ b/src/es/mesacarlos/webconsole/websocket/response/Tps.java
@@ -0,0 +1,51 @@
+package es.mesacarlos.webconsole.websocket.response;
+
+//------------------------------
+//
+// This class was developed by Rafael K.
+// On 1/8/2022 at 10:23 PM
+// In the project WebConsole
+//
+//------------------------------
+
+import com.google.gson.JsonObject;
+
+public class Tps implements JSONOutput {
+
+ private final String message;
+ private final double tps;
+
+ public Tps(String message, double tps) {
+ this.message = message;
+ this.tps = tps;
+ }
+
+ @Override
+ public int getStatusCode() {
+ return 1003;
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+ /**
+ * Gets current server TPS
+ * @return Global Server TPS
+ */
+ public double getTps() {
+ return tps;
+ }
+
+ @Override
+ public String toJSON() {
+ JsonObject object = new JsonObject();
+ object.addProperty("status", getStatusCode());
+ object.addProperty("statusDescription", "TPS Usage");
+ object.addProperty("tps", getTps());
+ object.addProperty("message", getMessage());
+ return object.toString();
+ }
+
+}
diff --git a/src/es/mesacarlos/webconsole/websocket/response/UnknownCommand.java b/src/es/mesacarlos/webconsole/websocket/response/UnknownCommand.java
index 0fff41d..a405b64 100644
--- a/src/es/mesacarlos/webconsole/websocket/response/UnknownCommand.java
+++ b/src/es/mesacarlos/webconsole/websocket/response/UnknownCommand.java
@@ -2,9 +2,10 @@ package es.mesacarlos.webconsole.websocket.response;
import com.google.gson.JsonObject;
-public class UnknownCommand implements JSONOutput{
- private String message;
- private String respondsTo;
+public class UnknownCommand implements JSONOutput {
+
+ private final String message;
+ private final String respondsTo;
public UnknownCommand(String message, String respondsTo) {
this.message = message;