From 141d64e36b8d383184c90d1a8a7e7ef639c77dcb Mon Sep 17 00:00:00 2001
From: Isabel Jenkins <unreturnable@sucs.org>
Date: Tue, 18 Jul 2017 10:00:44 +0100
Subject: [PATCH] it now does chat

---
 index.html                    |   2 +-
 package-lock.json             |  20 +++-
 package.json                  |   1 +
 src/App.vue                   |  26 ++++
 src/assets/logo-orange.png    | Bin 0 -> 17072 bytes
 src/components/chat.vue       |  44 ++++++-
 src/components/login.vue      | 126 ++++++++++++++++++++
 src/components/online.vue     |  83 +++++++++++--
 src/components/rooms.vue      |   2 +-
 src/components/talk.vue       |  14 ++-
 src/components/topbar.vue     |  25 +++-
 src/mixins/mw-command.js      |  56 +++++++++
 src/mixins/mw-sync.js         | 216 ++++++++++++++++++++++++++++++++++
 src/mixins/string-to-color.js |  19 +++
 src/mixins/url-checker.js     |  10 ++
 src/pages/chat.vue            |  28 +++--
 src/pages/login.vue           |  20 ----
 src/router/index.js           |   6 -
 18 files changed, 638 insertions(+), 60 deletions(-)
 create mode 100644 src/assets/logo-orange.png
 create mode 100644 src/components/login.vue
 create mode 100644 src/mixins/mw-command.js
 create mode 100644 src/mixins/mw-sync.js
 create mode 100644 src/mixins/string-to-color.js
 create mode 100644 src/mixins/url-checker.js
 delete mode 100644 src/pages/login.vue

diff --git a/index.html b/index.html
index 6c854be..76e31ba 100644
--- a/index.html
+++ b/index.html
@@ -4,7 +4,7 @@
     <meta charset="utf-8">
     <link rel="shortcut icon" type="image/png" href="./static/favicon.png"/>
     <meta name="theme-color" content="#e65c00">
-    <meta name="viewport" content="width=device-width, initial-scale=0.8">
+    <meta name="viewport" content="width=0.7, initial-scale=0.7">
     <title>Web Milliways</title>
   </head>
   <body>
diff --git a/package-lock.json b/package-lock.json
index 61352b0..3312d5b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -321,6 +321,15 @@
       "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
       "dev": true
     },
+    "axios": {
+      "version": "0.16.2",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.16.2.tgz",
+      "integrity": "sha1-uk+S8XFn37q0CYN4VFS5rBScPG0=",
+      "requires": {
+        "follow-redirects": "1.2.4",
+        "is-buffer": "1.1.5"
+      }
+    },
     "babel-code-frame": {
       "version": "6.22.0",
       "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz",
@@ -3526,6 +3535,14 @@
       "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=",
       "dev": true
     },
