From 1f4fb056ab55c7cfd0e3bc7f7b19f782c509787c Mon Sep 17 00:00:00 2001
From: matanp <mgp64@cornell.edu>
Date: Sun, 7 Feb 2021 00:32:59 -0800
Subject: [PATCH 1/6] basic emotes showing on screen

---
 src/backend/twitch_main.js                | 10 +++----
 src/frontend/.eslintcache                 |  2 +-
 src/frontend/src/components/TwitchChat.js | 33 ++++++++++++++++-------
 3 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/src/backend/twitch_main.js b/src/backend/twitch_main.js
index 59fab01..e4465be 100644
--- a/src/backend/twitch_main.js
+++ b/src/backend/twitch_main.js
@@ -50,18 +50,18 @@ function repeatedMessageSay(message) {
 /*
 // Called every time a message comes in
  target_channel is the twitch channel the message is coming from
- user_info is information about the user -- see example_context
+ msg_tags is extra metadata sent with the message, like username
  user_msg is the actual message
  from_self is a boolean of if the message is coming from this client
 */
-function onMessageHandler(target_channel, user_info, user_msg, from_self) {
+function onMessageHandler(target_channel, msg_tags, user_msg, from_self) {
     if (from_self) {
         return;
     }
-    console.log(user_msg);
+    console.log(msg_tags.emotes);
 
     //send message over websocket, frontend listening for messages
-    twitch_chat_websocket.chat_client.send(`{"user": "${user_info.username}", "text": "${user_msg}"}`);
+    twitch_chat_websocket.chat_client.send(`{"user": "${msg_tags.username}", "text": "${user_msg}", "emotes": ${JSON.stringify(msg_tags.emotes)}}`);
 
     //handle timer logic
     for (let message of repeated_messages_out.timers) {
@@ -72,7 +72,7 @@ function onMessageHandler(target_channel, user_info, user_msg, from_self) {
     }
 
     //pass the message into the bot
-    let response_promise = bot.message_main(user_info, user_msg);
+    let response_promise = bot.message_main(msg_tags, user_msg);
     response_promise.then(
         (result) => {
             if (result) client.say(channelOut, result);
diff --git a/src/frontend/.eslintcache b/src/frontend/.eslintcache
index 404213f..87e7cb8 100644
--- a/src/frontend/.eslintcache
+++ b/src/frontend/.eslintcache
@@ -1 +1 @@
-[{"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js":"1","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js":"2","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js":"3"},{"size":504,"mtime":1610254160076,"results":"4","hashOfConfig":"5"},{"size":203,"mtime":1610258278547,"results":"6","hashOfConfig":"5"},{"size":2054,"mtime":1610261371511,"results":"7","hashOfConfig":"5"},{"filePath":"8","messages":"9","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},"82sdiv",{"filePath":"11","messages":"12","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},{"filePath":"13","messages":"14","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js",[],["15","16"],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js",[],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js",[],{"ruleId":"17","replacedBy":"18"},{"ruleId":"19","replacedBy":"20"},"no-native-reassign",["21"],"no-negated-in-lhs",["22"],"no-global-assign","no-unsafe-negation"]
\ No newline at end of file
+[{"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js":"1","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js":"2","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js":"3"},{"size":521,"mtime":1611527873653,"results":"4","hashOfConfig":"5"},{"size":215,"mtime":1611527873652,"results":"6","hashOfConfig":"5"},{"size":2524,"mtime":1612686633752,"results":"7","hashOfConfig":"5"},{"filePath":"8","messages":"9","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},"82sdiv",{"filePath":"11","messages":"12","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},{"filePath":"13","messages":"14","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js",[],["15","16"],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js",[],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js",[],{"ruleId":"17","replacedBy":"18"},{"ruleId":"19","replacedBy":"20"},"no-native-reassign",["21"],"no-negated-in-lhs",["22"],"no-global-assign","no-unsafe-negation"]
\ No newline at end of file
diff --git a/src/frontend/src/components/TwitchChat.js b/src/frontend/src/components/TwitchChat.js
index 1087990..32ada04 100644
--- a/src/frontend/src/components/TwitchChat.js
+++ b/src/frontend/src/components/TwitchChat.js
@@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react";
 import Websocket from "react-websocket";
 import "./twitch-chat-style.css";
 
-
 const chat_timeout = 30000; //time in milliseconds
+const EMOTE_URL_BASE = `http://static-cdn.jtvnw.net/emoticons/v1/`
 
 const TwitchChat = () => {
     const [messageList, setMessageList] = useState([
@@ -16,36 +16,44 @@ const TwitchChat = () => {
             time: Date.now() + 1000,
             user: "matan",
             text: "oh hi 2",
-        }
+        },
     ]);
 
+    const [emotes, setEmotes] = useState([304047803, 304214060]);
+
     useEffect(() => {
         const clearOldMessages = setInterval(() => {
-            const newMessageList = []
+            const newMessageList = [];
             for (let index = 0; index < messageList.length; index = index + 1) {
-                console.log(messageList[index]);
+                //console.log(messageList[index]);
                 if (Date.now() - messageList[index].time < chat_timeout) {
                     newMessageList.push(messageList[index]);
                 }
             }
-            console.log(newMessageList)
+            //console.log(newMessageList);
             setMessageList(newMessageList);
         }, 3000);
         return () => clearInterval(clearOldMessages);
     }, [messageList]);
 
     const handleData = (message_data) => {
-        console.log(message_data);
+        //console.log(message_data);
         const message = JSON.parse(message_data);
-        setMessageList(
-            messageList.push({
+        setMessageList([
+            ...messageList,
+            {
                 time: Date.now(),
                 user: message.user,
                 text: message.text,
-            })
-        );
+            },
+        ]);
+
+        setEmotes([...emotes, ...Object.keys(message.emotes)]);
+
     };
 
+    // function renderMessage(message) {}
+
     return (
         <div className="message-area">
             <ul className="list">
@@ -55,6 +63,11 @@ const TwitchChat = () => {
                     </li>
                 ))}
             </ul>
+            <div>
+                {emotes.map((item, index) => (
+                    <img src={`${EMOTE_URL_BASE}/${item}/3.0`} alt="" key={index}></img>
+                ))}
+            </div>
             <Websocket
                 url="ws://127.0.0.1:8080/"
                 onMessage={handleData}

From 416cb0830719e70659951e1312e776f24faa1768 Mon Sep 17 00:00:00 2001
From: matanp <mgp64@cornell.edu>
Date: Sun, 7 Feb 2021 21:58:20 -0800
Subject: [PATCH 2/6] basic animation testing

---
 src/frontend/.eslintcache                     |  2 +-
 src/frontend/src/components/TwitchChat.js     | 44 ++++++++++---------
 .../src/components/twitch-chat-style.css      | 15 +++++++
 3 files changed, 39 insertions(+), 22 deletions(-)

diff --git a/src/frontend/.eslintcache b/src/frontend/.eslintcache
index 87e7cb8..5de5fdc 100644
--- a/src/frontend/.eslintcache
+++ b/src/frontend/.eslintcache
@@ -1 +1 @@
-[{"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js":"1","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js":"2","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js":"3"},{"size":521,"mtime":1611527873653,"results":"4","hashOfConfig":"5"},{"size":215,"mtime":1611527873652,"results":"6","hashOfConfig":"5"},{"size":2524,"mtime":1612686633752,"results":"7","hashOfConfig":"5"},{"filePath":"8","messages":"9","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},"82sdiv",{"filePath":"11","messages":"12","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},{"filePath":"13","messages":"14","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js",[],["15","16"],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js",[],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js",[],{"ruleId":"17","replacedBy":"18"},{"ruleId":"19","replacedBy":"20"},"no-native-reassign",["21"],"no-negated-in-lhs",["22"],"no-global-assign","no-unsafe-negation"]
\ No newline at end of file
+[{"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js":"1","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js":"2","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js":"3"},{"size":521,"mtime":1611527873653,"results":"4","hashOfConfig":"5"},{"size":215,"mtime":1611527873652,"results":"6","hashOfConfig":"5"},{"size":2661,"mtime":1612756834973,"results":"7","hashOfConfig":"5"},{"filePath":"8","messages":"9","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},"82sdiv",{"filePath":"11","messages":"12","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},{"filePath":"13","messages":"14","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js",[],["15","16"],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js",[],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js",[],{"ruleId":"17","replacedBy":"18"},{"ruleId":"19","replacedBy":"20"},"no-native-reassign",["21"],"no-negated-in-lhs",["22"],"no-global-assign","no-unsafe-negation"]
\ No newline at end of file
diff --git a/src/frontend/src/components/TwitchChat.js b/src/frontend/src/components/TwitchChat.js
index 32ada04..94fc4fb 100644
--- a/src/frontend/src/components/TwitchChat.js
+++ b/src/frontend/src/components/TwitchChat.js
@@ -6,18 +6,20 @@ const chat_timeout = 30000; //time in milliseconds
 const EMOTE_URL_BASE = `http://static-cdn.jtvnw.net/emoticons/v1/`
 
 const TwitchChat = () => {
-    const [messageList, setMessageList] = useState([
-        {
-            time: Date.now(),
-            user: "matan",
-            text: "oh hi",
-        },
-        {
-            time: Date.now() + 1000,
-            user: "matan",
-            text: "oh hi 2",
-        },
-    ]);
+    // const [messageList, setMessageList] = useState([
+    //     {
+    //         time: Date.now(),
+    //         user: "matan",
+    //         text: "oh hi",
+    //     },
+    //     {
+    //         time: Date.now() + 1000,
+    //         user: "matan",
+    //         text: "oh hi 2",
+    //     },
+    // ]);
+
+    const [messageList, setMessageList] = useState([]);
 
     const [emotes, setEmotes] = useState([304047803, 304214060]);
 
@@ -39,14 +41,14 @@ const TwitchChat = () => {
     const handleData = (message_data) => {
         //console.log(message_data);
         const message = JSON.parse(message_data);
-        setMessageList([
-            ...messageList,
-            {
-                time: Date.now(),
-                user: message.user,
-                text: message.text,
-            },
-        ]);
+        // setMessageList([
+        //     ...messageList,
+        //     {
+        //         time: Date.now(),
+        //         user: message.user,
+        //         text: message.text,
+        //     },
+        // ]);
 
         setEmotes([...emotes, ...Object.keys(message.emotes)]);
 
@@ -65,7 +67,7 @@ const TwitchChat = () => {
             </ul>
             <div>
                 {emotes.map((item, index) => (
-                    <img src={`${EMOTE_URL_BASE}/${item}/3.0`} alt="" key={index}></img>
+                    <img className="emote" src={`${EMOTE_URL_BASE}/${item}/3.0`} alt="" key={index}></img>
                 ))}
             </div>
             <Websocket
diff --git a/src/frontend/src/components/twitch-chat-style.css b/src/frontend/src/components/twitch-chat-style.css
index 259b0e4..9564da7 100644
--- a/src/frontend/src/components/twitch-chat-style.css
+++ b/src/frontend/src/components/twitch-chat-style.css
@@ -13,3 +13,18 @@
     text-align: left!important;
     margin-bottom: 3px;
 }
+
+.emote {
+    animation : pulse 1s;
+}
+
+@keyframes pulse {
+    from {
+        transform : scale(0);
+        opacity   : 0;
+    }
+    to {
+        transform : scale(1);
+        opacity   : 1;
+    }
+}

From bb35a047613393ffbf94e7b312a2b79ca721ae82 Mon Sep 17 00:00:00 2001
From: matanp <mgp64@cornell.edu>
Date: Tue, 23 Feb 2021 01:01:34 -0800
Subject: [PATCH 3/6] fix crash on message without emotes

---
 src/frontend/.eslintcache                     |  2 +-
 src/frontend/.gitignore                       |  1 +
 src/frontend/src/components/TwitchChat.js     |  5 +++--
 .../src/components/twitch-chat-style.css      | 21 ++++++++++++++++++-
 4 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/src/frontend/.eslintcache b/src/frontend/.eslintcache
index 5de5fdc..d848f56 100644
--- a/src/frontend/.eslintcache
+++ b/src/frontend/.eslintcache
@@ -1 +1 @@
-[{"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js":"1","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js":"2","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js":"3"},{"size":521,"mtime":1611527873653,"results":"4","hashOfConfig":"5"},{"size":215,"mtime":1611527873652,"results":"6","hashOfConfig":"5"},{"size":2661,"mtime":1612756834973,"results":"7","hashOfConfig":"5"},{"filePath":"8","messages":"9","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},"82sdiv",{"filePath":"11","messages":"12","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},{"filePath":"13","messages":"14","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js",[],["15","16"],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js",[],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js",[],{"ruleId":"17","replacedBy":"18"},{"ruleId":"19","replacedBy":"20"},"no-native-reassign",["21"],"no-negated-in-lhs",["22"],"no-global-assign","no-unsafe-negation"]
\ No newline at end of file
+[{"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js":"1","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js":"2","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js":"3"},{"size":521,"mtime":1611527873653,"results":"4","hashOfConfig":"5"},{"size":215,"mtime":1611527873652,"results":"6","hashOfConfig":"5"},{"size":2704,"mtime":1614070762675,"results":"7","hashOfConfig":"5"},{"filePath":"8","messages":"9","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},"82sdiv",{"filePath":"11","messages":"12","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},{"filePath":"13","messages":"14","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js",[],["15","16"],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js",[],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js",[],{"ruleId":"17","replacedBy":"18"},{"ruleId":"19","replacedBy":"20"},"no-native-reassign",["21"],"no-negated-in-lhs",["22"],"no-global-assign","no-unsafe-negation"]
\ No newline at end of file
diff --git a/src/frontend/.gitignore b/src/frontend/.gitignore
index 4d29575..00ec607 100644
--- a/src/frontend/.gitignore
+++ b/src/frontend/.gitignore
@@ -17,6 +17,7 @@
 .env.development.local
 .env.test.local
 .env.production.local
+.eslintcache
 
 npm-debug.log*
 yarn-debug.log*
diff --git a/src/frontend/src/components/TwitchChat.js b/src/frontend/src/components/TwitchChat.js
index 94fc4fb..c21106e 100644
--- a/src/frontend/src/components/TwitchChat.js
+++ b/src/frontend/src/components/TwitchChat.js
@@ -49,8 +49,9 @@ const TwitchChat = () => {
         //         text: message.text,
         //     },
         // ]);
-
-        setEmotes([...emotes, ...Object.keys(message.emotes)]);
+        if(message.emotes) {
+            setEmotes([...emotes, ...Object.keys(message.emotes)]);
+        }
 
     };
 
diff --git a/src/frontend/src/components/twitch-chat-style.css b/src/frontend/src/components/twitch-chat-style.css
index 9564da7..5213e1b 100644
--- a/src/frontend/src/components/twitch-chat-style.css
+++ b/src/frontend/src/components/twitch-chat-style.css
@@ -15,7 +15,9 @@
 }
 
 .emote {
-    animation : pulse 1s;
+    position: absolute;
+    right: 0px;
+    animation : pulse 1s, fall 4s, disapear .3s 3.7s forwards;
 }
 
 @keyframes pulse {
@@ -28,3 +30,20 @@
         opacity   : 1;
     }
 }
+
+@keyframes disapear {
+    from {
+        opacity: 1;
+    } to {
+        opacity: 0;
+    }
+}
+
+@keyframes fall {
+    from {
+        top: 0px;
+    }
+    to {
+        top: 250px;
+    }
+}

From 478ae3285fde52cc022dd020359f0aaca704e223 Mon Sep 17 00:00:00 2001
From: matanp <mgp64@cornell.edu>
Date: Sat, 6 Mar 2021 11:35:12 -0800
Subject: [PATCH 4/6] WIP

---
 src/backend/commands.json                     | 104 +---
 src/backend/consts.js                         |   4 +-
 src/backend/package-lock.json                 | 540 ++++++++++++++++++
 src/backend/package.json                      |   5 +
 src/backend/twitch_events_ws.js               |  94 +++
 src/frontend/.eslintcache                     |   2 +-
 .../src/components/twitch-chat-style.css      |   2 +-
 7 files changed, 645 insertions(+), 106 deletions(-)
 create mode 100644 src/backend/twitch_events_ws.js

diff --git a/src/backend/commands.json b/src/backend/commands.json
index fdbae21..fcbf5d3 100644
--- a/src/backend/commands.json
+++ b/src/backend/commands.json
@@ -1,103 +1 @@
-{
-    "commands": [
-        {
-            "command_word": "hello",
-            "response_array": ["world"],
-            "mod_only": false,
-            "added_by": "matanjuggles",
-            "added_date": "1-25, 2021",
-            "usage_count": 6
-        },
-        {
-            "command_word": "a",
-            "response_array": [
-                "this",
-                "has",
-                "been",
-                "used",
-                "{count}",
-                "times"
-            ],
-            "mod_only": false,
-            "added_by": "matanjuggles",
-            "added_timestamp": "1-28, 2021",
-            "usage_count": 10
-        },
-        {
-            "command_word": "fam",
-            "response_array": ["Jugg", "LEFam"],
-            "mod_only": false,
-            "added_by": "matanjuggles",
-            "added_timestamp": "1-30, 2021",
-            "usage_count": 13
-        },
-        {
-            "command_word": "siteswap",
-            "response_array": [
-                "Siteswap,",
-                "also",
-                "called",
-                "quantum",
-                "juggling",
-                "or",
-                "the",
-                "Cambridge",
-                "notation,",
-                "is",
-                "a",
-                "numeric",
-                "juggling",
-                "notation",
-                "used",
-                "to",
-                "describe",
-                "or",
-                "represent",
-                "juggling",
-                "patterns.",
-                "...",
-                "Siteswap",
-                "assumes",
-                "that",
-                "\"throws",
-                "happen",
-                "on",
-                "beats",
-                "that",
-                "are",
-                "equally",
-                "spaced",
-                "in",
-                "time.\""
-            ],
-            "mod_only": false,
-            "added_by": "matanjuggles",
-            "added_timestamp": "2-4, 2021",
-            "usage_count": 1
-        },
-        {
-            "command_word": "flowtoys",
-            "response_array": ["https://flowtoys.com/"],
-            "mod_only": false,
-            "added_by": "matanjuggles",
-            "added_timestamp": "2-20, 2021",
-            "usage_count": 1
-        },
-        {
-            "command_word": "cathedral",
-            "response_array": ["https://www.cathedraljuggling.com/"],
-            "mod_only": false,
-            "added_by": "matanjuggles",
-            "added_timestamp": "2-20, 2021",
-            "usage_count": 0
-        },
-        {
-            "command_word": "cathedraljuggling",
-            "response_array": ["https://www.cathedraljuggling.com/"],
-            "mod_only": false,
-            "added_by": "matanjuggles",
-            "added_timestamp": "2-20, 2021",
-            "usage_count": 0
-        }
-    ]
-}
+{"commands":[{"command_word":"hello","response_array":["world"],"mod_only":false,"added_by":"matanjuggles","added_date":"1-25, 2021","usage_count":6},{"command_word":"a","response_array":["this","has","been","used","{count}","times"],"mod_only":false,"added_by":"matanjuggles","added_timestamp":"1-28, 2021","usage_count":10},{"command_word":"fam","response_array":["Jugg","LEFam"],"mod_only":false,"added_by":"matanjuggles","added_timestamp":"1-30, 2021","usage_count":13},{"command_word":"siteswap","response_array":["Siteswap,","also","called","quantum","juggling","or","the","Cambridge","notation,","is","a","numeric","juggling","notation","used","to","describe","or","represent","juggling","patterns.","...","Siteswap","assumes","that","\"throws","happen","on","beats","that","are","equally","spaced","in","time.\""],"mod_only":false,"added_by":"matanjuggles","added_timestamp":"2-4, 2021","usage_count":1},{"command_word":"flowtoys","response_array":["https://flowtoys.com/"],"mod_only":false,"added_by":"matanjuggles","added_timestamp":"2-20, 2021","usage_count":1},{"command_word":"cathedral","response_array":["https://www.cathedraljuggling.com/"],"mod_only":false,"added_by":"matanjuggles","added_timestamp":"2-20, 2021","usage_count":0},{"command_word":"cathedraljuggling","response_array":["https://www.cathedraljuggling.com/"],"mod_only":false,"added_by":"matanjuggles","added_timestamp":"2-20, 2021","usage_count":0},{"command_word":"drop","response_array":["Matan","has","dropped","{count}","times.","Total","in","his","life."],"mod_only":false,"added_by":"matanjuggles","added_timestamp":"3-4, 2021","usage_count":7}]}
\ No newline at end of file
diff --git a/src/backend/consts.js b/src/backend/consts.js
index aba0f92..9cf2e73 100644
--- a/src/backend/consts.js
+++ b/src/backend/consts.js
@@ -24,7 +24,9 @@ module.exports.background_images = [
     { obs_name: "invisible", command_name: "invisible" },
     { obs_name: "tornado", command_name: "fire" },
     { obs_name: "rainbow", command_name: "rainbow" },
-    { obs_name: "static", command_name: "static" }
+    { obs_name: "static", command_name: "static" },
+    { obs_name: "secret", command_name: "secret"},
+    { obs_name: "synth", command_name: "synth"}
 ];
 
 module.exports.backgrounds_help_message = `Possible backgrounds are, pool, tile, earth, duck, universe, invisible, fire, rainbow, static. E.g. !background duck`;
diff --git a/src/backend/package-lock.json b/src/backend/package-lock.json
index dde1906..aedf0b9 100644
--- a/src/backend/package-lock.json
+++ b/src/backend/package-lock.json
@@ -14,6 +14,62 @@
         "kuler": "^2.0.0"
       }
     },
+    "accepts": {
+      "version": "1.3.7",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+      "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+      "requires": {
+        "mime-types": "~2.1.24",
+        "negotiator": "0.6.2"
+      }
+    },
+    "array-flatten": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+      "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+    },
+    "base64url": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz",
+      "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A=="
+    },
+    "body-parser": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+      "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+      "requires": {
+        "bytes": "3.1.0",
+        "content-type": "~1.0.4",
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "http-errors": "1.7.2",
+        "iconv-lite": "0.4.24",
+        "on-finished": "~2.3.0",
+        "qs": "6.7.0",
+        "raw-body": "2.4.0",
+        "type-is": "~1.6.17"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+        }
+      }
+    },
+    "bytes": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+      "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
+    },
     "color-convert": {
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -61,6 +117,29 @@
         }
       }
     },
+    "content-disposition": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+      "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+      "requires": {
+        "safe-buffer": "5.1.2"
+      }
+    },
+    "content-type": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+    },
+    "cookie": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
+      "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
+    },
+    "cookie-signature": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+    },
     "core-util-is": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
