Quellcode durchsuchen

[refactor] multichat manager into client

B Thibault vor 8 Jahren
Ursprung
Commit
4c52b08f85
14 geänderte Dateien mit 432 neuen und 296 gelöschten Zeilen
  1. 17 16
      Makefile
  2. 24 15
      cli/contextBackground.js
  3. 59 18
      cli/data.js
  4. 3 3
      cli/dom.js
  5. 8 6
      cli/emojiBar.js
  6. 76 70
      cli/ui.js
  7. 26 8
      cli/uiMessage.js
  8. 17 9
      cli/workflow.js
  9. 92 89
      srv/public/slack.min.js
  10. 3 3
      srv/src/context.js
  11. 8 8
      srv/src/httpServ.js
  12. 88 34
      srv/src/multichatManager.js
  13. 10 17
      srv/src/slack.js
  14. 1 0
      srv/src/slackData.js

+ 17 - 16
Makefile

@@ -1,24 +1,25 @@
 
-SRC=		srv/src/context.js		\
-			srv/src/room.js			\
-			srv/src/message.js		\
-			srv/src/chatter.js		\
+SRC=		srv/src/context.js			\
+			srv/src/room.js				\
+			srv/src/message.js			\
+			srv/src/chatter.js			\
+			srv/src/multichatManager.js	\
 			\
-			cli/lang/core.js		\
-			cli/lang/fr.js			\
-			cli/lang/en.js			\
+			cli/lang/core.js			\
+			cli/lang/fr.js				\
+			cli/lang/en.js				\
 			\
 			cli/msgFormatter/msgFormatter.js	\
 			\
-			cli/confirmDialog.js	\
-			cli/resources.js		\
-			cli/ui.js				\
-			cli/dom.js				\
-			cli/emojiBar.js			\
-			cli/data.js				\
-			cli/contextBackground.js\
-			cli/workflow.js			\
-			cli/uiMessage.js		\
+			cli/confirmDialog.js		\
+			cli/resources.js			\
+			cli/ui.js					\
+			cli/dom.js					\
+			cli/emojiBar.js				\
+			cli/data.js					\
+			cli/contextBackground.js	\
+			cli/workflow.js				\
+			cli/uiMessage.js			\
 			cli/utils.js
 
 OUTPUT=		srv/public/slack.min.js

+ 24 - 15
cli/contextBackground.js