+    "follow-redirects": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.2.4.tgz",
+      "integrity": "sha512-Suw6KewLV2hReSyEOeql+UUkBVyiBm3ok1VPrVFRZnQInWpdoZbbiG5i8aJVSjTr0yQ4Ava0Sh6/joCg1Brdqw==",
+      "requires": {
+        "debug": "2.6.8"
+      }
+    },
     "for-in": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@@ -4401,8 +4418,7 @@
     "is-buffer": {
       "version": "1.1.5",
       "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz",
-      "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=",
-      "dev": true
+      "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw="
     },
     "is-builtin-module": {
       "version": "1.0.0",
diff --git a/package.json b/package.json
index ca9564e..3bd06a3 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
     "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs"
   },
   "dependencies": {
+    "axios": "^0.16.2",
     "pouchdb-browser": "^6.3.2",
     "pouchdb-find": "^6.3.2",
     "pouchdb-live-find": "^0.4.0",
diff --git a/src/App.vue b/src/App.vue
index 964361b..bc4699e 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -24,4 +24,30 @@ body {
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
 }
+
+.scroll {
+  overflow-y: hidden;
+}
+
+@media only screen and (max-width: 800px) {
+  .scroll {
+    overflow-y: overlay;
+  }
+}
+
+.scroll:hover {
+  overflow-y: overlay;
+}
+
+.scroll::-webkit-scrollbar-track {
+  background: rgba(0, 0, 0, 0.5);
+}
+
+.scroll::-webkit-scrollbar {
+  width: 8px;
+}
+
+.scroll::-webkit-scrollbar-thumb {
+  background-color: #000000;
+}
 </style>
diff --git a/src/assets/logo-orange.png b/src/assets/logo-orange.png
new file mode 100644
index 0000000000000000000000000000000000000000..e7f4c58dfada980e6b3046c93e52a53d9d079af1
GIT binary patch
literal 17072
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
C4AGAO

literal 0
HcmV?d00001

diff --git a/src/components/chat.vue b/src/components/chat.vue
index 73fc0dc..68c8e40 100644
--- a/src/components/chat.vue
+++ b/src/components/chat.vue
@@ -1,16 +1,25 @@
 <template>
-  <div id="chat">
-    <p>{{ msg }}</p>
+  <div id="chat" class="scroll">
+    <div id="chat-inner">
+      <div v-for="msg in talker">
+        <div class="msg">
+          {{ msg.photo }}
+          <p>
+            <b>{{ msg.user }}</b> {{ msg.timestamp }}
+            <br>
+            <span v-html="msg.msg"/>
+          </p>
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
 <script>
 export default {
   name: 'chat',
-  data () {
-    return {
-      msg: 'Test message'
-    }
+  pouch: {
+    talker: {}
   }
 }
 </script>
@@ -18,7 +27,30 @@ export default {
 <!-- Add "scoped" attribute to limit CSS to this component only -->
 <style scoped>
 #chat {
+  height: calc(100vh - 110px);
   margin-left: 10px;
   margin-right: 10px;
+  margin-top: 10px;
+  overflow-x: hidden;
+}
+
+#chat-inner {
+  margin-right: 5px;
+}
+
+@media only screen and (max-width: 800px) {
+  #chat {
+    height: calc(100vh - 180px);
+    margin-left: 5px;
+    margin-right: 0px;
+  }
+
+  #chat-inner {
+    margin-right: 10px;
+  }
+
+  .msg {
+    font-size: 8pt;
+  }
 }
 </style>
diff --git a/src/components/login.vue b/src/components/login.vue
new file mode 100644
index 0000000..c2b67be
--- /dev/null
+++ b/src/components/login.vue
@@ -0,0 +1,126 @@
+<template>
+  <div id="login">
+    <div id="login-wrap">
+      <img src="../assets/logo-orange.png" class="logo">
+      <form id="login-form">
+        <input type="text" id="login-user" placeholder="Username" autofocus/><br>
+        <input type="password" id="login-pass" placeholder="Password"/><br>
+        <input type="submit" id="login-submit" class="button" value="Login">
+      </form>
+    </div>
+  </div>
+</template>
+
+<script>
+import PouchDB from 'pouchdb-browser'
+import axios from 'axios'
+
+export default {
+  name: 'login',
+  data () {
+    return {
+    }
+  },
+  mounted: function () {
+    var db = new PouchDB('auth')
+
+    db.get('user')
+    .then(function (result) {
+      hideLogin()
+      return
+    }).catch(function () {
+      // Do nothing since we need to auth the user
+    })
+
+    document.getElementById('login-form').addEventListener('submit', function (e) {
+      var user = document.getElementById('login-user').value
+      var pass = document.getElementById('login-pass').value
+
+      axios.post('https://sucs.org/~unreturnable/webmw-test/', { username: user, password: pass, action: 'login' })
+      .then(function (response) {
+        if (typeof response.data === 'string') {
+          if (response.data.startsWith('success:')) {
+            var token = response.data.replace('success:', '')
+
+            db.get('user')
+            .then(function (success) {
+              db.remove(success)
+              .then(function (success) {
+                db.put({ _id: 'user', token: token })
+                .then(function (success) {
+                  location.reload()
+                }).catch(function () {
+                })
+              }).catch(function () {
+              })
+            }).catch(function () {
+              db.put({ _id: 'user', token: token })
+              .then(function (success) {
+                location.reload()
+              }).catch(function () {
+              })
+            })
+          }
+        } else {
+          console.log(response.data.error)
+        }
+      }).catch(function (error) {
+        console.log(error.message)
+      })
+
+      return false
+    })
+  }
+}
+
+function hideLogin () {
+  var login = document.getElementById('login')
+  login.parentElement.removeChild(login)
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+#login {
+  position: absolute;
+  top: 0;
+  width: 100vw;
+  height: 100vh;
+  background-color: #f2f2f2;
+}
+
+#login-wrap {
+  width: 100%;
+  text-align: center;
+  margin-top: 100px;
+}
+
+#login-header {
+  font-size: 32pt;
+}
+
+#login-user {
+  padding: 10px;
+}
+
+#login-pass {
+  margin-top: 10px;
+  padding: 10px;
+}
+
+#login-submit {
+  margin-top: 10px;
+}
+
+.button {
+  background: #e65c00;
+  color: #f2f2f2;
+  padding: 10px 40px 10px 40px;
+  border: none;
+}
+
+.logo {
+  width: 200px;
+  margin-left: -15px;
+}
+</style>
diff --git a/src/components/online.vue b/src/components/online.vue
index b3f3241..e21a5f2 100644
--- a/src/components/online.vue
+++ b/src/components/online.vue
@@ -1,15 +1,25 @@
 <template>
   <div class="bar-wrapper" v-if="config">