@@ -74,11 +153,133 @@
         "ms": "2.1.2"
       }
     },
+    "depd": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+    },
+    "destroy": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+    },
+    "ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+    },
     "enabled": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
       "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="
     },
+    "encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+    },
+    "escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+    },
+    "etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+    },
+    "express": {
+      "version": "4.17.1",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
+      "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+      "requires": {
+        "accepts": "~1.3.7",
+        "array-flatten": "1.1.1",
+        "body-parser": "1.19.0",
+        "content-disposition": "0.5.3",
+        "content-type": "~1.0.4",
+        "cookie": "0.4.0",
+        "cookie-signature": "1.0.6",
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "finalhandler": "~1.1.2",
+        "fresh": "0.5.2",
+        "merge-descriptors": "1.0.1",
+        "methods": "~1.1.2",
+        "on-finished": "~2.3.0",
+        "parseurl": "~1.3.3",
+        "path-to-regexp": "0.1.7",
+        "proxy-addr": "~2.0.5",
+        "qs": "6.7.0",
+        "range-parser": "~1.2.1",
+        "safe-buffer": "5.1.2",
+        "send": "0.17.1",
+        "serve-static": "1.14.1",
+        "setprototypeof": "1.1.1",
+        "statuses": "~1.5.0",
+        "type-is": "~1.6.18",
+        "utils-merge": "1.0.1",
+        "vary": "~1.1.2"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+        }
+      }
+    },
+    "express-session": {
+      "version": "1.17.1",
+      "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.1.tgz",
+      "integrity": "sha512-UbHwgqjxQZJiWRTMyhvWGvjBQduGCSBDhhZXYenziMFjxst5rMV+aJZ6hKPHZnPyHGsrqRICxtX8jtEbm/z36Q==",
+      "requires": {
+        "cookie": "0.4.0",
+        "cookie-signature": "1.0.6",
+        "debug": "2.6.9",
+        "depd": "~2.0.0",
+        "on-headers": "~1.0.2",
+        "parseurl": "~1.3.3",
+        "safe-buffer": "5.2.0",
+        "uid-safe": "~2.1.5"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "depd": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+          "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+        },
+        "safe-buffer": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
+          "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
+        }
+      }
+    },
     "fast-safe-stringify": {
       "version": "2.0.7",
       "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz",
@@ -97,16 +298,80 @@
         "moment": "^2.11.2"
       }
     },