@@ -1,3 +1,4 @@
+/** @type {function(string, Object<string, Chatter>, Function)} */
 var createContextBackground = (function() {
     var canvas = document.createElement("canvas")
         ,ctx = canvas.getContext('2d')
@@ -17,7 +18,8 @@ var createContextBackground = (function() {
         ,ITEM_INNER_SIZE = Math.floor(ITEM_SIZE -(ITEM_SPACING*2))
         /** @const */
         ,AVATAR_SIZE = ITEM_INNER_SIZE * 0.5
-        ,RESULT;
+        /** @type {Object<string, string>} */
+        ,RESULT = {};
 
     var drawItem = function(background, avatar, x0, y0) {
         var y0Index = Math.floor(y0)
@@ -166,31 +168,38 @@ var createContextBackground = (function() {
             }
     }
 
-    var callbacks = [],
-        isLoading = false;
-    return function(cb) {
-        if (RESULT) {
+    var callbacks = {},
+        isLoading = {};
+
+    return function(ctxId, users, cb) {
+        if (RESULT[ctxId]) {
             cb(RESULT);
-        } else if (isLoading) {
-            callbacks.push(cb);
+        } else if (isLoading[ctxId]) {
+            if (!callbacks[ctxId])
+                callbacks[ctxId] = [ cb ];
+            else
+                callbacks[ctxId].push(cb);
         } else {
             var background = drawBackground()
                 ,userImgs = [];
 
-            isLoading = true;
-            callbacks.push(cb);
-            for (var userId in DATA.context.users) {
-                if (!DATA.context.users[userId].deleted && !DATA.context.users[userId].isBot)
+            isLoading[ctxId] = true;
+            if (!callbacks[ctxId])
+                callbacks[ctxId] = [ cb ];
+            else
+                callbacks[ctxId].push(cb);
+            for (var userId in users) {
+                if (!users[userId].deleted && !users[userId].isBot)
                     userImgs.push({
-                        src: DATA.context.users[userId].getSmallIcon()
+                        src: users[userId].getSmallIcon()
                     });
             }
 
             loadImages(userImgs, function(imgs) {
                 renderAvatars(background, imgs);
-                RESULT = canvas.toDataURL();
-                callbacks.forEach(function(i) {
-                    i(RESULT);
+                RESULT[ctxId] = canvas.toDataURL();
+                callbacks[ctxId].forEach(function(i) {
+                    i();
                 });
             });
         }

+ 59 - 18
cli/data.js

@@ -9,9 +9,39 @@ var
      * @type {Array.<Room>}
     **/
     ,HIGHLIGHTED_CHANS = [];
-
 ;
 
+/**
+ * @constructor
+ * @implements {ChatSystem}
+ * @extends {ChatContext}
+**/
+function SimpleChatSystem() {
+    ChatContext.call(this);
+};
+SimpleChatSystem.prototype = Object.create(ChatContext.prototype);
+SimpleChatSystem.prototype.constructor = SimpleChatSystem;
+
+SimpleChatSystem.prototype.getId = function() {
+    return this.team ? this.team.id : null;
+};
+SimpleChatSystem.prototype.getChatContext = function() {
+    return this;
+};
+SimpleChatSystem.prototype.onRequest = function() { console.error("unimplemented"); };
+SimpleChatSystem.prototype.sendMeMsg = function(chan, text) { console.error("unimplemented"); };
+SimpleChatSystem.prototype.sendMsg = function(chan, text, attachments) { console.error("unimplemented"); };
+SimpleChatSystem.prototype.removeMsg = function(chan, ts) { console.error("unimplemented"); };
+SimpleChatSystem.prototype.editMsg = function(chan, ts, newText) { console.error("unimplemented"); };
+SimpleChatSystem.prototype.addReaction = function(chan, ts, reaction) { console.error("unimplemented"); };
+SimpleChatSystem.prototype.removeReaction = function(chan, ts, reaction) { console.error("unimplemented"); };
+SimpleChatSystem.prototype.openUploadFileStream = function(chan, contentType, callback) { console.error("unimplemented"); };
+SimpleChatSystem.prototype.fetchHistory = function(chan) { console.error("unimplemented"); };
+SimpleChatSystem.prototype.sendTyping = function(chan) { console.error("unimplemented"); };
+SimpleChatSystem.prototype.markRead = function(chan, ts) { console.error("unimplemented"); };
+SimpleChatSystem.prototype.sendCommand = function(chan, cmd, args) { console.error("unimplemented"); };
+SimpleChatSystem.prototype.poll = function(knownVersion) { console.error("unimplemented"); return null; };
+
 /**
  * @constructor
 **/
@@ -19,8 +49,8 @@ function SlackWrapper() {
     /** @type {number} */
     this.lastServerVersion = 0;
 
-    /** @type {ChatContext} */
-    this.context = new ChatContext();
+    /** @type {MultiChatManager} */
+    this.context = new MultiChatManager();
 
     /** @type {!Object.<string, UiRoomHistory>} **/
     this.history = {};
@@ -31,16 +61,20 @@ SlackWrapper.prototype.update = function(data) {
     if (data["v"])
         this.lastServerVersion = data["v"];
     if (data["static"]) {
-        this.context.updateStatic(data["static"], Date.now());
+        for (var i in data["static"]) {
+            var ctx = this.context[i];
+            if (!ctx)
+                ctx = this.context[i] = new SimpleChatSystem();
+            ctx.updateStatic(data["static"], now);
+        }
     }
-    for (var chanId in this.context.channels) {
-        var i = this.context.channels[chanId];
-        if (i.lastMsg === i.lastRead) {
-            var pos = HIGHLIGHTED_CHANS.indexOf(i);
+    this.context.foreachChannels(function(chan) {
+        if (chan.lastMsg === chan.lastRead) {
+            var pos = HIGHLIGHTED_CHANS.indexOf(chan);
             if (pos !== -1)
                 HIGHLIGHTED_CHANS.splice(pos, 1);
         }
-    }
+    });
     if (data["live"]) {
         for (var i in data["live"]) {
             var history = this.history[i];
@@ -50,12 +84,14 @@ SlackWrapper.prototype.update = function(data) {
                 history.pushAll(data["live"][i], now);
         }
         for (var roomId in data["live"]) {
-            var chan = this.context.channels[roomId];
+            var ctx = this.context.getChannelContext(roomId).getChatContext(),
+                chan = ctx.channels[roomId];
+
             if (chan) {
                 if (this.history[roomId].messages.length)
                     chan.lastMsg = Math.max(chan.lastMsg, this.history[roomId].lastMessage().ts);
                 if (!chan.archived) {
-                    onMsgReceived(chan, data["live"][roomId]);
+                    onMsgReceived(ctx, chan, data["live"][roomId]);
                     if (SELECTED_ROOM && data["live"][SELECTED_ROOM.id])
                         onRoomUpdated();
                 }
@@ -66,8 +102,11 @@ SlackWrapper.prototype.update = function(data) {
     }
     if (data["static"]) {
         onContextUpdated();
-        if (data["static"]["typing"])
-            onTypingUpdated();
+        for (var i in data["static"])
+            if (data["static"][i]["typing"]) {
+                onTypingUpdated();
+                break;
+            }
     }
 };
 
@@ -77,11 +116,12 @@ setInterval(function() {
 }, 1000);
 
 /**
+ * @param {ChatContext} ctx
  * @param {string} text
  * @return {boolean}
 **/
-function isHighlighted(text) {
-    var highlights = DATA.context.self.prefs.highlights;
+function isHighlighted(ctx, text) {
+    var highlights = ctx.self.prefs.highlights;
     for (var i =0, nbHighlights = highlights.length; i < nbHighlights; i++)
         if (text.indexOf(highlights[i]) !== -1) {
             return true;
@@ -90,12 +130,13 @@ function isHighlighted(text) {
 }
 
 /**
+ * @param {ChatContext} ctx
  * @param {Room} chan
  * @param {Array.<*>} msg
 **/
-function onMsgReceived(chan, msg) {
+function onMsgReceived(ctx, chan, msg) {
     if (chan !== SELECTED_ROOM || !window.hasFocus) {
-        var selfReg = new RegExp("<@" +DATA.context.self.id) // FIXME remove context id
+        var selfReg = new RegExp("<@" +ctx.self.id) // FIXME remove context id
             ,highligted = false
             ,areNew = false
             ,newHighlited = false;
@@ -105,7 +146,7 @@ function onMsgReceived(chan, msg) {
                 return;
             }
             areNew = true;
-            if (chan instanceof PrivateMessageRoom || (i["text"] && (i["text"].match(selfReg) || isHighlighted(i["text"])))) {
+            if (chan instanceof PrivateMessageRoom || (i["text"] && (i["text"].match(selfReg) || isHighlighted(ctx, i["text"])))) {
                 if (HIGHLIGHTED_CHANS.indexOf(chan) === -1) {
                     newHighlited = true;
                     HIGHLIGHTED_CHANS.push(chan);

+ 3 - 3
cli/dom.js

@@ -109,7 +109,7 @@ function createReactionDom(chanId, msgId, reaction, users) {
             ,userNames = [];
 
         for (var i =0, nbUser = users.length; i < nbUser; i++) {
-            var user = DATA.context.users[users[i]];
+            var user = DATA.context.getUser(users[i]);
             if (user)
                 userNames.push(user.name);
         }
@@ -180,7 +180,7 @@ function doCreateMessageDom(msg, skipAttachment) {
         }
         hover.appendChild(hoverReaction);
 
-        if (msg.userId === DATA.context.self.id) {
+        if (DATA.context.isMe(msg.userId)) {
             var hoverEdit = document.createElement("li");
             hoverEdit.className = R.klass.msg.hover.edit;
             if (domEdit)
@@ -202,7 +202,7 @@ function doCreateMessageDom(msg, skipAttachment) {
 
     } else {
         hoverReply.style.backgroundImage = 'url("repl.svg")';
-        if (msg.userId === DATA.context.self.id) {
+        if (DATA.context.isMe(msg.userId)) {
             var hoverEdit = document.createElement("li");
             hoverEdit.className = R.klass.msg.hover.edit;
             hoverEdit.style.backgroundImage = 'url("edit.svg")';

+ 8 - 6
cli/emojiBar.js

@@ -12,6 +12,7 @@ var EMOJI_BAR = (function() {
         ,emojiDetailName = document.createElement("span")
         /** @type {function((string|null))|undefined} */
         ,emojiSelectedHandler
+        ,context
 
     /** @type {function():boolean} */
     ,isSupported = function() {
@@ -96,7 +97,7 @@ var EMOJI_BAR = (function() {
             /** @type {Object.<string, *>} */
             var foundEmojis = window['searchEmojis'](queryString);
 
-            sortedEmojiNames = sortEmojis(foundEmojis, DATA.context.self.prefs.favoriteEmojis);
+            sortedEmojiNames = sortEmojis(foundEmojis, context.self.prefs.favoriteEmojis);
             for (var i in emojiCache.unicode) {
                 if (emojiCache.unicode[i].visible) {
                     // We remove every item to reorder them (add them in order)
@@ -124,13 +125,13 @@ var EMOJI_BAR = (function() {
                 customEmojis.removeChild(emojiCache.custom[i].dom);
             }
         }
-        sortedEmojiNames = sortEmojis(DATA.context.emojis.data, DATA.context.self.prefs.favoriteEmojis);
+        sortedEmojiNames = sortEmojis(context.emojis.data, context.self.prefs.favoriteEmojis);
         for (var i =0, nbEmojis = sortedEmojiNames.length; i < nbEmojis; i++) {
             var emojiName = sortedEmojiNames[i].name;
-            if ((queryString === '' || emojiName.substr(0, queryString.length) === queryString) && DATA.context.emojis.data[emojiName].substr(0, 6) !== 'alias:') {
+            if ((queryString === '' || emojiName.substr(0, queryString.length) === queryString) && context.emojis.data[emojiName].substr(0, 6) !== 'alias:') {
                 var e = emojiCache.custom[emojiName];
                 if (!e)
-                    e = emojiCache.custom[emojiName] = makeCustomEmoji(emojiName, DATA.context.emojis.data[emojiName]);
+                    e = emojiCache.custom[emojiName] = makeCustomEmoji(emojiName, context.emojis.data[emojiName]);
                 if (!e.visible) {
                     e.visible = true;
                     customEmojis.appendChild(e.dom);
@@ -141,9 +142,10 @@ var EMOJI_BAR = (function() {
         return emojiCount;
     }
 
-    /** @type function(Element, function((string|null))=):boolean */
-    ,spawn = function(domParent, handler) {
+    /** @type function(Element, ChatContext, function((string|null))=):boolean */
+    ,spawn = function(domParent, ctx, handler) {
         if (isSupported()) {
+            context = ctx;
             emojiSelectedHandler = handler;
             domParent.appendChild(overlay);
             domParent.appendChild(dom);

+ 76 - 70
cli/ui.js

@@ -22,7 +22,9 @@ var
 
 function onContextUpdated() {
     var chanListFram = document.createDocumentFragment()
-        ,sortedChans = Object.keys(DATA.context.channels || {})
+        ,sortedChans = DATA.context.getChannelIds(function(chan) {
+            return !chan.archived && chan.isMember !== false;
+        })
         ,starred = []
         ,channels = []
         ,privs = []
@@ -32,32 +34,30 @@ function onContextUpdated() {
         if (a[0] !== b[0]) {
             return a[0] - b[0];
         }
-        return DATA.context.channels[a].name.localeCompare(DATA.context.channels[b].name);
+        return DATA.context.getChannel(a).name.localeCompare(DATA.context.getChannel(b).name);
     });
     sortedChans.forEach(function(chanId) {
-        var chan = DATA.context.channels[chanId];
-        if (!chan.archived && chan.isMember !== false) {
-            if (chan instanceof PrivateMessageRoom) {
-                if (!chan.user.deleted) {
-                    var chanListItem = createImsListItem(chan);
-                    if (chanListItem) {
-                        if (chan.starred)
-                            starred.push(chanListItem);
-                        else
-                            priv.push(chanListItem);
-                    }
-                }
-            } else {
-                var chanListItem = createChanListItem(chan);
+        var chan = DATA.context.getChannel(chanId);
+        if (chan instanceof PrivateMessageRoom) {
+            if (!chan.user.deleted) {
+                var chanListItem = createImsListItem(chan);
                 if (chanListItem) {
                     if (chan.starred)
                         starred.push(chanListItem);
-                    else if (chan.isPrivate)
-                        privs.push(chanListItem);
                     else
-                        channels.push(chanListItem);
+                        priv.push(chanListItem);
                 }
             }
+        } else {
+            var chanListItem = createChanListItem(chan);
+            if (chanListItem) {
+                if (chan.starred)
+                    starred.push(chanListItem);
+                else if (chan.isPrivate)
+                    privs.push(chanListItem);
+                else
+                    channels.push(chanListItem);
+            }
         }
     });
     if (starred.length)
@@ -82,45 +82,50 @@ function onContextUpdated() {
     document.getElementById(R.id.chanList).appendChild(chanListFram);
     setRoomFromHashBang();
     updateTitle();
-    createContextBackground(function(imgData) {
-        document.getElementById(R.id.context).style.backgroundImage = 'url(' +imgData +')';
-    });
+    if (SELECTED_CONTEXT) {
+        createContextBackground(SELECTED_CONTEXT.getChatContext().team.id, SELECTED_CONTEXT.getChatContext().users, function(imgData) {
+            document.getElementById(R.id.context).style.backgroundImage = 'url(' +imgData +')';
+        });
+    }
 }
 
 function onTypingUpdated() {
-    var typing = DATA.context.typing;
-    for (var chanId in DATA.context.self.channels) {
-        if (!DATA.context.self.channels[chanId].archived) {
-            var dom = document.getElementById("room_" +chanId);
-            if (typing[chanId])
-                dom.classList.add(R.klass.chatList.typing);
-            else
-                dom.classList.remove(R.klass.chatList.typing);
-        }
-    }
-    for (var userId in DATA.context.users) {
-        var ims = DATA.context.users[userId].privateRoom;
-        if (ims && !ims.archived) {
-            var dom = document.getElementById("room_" +ims.id);
-            if (dom) {
-                if (typing[ims.id])
+    DATA.context.foreachContext(function(ctx) {
+        var typing = ctx.typing;
+        for (var chanId in ctx.self.channels) {
+            if (!ctx.self.channels[chanId].archived) {
+                var dom = document.getElementById("room_" +chanId);
+                if (typing[chanId])
                     dom.classList.add(R.klass.chatList.typing);
                 else
                     dom.classList.remove(R.klass.chatList.typing);
             }
         }
-    }
+        for (var userId in ctx.users) {
+            var ims = ctx.users[userId].privateRoom;
+            if (ims && !ims.archived) {
+                var dom = document.getElementById("room_" +ims.id);
+                if (dom) {
+                    if (typing[ims.id])
+                        dom.classList.add(R.klass.chatList.typing);
+                    else
+                        dom.classList.remove(R.klass.chatList.typing);
+                }
+            }
+        }
+    });
     updateTypingChat();
 }
 
 function updateTypingChat() {
-    var typing = DATA.context.typing;
+    var typing;
+
     document.getElementById(R.id.typing).textContent = "";
-    if (SELECTED_ROOM && typing[SELECTED_ROOM.id]) {
+    if (SELECTED_CONTEXT && SELECTED_ROOM && (typing = SELECTED_CONTEXT.getChatContext().typing[SELECTED_ROOM.id])) {
         var areTyping = document.createDocumentFragment()
             ,isOutOfSync = false;
         for (var i in typing[SELECTED_ROOM.id]) {
-            var member = DATA.context.users[i];
+            var member = DATA.context.getUser(i);
             if (member)
                 areTyping.appendChild(makeUserIsTypingDom(member));
             else
@@ -216,12 +221,11 @@ function onEditingUpdated() {
  * @param {string} reaction
 **/
 window['toggleReaction'] = function(chanId, msgId, reaction) {
-    var hist = DATA.history[chanId];
-    if (!hist)
-        return;
-    var msg = hist.getMessageById(msgId);
-    if (msg) {
-        if (msg.hasReactionForUser(reaction, DATA.context.self.id)) {
+    var hist = DATA.history[chanId]
+        ,msg
+        ,ctx;
+    if ((hist = DATA.history[chanId]) && (msg = hist.getMessageById(msgId)) && (ctx = DATA.context.getChannelContext(chanId))) {
+        if (msg.hasReactionForUser(reaction, ctx.getChatContext().self.id)) {
             removeReaction(chanId, msgId, reaction);
         } else {
             addReaction(chanId, msgId, reaction);
@@ -237,20 +241,24 @@ window['toggleReaction'] = function(chanId, msgId, reaction) {
 function tryGetCustomEmoji(emoji) {
     var loop = {};
 
-    while (!loop[emoji]) {
-        var emojisrc= DATA.context.emojis.data[emoji];
-        if (emojisrc) {
-            if (emojisrc.substr(0, 6) == "alias:") {
-                loop[emoji] = true;
-                emoji = emojisrc.substr(6);
-            } else {
-                var dom = document.createElement("span");
-                dom.className = R.klass.emoji.custom +' ' +R.klass.emoji.emoji;
-                dom.style.backgroundImage = "url('" +emojisrc +"')";
-                return dom;
+    if (SELECTED_CONTEXT) {
+        var ctx = SELECTED_CONTEXT.getChatContext();
+
+        while (!loop[emoji]) {
+            var emojisrc= ctx.emojis.data[emoji];
+            if (emojisrc) {
+                if (emojisrc.substr(0, 6) == "alias:") {
+                    loop[emoji] = true;
+                    emoji = emojisrc.substr(6);
+                } else {
+                    var dom = document.createElement("span");
+                    dom.className = R.klass.emoji.custom +' ' +R.klass.emoji.emoji;
+                    dom.style.backgroundImage = "url('" +emojisrc +"')";
+                    return dom;
+                }
             }
+            return emoji; // Emoji not found, fallback to std emoji
         }
-        return emoji; // Emoji not found, fallback to std emoji
     }
     return emoji; //loop detected, return first emoji
 }
@@ -291,11 +299,10 @@ function updateTitle() {
         setFavicon(hasHl, hasHl);
     } else {
         var hasUnread = 0;
-        for (var chanId in DATA.context.channels) {
-            var i = DATA.context.channels[chanId];
+        DATA.context.foreachChannels(function(i) {
             if (i.lastMsg > i.lastRead)
                 hasUnread++;
-        }
+        });
         if (hasUnread)
             title = "(" +hasUnread +") - ";
         setFavicon(0, hasUnread);
@@ -359,7 +366,7 @@ function onRoomUpdated() {
                     currentMsgGroupDom = null;
                 } else {
                     if (newGroupDom || !currentMsgGroupDom) {
-                        currentMsgGroupDom = createMessageGroupDom(DATA.context.users[msg.userId], msg.username);
+                        currentMsgGroupDom = createMessageGroupDom(DATA.context.getUser(msg.userId), msg.username);
                         MSG_GROUPS.push(currentMsgGroupDom);
                         chatFrag.appendChild(currentMsgGroupDom);
                     }
@@ -480,12 +487,12 @@ function focusInput() {
 
 function setRoomFromHashBang() {
     var hashId = document.location.hash.substr(1)
-        ,room = DATA.context.channels[hashId];
+        ,room = DATA.context.getChannel(hashId);
 
     if (room && room !== SELECTED_ROOM)
         selectRoom(room);
     else {
-        var user = DATA.context.users[hashId];
+        var user = DATA.context.getUser(hashId);
         if (user && user.ims)
             selectRoom(user.ims);
     }
@@ -584,7 +591,7 @@ document.addEventListener('DOMContentLoaded', function() {
     document.getElementById(R.id.message.input).addEventListener('input', function() {
         if (SELECTED_ROOM) {
             var now = Date.now();
-            if (lastKeyDown + 3000 < now && (DATA.context.self.presence || (SELECTED_ROOM instanceof PrivateMessageRoom))) {
+            if (lastKeyDown + 3000 < now && (SELECTED_CONTEXT.getChatContext().self.presence || (SELECTED_ROOM instanceof PrivateMessageRoom))) {
                 sendTyping(SELECTED_ROOM);
                 lastKeyDown = now;
             }
@@ -596,12 +603,11 @@ document.addEventListener('DOMContentLoaded', function() {
                 endCmd = endCmd === -1 ? input.length : endCmd;
                 var inputCmd = input.substr(0, endCmd);
 
-                for (var i in DATA.context.commands.data) {
-                    var currentCmd = DATA.context.commands.data[i]
+                (SELECTED_CONTEXT ? SELECTED_CONTEXT.getChatContext().commands.data : []).forEach(function(currentCmd) {
                     if ((!inputFinished && currentCmd.name.substr(0, endCmd) === inputCmd) ||
                         (inputFinished && currentCmd.name === inputCmd))
                         commands.push(currentCmd);
-                }
+                });
             }
             commands.sort(function(a, b) {
                 return a.category.localeCompare(b.category) || a.name.localeCompare(b.name);

+ 26 - 8
cli/uiMessage.js

@@ -74,7 +74,7 @@ var AbstractUiMessage = (function() {
         var sep = str.indexOf('|')
             ,link
             ,text
-            ,isInternal;
+            ,isInternal = false;
 
         if (sep === -1) {
             link = str;
@@ -83,18 +83,27 @@ var AbstractUiMessage = (function() {
             text = str.substr(sep +1);
         }
         if (link[0] === '@') {
-            isInternal = true;
             //FIXME pointer back from message to team to prepend team id to remote userId
-            var user = DATA.context.users[link.substr(1)];
+            var newLink = msgContext.context.getId() +'|' +link.substr(1)
+                ,user = DATA.context.getUser(newLink);
+
             if (user) {
+                isInternal = true;
+                link = newLink;
                 text = '@' +user.name;
+            } else {
+                return null;
             }
         } else if (link[0] === '#') {
-            isInternal = true;
-            //FIXME pointer back from message to team to prepend team id to remote userId
-            var chan = DATA.context.channels[link.substr(1)];
+            var newLink = msgContext.context.getId() +'|' +link.substr(1)
+                ,chan = DATA.context.getChannel(newLink);
+
             if (chan) {
+                isInternal = true;
+                link = newLink;
                 text = '#' +chan.name;
+            } else {
+                return null;
             }
         } else {
             isInternal = false;
@@ -109,7 +118,7 @@ var AbstractUiMessage = (function() {
 
     _formatText = function(_this, text) {
         return formatText(text, {
-            highlights: DATA.context.self.prefs.highlights,
+            highlights: _this.context.self.prefs.highlights,
             emojiFormatFunction: function(emoji) {
                 if (emoji[0] === ':' && emoji[emoji.length -1] === ':')
                     emoji = emoji.substr(1, emoji.length -2);
@@ -186,7 +195,7 @@ var AbstractUiMessage = (function() {
 
         /** @param {UiMessage|UiMeMessage|UiNoticeMessage} _this */
         updateDom: function(_this) {
-            var sender = DATA.context.users[_this.userId];
+            var sender = DATA.context.getUser(_this.userId);
 
             updateCommon(_this, sender);
             updateAttachments(_this, _this.channelId);
@@ -217,6 +226,9 @@ function UiMeMessage(channelId, ev, ts) {
     // Extends AbstractUiMessage and MeMessage
     MeMessage.call(this, ev, ts);
 
+    /** @const @type {ChatContext} */
+    this.context = DATA.context.getChannelContext(channelId).getChatContext();
+
     /** @type {string} @const */
     this.channelId = channelId;
     this.dom = AbstractUiMessage.dom;
@@ -272,6 +284,9 @@ function UiMessage(channelId, ev, ts) {
     // Extends AbstractUiMessage and Message
     Message.call(this, ev, ts);
 
+    /** @const @type {ChatContext} */
+    this.context = DATA.context.getChannelContext(channelId).getChatContext();
+
     /** @type {string} @const */
     this.channelId = channelId;
     /** @type {Element} */
@@ -328,6 +343,9 @@ function UiNoticeMessage(channelId, ev, ts) {
     // Extends AbstractUiMessage and NoticeMessage
     NoticeMessage.call(this, ev, ts);
 
+    /** @const @type {ChatContext} */
+    this.context = DATA.context.getChannelContext(channelId).getChatContext();
+
     /** @type {string} @const */
     this.channelId = channelId;
 

+ 17 - 9
cli/workflow.js

@@ -6,10 +6,15 @@ var
     NEXT_RETRY = 0
 
     /**
-     * @type {Room}
+     * @type {Room|null}
     **/
     ,SELECTED_ROOM = null
 
+    /**
+     * @type {SimpleChatSystem|null}
+    **/
+    ,SELECTED_CONTEXT = null
+
     /** @type {Message|null} */
     ,REPLYING_TO = null
 
@@ -112,7 +117,11 @@ function selectRoom(room) {
     document.getElementById("room_" +room.id).classList.add(R.klass.selected);
     document.body.classList.remove(R.klass.noRoomSelected);
     SELECTED_ROOM = room;
+    SELECTED_CONTEXT = /** @type {SimpleChatSystem} */ (DATA.context.getChannelContext(room.id));
     onRoomSelected();
+    createContextBackground(SELECTED_CONTEXT.getChatContext().team.id, SELECTED_CONTEXT.getChatContext().users, function(imgData) {
+        document.getElementById(R.id.context).style.backgroundImage = 'url(' +imgData +')';
+    });
     if (SELECTED_ROOM.lastMsg && !DATA.history[SELECTED_ROOM.id])
         fetchHistory(SELECTED_ROOM, function(success) {});
 }
@@ -206,15 +215,13 @@ function sendMsg(chan, msg, replyTo) {
     var xhr = new XMLHttpRequest();
     var url = 'api/msg?room=' +chan.id +"&text=" +encodeURIComponent(msg);
     if (replyTo) {
-        var sender = DATA.context.users[replyTo.userId]
+        var sender = DATA.context.getUser(replyTo.userId)
             ,footer = "Message";
 
-        if (chan.id[0] === 'C') {
-            footer = "Channel message";
-        } else if (chan.id[0] === 'D') {
-            footer = "Direct message";
-        } else if (chan.id[0] === 'G') {
-            footer = "Group message";
+        if (chan.isPrivate) {
+            footer = "Private message";
+        } else {
+            footer = chan.name;
         }
         var attachment = {
             "fallback": replyTo.text
@@ -244,7 +251,8 @@ function onTextEntered(input, skipCommand) {
         var endCmd = input.indexOf(' ')
             ,cmd = input.substr(0, endCmd === -1 ? undefined : endCmd)
             ,args = endCmd === -1 ? "" : input.substr(endCmd)
-            ,cmdObject = DATA.context.commands.data[cmd];
+            ,ctx = SELECTED_CONTEXT
+            ,cmdObject = ctx ? ctx.getChatContext().commands.data[cmd] : null;
 
         if (cmdObject) {
             doCommand(SELECTED_ROOM, cmdObject, args.trim());

+ 92 - 89
srv/public/slack.min.js

@@ -1,91 +1,94 @@
 "use strict";(function(){
-var n;function q(a){this.id=a;this.version=0}q.prototype.update=function(a,b){void 0!==a.name&&(this.name=a.name);this.version=Math.max(this.version,b)};function aa(a){this.a=a.desc;this.name=a.name;this.type=a.type;this.usage=a.usage;this.P=a.category}function ba(){this.a={};this.A=[]}
-ba.prototype.update=function(a,b){this.a=JSON.parse(a.emoji_use);a.highlight_words?this.A=(a.highlight_words||"").split(",").filter(function(a){return""!==a.trim()}):a.highlights&&(this.A=a.highlights);this.version=Math.max(this.version,b)};function ca(){this.s=null;this.l={};this.a={};this.b=null;this.m={version:0,data:{}};this.j={version:0,data:{}};this.f={};this.C=0}"undefined"!==typeof module&&(module.J.Ha=ca,module.J.Ia=q,module.J.Ka=aa);function t(a){this.id=a;this.G=!1;this.a=this.b=0;this.j={};this.version=0}
-t.prototype.update=function(a,b,c,d){d=d||"";void 0!==a.name&&(this.name=a.name);void 0!==a.is_archived&&(this.m=a.is_archived);void 0!==a.is_member&&(this.C=a.is_member);void 0!==a.last_read&&(this.b=Math.max(parseFloat(a.last_read),this.b));void 0!==a.last_msg&&(this.a=parseFloat(a.last_msg));void 0!==a.is_private&&(this.s=a.is_private);a.latest&&(this.a=parseFloat(a.latest.ts));void 0!==a.is_starred&&(this.G=a.is_starred);if(a.members&&(this.j={},a.members))for(var e=0,g=a.members.length;e<g;e++){var f=
-b.a[d+a.members[e]];this.j[f.id]=f;f.l[this.id]=this}this.version=Math.max(this.version,c)};function w(a,b){t.call(this,a);this.f=b;this.name=this.f.name;this.s=!0;b.j=this}w.prototype=Object.create(t.prototype);w.prototype.constructor=w;"undefined"!==typeof module&&(module.J.Pa=t,module.J.Oa=w);function y(a,b){this.F=a.user;this.username=a.username;this.id=a.id||a.ts;this.o=parseFloat(a.ts);this.text="";this.u=[];this.f=this.R=this.G=!1;this.B={};this.version=b;this.update(a,b)}function z(a,b){y.call(this,a,b)}function B(a,b){y.call(this,a,b)}
-y.prototype.update=function(a,b){if(a){if(this.text=a.text||"",a.attachments&&(this.u=a.attachments),this.G=!!a.is_starred,this.R=!!a.edited,this.f=!!a.removed,a.reactions){var c={};a.reactions.forEach(function(a){c[a.name]=[];a.users.forEach(function(b){c[a.name].push(b)})});this.B=c}}else this.f=!0;this.version=b};function E(a,b,c,d){this.id="string"===typeof a?a:a.id;this.a=[];this.f=b;c&&da(this,c,d)}
-function da(a,b,c){var d=0;b.forEach(function(a){d=Math.max(this.push(a,c),d)}.bind(a));ea(a)}E.prototype.b=function(a,b){return!0===a.isMeMessage?new z(a,b):!0===a.isNotice?new B(a,b):new y(a,b)};E.prototype.push=function(a,b){for(var c,d=!1,e,g=0,f=this.a.length;g<f;g++)if(c=this.a[g],c.id===a.id){e=c.update(a,b);d=!0;break}d||(c=this.b(a,b),this.a.push(c),e=c.o);for(;this.a.length>this.f;)this.a.shift();return e||0};
-function fa(a){for(var b=F.b[G.id],c=0,d=b.a.length;c<d&&a>=b.a[c].o;c++)if(b.a[c].o===a)return b.a[c];return null}function ea(a){a.a.sort(function(a,c){return a.o-c.o})}z.prototype=Object.create(y.prototype);z.prototype.constructor=z;B.prototype=Object.create(y.prototype);B.prototype.constructor=B;"undefined"!==typeof module&&(module.J={Ma:y,La:z,Na:B,Qa:E});function H(a){this.id=a;this.l={};this.j=this.a=null;this.version=0}H.prototype.update=function(a,b){void 0!==a.name&&(this.name=a.name);void 0!==a.deleted&&(this.f=a.deleted);void 0!==a.status&&(this.status=a.status);void 0!==a.presence&&(this.b="away"!==a.presence);void 0!==a.isPresent&&(this.b=a.isPresent);a.isBot&&(this.s=a.isBot);this.version=Math.max(this.version,b)};"undefined"!==typeof module&&(module.J.Ja=H);var J={},K;function ga(){if(!c){for(var a=0,b=navigator.languages.length;a<b;a++)if(J.hasOwnProperty(navigator.languages[a])){var c=navigator.languages[a];break}c||(c="en")}K=J[c];console.log("Loading language pack: "+c);if(K.c)for(a in K.c)document.getElementById(a).textContent=K.c[a]};J.fr={Ga:"Utilisateur inconnu",Fa:"Channel inconnu",xa:"Nouveau message",wa:"Reseau",R:"(edit&eacute;)",ya:"(visible seulement par vous)",G:"Favoris",l:"Discutions",Aa:"Discutions priv\u00e9es",ok:"Ok",va:"Annuler",ba:function(a){"string"!==typeof a&&(a=parseFloat(a));var b=new Date,c=new Date;a=new Date(1E3*a);b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0);c.setTime(b.getTime());c.setDate(c.getDate()-1);return a.getTime()>b.getTime()?a.toLocaleTimeString():a.getTime()>c.getTime()?
-"hier, "+a.toLocaleTimeString():a.toLocaleString()},c:{fileUploadCancel:"Annuler",neterror:"Impossible de se connecter au chat !"}};J.en={Ga:"Unknown member",Fa:"Unknown channel",xa:"New message",wa:"Network",R:"(edited)",ya:"(only visible to you)",G:"Starred",l:"Channels",Aa:"Direct messages",ok:"Ok",va:"Cancel",ba:function(a){"string"!==typeof a&&(a=parseFloat(a));var b=new Date,c=new Date;a=new Date(1E3*a);b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0);c.setTime(b.getTime());c.setDate(c.getDate()-1);return a.getTime()>b.getTime()?a.toLocaleTimeString():a.getTime()>c.getTime()?"yesterday, "+a.toLocaleTimeString():
-a.toLocaleString()},c:{fileUploadCancel:"Cancel",neterror:"Cannot connect to chat !"}};var ha=function(){function a(a){this.text="";this.h=a}function b(b,c,d){this.N=c;this.g=null;this.i=[];this.a=d||"";this.X="<"===this.a;this.ea="*"===this.a;this.ja="_"===this.a;this.Y="~"===this.a||"-"===this.a;this.f=">"===this.a||"&gt;"===this.a;this.m=":"===this.a;this.fa="`"===this.a;this.ta="```"===this.a;this.ga="\n"===this.a;this.ia=void 0!==d&&-1!==p.A.indexOf(d);this.h=b;this.Z=null;this.b=this.ga||this.ia?c+d.length-1:!1;this.ia&&(this.g=new a(this),this.i.push(this.g),this.g.text=d)}function c(a){return"A"<=
-a&&"Z">=a||"a"<=a&&"z">=a||"0"<=a&&"9">=a||-1!=="\u00e0\u00e8\u00ec\u00f2\u00f9\u00c0\u00c8\u00cc\u00d2\u00d9\u00e1\u00e9\u00ed\u00f3\u00fa\u00fd\u00c1\u00c9\u00cd\u00d3\u00da\u00dd\u00e2\u00ea\u00ee\u00f4\u00fb\u00c2\u00ca\u00ce\u00d4\u00db\u00e3\u00f1\u00f5\u00c3\u00d1\u00d5\u00e4\u00eb\u00ef\u00f6\u00fc\u00ff\u00c4\u00cb\u00cf\u00d6\u00dc\u0178\u00e7\u00c7\u00df\u00d8\u00f8\u00c5\u00e5\u00c6\u00e6\u0153".indexOf(a)}function d(a){a=a||h;for(var c=0,k=a.i.length;c<k;c++){var f=a.i[c];if(f instanceof
-b)if(f.b){if(f=d(f))return f}else return f}return null}function e(a,c){a.h instanceof b&&(a.h.i.splice(a.h.i.indexOf(a)+(c?1:0)),a.h.g=a.h.i[a.h.i.length-1],e(a.h,!0))}function g(a){return a}function f(a){return{link:a,text:a,Ea:!1}}var l,h,p={A:[],S:g,W:g,U:f};b.prototype.la=function(){return this.ea&&!!this.b||this.h instanceof b&&this.h.la()};b.prototype.oa=function(){return this.ja&&!!this.b||this.h instanceof b&&this.h.oa()};b.prototype.pa=function(){return this.Y&&!!this.b||this.h instanceof
-b&&this.h.pa()};b.prototype.ca=function(){return this.m&&!!this.b||this.h instanceof b&&this.h.ca()};b.prototype.na=function(){return this.ia&&!!this.b||this.h instanceof b&&this.h.na()};b.prototype.ma=function(){return this.fa&&!!this.b||this.h instanceof b&&this.h.ma()};b.prototype.C=function(){return this.ta&&!!this.b||this.h instanceof b&&this.h.C()};b.prototype.qa=function(){for(var a=0,c=this.i.length;a<c;a++)if(this.i[a]instanceof b&&(!this.i[a].b||this.i[a].qa()))return!0;return!1};b.prototype.ra=
-function(a){if("<"===this.a&&">"===l[a])return!0;var b=c(l[a-1]);if(!this.f&&l.substr(a,this.a.length)===this.a){if(!b&&(this.ea||this.ja||this.Y))return!1;if(this.g&&this.qa())return this.g.ua();if(this.Ba())return!0}return"\n"===l[a]&&this.f?!0:!1};b.prototype.Ba=function(){for(var a=this;a;){for(var c=0,d=a.i.length;c<d;c++)if(a.i[c]instanceof b||a.i[c].text.length)return!0;a=a.Z}return!1};b.prototype.ua=function(){var a=new b(this.h,this.N,this.a);a.Z=this;this.g&&this.g instanceof b&&(a.g=this.g.ua(),
-a.i=[a.g]);return a};b.prototype.Ca=function(a){return this.m&&(" "===l[a]||"\t"===l[a])||(this.m||this.X||this.ea||this.ja||this.Y||this.fa)&&"\n"===l[a]?!1:!0};b.prototype.Da=function(b){if(this.fa||this.m||this.ta||this.X)return null;if(!this.g||this.g.b||this.g instanceof a){var d=c(l[b+1]);if("```"===l.substr(b,3))return"```";var f=h.da();if(void 0===f||f){if("&gt;"===l.substr(b,4))return"&gt;";if(">"===l[b])return l[b]}if(-1!==["`","\n"].indexOf(l[b])||-1!==["*","~","-","_"].indexOf(l[b])&&
-(d||-1!=="*~-_<&".split("").indexOf(l[b+1]))||-1!==[":"].indexOf(l[b])&&d||-1!==["<"].indexOf(l[b]))return l[b];d=0;for(f=p.A.length;d<f;d++){var e=p.A[d];if(l.substr(b,e.length)===e)return e}}return null};a.prototype.da=function(){if(""!==this.text.trim())return!1};b.prototype.da=function(){for(var a=this.i.length-1;0<=a;a--){var b=this.i[a].da();if(void 0!==b)return b}if(this.ga||this.f)return!0};a.prototype.j=function(a){this.text+=l[a];return 1};b.prototype.j=function(c){var d=this.g&&!this.g.b&&
-this.g.ra?this.g.ra(c):null;if(d){var f=this.g.a.length;this.g.ka(c);d instanceof b&&(this.g=d,this.i.push(d));return f}if(!this.g||this.g.b||this.g instanceof a||this.g.Ca(c)){if(d=this.Da(c))return this.g=new b(this,c,d),this.i.push(this.g),this.g.a.length;if(!this.g||this.g.b)this.g=new a(this),this.i.push(this.g);return this.g.j(c)}d=this.g.N+1;h.s(this.g.N);this.g=new a(this);this.g.j(d-1);this.i.pop();this.i.push(this.g);return d-c};b.prototype.ka=function(a){for(var b=this;b;)b.b=a,b=b.Z};
-b.prototype.s=function(a){this.b&&this.b>=a&&(this.b=!1);this.i.forEach(function(c){c instanceof b&&c.s(a)})};a.prototype.innerHTML=function(){var a;if(this.h.ca()){for(a=this.h;a&&!a.m;)a=a.h;if(a){var b=a.a+this.text+a.a;return(a=p.S(b))?a:b}return(a=p.S(this.text))?a:this.text}return this.h.C()?this.text.replace(/\n/g,"<br/>"):p.W(this.text)};a.prototype.outerHTML=function(){var a="span",b=[],c="";if(this.h.C()){b.push("codeblock");var d=this.innerHTML()}else this.h.ma()?(b.push("code"),d=this.innerHTML()):
-(this.h.X?(d=p.U(this.text),a="a",c=' href="'+d.link+'"',d.Ra&&(c+=' target="_blank"'),d=p.W(d.text)):d=this.innerHTML(),this.h.la()&&b.push("bold"),this.h.oa()&&b.push("italic"),this.h.pa()&&b.push("strike"),this.h.ca()&&b.push("emoji"),this.h.na()&&b.push("highlight"));return"<"+a+c+(b.length?' class="'+b.join(" ")+'"':"")+">"+d+"</"+a+">"};b.prototype.outerHTML=function(){var a="";this.f&&(a+='<span class="quote">');this.ga&&(a+="<br/>");this.i.forEach(function(b){a+=b.outerHTML()});this.f&&(a+=
-"</span>");return a};b.prototype.sa=function(a){this.f&&!this.b&&this.ka(a);this.i.forEach(function(c){c instanceof b&&c.sa(a)})};return function(c,m){m||(m={});p.A=m.A||[];p.S=m.S||g;p.W=m.W||g;p.U=m.U||f;l=c;h=new b(this,0);m=0;c=l.length;do{for(;m<c;)m+=h.j(m);h.sa(l.length);if(m=d()){e(m,!1);h.s(m.N);var k=new a(m.h);k.j(m.N);m.h.i.push(k);m.h.g=k;m=m.N+1}else m=void 0}while(void 0!==m);return h.outerHTML()}}();window._formatText=function(a,b){return ha(a,{A:b?b.highlights:void 0})};
-"undefined"!==typeof module&&(module.J.w=ha);function ia(a,b){this.f=a;this.content=b;this.c=ja(this);this.b=ka(this);this.a=[];this.j=[]}
-function ja(a){var b=document.createElement("div"),c=document.createElement("header"),d=document.createElement("span"),e=document.createElement("span"),g=document.createElement("div"),f=document.createElement("footer");b.a=document.createElement("span");b.b=document.createElement("span");d.textContent=a.f;"string"==typeof a.content?g.innerHTML=a.content:g.appendChild(a.content);c.className=la;d.className=ma;e.className=na;e.textContent="x";c.appendChild(d);c.appendChild(e);b.appendChild(c);g.className=
-oa;b.appendChild(g);b.b.className=pa;b.b.textContent=K.va;b.b.addEventListener("click",function(){L(a,!1)});e.addEventListener("click",function(){L(a,!1)});b.a.addEventListener("click",function(){L(a,!0)});f.appendChild(b.b);b.a.className=pa;b.a.textContent=K.ok;f.appendChild(b.a);f.className=qa+" "+ra;b.appendChild(f);b.className=sa;return b}function L(a,b){(b?a.a:a.j).forEach(function(a){a()});a.close()}
-function ka(a){var b=document.createElement("div");b.className=ta;b.addEventListener("click",function(){L(this,!1)}.bind(a));return b}function ua(a,b,c){a.c.a.textContent=b;a.c.b.textContent=c;return a}ia.prototype.V=function(a){a=a||document.body;a.appendChild(this.b);a.appendChild(this.c);return this};ia.prototype.close=function(){this.c.remove();this.b.remove();return this};function va(a,b){a.a.push(b);return a};var pa="button",qa="button-container",sa="dialog",ta="dialog-overlay",la="dialog-title",ma="dialog-title-label",na="dialog-title-close",oa="dialog-body",ra="dialog-footer";var wa=[],xa=0;
-function ya(){var a=document.createDocumentFragment(),b=Object.keys(F.a.l||{}),c=[],d=[],e=[],g=[];b.sort(function(a,b){return a[0]!==b[0]?a[0]-b[0]:F.a.l[a].name.localeCompare(F.a.l[b].name)});b.forEach(function(a){a=F.a.l[a];if(!a.m&&!1!==a.C)if(a instanceof w){if(!a.f.f){var b=document.createElement("li");var f=document.createElement("a");b.id="room_"+a.id;f.href="#"+a.id;b.className="slack-context-room slack-ims";f.textContent=a.f.name;b.appendChild(za());b.appendChild(f);a.f.b||b.classList.add("away");
-G===a&&b.classList.add("selected");a.a>a.b&&(b.classList.add("unread"),0<=M.indexOf(a)&&b.classList.add("unreadHi"));b&&(a.G?c.push(b):g.push(b))}}else b=document.createElement("li"),f=document.createElement("a"),b.id="room_"+a.id,f.href="#"+a.id,a.s?(b.className="slack-context-room slack-group",b.dataset.count=Object.keys(a.j||{}).length):b.className="slack-context-room slack-channel",G===a&&b.classList.add("selected"),f.textContent=a.name,b.appendChild(za()),b.appendChild(f),a.a>a.b&&(b.classList.add("unread"),
-0<=M.indexOf(a)&&b.classList.add("unreadHi")),b&&(a.G?c.push(b):a.s?e.push(b):d.push(b))});c.length&&a.appendChild(Aa(K.G));c.forEach(function(b){a.appendChild(b)});d.length&&a.appendChild(Aa(K.l));d.forEach(function(b){a.appendChild(b)});e.forEach(function(b){a.appendChild(b)});g.length&&a.appendChild(Aa(K.Aa));g.forEach(function(b){a.appendChild(b)});document.getElementById("chanList").textContent="";document.getElementById("chanList").appendChild(a);Ba();N();Ca(function(a){document.getElementById("slackCtx").style.backgroundImage=
-"url("+a+")"})}function Da(){var a=F.a.f,b;for(b in F.a.b.l)if(!F.a.b.l[b].m){var c=document.getElementById("room_"+b);a[b]?c.classList.add("slack-context-typing"):c.classList.remove("slack-context-typing")}for(var d in F.a.a)(b=F.a.a[d].j)&&!b.m&&(c=document.getElementById("room_"+b.id))&&(a[b.id]?c.classList.add("slack-context-typing"):c.classList.remove("slack-context-typing"));Ea()}
-function Ea(){var a=F.a.f;document.getElementById("whoistyping").textContent="";if(G&&a[G.id]){var b=document.createDocumentFragment(),c=!1,d;for(d in a[G.id])(a=F.a.a[d])?b.appendChild(Fa(a)):c=!0;c&&(F.f=0);document.getElementById("whoistyping").appendChild(b)}}function Ga(a){a?document.body.classList.remove("no-network"):document.body.classList.add("no-network");N()}
-function Ha(){var a=G.name||(G.f?G.f.name:void 0);if(!a){var b=[];G.j.forEach(function(a){b.push(a.name)});a=b.join(", ")}document.getElementById("currentRoomTitle").textContent=a;Ia();O();document.getElementById("fileUploadContainer").classList.add("hidden");Ja();P&&(P=null,Q());R&&(R=null,Q());Ea()}
-function Q(){if(P){document.body.classList.add("replyingTo");var a=document.getElementById("replyToContainer"),b=document.createElement("a");b.addEventListener("click",function(){P=null;Q()});b.className="replyto-close";b.textContent="x";a.textContent="";a.appendChild(b);a.appendChild(P.I())}else document.body.classList.remove("replyingTo"),document.getElementById("replyToContainer").textContent="";O()}
-function S(){if(R){document.body.classList.add("replyingTo");var a=document.getElementById("replyToContainer"),b=document.createElement("a");b.addEventListener("click",function(){R=null;S()});b.className="replyto-close";b.textContent="x";a.textContent="";a.appendChild(b);a.appendChild(R.I());document.getElementById("msgInput").value=R.text}else document.body.classList.remove("replyingTo"),document.getElementById("replyToContainer").textContent="";O()}
-window.toggleReaction=function(a,b,c){var d=F.b[a];if(d){a:{for(var e=0,g=d.a.length;e<g;e++)if(d.a[e].id==b){d=d.a[e];break a}d=null}d&&(e=F.a.b.id,d.B[c]&&-1!==d.B[c].indexOf(e)?(d=new XMLHttpRequest,d.open("DELETE","api/reaction?room="+a+"&msg="+b+"&reaction="+encodeURIComponent(c),!0),d.send(null)):Ka(a,b,c))}};
-function La(a){a:{for(var b=a,c={};!c[b];){if(a=F.a.m.data[b])if("alias:"==a.substr(0,6))c[b]=!0,b=a.substr(6);else{b=document.createElement("span");b.className="emoji-custom emoji";b.style.backgroundImage="url('"+a+"')";a=b;break a}break}a=b}"string"===typeof a&&"makeEmoji"in window&&(a=window.makeEmoji(a));return"string"===typeof a?null:a}function Ma(a,b){document.getElementById("linkFavicon").href=a||b?"favicon.png?h="+a+"&m="+b:"favicon_ok.png"}
-function N(){var a=M.length,b="";if(T)b="!"+K.wa+" - ",document.getElementById("linkFavicon").href="favicon_err.png";else if(a)b="(!"+a+") - ",Ma(a,a);else{var a=0,c;for(c in F.a.l){var d=F.a.l[c];d.a>d.b&&a++}a&&(b="("+a+") - ");Ma(0,a)}F.a.s&&(b+=F.a.s.name);document.title=b}
-function Na(){if("Notification"in window)if("granted"===Notification.permission){var a=Date.now();if(xa+3E4<a){var b=new Notification(K.xa);xa=a;setTimeout(function(){b.close()},5E3)}}else"denied"!==Notification.permission&&Notification.requestPermission()}
-function Ia(){var a=document.createDocumentFragment(),b=G.id,c=null,d=0,e=null,g;wa=[];F.b[b]&&F.b[b].a.forEach(function(b){if(b.f)b.M();else{var f=b.K(),h=!1;c&&c.F===b.F&&b.F?30>Math.abs(d-b.o)&&!(b instanceof z)?e.classList.add("slackmsg-same-ts"):d=b.o:(d=b.o,h=!0);(!c||c.o<=G.b)&&b.o>G.b?f.classList.add("slackmsg-first-unread"):f.classList.remove("slackmsg-first-unread");if(b instanceof z)e=c=null,d=0,a.appendChild(f),g=null;else{if(h||!g){var h=F.a.a[b.F],p=b.username,k=document.createElement("div"),
-m=document.createElement("div"),u=document.createElement("span");k.O=document.createElement("img");k.O.className="slackmsg-author-img";u.className="slackmsg-author-name";h?(u.textContent=h.name,k.O.src="api/avatar?user="+h.id):(u.textContent=p||"?",k.O.src="");m.appendChild(k.O);m.appendChild(u);m.className="slackmsg-author";k.className="slackmsg-authorGroup";k.appendChild(m);k.content=document.createElement("div");k.content.className="slackmsg-author-messages";k.appendChild(k.content);g=k;wa.push(g);
-a.appendChild(g)}c=b;e=f;g.content.appendChild(f)}}});b=document.getElementById("chatWindow");b.textContent="";b.appendChild(a);b.scrollTop=b.scrollHeight-b.clientHeight;window.hasFocus&&Ja()}
-function Oa(a){function b(a,b){for(b=b||a.target;b!==a.currentTarget&&b;){if(b.classList.contains("slackmsg-item"))return b.id;b=b.parentElement}}for(var c,d,e=a.target;e!==a.currentTarget&&e&&!e.classList.contains("slackmsg-hover");){if(e.parentElement&&e.classList.contains("slackmsg-attachment-actions-item")){d=b(a,e);var g=e.dataset.attachmentIndex,f=e.dataset.actionIndex;if(d&&void 0!==g&&void 0!==f){d=parseFloat(d.split("_")[1]);(c=fa(d))&&c.u[g]&&c.u[g].actions&&c.u[g].actions[f]&&Pa(c,c.u[g],
-c.u[g].actions[f]);break}}if(e.parentElement&&e.parentElement.classList.contains("slackmsg-hover")){if(d=b(a,e))d=parseFloat(d.split("_")[1]),(c=fa(d))&&e.classList.contains("slackmsg-hover-reply")?(R&&(R=null,S()),P!==c&&(P=c,Q())):c&&e.classList.contains("slackmsg-hover-reaction")?Qa.V(document.body,function(a){a&&Ka(G.id,c.id,a)}):c&&e.classList.contains("slackmsg-hover-edit")?(P&&(P=null,Q()),R!==c&&(R=c,S())):c&&e.classList.contains("slackmsg-hover-remove")&&(P&&(P=null,Q()),R&&(R=null,S()),
-Ra(c));break}e=e.parentElement}}function Pa(a,b,c){function d(){var d=JSON.stringify({actions:[c],attachment_id:b.id,callback_id:b.callback_id,channel_id:e,is_ephemeral:a instanceof B,message_ts:a.id}),f=a.F,l=new FormData,h=new XMLHttpRequest;l.append("payload",d);l.append("service_id",f);h.open("POST","api/attachmentAction");h.send(l)}var e=G.id;c.confirm?va(ua(new ia(c.confirm.title,c.confirm.text),c.confirm.ok_text,c.confirm.dismiss_text),d).V():d()}
-function O(){document.getElementById("msgInput").focus()}function Ba(){var a=document.location.hash.substr(1),b=F.a.l[a];b&&b!==G?Sa(b):(a=F.a.a[a])&&a.m&&Sa(a.m)}function Ta(){var a=document.getElementById("chatWindow").getBoundingClientRect().top;wa.forEach(function(b){var c=b.O,d=c.clientHeight;b=b.getBoundingClientRect();c.style.top=Math.max(0,Math.min(a-b.top,b.height-d-d/2))+"px"})}
-document.addEventListener("DOMContentLoaded",function(){ga();document.getElementById("chatWindow").addEventListener("click",Oa);window.addEventListener("hashchange",function(){document.location.hash&&"#"===document.location.hash[0]&&Ba()});document.getElementById("fileUploadCancel").addEventListener("click",function(a){a.preventDefault();document.getElementById("fileUploadError").classList.add("hidden");document.getElementById("fileUploadContainer").classList.add("hidden");document.getElementById("fileUploadInput").value=
-"";return!1});document.getElementById("fileUploadForm").addEventListener("submit",function(a){a.preventDefault();a=document.getElementById("fileUploadInput");var b=a.value;b&&(b=b.substr(b.lastIndexOf("\\")+1),Ua(b,a.files[0],function(a){var b=document.getElementById("fileUploadError");a?(b.textContent=a,b.classList.remove("hidden")):(b.classList.add("hidden"),document.getElementById("fileUploadInput").value="",document.getElementById("fileUploadContainer").classList.add("hidden"))}));return!1});
-document.getElementById("attachFile").addEventListener("click",function(a){a.preventDefault();G&&document.getElementById("fileUploadContainer").classList.remove("hidden");return!1});document.getElementById("msgForm").addEventListener("submit",function(a){a.preventDefault();a=document.getElementById("msgInput");G&&a.value&&Va(a.value)&&(a.value="",P&&(P=null,Q()),R&&(R=null,Q()),document.getElementById("slashList").textContent="");O();return!1});window.addEventListener("blur",function(){window.hasFocus=
-!1});window.addEventListener("focus",function(){window.hasFocus=!0;xa=0;G&&Ja();O()});document.getElementById("chatWindow").addEventListener("scroll",Ta);var a=0;document.getElementById("msgInput").addEventListener("input",function(){if(G){var b=Date.now();a+3E3<b&&(F.a.b.b||G instanceof w)&&(Wa(),a=b);var b=[],c=this.value;if("/"===this.value[0]){var d=c.indexOf(" "),e=-1!==d,d=-1===d?c.length:d,c=c.substr(0,d);for(f in F.a.j.data){var g=F.a.j.data[f];(!e&&g.name.substr(0,d)===c||e&&g.name===c)&&
-b.push(g)}}b.sort(function(a,b){return a.P.localeCompare(b.P)||a.name.localeCompare(b.name)});var d=document.getElementById("slashList"),e=document.createDocumentFragment();d.textContent="";var f=0;for(c=b.length;f<c;f++){g=b[f];if(l!==g.P){var l=g.P;e.appendChild(Xa(g.P))}e.appendChild(Ya(g))}d.appendChild(e)}});window.hasFocus=!0;(function(){var a=document.getElementById("emojiButton");if("makeEmoji"in window){var c=window.makeEmoji("smile");c?a.innerHTML="<span class='emoji-small'>"+c.outerHTML+
-"</span>":a.style.backgroundImage='url("smile.svg")';(c=window.makeEmoji("paperclip"))?document.getElementById("attachFile").innerHTML="<span class='emoji-small'>"+c.outerHTML+"</span>":document.getElementById("attachFile").style.backgroundImage='url("public/paperclip.svg")';a.addEventListener("click",function(){Qa.V(document.body,function(a){a&&(document.getElementById("msgInput").value+=":"+a+":");O()})})}else a.classList.add("hidden")})();Za()});function za(){var a=document.createElement("span"),b=document.createElement("span"),c=document.createElement("span"),d=document.createElement("span");a.className="typing-container";b.className="typing-dot1";c.className="typing-dot2";d.className="typing-dot3";b.textContent=c.textContent=d.textContent=".";a.appendChild(b);a.appendChild(c);a.appendChild(d);return a}var Aa=function(){var a={};return function(b){var c=a[b];c||(c=a[b]=document.createElement("header"),c.textContent=b);return c}}();
-function $a(a){var b=a.b,c=document.createElement("div"),d=document.createElement("div"),e=document.createElement("ul"),g=document.createElement("li");c.u=document.createElement("ul");c.B=document.createElement("ul");c.o=document.createElement("div");c.ha=document.createElement("div");c.aa=document.createElement("span");c.id=b+"_"+a.id;c.className="slackmsg-item";c.o.className="slackmsg-ts";c.ha.className="slackmsg-msg";c.aa.className="slackmsg-author-name";e.className="slackmsg-hover";g.className=
-"slackmsg-hover-reply";e.appendChild(g);if("makeEmoji"in window){var f=document.createElement("li"),l=window.makeEmoji("arrow_heading_down"),h=window.makeEmoji("smile"),p=window.makeEmoji("pencil2"),b=window.makeEmoji("x");f.className="slackmsg-hover-reaction";h?(f.classList.add("emoji-small"),f.appendChild(h)):f.style.backgroundImage='url("smile.svg")';l?(g.classList.add("emoji-small"),g.appendChild(l)):g.style.backgroundImage='url("repl.svg")';e.appendChild(f);a.F===F.a.b.id&&(a=document.createElement("li"),
-a.className="slackmsg-hover-edit",p?a.classList.add("emoji-small"):a.style.backgroundImage='url("edit.svg")',a.appendChild(p),e.appendChild(a),a=document.createElement("li"),a.className="slackmsg-hover-remove",b?a.classList.add("emoji-small"):a.style.backgroundImage='url("remove.svg")',a.appendChild(b),e.appendChild(a))}else g.style.backgroundImage='url("repl.svg")',a.F===F.a.b.id&&(a=document.createElement("li"),a.className="slackmsg-hover-edit",a.style.backgroundImage='url("edit.svg")',e.appendChild(a),
-a=document.createElement("li"),a.className="slackmsg-hover-remove",a.style.backgroundImage='url("remove.svg")',e.appendChild(a));d.appendChild(c.aa);d.appendChild(c.ha);d.appendChild(c.o);d.appendChild(c.u);b=document.createElement("div");b.innerHTML=K.R;b.className="slackmsg-edited";d.appendChild(b);d.appendChild(c.B);d.className="slackmsg-content";c.u.className="slackmsg-attachments";c.B.className="slackmsg-reactions";c.appendChild(d);c.appendChild(e);return c}
-function ab(a){var b={good:"#2fa44f",warning:"#de9e31",danger:"#d50200"};if(a){if("#"===a[0])return a;if(b[a])return b[a]}return"#e3e4e6"}
-function bb(a,b,c){var d=document.createElement("li"),e=document.createElement("div"),g=document.createElement("div"),f=document.createElement("a"),l=document.createElement("div"),h=document.createElement("img"),p=document.createElement("a"),k=document.createElement("div"),m=document.createElement("div"),u=document.createElement("div"),r=document.createElement("img"),v=document.createElement("div");d.className="slackmsg-attachment";e.style.borderColor=ab(b.color||"");e.className="slackmsg-attachment-block";
-g.className="slackmsg-attachment-pretext";b.pretext?g.innerHTML=a.w(b.pretext):g.classList.add("hidden");f.target="_blank";b.title?(f.innerHTML=a.w(b.title),b.title_link&&(f.href=b.title_link),f.className="slackmsg-attachment-title"):f.className="hidden slackmsg-attachment-title";p.target="_blank";l.className="slackmsg-author";b.author_name&&(p.innerHTML=a.w(b.author_name),p.href=b.author_link||"",p.className="slackmsg-author-name",h.className="slackmsg-author-img",b.author_icon&&(h.src=b.author_icon,
-l.appendChild(h)),l.appendChild(p));u.className="slackmsg-attachment-thumb";b.thumb_url?(h=document.createElement("img"),h.src=b.thumb_url,u.appendChild(h),e.classList.add("has-thumb"),b.video_html&&(u.dataset.video=b.video_html)):u.classList.add("hidden");k.className="slackmsg-attachment-content";h=a.w(b.text||"");m.className="slackmsg-attachment-text";h&&""!=h?m.innerHTML=h:m.classList.add("hidden");r.className="slackmsg-attachment-img";b.image_url?r.src=b.image_url:r.classList.add("hidden");v.className=
-"slackmsg-attachment-footer";b.footer&&(h=document.createElement("span"),h.className="slackmsg-attachment-footer-text",h.innerHTML=a.w(b.footer),b.footer_icon&&(p=document.createElement("img"),p.src=b.footer_icon,p.className="slackmsg-attachment-footer-icon",v.appendChild(p)),v.appendChild(h));b.ts&&(h=document.createElement("span"),h.className="slackmsg-ts",h.innerHTML=K.ba(b.ts),v.appendChild(h));k.appendChild(u);k.appendChild(m);e.appendChild(f);e.appendChild(l);e.appendChild(k);e.appendChild(r);
-if(b.fields&&b.fields.length){var x=document.createElement("ul");e.appendChild(x);x.className="slackmsg-attachment-fields";b.fields.forEach(function(b){var c=b.title||"",d=b.value||"";b=!!b["short"];var e=document.createElement("li"),f=document.createElement("div"),g=document.createElement("div");e.className="field";b||e.classList.add("field-long");f.className="field-title";f.textContent=c;g.className="field-text";g.innerHTML=a.w(d);e.appendChild(f);e.appendChild(g);e&&x.appendChild(e)})}if(b.actions&&
-b.actions.length)for(f=document.createElement("ul"),f.className="slackmsg-attachment-actions "+qa,e.appendChild(f),l=0,k=b.actions.length;l<k;l++)(m=b.actions[l])&&(m=cb(c,l,m))&&f.appendChild(m);e.appendChild(v);d.appendChild(g);d.appendChild(e);return d}
-function cb(a,b,c){var d=document.createElement("li"),e=ab(c.style);d.textContent=c.text;e!==ab()&&(d.style.color=e);d.style.borderColor=e;d.dataset.attachmentIndex=a;d.dataset.actionIndex=b;d.className="slackmsg-attachment-actions-item "+pa;return d}function Fa(a){var b=document.createElement("li"),c=document.createElement("span");c.textContent=a.name;b.appendChild(za());b.appendChild(c);return b}
-function Xa(a){var b=document.createElement("lh");b.textContent=a;b.className="slack-command-header";return b}
-function Ya(a){var b=document.createElement("li"),c=document.createElement("span"),d=document.createElement("span"),e=document.createElement("span");c.textContent=a.name;d.textContent=a.usage;e.textContent=a.a;b.appendChild(c);b.appendChild(d);b.appendChild(e);b.className="slack-command-item";c.className="slack-command-name";d.className="slack-command-usage";e.className="slack-command-desc";return b};var Qa=function(){function a(a,b){for(a=a.target;a!==h&&a&&"LI"!==a.nodeName;)a=a.parentElement;a&&"LI"===a.nodeName&&a.id&&"emojibar-"===a.id.substr(0,9)?b(a.id.substr(9)):b(null)}function b(){if(!c())return!1;D&&D(null);return!0}function c(){return h.parentElement?(h.parentElement.removeChild(p),h.parentElement.removeChild(h),!0):!1}function d(a){var b=0;a=void 0===a?r.value:a;if(l()){var c=window.searchEmojis(a);var d=e(c);for(var f in v)v[f].visible&&(v[f].visible=!1,m.removeChild(v[f].c));f=
-0;for(var h=d.length;f<h;f++){var k=d[f].name;var A=v[k];if(!A){A=v;var p=k,C=k;k=window.makeEmoji(c[k]);var D=document.createElement("span");D.appendChild(k);D.className="emoji-medium";k=g(C,D);A=A[p]=k}A.visible||(A.visible=!0,m.appendChild(A.c));b++}}for(f in x)x[f].visible&&(x[f].visible=!1,u.removeChild(x[f].c));d=e(F.a.m.data);f=0;for(h=d.length;f<h;f++)k=d[f].name,""!==a&&k.substr(0,a.length)!==a||"alias:"===F.a.m.data[k].substr(0,6)||(A=x[k],A||(c=x,p=A=k,k=F.a.m.data[k],C=document.createElement("span"),
-D=document.createElement("span"),C.className="emoji emoji-custom",C.style.backgroundImage='url("'+k+'")',D.appendChild(C),D.className="emoji-medium",k=g(p,D),A=c[A]=k),A.visible||(A.visible=!0,u.appendChild(A.c)),b++);return b}function e(a){var b=F.a.b.a.a,c=[],d;for(d in a){var e={name:d,za:0,count:0};a[d].names&&a[d].names.forEach(function(a){e.count+=b[a]||0});c.push(e)}return c=c.sort(function(a,b){var c=b.count-a.count;return c?c:a.za-b.za})}function g(a,b){var c=document.createElement("li");
-c.appendChild(b);c.className="emojibar-list-item";c.id="emojibar-"+a;return{visible:!1,c:c}}function f(a){var b=document.createElement("img"),c=document.createElement("div");b.src=a;c.appendChild(b);c.className="emojibar-header";return c}function l(){return"searchEmojis"in window}var h=document.createElement("div"),p=document.createElement("div"),k=document.createElement("div"),m=document.createElement("ul"),u=document.createElement("ul"),r=document.createElement("input"),v={},x={},I=document.createElement("div"),
-C=document.createElement("span"),U=document.createElement("span"),D;p.addEventListener("click",function(a){var c=h.getBoundingClientRect();(a.screenY<c.top||a.screenY>c.bottom||a.screenX<c.left||a.screenX>c.right)&&b()});p.className="emojibar-overlay";h.className="emojibar";k.className="emojibar-emojis";I.className="emojibar-detail";C.className="emojibar-detail-img";U.className="emojibar-detail-name";m.className=u.className="emojibar-list";r.className="emojibar-search";I.appendChild(C);I.appendChild(U);
-k.appendChild(f(window.emojiProviderHeader));k.appendChild(m);k.appendChild(f("emojicustom.png"));k.appendChild(u);h.appendChild(k);h.appendChild(I);h.appendChild(r);r.addEventListener("keyup",function(){d()});h.addEventListener("mousemove",function(b){a(b,function(a){var b=a?v[a]||x[a]:null;b?(C.innerHTML=b.c.outerHTML,U.textContent=":"+a+":"):(C.textContent="",U.textContent="")})});h.addEventListener("click",function(b){a(b,function(a){a&&c()&&D&&D(a)})});return{isSupported:l,V:function(a,b){return l()?
-(D=b,a.appendChild(p),a.appendChild(h),r.value="",d(),r.focus(),!0):!1},search:d,close:b}}();var F,M=[];function db(){this.f=0;this.a=new ca;this.b={}}
-db.prototype.update=function(a){var b=Date.now();a.v&&(this.f=a.v);if(a["static"]){var c=this.a,d=a["static"],e=Date.now();var g=g||"";d.team&&(c.s||(c.s=new q(d.team.id)),c.s.update(d.team,e));if(d.users)for(var f=0,l=d.users.length;f<l;f++){var h=c.a[g+d.users[f].id];h||(h=c.a[g+d.users[f].id]=new H(d.users[f].id));h.update(d.users[f],e)}if(d.channels)for(f=0,l=d.channels.length;f<l;f++){h=c.l[g+d.channels[f].id];if(!h){var h=c.l,p=g+d.channels[f].id;var k=d.channels[f];k=k.pv?new w(k.id,c.a[k.user]):
-new t(k.id);h=h[p]=k}h.update(d.channels[f],c,e,g)}d.emojis&&(c.m.data=d.emojis,c.m.version=e);if(void 0!==d.commands){c.j.data={};for(f in d.commands)c.j.data[f]=new aa(d.commands[f]);c.j.version=e}c.C=Math.max(c.C,e);d.self&&(c.b=c.a[g+d.self.id]||null,c.b?(c.b.a||(c.b.a=new ba),c.b.a.update(d.self.prefs,e)):c.C=0);if(void 0!==d.typing)for(f in c.f={},d.typing){c.f[f]={};for(var m in d.typing[f])c.f[f][m]=e}}for(var u in this.a.l){var r=this.a.l[u];r.a===r.b&&(c=M.indexOf(r),-1!==c&&M.splice(c,
-1))}if(a.live){for(r in a.live)(u=this.b[r])?da(u,a.live[r],b):this.b[r]=new V(r,250,a.live[r],b);for(var v in a.live)(r=this.a.l[v])?(this.b[v].a.length&&(b=this.b[v],r.a=Math.max(r.a,b.a[b.a.length-1].o)),r.m||(eb(r,a.live[v]),G&&a.live[G.id]&&Ia())):F.f=0}a["static"]&&(ya(),a["static"].typing&&Da())};setInterval(function(){var a=F.a,b=Date.now(),c=!1,d;for(d in a.f){var e=!0,g;for(g in a.f[d])a.f[d][g]+3E3<b?(delete a.f[d][g],c=!0):e=!1;e&&(delete a.f[d],c=!0)}c&&Da()},1E3);
-function eb(a,b){if(a!==G||!window.hasFocus){var c=new RegExp("<@"+F.a.b.id),d=!1,e=!1,g=!1;b.forEach(function(b){if(!(parseFloat(b.ts)<=a.b)){e=!0;var f;if(!(f=a instanceof w)&&(f=b.text)&&!(f=b.text.match(c)))a:{f=F.a.b.a.A;for(var h=0,p=f.length;h<p;h++)if(-1!==b.text.indexOf(f[h])){f=!0;break a}f=!1}f&&(-1===M.indexOf(a)&&(g=!0,M.push(a)),d=!0)}});if(e){N();if(b=document.getElementById("room_"+a.id))b.classList.add("unread"),d&&b.classList.add("unreadHi");g&&!window.hasFocus&&Na()}}}
-function Ja(){var a=G,b=M.indexOf(a);if(a.a>a.b){var c=new XMLHttpRequest;c.open("POST","api/markread?room="+a.id+"&ts="+a.a,!0);c.send(null);a.b=a.a}0<=b&&(M.splice(b,1),N());a=document.getElementById("room_"+a.id);a.classList.remove("unread");a.classList.remove("unreadHi")}F=new db;var Ca=function(){function a(a,b){b.sort(function(){return Math.random()-.5});for(var c=0,d=20;d<h-40;d+=k)for(var e=0;e+k<=p;e+=k)g(a,b[c],d,e),c++,c===b.length&&(b.sort(function(a,b){return a.T?b.T?Math.random()-.5:-1:1}),c=0)}function b(a,d){for(var e=0,f=a.length;e<f;e++)if(void 0===a[e].T){c(a[e].src,function(c){a[e].T=c;b(a,d)});return}var g=[];a.forEach(function(a){a.T&&g.push(a.T)});d(g)}function c(a,b){var c=new XMLHttpRequest;c.responseType="blob";c.onreadystatechange=function(){if(4===
-c.readyState)if(c.response){var a=new Image;a.onload=function(){var c=document.createElement("canvas");c.height=c.width=r;c=c.getContext("2d");c.drawImage(a,0,0,r,r);for(var c=c.getImageData(0,0,r,r),d=0,e=0;e<c.width*c.height*4;e+=4)c.data[e]=c.data[e+1]=c.data[e+2]=(c.data[e]+c.data[e+1]+c.data[e+2])/3,c.data[e+3]=50,d+=c.data[e];if(50>d/(c.height*c.width))for(e=0;e<c.width*c.height*4;e+=4)c.data[e]=c.data[e+1]=c.data[e+2]=255-c.data[e];b(c)};a.onerror=function(){b(null)};a.src=window.URL.createObjectURL(c.response)}else b(null)};
-c.open("GET",a,!0);c.send(null)}function d(){var a=l.createLinearGradient(0,0,0,p);a.addColorStop(0,"#4D394B");a.addColorStop(1,"#201820");l.fillStyle=a;l.fillRect(0,0,h,p);return l.getImageData(0,0,h,p)}function e(a,b){for(var c=(a.height-b.height)/2,d=0;d<b.height;d++)for(var e=0;e<b.width;e++){var f=b.data[4*(d*b.width+e)]/255,g=4*((d+c)*a.width+e+c);a.data[g]*=f;a.data[g+1]*=f;a.data[g+2]*=f}return a}function g(a,b,c,d){var f=Math.floor(d);a=[a.data[f*h*4+0],a.data[f*h*4+1],a.data[f*h*4+2]];l.fillStyle=
-"#"+(1.1*a[0]<<16|1.1*a[1]<<8|1.1*a[2]).toString(16);l.beginPath();l.moveTo(c+k/2,d+m);l.lineTo(c-m+k,d+k/2);l.lineTo(c+k/2,d-m+k);l.lineTo(c+m,d+k/2);l.closePath();l.fill();l.putImageData(e(l.getImageData(c+m,d+m,u,u),b),c+m,d+m)}var f=document.createElement("canvas"),l=f.getContext("2d"),h=f.width=250,p=f.height=290,k=(h-40)/3,m=.1*k,u=Math.floor(k-2*m),r=.5*u,v,x=[],I=!1;return function(c){if(v)c(v);else if(I)x.push(c);else{var e=d(),g=[];I=!0;x.push(c);for(var h in F.a.a)F.a.a[h].f||F.a.a[h].s||
-g.push({src:"api/avatar?user="+F.a.a[h].id});b(g,function(b){a(e,b);v=f.toDataURL();x.forEach(function(a){a(v)})})}}}();var T=0,G=null,P=null,R=null;function fb(a){var b=new XMLHttpRequest;b.timeout=6E4;b.onreadystatechange=function(){if(4===b.readyState)if(b.status){var c=null,d=2===Math.floor(b.status/100);if(d){T&&(T=0,Ga(!0));c=b.response;try{c=JSON.parse(c)}catch(e){c=null}}else T?(T+=Math.floor((T||5)/2),T=Math.min(60,T)):(T=5,Ga(!1));a(d,c)}else T&&(T=0,Ga(!0)),fb(a)};b.open("GET","api?v="+F.f,!0);b.send(null)}function Wa(){var a=new XMLHttpRequest;a.open("POST","api/typing?room="+G.id,!0);a.send(null)}
-function gb(a,b){a?(b&&F.update(b),Za()):setTimeout(Za,1E3*T)}function Za(){fb(gb)}function Sa(a){G&&document.getElementById("room_"+G.id).classList.remove("selected");document.getElementById("room_"+a.id).classList.add("selected");document.body.classList.remove("no-room-selected");G=a;Ha();G.a&&!F.b[G.id]&&(a=new XMLHttpRequest,a.open("GET","api/hist?room="+G.id,!0),a.send(null))}
-function Ua(a,b,c){var d=G;new FileReader;var e=new FormData,g=new XMLHttpRequest;e.append("file",b);e.append("filename",a);g.onreadystatechange=function(){4===g.readyState&&(204===g.status?c(null):c(g.statusText))};g.open("POST","api/file?room="+d.id);g.send(e)}
-function Va(a){if(R){var b=new XMLHttpRequest;b.open("PUT","api/msg?room="+G.id+"&ts="+R.id+"&text="+encodeURIComponent(a),!0);b.send(null);return!0}if("/"===a[0]){var c=a.indexOf(" "),b=-1===c?"":a.substr(c);return(a=F.a.j.data[a.substr(0,-1===c?void 0:c)])?(c=new XMLHttpRequest,c.open("POST","api/cmd?room="+G.id+"&cmd="+encodeURIComponent(a.name.substr(1))+"&args="+encodeURIComponent(b.trim()),!0),c.send(null),!0):!1}var b=G,c=P,d=new XMLHttpRequest;a="api/msg?room="+b.id+"&text="+encodeURIComponent(a);
-if(c){var e=F.a.a[c.F],g="Message";"C"===b.id[0]?g="Channel message":"D"===b.id[0]?g="Direct message":"G"===b.id[0]&&(g="Group message");a+="&attachments="+encodeURIComponent(JSON.stringify([{fallback:c.text,author_name:"<@"+e.id+"|"+e.name+">",text:c.text,footer:g,ts:c.o}]))}d.open("POST",a,!0);d.send(null);return!0}function Ra(a){var b=new XMLHttpRequest;b.open("DELETE","api/msg?room="+G.id+"&ts="+a.id,!0);b.send(null)}
-function Ka(a,b,c){var d=new XMLHttpRequest;d.open("POST","api/reaction?room="+a+"&msg="+b+"&reaction="+encodeURIComponent(c),!0);d.send(null)};function V(a,b,c,d){E.call(this,a,b,c,d)}V.prototype=Object.create(E.prototype);V.prototype.constructor=V;V.prototype.b=function(a,b){return!0===a.isMeMessage?new W(this.id,a,b):!0===a.isNotice?new X(this.id,a,b):new Y(this.id,a,b)};
-var Z=function(){function a(a){return ha(a,{A:F.a.b.a.A,S:function(a){":"===a[0]&&":"===a[a.length-1]&&(a=a.substr(1,a.length-2));if(a=La(a)){var b=document.createElement("span");b.className="emoji-small";b.appendChild(a);return b.outerHTML}return null},U:function(a){var b=a.indexOf("|");if(-1===b)var c=a;else{c=a.substr(0,b);var g=a.substr(b+1)}"@"===c[0]?(a=!0,(b=F.a.a[c.substr(1)])&&(g="@"+b.name)):"#"===c[0]?(a=!0,(b=F.a.l[c.substr(1)])&&(g="#"+b.name)):a=!1;return{link:c,text:g||c,Ea:a}}})}return{D:function(a){a.L=
-!0;return a},M:function(a){a.c&&a.c.parentElement&&(a.c.remove(),delete a.c);return a},K:function(a){a.c?a.L&&(a.L=!1,a.H()):a.$().H();return a.c},H:function(b){var c=F.a.a[b.F];b.c.o.innerHTML=K.ba(b.o);b.c.ha.innerHTML=a(b.text);b.c.aa.textContent=c?c.name:b.username||"?";for(var c=document.createDocumentFragment(),d=0,e=b.u.length;d<e;d++){var g=b.u[d];g&&(g=bb(b,g,d))&&c.appendChild(g)}b.c.u.textContent="";b.c.u.appendChild(c);c=b.b;d=document.createDocumentFragment();if(b.B)for(var f in b.B){var e=
-c,g=b.id,l=f,h=b.B[f],p=La(l);if(p){for(var k=document.createElement("li"),m=document.createElement("a"),u=document.createElement("span"),r=document.createElement("span"),v=[],x=0,I=h.length;x<I;x++){var C=F.a.a[h[x]];C&&v.push(C.name)}v.sort();r.textContent=v.join(", ");u.appendChild(p);u.className="emoji-small";m.href="javascript:toggleReaction('"+e+"', '"+g+"', '"+l+"')";m.appendChild(u);m.appendChild(r);k.className="slackmsg-reaction-item";k.appendChild(m);e=k}else console.warn("Reaction id not found: "+
-l),e=null;e&&d.appendChild(e)}b.c.B.textContent="";b.c.B.appendChild(d);b.R&&b.c.classList.add("edited");return b},I:function(a){return a.c.cloneNode(!0)},w:function(b,c){return a(c)}}}();function W(a,b,c){y.call(this,b,c);this.b=a;this.c=Z.c;this.L=Z.L}W.prototype=Object.create(z.prototype);n=W.prototype;n.constructor=W;n.D=function(){return Z.D(this)};n.w=function(a){return Z.w(this,a)};n.M=function(){return Z.M(this)};n.K=function(){return Z.K(this)};
-n.$=function(){this.c=$a(this);this.c.classList.add("slackmsg-me_message");return this};n.I=function(){return Z.I(this)};n.H=function(){Z.H(this);return this};n.update=function(a,b){z.prototype.update.call(this,a,b);this.D()};function Y(a,b,c){y.call(this,b,c);this.b=a;this.c=Z.c;this.L=Z.L}Y.prototype=Object.create(y.prototype);n=Y.prototype;n.constructor=Y;n.D=function(){return Z.D(this)};n.w=function(a){return Z.w(this,a)};n.M=function(){return Z.M(this)};n.K=function(){return Z.K(this)};
-n.$=function(){this.c=$a(this);return this};n.I=function(){return Z.I(this)};n.H=function(){Z.H(this);return this};n.update=function(a,b){y.prototype.update.call(this,a,b);this.D()};function X(a,b,c){y.call(this,b,c);this.b=a;this.a=null;this.L=!0}X.prototype=Object.create(B.prototype);n=X.prototype;n.constructor=X;n.D=function(){return Z.D(this)};n.w=function(a){return Z.w(this,a)};n.M=function(){this.a&&this.a.parentElement&&(this.a.remove(),delete this.a);this.c&&delete this.c;return this};
-n.K=function(){Z.K(this);return this.a};n.I=function(){return this.a.cloneNode(!0)};n.$=function(){this.c=$a(this);this.a=document.createElement("span");this.c.classList.add("slackmsg-notice");this.a.className="slackmsg-notice";this.a.textContent=K.ya;this.a.appendChild(this.c);return this};n.H=function(){Z.H(this);return this};n.update=function(a,b){B.prototype.update.call(this,a,b);this.D()};
+var p;function aa(a){this.id=a;this.version=0}aa.prototype.update=function(a,b){void 0!==a.name&&(this.name=a.name);this.version=Math.max(this.version,b)};function ba(a){this.a=a.desc;this.name=a.name;this.type=a.type;this.usage=a.usage;this.S=a.category}function ca(){this.fa={};this.u=[]}
+ca.prototype.update=function(a,b){this.fa=JSON.parse(a.emoji_use);a.highlight_words?this.u=(a.highlight_words||"").split(",").filter(function(a){return""!==a.trim()}):a.highlights&&(this.u=a.highlights);this.version=Math.max(this.version,b)};function da(){this.b=null;this.l={};this.m={};this.self=null;this.a={version:0,data:{}};this.i={version:0,data:{}};this.D={};this.A=0}
+function ea(a,b,c){var d=d||"";b.team&&(a.b||(a.b=new aa(b.team.id)),a.b.update(b.team,c));if(b.users)for(var e=0,g=b.users.length;e<g;e++){var f=a.m[d+b.users[e].id];f||(f=a.m[d+b.users[e].id]=new fa(b.users[e].id));f.update(b.users[e],c)}if(b.channels)for(e=0,g=b.channels.length;e<g;e++){f=a.l[d+b.channels[e].id];if(!f){var f=a.l,l=d+b.channels[e].id;var h=b.channels[e];h=h.pv?new q(h.id,a.m[h.user]):new r(h.id);f=f[l]=h}f.update(b.channels[e],a,c,d)}b.emojis&&(a.a.data=b.emojis,a.a.version=c);
+if(void 0!==b.commands){a.i.data={};for(e in b.commands)a.i.data[e]=new ba(b.commands[e]);a.i.version=c}a.A=Math.max(a.A,c);b.self&&(a.self=a.m[d+b.self.id]||null,a.self?(a.self.M||(a.self.M=new ca),a.self.M.update(b.self.prefs,c)):a.A=0);if(void 0!==b.typing)for(e in a.D={},b.typing){a.D[e]={};for(var n in b.typing[e])a.D[e][n]=c}}"undefined"!==typeof module&&(module.H.Ra=da,module.H.Sa=aa,module.H.Ua=ba);function r(a){this.id=a;this.I=!1;this.w=this.B=0;this.m={};this.version=0}
+r.prototype.update=function(a,b,c,d){d=d||"";void 0!==a.name&&(this.name=a.name);void 0!==a.is_archived&&(this.X=a.is_archived);void 0!==a.is_member&&(this.i=a.is_member);void 0!==a.last_read&&(this.B=Math.max(parseFloat(a.last_read),this.B));void 0!==a.last_msg&&(this.w=parseFloat(a.last_msg));void 0!==a.is_private&&(this.b=a.is_private);a.latest&&(this.w=parseFloat(a.latest.ts));void 0!==a.is_starred&&(this.I=a.is_starred);if(a.members&&(this.m={},a.members))for(var e=0,g=a.members.length;e<g;e++){var f=
+b.m[d+a.members[e]];this.m[f.id]=f;f.l[this.id]=this}this.version=Math.max(this.version,c)};function q(a,b){r.call(this,a);this.a=b;this.name=this.a.name;this.b=!0;b.Ja=this}q.prototype=Object.create(r.prototype);q.prototype.constructor=q;"undefined"!==typeof module&&(module.H.$a=r,module.H.Za=q);function x(a,b){this.G=a.user;this.username=a.username;this.id=a.id||a.ts;this.j=parseFloat(a.ts);this.text="";this.o=[];this.i=this.T=this.I=!1;this.C={};this.version=b;this.update(a,b)}function z(a,b){x.call(this,a,b)}function A(a,b){x.call(this,a,b)}
+x.prototype.update=function(a,b){if(a){if(this.text=a.text||"",a.attachments&&(this.o=a.attachments),this.I=!!a.is_starred,this.T=!!a.edited,this.i=!!a.removed,a.reactions){var c={};a.reactions.forEach(function(a){c[a.name]=[];a.users.forEach(function(b){c[a.name].push(b)})});this.C=c}}else this.i=!0;this.version=b};function B(a,b,c,d){this.id="string"===typeof a?a:a.id;this.a=[];this.i=b;c&&ga(this,c,d)}
+function ga(a,b,c){var d=0;b.forEach(function(a){d=Math.max(this.push(a,c),d)}.bind(a));ha(a)}B.prototype.b=function(a,b){return!0===a.isMeMessage?new z(a,b):!0===a.isNotice?new A(a,b):new x(a,b)};B.prototype.push=function(a,b){for(var c,d=!1,e,g=0,f=this.a.length;g<f;g++)if(c=this.a[g],c.id===a.id){e=c.update(a,b);d=!0;break}d||(c=this.b(a,b),this.a.push(c),e=c.j);for(;this.a.length>this.i;)this.a.shift();return e||0};function ia(a){return a.a[a.a.length-1]}
+function ja(a){for(var b=C.a[E.id],c=0,d=b.a.length;c<d&&a>=b.a[c].j;c++)if(b.a[c].j===a)return b.a[c];return null}function ha(a){a.a.sort(function(a,c){return a.j-c.j})}z.prototype=Object.create(x.prototype);z.prototype.constructor=z;A.prototype=Object.create(x.prototype);A.prototype.constructor=A;"undefined"!==typeof module&&(module.H={Wa:x,Va:z,Ya:A,ab:B});function fa(a){this.id=a;this.l={};this.Ja=this.M=null;this.version=0}fa.prototype.update=function(a,b){void 0!==a.name&&(this.name=a.name);void 0!==a.deleted&&(this.Ca=a.deleted);void 0!==a.status&&(this.status=a.status);void 0!==a.presence&&(this.a="away"!==a.presence);void 0!==a.isPresent&&(this.a=a.isPresent);a.isBot&&(this.Na=a.isBot);this.version=Math.max(this.version,b)};"undefined"!==typeof module&&(module.H.Ta=fa);function ka(){this.a=[]}ka.prototype.push=function(a){this.a.push(a)};function la(a,b){for(var c=0,d=a.a.length;c<d;c++){var e=a.a[c],g;for(g in e.l)if(!0===b(e.l[g],g))return}}function ma(a){for(var b=C.context,c=0,d=b.a.length;c<d&&!0!==a(b.a[c]);c++);}function F(a,b){for(var c=0,d=a.a.length;c<d;c++)if(a.a[c].l[b])return a.a[c];return null}function H(a){for(var b=C.context,c=0,d=b.a.length;c<d;c++){var e=b.a[c].l[a];if(e)return e}return null}
+function na(a){for(var b=C.context,c=[],d=0,e=b.a.length;d<e;d++){var g=b.a[d].l,f;for(f in g)a&&!a(g[f],b.a[d],f)||c.push(f)}return c}function I(a){for(var b=C.context,c=0,d=b.a.length;c<d;c++){var e=b.a[c].m[a];if(e)return e}return null}function oa(a){for(var b=C.context,c=0,d=b.a.length;c<d;c++)if(b.a[c].self.id===a)return!0;return!1}module.H.Xa=ka;var K={},L;function pa(){if(!c){for(var a=0,b=navigator.languages.length;a<b;a++)if(K.hasOwnProperty(navigator.languages[a])){var c=navigator.languages[a];break}c||(c="en")}L=K[c];console.log("Loading language pack: "+c);if(L.c)for(a in L.c)document.getElementById(a).textContent=L.c[a]};K.fr={Qa:"Utilisateur inconnu",Pa:"Channel inconnu",Fa:"Nouveau message",Ea:"Reseau",T:"(edit&eacute;)",Ga:"(visible seulement par vous)",I:"Favoris",l:"Discutions",Ia:"Discutions priv\u00e9es",ok:"Ok",Da:"Annuler",ga:function(a){"string"!==typeof a&&(a=parseFloat(a));var b=new Date,c=new Date;a=new Date(1E3*a);b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0);c.setTime(b.getTime());c.setDate(c.getDate()-1);return a.getTime()>b.getTime()?a.toLocaleTimeString():a.getTime()>c.getTime()?
+"hier, "+a.toLocaleTimeString():a.toLocaleString()},c:{fileUploadCancel:"Annuler",neterror:"Impossible de se connecter au chat !"}};K.en={Qa:"Unknown member",Pa:"Unknown channel",Fa:"New message",Ea:"Network",T:"(edited)",Ga:"(only visible to you)",I:"Starred",l:"Channels",Ia:"Direct messages",ok:"Ok",Da:"Cancel",ga:function(a){"string"!==typeof a&&(a=parseFloat(a));var b=new Date,c=new Date;a=new Date(1E3*a);b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0);c.setTime(b.getTime());c.setDate(c.getDate()-1);return a.getTime()>b.getTime()?a.toLocaleTimeString():a.getTime()>c.getTime()?"yesterday, "+a.toLocaleTimeString():
+a.toLocaleString()},c:{fileUploadCancel:"Cancel",neterror:"Cannot connect to chat !"}};var qa=function(){function a(a){this.text="";this.g=a}function b(b,c,d){this.P=c;this.f=null;this.h=[];this.a=d||"";this.aa="<"===this.a;this.la="*"===this.a;this.qa="_"===this.a;this.ba="~"===this.a||"-"===this.a;this.i=">"===this.a||"&gt;"===this.a;this.V=":"===this.a;this.ma="`"===this.a;this.Aa="```"===this.a;this.na="\n"===this.a;this.pa=void 0!==d&&-1!==n.u.indexOf(d);this.g=b;this.ca=null;this.b=this.na||this.pa?c+d.length-1:!1;this.pa&&(this.f=new a(this),this.h.push(this.f),this.f.text=d)}
+function c(a){return"A"<=a&&"Z">=a||"a"<=a&&"z">=a||"0"<=a&&"9">=a||-1!=="\u00e0\u00e8\u00ec\u00f2\u00f9\u00c0\u00c8\u00cc\u00d2\u00d9\u00e1\u00e9\u00ed\u00f3\u00fa\u00fd\u00c1\u00c9\u00cd\u00d3\u00da\u00dd\u00e2\u00ea\u00ee\u00f4\u00fb\u00c2\u00ca\u00ce\u00d4\u00db\u00e3\u00f1\u00f5\u00c3\u00d1\u00d5\u00e4\u00eb\u00ef\u00f6\u00fc\u00ff\u00c4\u00cb\u00cf\u00d6\u00dc\u0178\u00e7\u00c7\u00df\u00d8\u00f8\u00c5\u00e5\u00c6\u00e6\u0153".indexOf(a)}function d(a){a=a||h;for(var c=0,e=a.h.length;c<e;c++){var k=
+a.h[c];if(k instanceof b)if(k.b){if(k=d(k))return k}else return k}return null}function e(a,c){a.g instanceof b&&(a.g.h.splice(a.g.h.indexOf(a)+(c?1:0)),a.g.f=a.g.h[a.g.h.length-1],e(a.g,!0))}function g(a){return a}function f(a){return{link:a,text:a,Oa:!1}}var l,h,n={u:[],U:g,$:g,Y:f};b.prototype.sa=function(){return this.la&&!!this.b||this.g instanceof b&&this.g.sa()};b.prototype.va=function(){return this.qa&&!!this.b||this.g instanceof b&&this.g.va()};b.prototype.wa=function(){return this.ba&&!!this.b||
+this.g instanceof b&&this.g.wa()};b.prototype.ja=function(){return this.V&&!!this.b||this.g instanceof b&&this.g.ja()};b.prototype.ua=function(){return this.pa&&!!this.b||this.g instanceof b&&this.g.ua()};b.prototype.ta=function(){return this.ma&&!!this.b||this.g instanceof b&&this.g.ta()};b.prototype.ia=function(){return this.Aa&&!!this.b||this.g instanceof b&&this.g.ia()};b.prototype.xa=function(){for(var a=0,c=this.h.length;a<c;a++)if(this.h[a]instanceof b&&(!this.h[a].b||this.h[a].xa()))return!0;
+return!1};b.prototype.ya=function(a){if("<"===this.a&&">"===l[a])return!0;var b=c(l[a-1]);if(!this.i&&l.substr(a,this.a.length)===this.a){if(!b&&(this.la||this.qa||this.ba))return!1;if(this.f&&this.xa())return this.f.Ba();if(this.Ka())return!0}return"\n"===l[a]&&this.i?!0:!1};b.prototype.Ka=function(){for(var a=this;a;){for(var c=0,d=a.h.length;c<d;c++)if(a.h[c]instanceof b||a.h[c].text.length)return!0;a=a.ca}return!1};b.prototype.Ba=function(){var a=new b(this.g,this.P,this.a);a.ca=this;this.f&&
+this.f instanceof b&&(a.f=this.f.Ba(),a.h=[a.f]);return a};b.prototype.La=function(a){return this.V&&(" "===l[a]||"\t"===l[a])||(this.V||this.aa||this.la||this.qa||this.ba||this.ma)&&"\n"===l[a]?!1:!0};b.prototype.Ma=function(b){if(this.ma||this.V||this.Aa||this.aa)return null;if(!this.f||this.f.b||this.f instanceof a){var d=c(l[b+1]);if("```"===l.substr(b,3))return"```";var e=h.ka();if(void 0===e||e){if("&gt;"===l.substr(b,4))return"&gt;";if(">"===l[b])return l[b]}if(-1!==["`","\n"].indexOf(l[b])||
+-1!==["*","~","-","_"].indexOf(l[b])&&(d||-1!=="*~-_<&".split("").indexOf(l[b+1]))||-1!==[":"].indexOf(l[b])&&d||-1!==["<"].indexOf(l[b]))return l[b];d=0;for(e=n.u.length;d<e;d++){var f=n.u[d];if(l.substr(b,f.length)===f)return f}}return null};a.prototype.ka=function(){if(""!==this.text.trim())return!1};b.prototype.ka=function(){for(var a=this.h.length-1;0<=a;a--){var b=this.h[a].ka();if(void 0!==b)return b}if(this.na||this.i)return!0};a.prototype.A=function(a){this.text+=l[a];return 1};b.prototype.A=
+function(c){var d=this.f&&!this.f.b&&this.f.ya?this.f.ya(c):null;if(d){var e=this.f.a.length;this.f.ra(c);d instanceof b&&(this.f=d,this.h.push(d));return e}if(!this.f||this.f.b||this.f instanceof a||this.f.La(c)){if(d=this.Ma(c))return this.f=new b(this,c,d),this.h.push(this.f),this.f.a.length;if(!this.f||this.f.b)this.f=new a(this),this.h.push(this.f);return this.f.A(c)}d=this.f.P+1;h.ha(this.f.P);this.f=new a(this);this.f.A(d-1);this.h.pop();this.h.push(this.f);return d-c};b.prototype.ra=function(a){for(var b=
+this;b;)b.b=a,b=b.ca};b.prototype.ha=function(a){this.b&&this.b>=a&&(this.b=!1);this.h.forEach(function(c){c instanceof b&&c.ha(a)})};a.prototype.innerHTML=function(){var a;if(this.g.ja()){for(a=this.g;a&&!a.V;)a=a.g;if(a){var b=a.a+this.text+a.a;return(a=n.U(b))?a:b}return(a=n.U(this.text))?a:this.text}return this.g.ia()?this.text.replace(/\n/g,"<br/>"):n.$(this.text)};a.prototype.outerHTML=function(){var a="span",b=[],c="";if(this.g.ia()){b.push("codeblock");var d=this.innerHTML()}else this.g.ta()?
+(b.push("code"),d=this.innerHTML()):(this.g.aa&&(d=n.Y(this.text))?(a="a",c=' href="'+d.link+'"',d.bb&&(c+=' target="_blank"'),d=n.$(d.text)):d=this.innerHTML(),this.g.sa()&&b.push("bold"),this.g.va()&&b.push("italic"),this.g.wa()&&b.push("strike"),this.g.ja()&&b.push("emoji"),this.g.ua()&&b.push("highlight"));return"<"+a+c+(b.length?' class="'+b.join(" ")+'"':"")+">"+d+"</"+a+">"};b.prototype.outerHTML=function(){var a="";this.i&&(a+='<span class="quote">');this.na&&(a+="<br/>");this.h.forEach(function(b){a+=
+b.outerHTML()});this.i&&(a+="</span>");return a};b.prototype.za=function(a){this.i&&!this.b&&this.ra(a);this.h.forEach(function(c){c instanceof b&&c.za(a)})};return function(c,m){m||(m={});n.u=m.u||[];n.U=m.U||g;n.$=m.$||g;n.Y=m.Y||f;l=c;h=new b(this,0);m=0;c=l.length;do{for(;m<c;)m+=h.A(m);h.za(l.length);if(m=d()){e(m,!1);h.ha(m.P);var k=new a(m.g);k.A(m.P);m.g.h.push(k);m.g.f=k;m=m.P+1}else m=void 0}while(void 0!==m);return h.outerHTML()}}();
+window._formatText=function(a,b){return qa(a,{u:b?b.highlights:void 0})};"undefined"!==typeof module&&(module.H.s=qa);function ra(a,b){this.i=a;this.content=b;this.c=sa(this);this.b=ta(this);this.a=[];this.A=[]}
+function sa(a){var b=document.createElement("div"),c=document.createElement("header"),d=document.createElement("span"),e=document.createElement("span"),g=document.createElement("div"),f=document.createElement("footer");b.a=document.createElement("span");b.b=document.createElement("span");d.textContent=a.i;"string"==typeof a.content?g.innerHTML=a.content:g.appendChild(a.content);c.className=ua;d.className=va;e.className=wa;e.textContent="x";c.appendChild(d);c.appendChild(e);b.appendChild(c);g.className=
+xa;b.appendChild(g);b.b.className=ya;b.b.textContent=L.Da;b.b.addEventListener("click",function(){M(a,!1)});e.addEventListener("click",function(){M(a,!1)});b.a.addEventListener("click",function(){M(a,!0)});f.appendChild(b.b);b.a.className=ya;b.a.textContent=L.ok;f.appendChild(b.a);f.className=za+" "+Aa;b.appendChild(f);b.className=Ba;return b}function M(a,b){(b?a.a:a.A).forEach(function(a){a()});a.close()}
+function ta(a){var b=document.createElement("div");b.className=Ca;b.addEventListener("click",function(){M(this,!1)}.bind(a));return b}function Da(a,b,c){a.c.a.textContent=b;a.c.b.textContent=c;return a}ra.prototype.Z=function(a){a=a||document.body;a.appendChild(this.b);a.appendChild(this.c);return this};ra.prototype.close=function(){this.c.remove();this.b.remove();return this};function Ea(a,b){a.a.push(b);return a};var ya="button",za="button-container",Ba="dialog",Ca="dialog-overlay",ua="dialog-title",va="dialog-title-label",wa="dialog-title-close",xa="dialog-body",Aa="dialog-footer";var Fa=[],Ga=0;
+function Ha(){var a=document.createDocumentFragment(),b=na(function(a){return!a.X&&!1!==a.i}),c=[],d=[],e=[],g=[];b.sort(function(a,b){return a[0]!==b[0]?a[0]-b[0]:H(a).name.localeCompare(H(b).name)});b.forEach(function(a){a=H(a);if(a instanceof q){if(!a.a.Ca){var b=document.createElement("li");var f=document.createElement("a");b.id="room_"+a.id;f.href="#"+a.id;b.className="slack-context-room slack-ims";f.textContent=a.a.name;b.appendChild(Ia());b.appendChild(f);a.a.a||b.classList.add("away");E===
+a&&b.classList.add("selected");a.w>a.B&&(b.classList.add("unread"),0<=N.indexOf(a)&&b.classList.add("unreadHi"));b&&(a.I?c.push(b):g.push(b))}}else b=document.createElement("li"),f=document.createElement("a"),b.id="room_"+a.id,f.href="#"+a.id,a.b?(b.className="slack-context-room slack-group",b.dataset.count=Object.keys(a.m||{}).length):b.className="slack-context-room slack-channel",E===a&&b.classList.add("selected"),f.textContent=a.name,b.appendChild(Ia()),b.appendChild(f),a.w>a.B&&(b.classList.add("unread"),
+0<=N.indexOf(a)&&b.classList.add("unreadHi")),b&&(a.I?c.push(b):a.b?e.push(b):d.push(b))});c.length&&a.appendChild(Ja(L.I));c.forEach(function(b){a.appendChild(b)});d.length&&a.appendChild(Ja(L.l));d.forEach(function(b){a.appendChild(b)});e.forEach(function(b){a.appendChild(b)});g.length&&a.appendChild(Ja(L.Ia));g.forEach(function(b){a.appendChild(b)});document.getElementById("chanList").textContent="";document.getElementById("chanList").appendChild(a);Ka();O();P&&La(P.b.id,P.m,function(a){document.getElementById("slackCtx").style.backgroundImage=
+"url("+a+")"})}function Ma(){ma(function(a){var b=a.D,c;for(c in a.self.l)if(!a.self.l[c].X){var d=document.getElementById("room_"+c);b[c]?d.classList.add("slack-context-typing"):d.classList.remove("slack-context-typing")}for(var e in a.m)(c=a.m[e].Ja)&&!c.X&&(d=document.getElementById("room_"+c.id))&&(b[c.id]?d.classList.add("slack-context-typing"):d.classList.remove("slack-context-typing"))});Na()}
+function Na(){var a;document.getElementById("whoistyping").textContent="";if(P&&E&&(a=P.D[E.id])){var b=document.createDocumentFragment(),c=!1,d;for(d in a[E.id])(a=I(d))?b.appendChild(Oa(a)):c=!0;c&&(C.b=0);document.getElementById("whoistyping").appendChild(b)}}function Pa(a){a?document.body.classList.remove("no-network"):document.body.classList.add("no-network");O()}
+function Qa(){var a=E.name||(E.a?E.a.name:void 0);if(!a){var b=[];E.m.forEach(function(a){b.push(a.name)});a=b.join(", ")}document.getElementById("currentRoomTitle").textContent=a;Ra();R();document.getElementById("fileUploadContainer").classList.add("hidden");Sa();S&&(S=null,T());U&&(U=null,T());Na()}
+function T(){if(S){document.body.classList.add("replyingTo");var a=document.getElementById("replyToContainer"),b=document.createElement("a");b.addEventListener("click",function(){S=null;T()});b.className="replyto-close";b.textContent="x";a.textContent="";a.appendChild(b);a.appendChild(S.K())}else document.body.classList.remove("replyingTo"),document.getElementById("replyToContainer").textContent="";R()}
+function V(){if(U){document.body.classList.add("replyingTo");var a=document.getElementById("replyToContainer"),b=document.createElement("a");b.addEventListener("click",function(){U=null;V()});b.className="replyto-close";b.textContent="x";a.textContent="";a.appendChild(b);a.appendChild(U.K());document.getElementById("msgInput").value=U.text}else document.body.classList.remove("replyingTo"),document.getElementById("replyToContainer").textContent="";R()}
+window.toggleReaction=function(a,b,c){var d,e,g;if(g=d=C.a[a]){a:{var f=0;for(g=d.a.length;f<g;f++)if(d.a[f].id==b){d=d.a[f];break a}d=null}g=f=d}g&&(e=F(C.context,a))&&(f.C[c]&&-1!==f.C[c].indexOf(e.self.id)?(e=new XMLHttpRequest,e.open("DELETE","api/reaction?room="+a+"&msg="+b+"&reaction="+encodeURIComponent(c),!0),e.send(null)):Ta(a,b,c))};
+function Ua(a){a:{var b={};if(P){var c;for(c=P;!b[a];){if(c=c.a.data[a])if("alias:"==c.substr(0,6))b[a]=!0,a=c.substr(6);else{a=document.createElement("span");a.className="emoji-custom emoji";a.style.backgroundImage="url('"+c+"')";break a}break}}}"string"===typeof a&&"makeEmoji"in window&&(a=window.makeEmoji(a));return"string"===typeof a?null:a}function Va(a,b){document.getElementById("linkFavicon").href=a||b?"favicon.png?h="+a+"&m="+b:"favicon_ok.png"}
+function O(){var a=N.length,b="";if(W)b="!"+L.Ea+" - ",document.getElementById("linkFavicon").href="favicon_err.png";else if(a)b="(!"+a+") - ",Va(a,a);else{var c=0;la(C.context,function(a){a.w>a.B&&c++});c&&(b="("+c+") - ");Va(0,c)}C.context.b&&(b+=C.context.b.name);document.title=b}
+function Wa(){if("Notification"in window)if("granted"===Notification.permission){var a=Date.now();if(Ga+3E4<a){var b=new Notification(L.Fa);Ga=a;setTimeout(function(){b.close()},5E3)}}else"denied"!==Notification.permission&&Notification.requestPermission()}
+function Ra(){var a=document.createDocumentFragment(),b=E.id,c=null,d=0,e=null,g;Fa=[];C.a[b]&&C.a[b].a.forEach(function(b){if(b.i)b.O();else{var f=b.L(),h=!1;c&&c.G===b.G&&b.G?30>Math.abs(d-b.j)&&!(b instanceof z)?e.classList.add("slackmsg-same-ts"):d=b.j:(d=b.j,h=!0);(!c||c.j<=E.B)&&b.j>E.B?f.classList.add("slackmsg-first-unread"):f.classList.remove("slackmsg-first-unread");if(b instanceof z)e=c=null,d=0,a.appendChild(f),g=null;else{if(h||!g){var h=I(b.G),n=b.username,k=document.createElement("div"),
+m=document.createElement("div"),t=document.createElement("span");k.R=document.createElement("img");k.R.className="slackmsg-author-img";t.className="slackmsg-author-name";h?(t.textContent=h.name,k.R.src="api/avatar?user="+h.id):(t.textContent=n||"?",k.R.src="");m.appendChild(k.R);m.appendChild(t);m.className="slackmsg-author";k.className="slackmsg-authorGroup";k.appendChild(m);k.content=document.createElement("div");k.content.className="slackmsg-author-messages";k.appendChild(k.content);g=k;Fa.push(g);
+a.appendChild(g)}c=b;e=f;g.content.appendChild(f)}}});b=document.getElementById("chatWindow");b.textContent="";b.appendChild(a);b.scrollTop=b.scrollHeight-b.clientHeight;window.hasFocus&&Sa()}
+function Xa(a){function b(a,b){for(b=b||a.target;b!==a.currentTarget&&b;){if(b.classList.contains("slackmsg-item"))return b.id;b=b.parentElement}}for(var c,d,e=a.target;e!==a.currentTarget&&e&&!e.classList.contains("slackmsg-hover");){if(e.parentElement&&e.classList.contains("slackmsg-attachment-actions-item")){d=b(a,e);var g=e.dataset.attachmentIndex,f=e.dataset.actionIndex;if(d&&void 0!==g&&void 0!==f){d=parseFloat(d.split("_")[1]);(c=ja(d))&&c.o[g]&&c.o[g].actions&&c.o[g].actions[f]&&Ya(c,c.o[g],
+c.o[g].actions[f]);break}}if(e.parentElement&&e.parentElement.classList.contains("slackmsg-hover")){if(d=b(a,e))d=parseFloat(d.split("_")[1]),(c=ja(d))&&e.classList.contains("slackmsg-hover-reply")?(U&&(U=null,V()),S!==c&&(S=c,T())):c&&e.classList.contains("slackmsg-hover-reaction")?Za.Z(document.body,function(a){a&&Ta(E.id,c.id,a)}):c&&e.classList.contains("slackmsg-hover-edit")?(S&&(S=null,T()),U!==c&&(U=c,V())):c&&e.classList.contains("slackmsg-hover-remove")&&(S&&(S=null,T()),U&&(U=null,V()),
+$a(c));break}e=e.parentElement}}function Ya(a,b,c){function d(){var d=JSON.stringify({actions:[c],attachment_id:b.id,callback_id:b.callback_id,channel_id:e,is_ephemeral:a instanceof A,message_ts:a.id}),f=a.G,l=new FormData,h=new XMLHttpRequest;l.append("payload",d);l.append("service_id",f);h.open("POST","api/attachmentAction");h.send(l)}var e=E.id;c.confirm?Ea(Da(new ra(c.confirm.title,c.confirm.text),c.confirm.ok_text,c.confirm.dismiss_text),d).Z():d()}
+function R(){document.getElementById("msgInput").focus()}function Ka(){var a=document.location.hash.substr(1),b=H(a);b&&b!==E?ab(b):(a=I(a))&&a.b&&ab(a.b)}function bb(){var a=document.getElementById("chatWindow").getBoundingClientRect().top;Fa.forEach(function(b){var c=b.R,d=c.clientHeight;b=b.getBoundingClientRect();c.style.top=Math.max(0,Math.min(a-b.top,b.height-d-d/2))+"px"})}
+document.addEventListener("DOMContentLoaded",function(){pa();document.getElementById("chatWindow").addEventListener("click",Xa);window.addEventListener("hashchange",function(){document.location.hash&&"#"===document.location.hash[0]&&Ka()});document.getElementById("fileUploadCancel").addEventListener("click",function(a){a.preventDefault();document.getElementById("fileUploadError").classList.add("hidden");document.getElementById("fileUploadContainer").classList.add("hidden");document.getElementById("fileUploadInput").value=
+"";return!1});document.getElementById("fileUploadForm").addEventListener("submit",function(a){a.preventDefault();a=document.getElementById("fileUploadInput");var b=a.value;b&&(b=b.substr(b.lastIndexOf("\\")+1),cb(b,a.files[0],function(a){var b=document.getElementById("fileUploadError");a?(b.textContent=a,b.classList.remove("hidden")):(b.classList.add("hidden"),document.getElementById("fileUploadInput").value="",document.getElementById("fileUploadContainer").classList.add("hidden"))}));return!1});
+document.getElementById("attachFile").addEventListener("click",function(a){a.preventDefault();E&&document.getElementById("fileUploadContainer").classList.remove("hidden");return!1});document.getElementById("msgForm").addEventListener("submit",function(a){a.preventDefault();a=document.getElementById("msgInput");E&&a.value&&db(a.value)&&(a.value="",S&&(S=null,T()),U&&(U=null,T()),document.getElementById("slashList").textContent="");R();return!1});window.addEventListener("blur",function(){window.hasFocus=
+!1});window.addEventListener("focus",function(){window.hasFocus=!0;Ga=0;E&&Sa();R()});document.getElementById("chatWindow").addEventListener("scroll",bb);var a=0;document.getElementById("msgInput").addEventListener("input",function(){if(E){var b=Date.now();a+3E3<b&&(P.self.a||E instanceof q)&&(eb(),a=b);var c=[],b=this.value;if("/"===this.value[0]){var d=b.indexOf(" "),e=-1!==d,d=-1===d?b.length:d,g=b.substr(0,d);(P?P.i.data:[]).forEach(function(a){(!e&&a.name.substr(0,d)===g||e&&a.name===g)&&c.push(a)})}c.sort(function(a,
+b){return a.S.localeCompare(b.S)||a.name.localeCompare(b.name)});var b=document.getElementById("slashList"),f=document.createDocumentFragment();b.textContent="";for(var l=0,h=c.length;l<h;l++){var n=c[l];if(k!==n.S){var k=n.S;f.appendChild(fb(n.S))}f.appendChild(gb(n))}b.appendChild(f)}});window.hasFocus=!0;(function(){var a=document.getElementById("emojiButton");if("makeEmoji"in window){var c=window.makeEmoji("smile");c?a.innerHTML="<span class='emoji-small'>"+c.outerHTML+"</span>":a.style.backgroundImage=
+'url("smile.svg")';(c=window.makeEmoji("paperclip"))?document.getElementById("attachFile").innerHTML="<span class='emoji-small'>"+c.outerHTML+"</span>":document.getElementById("attachFile").style.backgroundImage='url("public/paperclip.svg")';a.addEventListener("click",function(){Za.Z(document.body,function(a){a&&(document.getElementById("msgInput").value+=":"+a+":");R()})})}else a.classList.add("hidden")})();hb()});function Ia(){var a=document.createElement("span"),b=document.createElement("span"),c=document.createElement("span"),d=document.createElement("span");a.className="typing-container";b.className="typing-dot1";c.className="typing-dot2";d.className="typing-dot3";b.textContent=c.textContent=d.textContent=".";a.appendChild(b);a.appendChild(c);a.appendChild(d);return a}var Ja=function(){var a={};return function(b){var c=a[b];c||(c=a[b]=document.createElement("header"),c.textContent=b);return c}}();
+function ib(a){var b=a.b,c=document.createElement("div"),d=document.createElement("div"),e=document.createElement("ul"),g=document.createElement("li");c.o=document.createElement("ul");c.C=document.createElement("ul");c.j=document.createElement("div");c.oa=document.createElement("div");c.ea=document.createElement("span");c.id=b+"_"+a.id;c.className="slackmsg-item";c.j.className="slackmsg-ts";c.oa.className="slackmsg-msg";c.ea.className="slackmsg-author-name";e.className="slackmsg-hover";g.className=
+"slackmsg-hover-reply";e.appendChild(g);if("makeEmoji"in window){var f=document.createElement("li"),l=window.makeEmoji("arrow_heading_down"),h=window.makeEmoji("smile"),n=window.makeEmoji("pencil2"),b=window.makeEmoji("x");f.className="slackmsg-hover-reaction";h?(f.classList.add("emoji-small"),f.appendChild(h)):f.style.backgroundImage='url("smile.svg")';l?(g.classList.add("emoji-small"),g.appendChild(l)):g.style.backgroundImage='url("repl.svg")';e.appendChild(f);oa(a.G)&&(a=document.createElement("li"),
+a.className="slackmsg-hover-edit",n?a.classList.add("emoji-small"):a.style.backgroundImage='url("edit.svg")',a.appendChild(n),e.appendChild(a),a=document.createElement("li"),a.className="slackmsg-hover-remove",b?a.classList.add("emoji-small"):a.style.backgroundImage='url("remove.svg")',a.appendChild(b),e.appendChild(a))}else g.style.backgroundImage='url("repl.svg")',oa(a.G)&&(a=document.createElement("li"),a.className="slackmsg-hover-edit",a.style.backgroundImage='url("edit.svg")',e.appendChild(a),
+a=document.createElement("li"),a.className="slackmsg-hover-remove",a.style.backgroundImage='url("remove.svg")',e.appendChild(a));d.appendChild(c.ea);d.appendChild(c.oa);d.appendChild(c.j);d.appendChild(c.o);b=document.createElement("div");b.innerHTML=L.T;b.className="slackmsg-edited";d.appendChild(b);d.appendChild(c.C);d.className="slackmsg-content";c.o.className="slackmsg-attachments";c.C.className="slackmsg-reactions";c.appendChild(d);c.appendChild(e);return c}
+function jb(a){var b={good:"#2fa44f",warning:"#de9e31",danger:"#d50200"};if(a){if("#"===a[0])return a;if(b[a])return b[a]}return"#e3e4e6"}
+function kb(a,b,c){var d=document.createElement("li"),e=document.createElement("div"),g=document.createElement("div"),f=document.createElement("a"),l=document.createElement("div"),h=document.createElement("img"),n=document.createElement("a"),k=document.createElement("div"),m=document.createElement("div"),t=document.createElement("div"),w=document.createElement("img"),v=document.createElement("div");d.className="slackmsg-attachment";e.style.borderColor=jb(b.color||"");e.className="slackmsg-attachment-block";
+g.className="slackmsg-attachment-pretext";b.pretext?g.innerHTML=a.s(b.pretext):g.classList.add("hidden");f.target="_blank";b.title?(f.innerHTML=a.s(b.title),b.title_link&&(f.href=b.title_link),f.className="slackmsg-attachment-title"):f.className="hidden slackmsg-attachment-title";n.target="_blank";l.className="slackmsg-author";b.author_name&&(n.innerHTML=a.s(b.author_name),n.href=b.author_link||"",n.className="slackmsg-author-name",h.className="slackmsg-author-img",b.author_icon&&(h.src=b.author_icon,
+l.appendChild(h)),l.appendChild(n));t.className="slackmsg-attachment-thumb";b.thumb_url?(h=document.createElement("img"),h.src=b.thumb_url,t.appendChild(h),e.classList.add("has-thumb"),b.video_html&&(t.dataset.video=b.video_html)):t.classList.add("hidden");k.className="slackmsg-attachment-content";h=a.s(b.text||"");m.className="slackmsg-attachment-text";h&&""!=h?m.innerHTML=h:m.classList.add("hidden");w.className="slackmsg-attachment-img";b.image_url?w.src=b.image_url:w.classList.add("hidden");v.className=
+"slackmsg-attachment-footer";b.footer&&(h=document.createElement("span"),h.className="slackmsg-attachment-footer-text",h.innerHTML=a.s(b.footer),b.footer_icon&&(n=document.createElement("img"),n.src=b.footer_icon,n.className="slackmsg-attachment-footer-icon",v.appendChild(n)),v.appendChild(h));b.ts&&(h=document.createElement("span"),h.className="slackmsg-ts",h.innerHTML=L.ga(b.ts),v.appendChild(h));k.appendChild(t);k.appendChild(m);e.appendChild(f);e.appendChild(l);e.appendChild(k);e.appendChild(w);
+if(b.fields&&b.fields.length){var u=document.createElement("ul");e.appendChild(u);u.className="slackmsg-attachment-fields";b.fields.forEach(function(b){var c=b.title||"",d=b.value||"";b=!!b["short"];var e=document.createElement("li"),g=document.createElement("div"),f=document.createElement("div");e.className="field";b||e.classList.add("field-long");g.className="field-title";g.textContent=c;f.className="field-text";f.innerHTML=a.s(d);e.appendChild(g);e.appendChild(f);e&&u.appendChild(e)})}if(b.actions&&
+b.actions.length)for(f=document.createElement("ul"),f.className="slackmsg-attachment-actions "+za,e.appendChild(f),l=0,k=b.actions.length;l<k;l++)(m=b.actions[l])&&(m=lb(c,l,m))&&f.appendChild(m);e.appendChild(v);d.appendChild(g);d.appendChild(e);return d}
+function lb(a,b,c){var d=document.createElement("li"),e=jb(c.style);d.textContent=c.text;e!==jb()&&(d.style.color=e);d.style.borderColor=e;d.dataset.attachmentIndex=a;d.dataset.actionIndex=b;d.className="slackmsg-attachment-actions-item "+ya;return d}function Oa(a){var b=document.createElement("li"),c=document.createElement("span");c.textContent=a.name;b.appendChild(Ia());b.appendChild(c);return b}
+function fb(a){var b=document.createElement("lh");b.textContent=a;b.className="slack-command-header";return b}
+function gb(a){var b=document.createElement("li"),c=document.createElement("span"),d=document.createElement("span"),e=document.createElement("span");c.textContent=a.name;d.textContent=a.usage;e.textContent=a.a;b.appendChild(c);b.appendChild(d);b.appendChild(e);b.className="slack-command-item";c.className="slack-command-name";d.className="slack-command-usage";e.className="slack-command-desc";return b};var Za=function(){function a(a,b){for(a=a.target;a!==h&&a&&"LI"!==a.nodeName;)a=a.parentElement;a&&"LI"===a.nodeName&&a.id&&"emojibar-"===a.id.substr(0,9)?b(a.id.substr(9)):b(null)}function b(){if(!c())return!1;D&&D(null);return!0}function c(){return h.parentElement?(h.parentElement.removeChild(n),h.parentElement.removeChild(h),!0):!1}function d(a){var b=0;a=void 0===a?w.value:a;if(l()){var c=window.searchEmojis(a);var d=e(c,Q.self.M.fa);for(var f in v)v[f].visible&&(v[f].visible=!1,m.removeChild(v[f].c));
+f=0;for(var h=d.length;f<h;f++){var y=d[f].name;var k=v[y];if(!k){k=v;var G=y,n=y;y=window.makeEmoji(c[y]);var D=document.createElement("span");D.appendChild(y);D.className="emoji-medium";y=g(n,D);k=k[G]=y}k.visible||(k.visible=!0,m.appendChild(k.c));b++}}for(f in u)u[f].visible&&(u[f].visible=!1,t.removeChild(u[f].c));d=e(Q.a.data,Q.self.M.fa);f=0;for(h=d.length;f<h;f++)y=d[f].name,""!==a&&y.substr(0,a.length)!==a||"alias:"===Q.a.data[y].substr(0,6)||(k=u[y],k||(c=u,G=k=y,y=Q.a.data[y],n=document.createElement("span"),
+D=document.createElement("span"),n.className="emoji emoji-custom",n.style.backgroundImage='url("'+y+'")',D.appendChild(n),D.className="emoji-medium",y=g(G,D),k=c[k]=y),k.visible||(k.visible=!0,t.appendChild(k.c)),b++);return b}function e(a,b){var c=[],d;for(d in a){var e={name:d,Ha:0,count:0};a[d].names&&a[d].names.forEach(function(a){e.count+=b[a]||0});c.push(e)}return c=c.sort(function(a,b){var c=b.count-a.count;return c?c:a.Ha-b.Ha})}function g(a,b){var c=document.createElement("li");c.appendChild(b);
+c.className="emojibar-list-item";c.id="emojibar-"+a;return{visible:!1,c:c}}function f(a){var b=document.createElement("img"),c=document.createElement("div");b.src=a;c.appendChild(b);c.className="emojibar-header";return c}function l(){return"searchEmojis"in window}var h=document.createElement("div"),n=document.createElement("div"),k=document.createElement("div"),m=document.createElement("ul"),t=document.createElement("ul"),w=document.createElement("input"),v={},u={},J=document.createElement("div"),
+G=document.createElement("span"),Z=document.createElement("span"),D,Q;n.addEventListener("click",function(a){var c=h.getBoundingClientRect();(a.screenY<c.top||a.screenY>c.bottom||a.screenX<c.left||a.screenX>c.right)&&b()});n.className="emojibar-overlay";h.className="emojibar";k.className="emojibar-emojis";J.className="emojibar-detail";G.className="emojibar-detail-img";Z.className="emojibar-detail-name";m.className=t.className="emojibar-list";w.className="emojibar-search";J.appendChild(G);J.appendChild(Z);
+k.appendChild(f(window.emojiProviderHeader));k.appendChild(m);k.appendChild(f("emojicustom.png"));k.appendChild(t);h.appendChild(k);h.appendChild(J);h.appendChild(w);w.addEventListener("keyup",function(){d()});h.addEventListener("mousemove",function(b){a(b,function(a){var b=a?v[a]||u[a]:null;b?(G.innerHTML=b.c.outerHTML,Z.textContent=":"+a+":"):(G.textContent="",Z.textContent="")})});h.addEventListener("click",function(b){a(b,function(a){a&&c()&&D&&D(a)})});return{isSupported:l,Z:function(a,b,c){return l()?
+(Q=b,D=c,a.appendChild(n),a.appendChild(h),w.value="",d(),w.focus(),!0):!1},search:d,close:b}}();var C,N=[];function mb(){da.call(this)}mb.prototype=Object.create(da.prototype);mb.prototype.constructor=mb;function nb(a){return a.b?a.b.id:null}function ob(){this.b=0;this.context=new ka;this.a={}}
+ob.prototype.update=function(a){var b,c=Date.now();a.v&&(this.b=a.v);if(a["static"])for(var d in a["static"])(b=this.context[d])||(b=this.context[d]=new mb),ea(b,a["static"],c);la(this.context,function(a){a.w===a.B&&(a=N.indexOf(a),-1!==a&&N.splice(a,1))});if(a.live){for(d in a.live)(b=this.a[d])?ga(b,a.live[d],c):b=this.a[d]=new X(d,250,a.live[d],c);for(var e in a.live)b=F(this.context,e),(c=b.l[e])?(this.a[e].a.length&&(c.w=Math.max(c.w,ia(this.a[e]).j)),c.X||(pb(b,c,a.live[e]),E&&a.live[E.id]&&
+Ra())):C.b=0}if(a["static"])for(d in Ha(),a["static"])if(a["static"][d].typing){Ma();break}};setInterval(function(){var a=C.context,b=Date.now(),c=!1,d;for(d in a.D){var e=!0,g;for(g in a.D[d])a.D[d][g]+3E3<b?(delete a.D[d][g],c=!0):e=!1;e&&(delete a.D[d],c=!0)}c&&Ma()},1E3);
+function pb(a,b,c){if(b!==E||!window.hasFocus){var d=new RegExp("<@"+a.self.id),e=!1,g=!1,f=!1;c.forEach(function(c){if(!(parseFloat(c.ts)<=b.B)){g=!0;var h;if(!(h=b instanceof q)&&(h=c.text)&&!(h=c.text.match(d)))a:{h=a.self.M.u;for(var l=0,k=h.length;l<k;l++)if(-1!==c.text.indexOf(h[l])){h=!0;break a}h=!1}h&&(-1===N.indexOf(b)&&(f=!0,N.push(b)),e=!0)}});if(g){O();if(c=document.getElementById("room_"+b.id))c.classList.add("unread"),e&&c.classList.add("unreadHi");f&&!window.hasFocus&&Wa()}}}
+function Sa(){var a=E,b=N.indexOf(a);if(a.w>a.B){var c=new XMLHttpRequest;c.open("POST","api/markread?room="+a.id+"&ts="+a.w,!0);c.send(null);a.B=a.w}0<=b&&(N.splice(b,1),O());a=document.getElementById("room_"+a.id);a.classList.remove("unread");a.classList.remove("unreadHi")}C=new ob;var La=function(){function a(a,b){b.sort(function(){return Math.random()-.5});for(var c=0,d=20;d<h-40;d+=k)for(var e=0;e+k<=n;e+=k)g(a,b[c],d,e),c++,c===b.length&&(b.sort(function(a,b){return a.W?b.W?Math.random()-.5:-1:1}),c=0)}function b(a,d){for(var e=0,f=a.length;e<f;e++)if(void 0===a[e].W){c(a[e].src,function(c){a[e].W=c;b(a,d)});return}var g=[];a.forEach(function(a){a.W&&g.push(a.W)});d(g)}function c(a,b){var c=new XMLHttpRequest;c.responseType="blob";c.onreadystatechange=function(){if(4===
+c.readyState)if(c.response){var a=new Image;a.onload=function(){var c=document.createElement("canvas");c.height=c.width=w;c=c.getContext("2d");c.drawImage(a,0,0,w,w);for(var c=c.getImageData(0,0,w,w),d=0,e=0;e<c.width*c.height*4;e+=4)c.data[e]=c.data[e+1]=c.data[e+2]=(c.data[e]+c.data[e+1]+c.data[e+2])/3,c.data[e+3]=50,d+=c.data[e];if(50>d/(c.height*c.width))for(e=0;e<c.width*c.height*4;e+=4)c.data[e]=c.data[e+1]=c.data[e+2]=255-c.data[e];b(c)};a.onerror=function(){b(null)};a.src=window.URL.createObjectURL(c.response)}else b(null)};
+c.open("GET",a,!0);c.send(null)}function d(){var a=l.createLinearGradient(0,0,0,n);a.addColorStop(0,"#4D394B");a.addColorStop(1,"#201820");l.fillStyle=a;l.fillRect(0,0,h,n);return l.getImageData(0,0,h,n)}function e(a,b){for(var c=(a.height-b.height)/2,d=0;d<b.height;d++)for(var e=0;e<b.width;e++){var f=b.data[4*(d*b.width+e)]/255,g=4*((d+c)*a.width+e+c);a.data[g]*=f;a.data[g+1]*=f;a.data[g+2]*=f}return a}function g(a,b,c,d){var f=Math.floor(d);a=[a.data[f*h*4+0],a.data[f*h*4+1],a.data[f*h*4+2]];l.fillStyle=
+"#"+(1.1*a[0]<<16|1.1*a[1]<<8|1.1*a[2]).toString(16);l.beginPath();l.moveTo(c+k/2,d+m);l.lineTo(c-m+k,d+k/2);l.lineTo(c+k/2,d-m+k);l.lineTo(c+m,d+k/2);l.closePath();l.fill();l.putImageData(e(l.getImageData(c+m,d+m,t,t),b),c+m,d+m)}var f=document.createElement("canvas"),l=f.getContext("2d"),h=f.width=250,n=f.height=290,k=(h-40)/3,m=.1*k,t=Math.floor(k-2*m),w=.5*t,v={},u={},J={};return function(c,e,g){if(v[c])g(v);else if(J[c])u[c]?u[c].push(g):u[c]=[g];else{var h=d(),l=[];J[c]=!0;u[c]?u[c].push(g):
+u[c]=[g];for(var k in e)e[k].Ca||e[k].Na||l.push({src:"api/avatar?user="+e[k].id});b(l,function(b){a(h,b);v[c]=f.toDataURL();u[c].forEach(function(a){a()})})}}}();var W=0,E=null,P=null,S=null,U=null;function qb(){var a=new XMLHttpRequest;a.open("GET","api/hist?room="+E.id,!0);a.send(null)}
+function rb(a){var b=new XMLHttpRequest;b.timeout=6E4;b.onreadystatechange=function(){if(4===b.readyState)if(b.status){var c=null,d=2===Math.floor(b.status/100);if(d){W&&(W=0,Pa(!0));c=b.response;try{c=JSON.parse(c)}catch(e){c=null}}else W?(W+=Math.floor((W||5)/2),W=Math.min(60,W)):(W=5,Pa(!1));a(d,c)}else W&&(W=0,Pa(!0)),rb(a)};b.open("GET","api?v="+C.b,!0);b.send(null)}function eb(){var a=new XMLHttpRequest;a.open("POST","api/typing?room="+E.id,!0);a.send(null)}
+function sb(a,b){a?(b&&C.update(b),hb()):setTimeout(hb,1E3*W)}function hb(){rb(sb)}function ab(a){E&&document.getElementById("room_"+E.id).classList.remove("selected");document.getElementById("room_"+a.id).classList.add("selected");document.body.classList.remove("no-room-selected");E=a;P=F(C.context,a.id);Qa();La(P.b.id,P.m,function(a){document.getElementById("slackCtx").style.backgroundImage="url("+a+")"});E.w&&!C.a[E.id]&&qb()}
+function cb(a,b,c){var d=E;new FileReader;var e=new FormData,g=new XMLHttpRequest;e.append("file",b);e.append("filename",a);g.onreadystatechange=function(){4===g.readyState&&(204===g.status?c(null):c(g.statusText))};g.open("POST","api/file?room="+d.id);g.send(e)}
+function db(a){if(U){var b=new XMLHttpRequest;b.open("PUT","api/msg?room="+E.id+"&ts="+U.id+"&text="+encodeURIComponent(a),!0);b.send(null);return!0}if("/"===a[0]){var c=a.indexOf(" "),b=a.substr(0,-1===c?void 0:c);a=-1===c?"":a.substr(c);return(b=(c=P)?c.i.data[b]:null)?(c=new XMLHttpRequest,c.open("POST","api/cmd?room="+E.id+"&cmd="+encodeURIComponent(b.name.substr(1))+"&args="+encodeURIComponent(a.trim()),!0),c.send(null),!0):!1}var b=E,c=S,d=new XMLHttpRequest;a="api/msg?room="+b.id+"&text="+
+encodeURIComponent(a);if(c){var e=I(c.G);a+="&attachments="+encodeURIComponent(JSON.stringify([{fallback:c.text,author_name:"<@"+e.id+"|"+e.name+">",text:c.text,footer:b.b?"Private message":b.name,ts:c.j}]))}d.open("POST",a,!0);d.send(null);return!0}function $a(a){var b=new XMLHttpRequest;b.open("DELETE","api/msg?room="+E.id+"&ts="+a.id,!0);b.send(null)}function Ta(a,b,c){var d=new XMLHttpRequest;d.open("POST","api/reaction?room="+a+"&msg="+b+"&reaction="+encodeURIComponent(c),!0);d.send(null)};function X(a,b,c,d){B.call(this,a,b,c,d)}X.prototype=Object.create(B.prototype);X.prototype.constructor=X;X.prototype.b=function(a,b){return!0===a.isMeMessage?new tb(this.id,a,b):!0===a.isNotice?new ub(this.id,a,b):new vb(this.id,a,b)};
+var Y=function(){function a(a,c){return qa(c,{u:a.context.self.M.u,U:function(a){":"===a[0]&&":"===a[a.length-1]&&(a=a.substr(1,a.length-2));if(a=Ua(a)){var b=document.createElement("span");b.className="emoji-small";b.appendChild(a);return b.outerHTML}return null},Y:function(b){a:{var c=b.indexOf("|");if(-1===c)var d=b;else{d=b.substr(0,c);var f=b.substr(c+1)}if("@"===d[0])if(d=nb(a.context)+"|"+d.substr(1),f=I(d))b=!0,f="@"+f.name;else{d=null;break a}else if("#"===d[0])if(d=nb(a.context)+"|"+d.substr(1),
+f=H(d))b=!0,f="#"+f.name;else{d=null;break a}else b=!1;d={link:d,text:f||d,Oa:b}}return d}})}return{F:function(a){a.N=!0;return a},O:function(a){a.c&&a.c.parentElement&&(a.c.remove(),delete a.c);return a},L:function(a){a.c?a.N&&(a.N=!1,a.J()):a.da().J();return a.c},J:function(b){var c=I(b.G);b.c.j.innerHTML=L.ga(b.j);b.c.oa.innerHTML=a(b,b.text);b.c.ea.textContent=c?c.name:b.username||"?";for(var c=document.createDocumentFragment(),d=0,e=b.o.length;d<e;d++){var g=b.o[d];g&&(g=kb(b,g,d))&&c.appendChild(g)}b.c.o.textContent=
+"";b.c.o.appendChild(c);c=b.b;d=document.createDocumentFragment();if(b.C)for(var f in b.C){var e=c,g=b.id,l=f,h=b.C[f],n=Ua(l);if(n){for(var k=document.createElement("li"),m=document.createElement("a"),t=document.createElement("span"),w=document.createElement("span"),v=[],u=0,J=h.length;u<J;u++){var G=I(h[u]);G&&v.push(G.name)}v.sort();w.textContent=v.join(", ");t.appendChild(n);t.className="emoji-small";m.href="javascript:toggleReaction('"+e+"', '"+g+"', '"+l+"')";m.appendChild(t);m.appendChild(w);
+k.className="slackmsg-reaction-item";k.appendChild(m);e=k}else console.warn("Reaction id not found: "+l),e=null;e&&d.appendChild(e)}b.c.C.textContent="";b.c.C.appendChild(d);b.T&&b.c.classList.add("edited");return b},K:function(a){return a.c.cloneNode(!0)},s:function(b,c){return a(b,c)}}}();function tb(a,b,c){x.call(this,b,c);this.context=F(C.context,a);this.b=a;this.c=Y.c;this.N=Y.N}tb.prototype=Object.create(z.prototype);p=tb.prototype;p.constructor=tb;p.F=function(){return Y.F(this)};
+p.s=function(a){return Y.s(this,a)};p.O=function(){return Y.O(this)};p.L=function(){return Y.L(this)};p.da=function(){this.c=ib(this);this.c.classList.add("slackmsg-me_message");return this};p.K=function(){return Y.K(this)};p.J=function(){Y.J(this);return this};p.update=function(a,b){z.prototype.update.call(this,a,b);this.F()};function vb(a,b,c){x.call(this,b,c);this.context=F(C.context,a);this.b=a;this.c=Y.c;this.N=Y.N}vb.prototype=Object.create(x.prototype);p=vb.prototype;p.constructor=vb;p.F=function(){return Y.F(this)};
+p.s=function(a){return Y.s(this,a)};p.O=function(){return Y.O(this)};p.L=function(){return Y.L(this)};p.da=function(){this.c=ib(this);return this};p.K=function(){return Y.K(this)};p.J=function(){Y.J(this);return this};p.update=function(a,b){x.prototype.update.call(this,a,b);this.F()};function ub(a,b,c){x.call(this,b,c);this.context=F(C.context,a);this.b=a;this.a=null;this.N=!0}ub.prototype=Object.create(A.prototype);p=ub.prototype;p.constructor=ub;p.F=function(){return Y.F(this)};
+p.s=function(a){return Y.s(this,a)};p.O=function(){this.a&&this.a.parentElement&&(this.a.remove(),delete this.a);this.c&&delete this.c;return this};p.L=function(){Y.L(this);return this.a};p.K=function(){return this.a.cloneNode(!0)};p.da=function(){this.c=ib(this);this.a=document.createElement("span");this.c.classList.add("slackmsg-notice");this.a.className="slackmsg-notice";this.a.textContent=L.Ga;this.a.appendChild(this.c);return this};p.J=function(){Y.J(this);return this};
+p.update=function(a,b){A.prototype.update.call(this,a,b);this.F()};
 })();

+ 3 - 3
srv/src/context.js

@@ -103,13 +103,13 @@ function ChatContext() {
     this.users = {};
 
     /** @type {Chatter} */
-    this.self = null; // FIXME move to team
+    this.self = null;
 
     /** @type {{version: number, data: Object.<string, string>}} */
-    this.emojis = { version: 0, data: {} }; // FIXME move to team
+    this.emojis = { version: 0, data: {} };
 
     /** @type {{version: number, data: Object.<string, Command>}} */
-    this.commands = {version: 0, data: {} }; // FIXME move to team
+    this.commands = {version: 0, data: {} };
 
     /** @type {Object.<string, Object.<string, number>>} */
     this.typing = {};

+ 8 - 8
srv/src/httpServ.js

@@ -130,7 +130,7 @@ Server.prototype.onRequest = function(req, res) {
             } else {
                 var ctx = res.chatContext.getChannelContext(req.urlObj.queryTokens.room[0]);
                 if (ctx) {
-                    ctx.fetchHistory(ctx.getChannel[targetId]);
+                    ctx.fetchHistory(ctx.channels[targetId]);
                     res.writeHeader("204", "No Content");
                 } else {
                     res.writeHeader("404", "Channel not found");
@@ -148,7 +148,7 @@ Server.prototype.onRequest = function(req, res) {
                 if (!ctx) {
                     res.writeHeader("404", "Chan not found");
                 } else {
-                    ctx.sendTyping(ctx.getChannel(req.urlObj.queryTokens.room[0]));
+                    ctx.sendTyping(ctx.channels[req.urlObj.queryTokens.room[0]);
                     res.writeHeader("204", "No Content");
                 }
                 res.end();
@@ -170,7 +170,7 @@ Server.prototype.onRequest = function(req, res) {
                     var args = req.urlObj.queryTokens.args ? req.urlObj.queryTokens.args[0] : "";
                     if (args === true)
                         args = "";
-                    ctx.sendCommand(ctx.getChannel(req.urlObj.queryTokens.room[0]), cmd, args);
+                    ctx.sendCommand(ctx.channels[req.urlObj.queryTokens.room[0]], cmd, args);
                     res.writeHeader("204", "No Content");
                 }
                 res.end();
@@ -188,7 +188,7 @@ Server.prototype.onRequest = function(req, res) {
                 } else if (isNaN(ts)) {
                     res.writeHeader("400", "Invalid date");
                 } else {
-                    ctx.markRead(ctx.getChannel(req.urlObj.queryTokens.room[0]), ts);
+                    ctx.markRead(ctx.channels[req.urlObj.queryTokens.room[0]], ts);
                     res.writeHeader("204", "No Content");
                 }
                 res.end();
@@ -233,9 +233,9 @@ Server.prototype.onRequest = function(req, res) {
                             catch (e) {}
                         }
                         if (req.urlObj.queryTokens.me)
-                            ctx.sendMeMsg(ctx.getChannel(req.urlObj.queryTokens.room[0]), req.urlObj.queryTokens.text);
+                            ctx.sendMeMsg(ctx.channels[req.urlObj.queryTokens.room[0]], req.urlObj.queryTokens.text);
                         else
-                            ctx.sendMsg(ctx.getChannel(req.urlObj.queryTokens.room[0]), req.urlObj.queryTokens.text, attachments);
+                            ctx.sendMsg(ctx.channels[req.urlObj.queryTokens.room[0]], req.urlObj.queryTokens.text, attachments);
                         res.writeHeader("204", "No Content");
                     } else {
                         res.writeHeader("404", "Channel not found");
@@ -247,7 +247,7 @@ Server.prototype.onRequest = function(req, res) {
                 } else {
                     var ctx = res.chatContext.getChannelContext(req.urlObj.queryTokens.room[0]);
                     if (chan) {
-                        ctx.removeMsg(ctx.getChannel(req.urlObj.queryTokens.room[0]), req.urlObj.queryTokens.ts[0]);
+                        ctx.removeMsg(ctx.channels[req.urlObj.queryTokens.room[0]], req.urlObj.queryTokens.ts[0]);
                         res.writeHeader("204", "No Content");
                     } else {
                         res.writeHeader("404", "Channel not found");
@@ -259,7 +259,7 @@ Server.prototype.onRequest = function(req, res) {
                 } else {
                     var ctx = res.chatContext.getChannelContext(req.urlObj.queryTokens.room[0]);
                     if (ctx) {
-                        ctx.editMsg(ctx.getChannel(req.urlObj.queryTokens.room[0]), req.urlObj.queryTokens.ts[0], req.urlObj.queryTokens.text);
+                        ctx.editMsg(ctx.channels[req.urlObj.queryTokens.room[0]], req.urlObj.queryTokens.ts[0], req.urlObj.queryTokens.text);
                         res.writeHeader("204", "No Content");
                     } else {
                         res.writeHeader("404", "Channel not found");

+ 88 - 34
srv/src/multichatManager.js

@@ -3,12 +3,7 @@
 function ChatSystem() {
 };
 
-/**
- * @param {string} chanId
- * @return {boolean}
-**/
-ChatSystem.prototype.chanExists = function(chanId) {};
-
+/** */
 ChatSystem.prototype.onRequest = function() {};
 
 /**
@@ -17,22 +12,9 @@ ChatSystem.prototype.onRequest = function() {};
 ChatSystem.prototype.getId = function() {};
 
 /**
- * @param {string} chanId
- * @return {Room}
-**/
-ChatSystem.prototype.getChannel = function(chanId) {};
-
-/**
- * @param {string} userId
- * @return {boolean}
-**/
-ChatSystem.prototype.userExists = function(userId) {};
-
-/**
- * @param {string} userId
- * @return {Chatter}
+ * @return {ChatContext}
 **/
-ChatSystem.prototype.getUser = function(userId) {};
+ChatSystem.prototype.getChatContext = function() {};
 
 /**
  * Async fetch history
@@ -84,7 +66,7 @@ ChatSystem.prototype.removeReaction = function(chan, ts, reaction) {};
  * Add reaction
  * @param {Room} chan
  * @param {string} contentType
- * @param {function(string|null)} callback
+ * @param {function((string|null))} callback
 **/
 ChatSystem.prototype.openUploadFileStream = function(chan, contentType, callback) {};
 
@@ -112,10 +94,17 @@ ChatSystem.prototype.markRead = function(chan, ts) {};
 **/
 ChatSystem.prototype.sendCommand = function(chan, cmd, args) {};
 
+/**
+ * @param {number} knownVersion
+ * @return {Object|null}
+**/
+ChatSystem.prototype.poll = function(knownVersion) {};
+
 /**
  * @constructor
 **/
 function MultiChatManager() {
+    /** @type {Array<ChatSystem>} */
     this.contexts = [];
 }
 
@@ -126,33 +115,98 @@ MultiChatManager.prototype.push = function(chatSystem) {
     this.contexts.push(chatSystem);
 };
 
+/**
+ * You may want to return true to break the loop
+**/
+MultiChatManager.prototype.foreachChannels = function(cb) {
+    for (var i =0, nbCtx =this.contexts.length; i < nbCtx; i++) {
+        var ctx = this.contexts[i].getChatContext();
+        for (var chanId in ctx.channels)
+            if (cb(ctx.channels[chanId], chanId) === true)
+                return;
+    }
+};
+
+/**
+ * You may want to return true to break the loop
+**/
+MultiChatManager.prototype.foreachContext = function(cb) {
+    for (var i =0, nbCtx =this.contexts.length; i < nbCtx; i++)
+        if (cb(this.contexts[i].getChatContext()) === true)
+            return;
+};
+
 /**
  * @param {string} chanId
  * @return {ChatSystem|null}
 **/
 MultiChatManager.prototype.getChannelContext = function(chanId) {
-    for (let i =0, nbCtx = this.contexts.length; i < nbCtx; i++)
-        if (this.contexts[i].chanExists(chanId))
+    for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) {
+        var ctx = this.contexts[i].getChatContext();
+        if (ctx.channels[chanId])
             return this.contexts[i];
+    }
+    return null;
+};
+
+/**
+ * @param {string} chanId
+ * @return {Room|null}
+**/
+MultiChatManager.prototype.getChannel = function(chanId) {
+    for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) {
+        var chan = this.contexts[i].getChatContext().channels[chanId];
+        if (chan)
+            return chan;
+    }
     return null;
 };
 
+/**
+ * @param {function(Room, ChatSystem, string):boolean=} filter (room, roomId)
+ * @return {Array<string>}
+**/
+MultiChatManager.prototype.getChannelIds = function(filter) {
+    var ids = [];
+
+    for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) {
+        var channels = this.contexts[i].getChatContext().channels;
+        for (var chanId in channels) {
+            if (!filter || filter(channels[chanId], this.contexts[i], chanId)) {
+                ids.push(chanId);
+            }
+        }
+    }
+    return ids;
+};
+
 /**
  * @param {string} userId
  * @return {Chatter|null}
 **/
 MultiChatManager.prototype.getUser = function(userId) {
-    for (let i =0, nbCtx = this.contexts.length; i < nbCtx; i++) {
-        let chatter = this.contexts[i].getUser(userId);
-        if (chatter)
-            return chatter;
+    for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) {
+        var user = this.contexts[i].getChatContext().users[userId];
+        if (user)
+            return user;
     }
     return null;
 };
 
+/**
+ * @param {string} userId
+ * @return {boolean}
+**/
+MultiChatManager.prototype.isMe = function(userId) {
+    for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++)
+        if (this.contexts[i].getChatContext().self.id === userId)
+            return true;
+    return false;
+};
+
 MultiChatManager.prototype.poll = function(knownVersion, callback) {
-    this.contexts.forEach((ctx) => {
-        ctx.onRequest(knownVersion);
+    this.contexts.forEach(function(ctx) {
+        ctx.onRequest();
     });
     setTimeout((function() {
         var liveFeed = {}
@@ -160,14 +214,14 @@ MultiChatManager.prototype.poll = function(knownVersion, callback) {
             ,v = 0
             ,updated = false;
 
-        this.contexts.forEach((ctx) => {
-            let id = ctx.getId();
+        this.contexts.forEach(function(ctx) {
+            var id = ctx.getId();
             if (id) {
-                let res = ctx.poll(knownVersion);
+                var res = ctx.poll(knownVersion);
 
                 if (res) {
                     if (res["static"])
-                        staticFeed[ctx.getId()] = res["static"];
+                        staticFeed[id] = res["static"];
                     if (res["live"])
                         for (var i in res["live"])
                             liveFeed[i] = res["live"][i];

+ 10 - 17
srv/src/slack.js

@@ -50,6 +50,9 @@ const SLACK_ENDPOINT = "https://slack.com/api/"
     ] // Message type that affect live history
 ;
 
+/**
+ * @implements {ChatSystem}
+**/
 function Slack(sess, manager) {
     this.token = sess.slackToken;
     this.sessId = sess.id;
@@ -66,9 +69,9 @@ Slack.prototype.getId = function() {
     return this.data.team ? this.data.team.id : null;
 };
 
-Slack.prototype.onRequest = function(knownVersion) {
+Slack.prototype.onRequest = function() {
     if (this.connected === false) {
-        this.connect(knownVersion);
+        this.connect();
     }
 };
 
@@ -97,7 +100,7 @@ function httpsRequest(url, cb) {
     }
 }
 
-Slack.prototype.connect = function(knownVersion, cb) {
+Slack.prototype.connect = function(cb) {
     var _this = this;
 
     this.connected = undefined;
@@ -501,20 +504,6 @@ Slack.prototype.editMsg = function(channel, msgId, text) {
         +"&as_user=true");
 };
 
-/**
- * @return {SlackChan|SlackGroup|SlackIms}
-**/
-Slack.prototype.getChannel = function(chanId) {
-    return this.data.channels[chanId] || null;
-};
-
-/**
- * @return {boolean}
-**/
-Slack.prototype.chanExists = function(chanId) {
-    return !!this.data.channels[chanId];
-};
-
 /**
  * @param {SlackChan|SlackGroup|SlackIms} target
 **/
@@ -549,5 +538,9 @@ Slack.prototype.fetchHistory = function(target) {
     });
 };
 
+Slack.prototype.getChatContext = function() {
+    return this.data;
+};
+
 module.exports.Slack = Slack;
 

+ 1 - 0
srv/src/slackData.js

@@ -193,6 +193,7 @@ SlackBot.prototype.update = function(botData, t) {
 
 /**
  * @constructor
+ * @extends {ChatContext}
 **/
 function SlackData(slack) {
     ChatContext.call(this);