-    <div id="online" v-bind:style="{ 'background': config.onlineBg, 'color': config.onlineFg }">
+    <div id="online" class="scroll" v-bind:style="{ 'background': config.onlineBg, 'color': config.onlineFg }">
       <div id="online-list">
-	<h2>Online</h2>
-	<h3>{{ user }}</h3>
+        <h2 id="online-header">Online</h2>
+        <div v-for="user in online">
+          <div class="user">
+            {{ user.name }}
+            <div v-html="user.photo"></div>
+          </div>
+        </div>
       </div>
     </div>
   </div>
 </template>
 
 <script>
+import PouchDB from 'pouchdb-browser'
+import mwCommand from '../mixins/mw-command.js'
+import urlChecker from '../mixins/url-checker.js'
+import stringToColor from '../mixins/string-to-color.js'
+
 export default {
   name: 'rooms',
   pouch: {
@@ -19,11 +29,51 @@ export default {
         selector: { _id: 'user' },
         first: true
       }
-    }
+    },
+    online: {}
   },
-  data () {
-    return {
-      user: 'unreturnable'
+  mixins: [ mwCommand, urlChecker, stringToColor ],
+  created: function () {
+    var ctx = this
+    ctx.sendCmdCallback('who', ctx.syncWho)
+    setInterval(function () { ctx.sendCmdCallback('who', ctx.syncWho) }, 5000)
+  },
+  methods: {
+    syncWho: function (response) {
+      if (response.state !== 'WHOL') {
+        var ctx = this
+        var db = new PouchDB('online')
+
+        db.destroy()
+        .then(function (res) {
+          ctx.storeUsers(response.data)
+        }).catch(function (err) {
+          console.log(err)
+        })
+      }
+    },
+    storeUsers: function (users) {
+      var db = new PouchDB('online')
+
+      for (var i = 0; i < users.length; i++) {
+        users[i]._id = users[i].name.toLowerCase()
+        // users[i].photo = this.getHackergotchi(users[i].name)
+        db.put(users[i])
+        .then(function (result) {
+        }).catch(function () {
+          // This was likely caused by the same user logged in with two clients
+        })
+      }
+    },
+    getHackergotchi: function (username) {
+      var hackergotchi = 'https://sucs.org/pictures/people/' + username.toLowerCase() + '.png'
+      var profileImage = ''
+      if (this.urlExists(hackergotchi)) {
+        profileImage = '<img src="' + hackergotchi + '" width="36"/>'
+      } else {
+        profileImage = '<div style="width: 36px; height: 36px; font-size: 7pt; text-align:center;padding-top: 5px; background-color: ' + this.stringToColour(username) + '">Don\'t <br>Panic</div>'
+      }
+      return profileImage
     }
   }
 }
@@ -69,10 +119,13 @@ function handleGesure () {
   height: 100vh;
 }
 
+#online-header {
+  margin-right: 25px;
+}
+
 #online-list {
   text-align: right;