+    "finalhandler": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+      "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+      "requires": {
+        "debug": "2.6.9",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "on-finished": "~2.3.0",
+        "parseurl": "~1.3.3",
+        "statuses": "~1.5.0",
+        "unpipe": "~1.0.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+        }
+      }
+    },
     "fn.name": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
       "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
     },
+    "forwarded": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+      "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
+    },
+    "fresh": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+    },
+    "http-errors": {
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+      "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+      "requires": {
+        "depd": "~1.1.2",
+        "inherits": "2.0.3",
+        "setprototypeof": "1.1.1",
+        "statuses": ">= 1.5.0 < 2",
+        "toidentifier": "1.0.0"
+      }
+    },
+    "iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "requires": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      }
+    },
     "inherits": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
       "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
     },
+    "ipaddr.js": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+    },
     "isarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
@@ -141,6 +406,39 @@
         }
       }
     },
+    "media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+    },
+    "merge-descriptors": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+    },
+    "methods": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+    },
+    "mime": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+    },
+    "mime-db": {
+      "version": "1.46.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz",
+      "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ=="
+    },
+    "mime-types": {
+      "version": "2.1.29",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz",
+      "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==",
+      "requires": {
+        "mime-db": "1.46.0"
+      }
+    },
     "moment": {
       "version": "2.29.1",
       "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
@@ -151,6 +449,16 @@
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
     },
+    "negotiator": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+      "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
+    },
+    "oauth": {
+      "version": "0.9.15",
+      "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
+      "integrity": "sha1-vR/vr2hslrdUda7VGWQS/2DPucE="
+    },
     "object-hash": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.0.3.tgz",
@@ -167,6 +475,19 @@
         "ws": "^7.2.0"
       }
     },
+    "on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+      "requires": {
+        "ee-first": "1.1.1"
+      }
+    },
+    "on-headers": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+      "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
+    },
     "one-time": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
@@ -175,11 +496,120 @@
         "fn.name": "1.x.x"
       }
     },
+    "parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+    },
+    "passport": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz",
+      "integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==",
+      "requires": {
+        "passport-strategy": "1.x.x",
+        "pause": "0.0.1"
+      }
+    },
+    "passport-oauth": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/passport-oauth/-/passport-oauth-1.0.0.tgz",
+      "integrity": "sha1-kK/2M4dUDwIImvKM2tOep/gNd98=",
+      "requires": {
+        "passport-oauth1": "1.x.x",
+        "passport-oauth2": "1.x.x"
+      }
+    },
+    "passport-oauth1": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/passport-oauth1/-/passport-oauth1-1.1.0.tgz",
+      "integrity": "sha1-p96YiiEfnPRoc3cTDqdN8ycwyRg=",
+      "requires": {
+        "oauth": "0.9.x",
+        "passport-strategy": "1.x.x",
+        "utils-merge": "1.x.x"
+      }
+    },
+    "passport-oauth2": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.5.0.tgz",
+      "integrity": "sha512-kqBt6vR/5VlCK8iCx1/KpY42kQ+NEHZwsSyt4Y6STiNjU+wWICG1i8ucc1FapXDGO15C5O5VZz7+7vRzrDPXXQ==",
+      "requires": {
+        "base64url": "3.x.x",
+        "oauth": "0.9.x",
+        "passport-strategy": "1.x.x",
+        "uid2": "0.0.x",
+        "utils-merge": "1.x.x"
+      }
+    },
+    "passport-strategy": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
+      "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ="
+    },
+    "passport-twitch": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/passport-twitch/-/passport-twitch-1.0.3.tgz",
+      "integrity": "sha1-gqSh++GTaNROYvBX6TxBSp1P58w=",
+      "requires": {
+        "passport-oauth2": "^1.1.2",
+        "pkginfo": "0.2.x"
+      }
+    },
+    "path-to-regexp": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+    },
+    "pause": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
+      "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
+    },
+    "pkginfo": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.2.3.tgz",
+      "integrity": "sha1-cjnEKl72wwuPMoQ52bn/cQQkkPg="
+    },
     "process-nextick-args": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
       "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
     },