-  margin-top: 25px;
-  margin-right: 25px;
+  margin-top: 50px;
 }
 
 @media only screen and (max-width: 800px) {
@@ -81,4 +134,16 @@ function handleGesure () {
     right: -250px;
   }
 }
+
+.user {
+  font-size: 12pt;
+  padding-top: 5px;
+  padding-bottom: 5px;
+  padding-right: 25px;
+}
+
+.user:hover {
+    background: rgba(0, 0, 0, 0.5);
+    cursor: pointer;
+}
 </style>
diff --git a/src/components/rooms.vue b/src/components/rooms.vue
index b97357a..0ee5f58 100644
--- a/src/components/rooms.vue
+++ b/src/components/rooms.vue
@@ -1,6 +1,6 @@
 <template>
   <div class="bar-wrapper" v-if="config">
-    <div id="rooms" v-bind:style="{ 'background': config.roomsBg, 'color': config.roomsFg }">
+    <div id="rooms" class="scroll" v-bind:style="{ 'background': config.roomsBg, 'color': config.roomsFg }">
       <img src="../assets/logo.png" class="logo">
       <div id="rooms-list">
 	<h2>Rooms</h2>
diff --git a/src/components/talk.vue b/src/components/talk.vue
index b5156fc..265d0f2 100644
--- a/src/components/talk.vue
+++ b/src/components/talk.vue
@@ -1,13 +1,15 @@
 <template>
   <div id="talk" v-if="config">
     <textarea id="talk-bar" placeholder=""></textarea>
-    <button id="send" v-bind:style="{ 'background': config.buttonBg, 'color': config.buttonFg }">
+    <button id="send" v-on:click="onSubmit" v-bind:style="{ 'background': config.buttonBg, 'color': config.buttonFg }">
       Send
     </button>
   </div>
 </template>
 
 <script>
+import mwCommand from '../mixins/mw-command.js'
+
 export default {
   name: 'chat',
   pouch: {
@@ -19,10 +21,12 @@ export default {
       }
     }
   },
-  data () {
-    return {
-      bgColor: '#e65c00',
-      fgColor: '#f2f2f2'
+  mixins: [ mwCommand ],
+  methods: {
+    onSubmit: function () {
+      var text = document.getElementById('talk-bar').value
+      document.getElementById('talk-bar').value
+      this.sendSay(text)
     }
   }
 }
diff --git a/src/components/topbar.vue b/src/components/topbar.vue
index 187858f..adb1915 100644
--- a/src/components/topbar.vue
+++ b/src/components/topbar.vue
@@ -6,13 +6,15 @@
       Settings
     </button>
     <button id="logout" class="button" v-bind:style="{ 'background': config.buttonBg, 'color':
-    config.buttonFg }">
+    config.buttonFg }" v-on:click="logout">
       Logout
     </button>
   </div>
 </template>
 
 <script>
+import PouchDB from 'pouchdb-browser'
+
 export default {
   name: 'topbar',
   pouch: {
@@ -22,13 +24,32 @@ export default {
         selector: { _id: 'user' },
         first: true
       }
-    }
+    },
+    auth: {}
   },
   data () {
     return {
       bgColor: '#e65c00',
       fgColor: '#f2f2f2'
     }
+  },
+  methods: {
+    logout: function (event) {
+      var db = new PouchDB('auth')
+
+      db.get('user')
+      .then(function (result) {
+        console.log(result)
+        db.remove(result)
+        .then(function (result) {
+          location.reload()
+        }).catch(function (err) {
+          console.log(err)
+        })
+      }).catch(function () {
+        // Do nothing since we need to auth the user
+      })
+    }
   }
 }
 </script>