+    "proxy-addr": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
+      "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
+      "requires": {
+        "forwarded": "~0.1.2",
+        "ipaddr.js": "1.9.1"
+      }
+    },
+    "qs": {
+      "version": "6.7.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+      "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
+    },
+    "random-bytes": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
+      "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs="
+    },
+    "range-parser": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+    },
+    "raw-body": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+      "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+      "requires": {
+        "bytes": "3.1.0",
+        "http-errors": "1.7.2",
+        "iconv-lite": "0.4.24",
+        "unpipe": "1.0.0"
+      }
+    },
     "readable-stream": {
       "version": "3.6.0",
       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
@@ -195,6 +625,69 @@
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
       "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
     },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+    },
+    "send": {
+      "version": "0.17.1",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
+      "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+      "requires": {
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "destroy": "~1.0.4",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "fresh": "0.5.2",
+        "http-errors": "~1.7.2",
+        "mime": "1.6.0",
+        "ms": "2.1.1",
+        "on-finished": "~2.3.0",
+        "range-parser": "~1.2.1",
+        "statuses": "~1.5.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          },
+          "dependencies": {
+            "ms": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+              "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+            }
+          }
+        },
+        "ms": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+        }
+      }
+    },
+    "serve-static": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
+      "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+      "requires": {
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "parseurl": "~1.3.3",
+        "send": "0.17.1"
+      }
+    },
+    "setprototypeof": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+      "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
+    },
     "sha.js": {
       "version": "2.4.11",
       "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
@@ -224,6 +717,11 @@
       "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
       "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
     },
+    "statuses": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+    },
     "string_decoder": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -244,16 +742,58 @@
       "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
       "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="
     },
+    "toidentifier": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+      "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
+    },
     "triple-beam": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
       "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
     },
+    "type-is": {
+      "version": "1.6.18",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+      "requires": {
+        "media-typer": "0.3.0",
+        "mime-types": "~2.1.24"
+      }
+    },
+    "uid-safe": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
+      "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
+      "requires": {
+        "random-bytes": "~1.0.0"
+      }
+    },
+    "uid2": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz",
+      "integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I="
+    },
+    "unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+    },
     "util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
       "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
     },
+    "utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+    },
+    "vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+    },
     "winston": {
       "version": "3.3.3",
       "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz",
diff --git a/src/backend/package.json b/src/backend/package.json
index 83808fa..bf988bf 100644
--- a/src/backend/package.json
+++ b/src/backend/package.json
@@ -9,7 +9,12 @@
     "author": "Matan Presberg",
     "license": "MIT",
     "dependencies": {
+        "express": "^4.17.1",
+        "express-session": "^1.17.1",
         "obs-websocket-js": "^4.0.2",
+        "passport": "^0.4.1",
+        "passport-oauth": "^1.0.0",
+        "passport-twitch": "^1.0.3",
         "winston": "^3.3.3",
         "winston-daily-rotate-file": "^4.5.0"
     }
diff --git a/src/backend/twitch_events_ws.js b/src/backend/twitch_events_ws.js
new file mode 100644
index 0000000..6bc792c
--- /dev/null
+++ b/src/backend/twitch_events_ws.js
@@ -0,0 +1,94 @@
+//https://dev.twitch.tv/docs/pubsub
+require("dotenv").config();
+const WebSocket = require("ws");
+const passport = require("passport");
+var express        = require('express');
+var session        = require('express-session');
+const OAuth2Strategy = require('passport-oauth').OAuth2Strategy;
+
+let ws;
+let oath_code;
+
+const twitch_opts = new OAuth2Strategy({
+    authorizationURL: 'https://id.twitch.tv/oauth2/authorize',
+    tokenURL: 'https://id.twitch.tv/oauth2/token',
+    clientID: process.env.CLIENT_ID,
+    clientSecret: process.env.CLIENT_SECRET,
+    callbackURL: "https://127.0.0.1:3000",
+    state: true
+  },
+    function (accessToken, refreshToken, profile, done) {
+        console.log('here');
+        oath_code = accessToken;
+        profile.accessToken = accessToken;
+        profile.refreshToken = refreshToken;
+        return done(err, profile);
+    }
+);
+
+passport.serializeUser(function(user, done) {
+    done(null, user);
+});
+
+passport.deserializeUser(function(user, done) {
+    done(null, user);
+});
+
+passport.initialize();
+passport.session();
+
+passport.use(twitch_opts);
+
+passport.authenticate("twitch");
+
+setTimeout(() => connect(), 1000);
+
+function randomString(length) {
+    var text = "";
+    var possible =
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+    for (var i = 0; i < length; i++) {
+        text += possible.charAt(Math.floor(Math.random() * possible.length));
+    }
+    return text;
+}
+
+//all wrapped in a function to handle reconnecting
+function connect() {
+    ws = new WebSocket("wss://pubsub-edge.twitch.tv");
+
+    //TODO reconnect if don't receive PONG back from PING
+    ws.onopen = function (event) {
+        console.log("opened");
+        //ping server every 4.5 - 4.55 minutes
+        //randomness since Twitch asked nicely
+        (function heartbeat() {
+            let rand = 1000 * 60 * 4.5 + Math.random() * 5000;
+            setTimeout(function () {
+                ws.send(`{ "type": "PING" }`);
+                heartbeat();
+            }, rand);
+        })();
+
+        //stuck on getting channel id of my channel, this one incorrect
+        const listen_to_topics = {
+            type: "LISTEN",
+            nonce: randomString(17),
+            data: {
+                topics: ["channel-points-channel-v1.128811347"],
+                auth_token: oath_code,
+            },
+        };
+
+        ws.send(JSON.stringify(listen_to_topics));
+    };
+
+    ws.onerror = function (error) {
+        console.log(error);
+    };
+
+    //TODO handle RECONNECT messages from server
+    ws.onmessage = function (event) {
+        console.log(event.data.trim());
+    };
+}
diff --git a/src/frontend/.eslintcache b/src/frontend/.eslintcache
index d848f56..3258e32 100644
--- a/src/frontend/.eslintcache
+++ b/src/frontend/.eslintcache
@@ -1 +1 @@
-[{"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js":"1","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js":"2","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js":"3"},{"size":521,"mtime":1611527873653,"results":"4","hashOfConfig":"5"},{"size":215,"mtime":1611527873652,"results":"6","hashOfConfig":"5"},{"size":2704,"mtime":1614070762675,"results":"7","hashOfConfig":"5"},{"filePath":"8","messages":"9","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},"82sdiv",{"filePath":"11","messages":"12","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},{"filePath":"13","messages":"14","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js",[],["15","16"],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js",[],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js",[],{"ruleId":"17","replacedBy":"18"},{"ruleId":"19","replacedBy":"20"},"no-native-reassign",["21"],"no-negated-in-lhs",["22"],"no-global-assign","no-unsafe-negation"]
\ No newline at end of file
+[{"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js":"1","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js":"2","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js":"3"},{"size":521,"mtime":1611527873653,"results":"4","hashOfConfig":"5"},{"size":215,"mtime":1611527873652,"results":"6","hashOfConfig":"5"},{"size":2704,"mtime":1614905765818,"results":"7","hashOfConfig":"5"},{"filePath":"8","messages":"9","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},"82sdiv",{"filePath":"11","messages":"12","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"10"},{"filePath":"13","messages":"14","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js",[],["15","16"],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js",[],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js",[],{"ruleId":"17","replacedBy":"18"},{"ruleId":"19","replacedBy":"20"},"no-native-reassign",["21"],"no-negated-in-lhs",["22"],"no-global-assign","no-unsafe-negation"]
\ No newline at end of file
diff --git a/src/frontend/src/components/twitch-chat-style.css b/src/frontend/src/components/twitch-chat-style.css
index 5213e1b..42f435c 100644
--- a/src/frontend/src/components/twitch-chat-style.css
+++ b/src/frontend/src/components/twitch-chat-style.css
@@ -44,6 +44,6 @@
         top: 0px;
     }
     to {
-        top: 250px;
+        top: 480px;
     }
 }

From b084e57f02200b58e741e1c85fe12ab73292c5ab Mon Sep 17 00:00:00 2001
From: matanp <mgp64@cornell.edu>
Date: Sun, 23 May 2021 15:06:37 -0700
Subject: [PATCH 5/6] add script to start frontend and backend at the same time

---
 package.json              | 22 +++++++++++++
 src/backend/package.json  | 66 +++++++++++++++++++--------------------
 src/frontend/.eslintcache |  1 -
 3 files changed, 55 insertions(+), 34 deletions(-)
 create mode 100644 package.json
 delete mode 100644 src/frontend/.eslintcache

diff --git a/package.json b/package.json
new file mode 100644
index 0000000..d1a7b87
--- /dev/null
+++ b/package.json
@@ -0,0 +1,22 @@
+{
+  "name": "matanbot",
+  "version": "1.0.0",
+  "description": "A chatbot that can respond to users on a Twitch chat stream, control Open Broadcaster Software (OBS) via websocket connection, and display chat on a browser, used as an overlay for OBS.",
+  "main": "index.js",
+  "directories": {
+    "doc": "docs"
+  },
+  "scripts": {
+    "start": "(cd src/backend && npm run start) & (cd src/frontend && npm run start)"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/matanp/matanbot.git"
+  },
+  "author": "",
+  "license": "ISC",
+  "bugs": {
+    "url": "https://github.com/matanp/matanbot/issues"
+  },
+  "homepage": "https://github.com/matanp/matanbot#readme"
+}
diff --git a/src/backend/package.json b/src/backend/package.json
index c1399fb..0c6e1cf 100644
--- a/src/backend/package.json
+++ b/src/backend/package.json
@@ -1,35 +1,35 @@
 {
-  "name": "matanbot",
-  "version": "1.0.0",
-  "description": "Chat bot for matanjuggles social media.",
-  "main": "twitch_main.js",
-  "scripts": {
-    "start": "tsc && node dist/twitch_main.js",
-    "build": "babel --delete-dir-on-start --out-dir dist --copy-files --ignore \"**/__tests__/**,**/__mocks__/**\" --no-copy-ignored src",
-    "start:dev": "nodemon dist/index.js",
-    "build:dev": "tsc --watch --preserveWatchOutput",
-    "dev": "concurrently \"npm:build:dev\" \"npm:start:dev\""
-  },
-  "author": "Matan Presberg",
-  "license": "MIT",
-  "dependencies": {
-    "express": "^4.17.1",
-    "express-session": "^1.17.1",
-    "obs-websocket-js": "^4.0.2",
-    "passport": "^0.4.1",
-    "passport-oauth": "^1.0.0",
-    "passport-twitch": "^1.0.3",
-    "winston": "^3.3.3",
-    "winston-daily-rotate-file": "^4.5.0",
-    "dotenv": "^8.2.0",
-    "firebase-admin": "^9.8.0",
-    "tmi.js": "^1.7.5"
-  },
-  "devDependencies": {
-    "@types/node": "^15.0.2",
-    "@types/tmi.js": "^1.7.1",
-    "@types/ws": "^7.4.2",
-    "tslint": "^6.1.3",
-    "typescript": "^4.2.4"
-  }
+    "name": "matanbot",
+    "version": "1.0.0",
+    "description": "Chat bot for matanjuggles social media.",
+    "main": "twitch_main.js",
+    "scripts": {
+        "start": "tsc && node dist/twitch_main.js",
+        "build": "babel --delete-dir-on-start --out-dir dist --copy-files --ignore \"**/__tests__/**,**/__mocks__/**\" --no-copy-ignored src",
+        "start:dev": "nodemon dist/index.js",
+        "build:dev": "tsc --watch --preserveWatchOutput",
+        "dev": "concurrently \"npm:build:dev\" \"npm:start:dev\""
+    },
+    "author": "Matan Presberg",
+    "license": "MIT",
+    "dependencies": {
+        "express": "^4.17.1",
+        "express-session": "^1.17.1",
+        "obs-websocket-js": "^4.0.2",
+        "passport": "^0.4.1",
+        "passport-oauth": "^1.0.0",
+        "passport-twitch": "^1.0.3",
+        "winston": "^3.3.3",
+        "winston-daily-rotate-file": "^4.5.0",
+        "dotenv": "^8.2.0",
+        "firebase-admin": "^9.8.0",
+        "tmi.js": "^1.7.5"
+    },
+    "devDependencies": {
+        "@types/node": "^15.0.2",
+        "@types/tmi.js": "^1.7.1",
+        "@types/ws": "^7.4.2",
+        "tslint": "^6.1.3",
+        "typescript": "^4.2.4"
+    }
 }
diff --git a/src/frontend/.eslintcache b/src/frontend/.eslintcache
deleted file mode 100644
index c97e516..0000000
--- a/src/frontend/.eslintcache
+++ /dev/null
@@ -1 +0,0 @@
-[{"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js":"1","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js":"2","C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js":"3","C:\\Users\\mpres\\Documents\\Github\\matanbot\\src\\frontend\\src\\index.js":"4","C:\\Users\\mpres\\Documents\\Github\\matanbot\\src\\frontend\\src\\App.js":"5","C:\\Users\\mpres\\Documents\\Github\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js":"6"},{"size":504,"mtime":1610254160076,"results":"7","hashOfConfig":"8"},{"size":203,"mtime":1610258278547,"results":"9","hashOfConfig":"8"},{"size":2054,"mtime":1610261371511,"results":"10","hashOfConfig":"8"},{"size":504,"mtime":1617314991193,"results":"11","hashOfConfig":"12"},{"size":203,"mtime":1617314991191,"results":"13","hashOfConfig":"12"},{"size":1985,"mtime":1620611605371,"results":"14","hashOfConfig":"12"},{"filePath":"15","messages":"16","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"17"},"82sdiv",{"filePath":"18","messages":"19","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"17"},{"filePath":"20","messages":"21","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22","messages":"23","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"24"},"gnwjlf",{"filePath":"25","messages":"26","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"24"},{"filePath":"27","messages":"28","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\index.js",[],["29","30"],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\App.js",[],"C:\\Users\\mpres\\Documents\\GitHub\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js",[],"C:\\Users\\mpres\\Documents\\Github\\matanbot\\src\\frontend\\src\\index.js",[],["31","32"],"C:\\Users\\mpres\\Documents\\Github\\matanbot\\src\\frontend\\src\\App.js",[],"C:\\Users\\mpres\\Documents\\Github\\matanbot\\src\\frontend\\src\\components\\TwitchChat.js",[],{"ruleId":"33","replacedBy":"34"},{"ruleId":"35","replacedBy":"36"},{"ruleId":"33","replacedBy":"37"},{"ruleId":"35","replacedBy":"38"},"no-native-reassign",["39"],"no-negated-in-lhs",["40"],["39"],["40"],"no-global-assign","no-unsafe-negation"]

From dcb3c4522a8eb53b3d02d2406f71d523c694fe5f Mon Sep 17 00:00:00 2001
From: matanp <mgp64@cornell.edu>
Date: Thu, 27 May 2021 22:39:28 -0700
Subject: [PATCH 6/6] start frontend and backend concurrently

---
 .gitignore                                |   1 +
 package-lock.json                         | 429 ++++++++++++++++++++++
 package.json                              |  13 +-
 src/frontend/src/components/TwitchChat.js |   2 +-
 4 files changed, 439 insertions(+), 6 deletions(-)
 create mode 100644 package-lock.json

diff --git a/.gitignore b/.gitignore
index 1d74e21..6e5588d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 .vscode/
+/node_modules
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..809a23f
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,429 @@
+{
+  "name": "matanbot",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "@babel/code-frame": {
+      "version": "7.12.13",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
+      "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
+      "requires": {
+        "@babel/highlight": "^7.12.13"
+      }
+    },
+    "@babel/helper-validator-identifier": {
+      "version": "7.14.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz",
+      "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A=="
+    },
+    "@babel/highlight": {
+      "version": "7.14.0",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz",
+      "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==",
+      "requires": {
+        "@babel/helper-validator-identifier": "^7.14.0",
+        "chalk": "^2.0.0",
+        "js-tokens": "^4.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
+        "color-convert": {
+          "version": "1.9.3",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+          "requires": {
+            "color-name": "1.1.3"
+          }
+        },
+        "color-name": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+        },
+        "has-flag": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "@types/normalize-package-data": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+      "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA=="
+    },
+    "ansi-regex": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+      "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
+    },
+    "ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "requires": {
+        "color-convert": "^2.0.1"
+      }
+    },
+    "chalk": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
+      "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
+      "requires": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "dependencies": {
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "cliui": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+      "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+      "requires": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^7.0.0"
+      }
+    },
+    "color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "requires": {
+        "color-name": "~1.1.4"
+      }
+    },
+    "color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
+    "concurrently": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.2.0.tgz",
+      "integrity": "sha512-v9I4Y3wFoXCSY2L73yYgwA9ESrQMpRn80jMcqMgHx720Hecz2GZAvTI6bREVST6lkddNypDKRN22qhK0X8Y00g==",
+      "requires": {
+        "chalk": "^4.1.0",
+        "date-fns": "^2.16.1",
+        "lodash": "^4.17.21",
+        "read-pkg": "^5.2.0",
+        "rxjs": "^6.6.3",
+        "spawn-command": "^0.0.2-1",
+        "supports-color": "^8.1.0",
+        "tree-kill": "^1.2.2",
+        "yargs": "^16.2.0"
+      }
+    },
+    "date-fns": {
+      "version": "2.21.3",
+      "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.21.3.tgz",
+      "integrity": "sha512-HeYdzCaFflc1i4tGbj7JKMjM4cKGYoyxwcIIkHzNgCkX8xXDNJDZXgDDVchIWpN4eQc3lH37WarduXFZJOtxfw=="
+    },
+    "emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+    },
+    "error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "requires": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+    },
+    "function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+    },
+    "get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
+    },
+    "has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "requires": {
+        "function-bind": "^1.1.1"
+      }
+    },
+    "has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+    },
+    "hosted-git-info": {
+      "version": "2.8.9",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+      "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="
+    },
+    "is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
+    },
+    "is-core-module": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz",
+      "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==",
+      "requires": {
+        "has": "^1.0.3"
+      }
+    },
+    "is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
+    },
+    "js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+    },
+    "json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
+    },
+    "lines-and-columns": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
+      "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA="
+    },
+    "lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+    },
+    "normalize-package-data": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+      "requires": {
+        "hosted-git-info": "^2.1.4",
+        "resolve": "^1.10.0",
+        "semver": "2 || 3 || 4 || 5",
+        "validate-npm-package-license": "^3.0.1"
+      }
+    },
+    "parse-json": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+      "requires": {
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
+      }
+    },
+    "path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
+    },
+    "read-pkg": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+      "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+      "requires": {
+        "@types/normalize-package-data": "^2.4.0",
+        "normalize-package-data": "^2.5.0",
+        "parse-json": "^5.0.0",
+        "type-fest": "^0.6.0"
+      }
+    },
+    "require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
+    },
+    "resolve": {
+      "version": "1.20.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
+      "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
+      "requires": {
+        "is-core-module": "^2.2.0",
+        "path-parse": "^1.0.6"
+      }
+    },
+    "rxjs": {
+      "version": "6.6.7",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+      "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+      "requires": {
+        "tslib": "^1.9.0"
+      }
+    },
+    "semver": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+    },
+    "spawn-command": {
+      "version": "0.0.2-1",
+      "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz",
+      "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A="
+    },
+    "spdx-correct": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
+      "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
+      "requires": {
+        "spdx-expression-parse": "^3.0.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-exceptions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+      "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A=="
+    },
+    "spdx-expression-parse": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+      "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+      "requires": {
+        "spdx-exceptions": "^2.1.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-license-ids": {
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz",
+      "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ=="
+    },
+    "string-width": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
+      "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
+      "requires": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.0"
+      }
+    },
+    "strip-ansi": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+      "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+      "requires": {
+        "ansi-regex": "^5.0.0"
+      }
+    },
+    "supports-color": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+      "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+      "requires": {
+        "has-flag": "^4.0.0"
+      }
+    },
+    "tree-kill": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
+      "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="
+    },
+    "tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+    },
+    "type-fest": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+      "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg=="
+    },
+    "validate-npm-package-license": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+      "requires": {
+        "spdx-correct": "^3.0.0",
+        "spdx-expression-parse": "^3.0.0"
+      }
+    },
+    "wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "requires": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      }
+    },
+    "y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
+    },
+    "yargs": {
+      "version": "16.2.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+      "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+      "requires": {
+        "cliui": "^7.0.2",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.0",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^20.2.2"
+      }
+    },
+    "yargs-parser": {
+      "version": "20.2.7",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz",
+      "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw=="
+    }
+  }
+}
diff --git a/package.json b/package.json
index d1a7b87..ca0d242 100644
--- a/package.json
+++ b/package.json
@@ -2,21 +2,24 @@
   "name": "matanbot",
   "version": "1.0.0",
   "description": "A chatbot that can respond to users on a Twitch chat stream, control Open Broadcaster Software (OBS) via websocket connection, and display chat on a browser, used as an overlay for OBS.",