diff --git a/src/mixins/mw-command.js b/src/mixins/mw-command.js
new file mode 100644
index 0000000..af04a98
--- /dev/null
+++ b/src/mixins/mw-command.js
@@ -0,0 +1,56 @@
+import axios from 'axios'
+import PouchDB from 'pouchdb-browser'
+
+export default {
+  created: function () {
+  },
+  methods: {
+    sendCmdCallback: function (cmd, callback, err) {
+      var db = new PouchDB('auth')
+
+      db.get('user')
+      .then(function (result) {
+        axios.post('https://sucs.org/~unreturnable/webmw-test/send.php', { send: cmd, mwsess: result.token })
+        .then(function (response) {
+          callback(response)
+        }).catch(function (error) {
+          console.log(error)
+        })
+      }).catch(function (err) {
+        console.log(err)
+      })
+    },
+    sendCmd: function (cmd) {
+      var db = new PouchDB('auth')
+
+      db.get('user')
+      .then(function (result) {
+        axios.post('https://sucs.org/~unreturnable/webmw-test/send.php', { send: cmd, mwsess: result.token })
+        .then(function (response) {
+          // Do nothing because we didn't want
+        }).catch(function (error) {
+          console.log(error)
+        })
+      }).catch(function (err) {
+        console.log(err)
+      })
+    },
+    sendSay: function (text) {
+      var db = new PouchDB('auth')
+      var what = 'say ' + text
+
+      db.get('user')
+      .then(function (result) {
+        axios.post('https://sucs.org/~unreturnable/webmw-test/send.php', { send: what, mwsess: result.token })
+        .then(function (response) {
+        }).catch(function (error) {
+          console.log(error)
+        })
+      }).catch(function (err) {
+        console.log(err)
+      })
+
+      return false
+    }
+  }
+}
diff --git a/src/mixins/mw-sync.js b/src/mixins/mw-sync.js
new file mode 100644
index 0000000..6bb6c76
--- /dev/null
+++ b/src/mixins/mw-sync.js
@@ -0,0 +1,216 @@
+import PouchDB from 'pouchdb-browser'
+import axios from 'axios'
+import urlChecker from '../mixins/url-checker.js'
+
+var profileImages = {}
+
+export default {
+  created: function () {
+    var mixin = this
+    var db = new PouchDB('auth')
+
+    db.get('user')
+    .then(function (result) {
+      setInterval(function () { mixin.sync(result.token) }, 1000)
+    }).catch(function (err) {
+      console.log(err)
+    })
+  },
+  mixins: [ urlChecker ],
+  methods: {
+    sync: function (token) {
+      var mixin = this
+
+      axios.get('https://sucs.org/~unreturnable/webmw-test/poll.php', { params: { mwsess: token } })
+      .then(mixin.onMsg).catch(function (error) {
+        console.log(error)
+      })
+    },
+    filterString: function (str) {
+      var escapedStr = str.replace(/&/g, '&amp;')
+      escapedStr = escapedStr.replace(/</g, '&lt;')
+      escapedStr = escapedStr.replace(/>/g, '&gt;')
+      escapedStr = escapedStr.replace(/\n/g, '')
+      escapedStr = escapedStr.replace(/\r/g, '')
+
+      return escapedStr
+    },
+    filterColours: function (str) {
+      /* Replace colour codes with appropriate span tags */
+      var msgColours = str.match(/\u001b../g)
+      if (msgColours !== null) {
+        for (var i = 0; i < msgColours.length; i++) {
+          if (isNaN(msgColours[i].charAt(1))) {
+            var colourBold = ''
+            var fgColour = msgColours[i].charAt(1)
+            if (fgColour !== fgColour.toLowerCase()) {
+              colourBold = ' bold'
+            }
+            str = str.replace(msgColours[i], '</span><span class=\'colourfg' + msgColours[i].charAt(1) + colourBold + ' colourbg' + msgColours[i].charAt(2) + '\'>')
+          } else {
+            str = str.replace(msgColours[i], '</span><span class=\'colour' + msgColours[i].replace(/\u001b/g, '') + '\'>')
+          }
+        }
+      }
+      return str
+    },
+    pad: function (number, length) {
+      var str = '' + number
+      while (str.length < length) {
+        str = '0' + str
+      }
+      return str
+    },
+    getHackergotchi: function (username) {
+      if (typeof profileImages[username] === 'undefined') {
+        var hackergotchi = 'https://sucs.org/pictures/people/' + username.toLowerCase() + '.png'
+        if (this.urlExists(hackergotchi)) {
+          profileImages[username] = '<img src="' + hackergotchi + '" width="36" />'
+        } else {
+          profileImages[username] = '<div style="width: 36px; height: 36px; font-size: 7pt; text-align: center; padding-top: 5px; background-color: ' + this.stringToColour(username) + '">Don\'t <br>Panic</div>'
+        }
+      }
+
+      return profileImages[username]
+    },
+    onMsg: function (msg) {
+      console.log(msg)
+
+      var db = new PouchDB('talker')
+
+      if (msg.status !== 200) {
+        if (msg.status === 'Socket open error') {
+          console.log('Error connecting to socket')
+        } else {
+          console.log('Problem: ' + msg.status)
+        }
+      } else {
+        msg = msg.data
+
+        for (var one in msg) {
+          switch (msg[one].state) {
+            case 'SAYR':
+            case 'SAYU':
+              // decode the json message
+              var detail = JSON.parse(msg[one].text)
+
+              var body = detail.text
+              // make a crude approximation of the old message styles
+              switch (detail.type) {
+                case 'say':
+                  body = detail.text
+                  break
+                case 'raw':
+                  body = detail.text
+                  break
+                case 'emote':
+                  switch (detail.plural) {
+                    case 1:
+                      body = msg[one].name + '\'s ' + detail.text
+                      break
+                    case 2:
+                      body = msg[one].name + '\' ' + detail.text
+                      break
+                    case 3:
+                      body = msg[one].name + '\'d ' + detail.text
+                      break
+                    case 4:
+                      body = msg[one].name + '\'ll ' + detail.text
+                      break
+                    default:
+                      body = msg[one].name + ' ' + detail.text
+                      break
+                  }
+                  break
+                case 'notsayto':
+                  body = msg[one].name + ' says (-' + detail.exclude + '): ' + detail.text
+                  break
+                case 'says':
+                  body = msg[one].name + ' says: ' + detail.text
+                  break
+                case 'whispers':
+                  body = msg[one].name + ' whispers: ' + detail.text
+                  break
+                default:
+                  body = msg[one].name + ' ' + detail.text
+                  break
+              }
+
+              /* Escape HTML characters */
+              var escapedMsg = this.filterString(body)
+              escapedMsg = this.filterColours(escapedMsg)
+
+              var msgTime = new Date(msg[one].when * 1000)
+              var timestamp = this.pad(msgTime.getHours(), 2) + ':' + this.pad(msgTime.getMinutes(), 2)
+
+              var toStore = {
+                _id: msg[one].serial.toString(),
+                user: msg[one].name,
+                photo: this.getHackergotchi(msg[one].name),
+                timestamp: timestamp,
+                msg: escapedMsg
+              }
+
+              db.put(toStore)
+              .then(function (result) {
+              }).catch(function () {
+                // Messages currently can't get updated in MW
+              })
+              break
+
+            case 11: // Talker message
+            case 17: // Board Message
+              /* Escape HTML characters */
+              escapedMsg = this.filterString(msg[one].text)
+              escapedMsg = this.filterColours(escapedMsg)
+
+              msgTime = new Date(msg[one].when * 1000)
+              timestamp = this.pad(msgTime.getHours(), 2) + ':' + this.pad(msgTime.getMinutes(), 2)
+
+              toStore = {
+                id_: timestamp,
+                timestamp: timestamp,
+                msg: escapedMsg
+              }
+
+              db.put(toStore)
+              .then(function (result) {
+                console.log(result)
+              }).catch(function () {
+                // Messages currently can't get updated in MW
+              })
+              break
+
+            case 14: // IPC_KICK
+              var what = '<div class=\'msgkick user_system\'>'
+              if (msg[one].text.substr(0, 1) === 'm') {
+                what += 'Boing, Zebedee\'s arrived. "Look up!" says Zebedee<br />'
+                what += 'You look up; a large object is falling towards you very fast, very very fast. It looks like a Magic Roundabout!<br />'
+                what += '"I wouldn\'t stand there if I was you" says Zebedee<br />'
+                what += 'WWWHHHEEEEEEEKKKKEEEERRRRRUUUUUNNNNNCCCCCHHHHHH<br />'
+                what += msg[one].name + ' has just dropped the Magic Roundabout of Death on you.<br/>'
+              } else {
+                what += 'Boing, Zebedee arrived.<br />'
+                what += '"Time for bed" says Zebedee<br />'
+                what += msg[one].name + ' has just dropped the Zebedee of Death on you.<br />'
+              }
+              if (msg[one].text.substr(1, 1) === 'r') what += '"' + msg[one].text.substr(2) + '" says Zebedee<br />'
+              what += '</div>'
+
+              console.log(what)
+              break
+
+            case 23: // CheckOnOff
+              // Implement who check
+              break
+
+            default:
+              console.log('Unknown message type \'' + msg[one].state + '\'')
+              console.log(msg[one].text)
+              break
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/src/mixins/string-to-color.js b/src/mixins/string-to-color.js
new file mode 100644
index 0000000..68764cf
--- /dev/null
+++ b/src/mixins/string-to-color.js
@@ -0,0 +1,19 @@
+export default {
+  methods: {
+    stringToColour: function (str) {
+      var hash = 0
+
+      for (var i = 0; i < str.length; i++) {
+        hash = str.charCodeAt(i) + ((hash << 5) - hash)
+      }
+
+      var colour = '#'
+      for (i = 0; i < 3; i++) {
+        var value = (hash >> (i * 8)) & 0xFF
+        colour += ('00' + value.toString(16)).substr(-2)
+      }
+
+      return colour
+    }
+  }
+}
diff --git a/src/mixins/url-checker.js b/src/mixins/url-checker.js
new file mode 100644
index 0000000..d13520c
--- /dev/null
+++ b/src/mixins/url-checker.js
@@ -0,0 +1,10 @@
+export default {
+  methods: {
+    urlExists: function (url) {
+      var http = new XMLHttpRequest()
+      http.open('HEAD', url, false)
+      http.send()
+      return http.status !== 404
+    }
+  }
+}
diff --git a/src/pages/chat.vue b/src/pages/chat.vue
index 6bc87aa..f0f9ace 100644
--- a/src/pages/chat.vue
+++ b/src/pages/chat.vue
@@ -1,12 +1,15 @@
 <template>
-  <div id="container">
-    <rooms></rooms>
-    <div id="center-container">
-      <topbar></topbar>
-      <chat></chat>
-      <talk></talk>
+  <div>
+    <div id="container">
+      <rooms></rooms>
+      <div id="center-container">
+	<topbar></topbar>
+	<chat></chat>
+	<talk></talk>
+      </div>
+      <online></online>
     </div>
-    <online></online>
+    <login></login>
   </div>
 </template>
 
@@ -16,6 +19,10 @@ import topbar from '../components/topbar.vue'
 import chat from '../components/chat.vue'
 import talk from '../components/talk.vue'
 import online from '../components/online.vue'
+import login from '../components/login.vue'
+
+import mwSync from '../mixins/mw-sync.js'
+import mwCommand from '../mixins/mw-command.js'
 
 export default {
   components: {
@@ -23,7 +30,12 @@ export default {
     'topbar': topbar,
     'chat': chat,
     'talk': talk,
-    'online': online
+    'online': online,
+    'login': login
+  },
+  mixins: [ mwSync, mwCommand ],
+  created: function () {
+    this.sendCmd('replay count 999')
   }
 }
 </script>
diff --git a/src/pages/login.vue b/src/pages/login.vue
deleted file mode 100644
index abf65f7..0000000
--- a/src/pages/login.vue
+++ /dev/null
@@ -1,20 +0,0 @@
-<template>
-  <div class="login">
-    <h1>{{ msg }}</h1>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'login',
-  data () {
-    return {
-      msg: 'Login'
-    }
-  }
-}
-</script>
-
-<!-- Add "scoped" attribute to limit CSS to this component only -->
-<style scoped>
-</style>
diff --git a/src/router/index.js b/src/router/index.js
index 9a9b198..f92cfae 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -1,7 +1,6 @@
 import Vue from 'vue'
 import Router from 'vue-router'
 import chat from '@/pages/chat'
-import login from '@/pages/login'
 
 Vue.use(Router)
 
@@ -11,11 +10,6 @@ export default new Router({
       path: '/',
       name: 'Chat',
       component: chat
-    },
-    {
-      path: '/login',
-      name: 'Login',
-      component: login
     }
   ]
 })
-- 
GitLab