-  "main": "index.js",
+  "main": "src/backend/dist/twitch_main.js",
   "directories": {
     "doc": "docs"
   },
   "scripts": {
-    "start": "(cd src/backend && npm run start) & (cd src/frontend && npm run start)"
+    "start": "concurrently \"cd src/backend && npm run start\" \"cd src/frontend && npm run start\""
   },
   "repository": {
     "type": "git",
     "url": "git+https://github.com/matanp/matanbot.git"
   },
-  "author": "",
-  "license": "ISC",
+  "author": "Matan Presberg",
+  "license": "MIT",
   "bugs": {
     "url": "https://github.com/matanp/matanbot/issues"
   },
-  "homepage": "https://github.com/matanp/matanbot#readme"
+  "homepage": "https://github.com/matanp/matanbot#readme",
+  "dependencies": {
+    "concurrently": "^6.2.0"
+  }
 }
diff --git a/src/frontend/src/components/TwitchChat.js b/src/frontend/src/components/TwitchChat.js
index c21106e..23cd5cf 100644
--- a/src/frontend/src/components/TwitchChat.js
+++ b/src/frontend/src/components/TwitchChat.js
@@ -50,7 +50,7 @@ const TwitchChat = () => {
         //     },
         // ]);
         if(message.emotes) {
-            setEmotes([...emotes, ...Object.keys(message.emotes)]);
+            setEmotes((emotes) => [...emotes, ...Object.keys(message.emotes)]);
         }
 
     };