Jelajahi Sumber

[refactor] include presence in static fields
[add] send partial static informations
[add] lazy create context background

B Thibault 8 tahun lalu
induk
melakukan
75bd347cdf
10 mengubah file dengan 267 tambahan dan 277 penghapusan
  1. 22 13
      cli/contextBackground.js
  2. 4 21
      cli/data.js
  3. 4 10
      cli/ui.js
  4. 1 1
      cli/workflow.js
  5. 62 59
      srv/public/slack.min.js
  6. 1 1
      srv/public/style.css
  7. 0 1
      srv/src/httpServ.js
  8. 12 20
      srv/src/slack.js
  9. 148 137
      srv/src/slackData.js
  10. 13 14
      srv/src/slackHistory.js

+ 22 - 13
cli/contextBackground.js

@@ -16,7 +16,8 @@ var createContextBackground = (function() {
         /** @const */
         ,ITEM_INNER_SIZE = Math.floor(ITEM_SIZE -(ITEM_SPACING*2))
         /** @const */
-        ,AVATAR_SIZE = ITEM_INNER_SIZE * 0.5;
+        ,AVATAR_SIZE = ITEM_INNER_SIZE * 0.5
+        ,RESULT;
 
     var drawItem = function(background, avatar, x0, y0) {
         var y0Index = Math.floor(y0)
@@ -112,6 +113,9 @@ var createContextBackground = (function() {
                         imgCtx.drawImage(img, 0, 0, AVATAR_SIZE, AVATAR_SIZE);
                         cb(filterImage(imgCtx.getImageData(0, 0, AVATAR_SIZE, AVATAR_SIZE)));
                     };
+                    img.onerror = function() {
+                        cb(null);
+                    };
                     img.src = window.URL.createObjectURL(/** @type {Blob!} */ (xhr.response));
                 } else {
                     cb(null);
@@ -163,20 +167,25 @@ var createContextBackground = (function() {
     }
 
     return function(cb) {
-        var background = drawBackground()
-            ,userImgs = [];
+        if (RESULT) {
+            cb(RESULT);
+        } else {
+            var background = drawBackground()
+                ,userImgs = [];
+
+            for (var userId in SLACK.context.users) {
+                if (!SLACK.context.users[userId].deleted)
+                    userImgs.push({
+                        src: "api/avatar?user=" +userId
+                    });
+            }
 
-        for (var userId in SLACK.context.users) {
-            if (!SLACK.context.users[userId].deleted)
-                userImgs.push({
-                    src: "api/avatar?user=" +userId
-                });
+            loadImages(userImgs, function(imgs) {
+                renderAvatars(background, imgs);
+                RESULT = canvas.toDataURL();
+                cb(RESULT);
+            });
         }
-
-        loadImages(userImgs, function(imgs) {
-            renderAvatars(background, imgs);
-            cb(canvas.toDataURL());
-        });
     }
 })();
 

+ 4 - 21
cli/data.js

@@ -19,9 +19,6 @@ function SlackWrapper() {
     /** @type {number} */
     this.lastServerVersion = 0;
 
-    /** @type {number} */
-    this.lastUserVersion = 0;
-
     /** @type {SlackData} */
     this.context = new SlackData(null);
 
@@ -30,32 +27,20 @@ function SlackWrapper() {
 }
 
 SlackWrapper.prototype.update = function(data) {
+    var now = Date.now();
     if (data["v"])
         this.lastServerVersion = data["v"];
-    if (data["userV"])
-        this.lastUserVersion = data["userV"];
     if (data["static"]) {
-        this.context.updateStatic(data["static"]);
+        this.context.updateStatic(data["static"], 0);
         onContextUpdated();
     }
-    if (data["user"]) {
-        for (var userId in data["user"]) {
-            var member = this.context.getMember(userId);
-            if (member) {
-                member.onUserStream(data["user"][userId]);
-                onMemberChange(member);
-            } else {
-                this.lastUserVersion = this.lastServerVersion = -1;
-            }
-        }
-    }
     if (data["live"]) {
         for (var i in data["live"]) {
             var history = this.history[i];
             if (!history)
-                this.history[i] = new SlackHistory(i, 250, data["live"][i]);
+                this.history[i] = new SlackHistory(i, 250, data["live"][i], now);
             else
-                history.pushAll(data["live"][i]);
+                history.pushAll(data["live"][i], now);
         }
         for (var roomId in data["live"]) {
             var chan = this.context.getChannel(roomId);
@@ -65,8 +50,6 @@ SlackWrapper.prototype.update = function(data) {
                     if (SELECTED_ROOM && data["live"][SELECTED_ROOM.id])
                         onRoomUpdated();
                 }
-            } else {
-                this.lastUserVersion = this.lastServerVersion = 0;
             }
         }
     }

+ 4 - 10
cli/ui.js

@@ -40,6 +40,8 @@ function createChanListItem(chan) {
         dom.className = R.klass.chatList.entry + " " +R.klass.chatList.typeGroup;
     else if (chan.id[0] === 'C')
         dom.className = R.klass.chatList.entry + " " +R.klass.chatList.typeChannel;
+    if (SELECTED_ROOM === chan)
+        dom.classList.add(R.klass.selected);
     link.textContent = chan.name;
     dom.appendChild(link);
     return dom;
@@ -61,6 +63,8 @@ function createImsListItem(ims) {
 
     if (!ims.user.presence)
         dom.classList.add(R.klass.presenceAway);
+    if (SELECTED_ROOM === ims)
+        dom.classList.add(R.klass.selected);
     return dom;
 }
 
@@ -188,16 +192,6 @@ function onEditingUpdated() {
     }
 }
 
-function onMemberChange(member) {
-    var dom = document.getElementById(member.ims.id);
-    if (dom) {
-        if (member.presence)
-            dom.classList.remove(R.klass.presenceAway);
-        else
-            dom.classList.add(R.klass.presenceAway);
-    }
-}
-
 /**
  * @param {string} chanId
  * @param {string} msgId

+ 1 - 1
cli/workflow.js

@@ -60,7 +60,7 @@ function poll(callback) {
             callback(success, resp);
         }
     };
-    xhr.open('GET', 'api?v=' +SLACK.lastServerVersion +'&uv=' +SLACK.lastUserVersion, true);
+    xhr.open('GET', 'api?v=' +SLACK.lastServerVersion, true);
     xhr.send(null);
 }
 

+ 62 - 59
srv/public/slack.min.js

@@ -1,59 +1,62 @@
-function aa(a){this.id=a;this.a={S:"",U:"",W:"",X:"",L:"",M:"",O:"",Y:""}}function ba(a){this.id=a;this.a={}}function ca(a){this.id=a;this.a={}}function da(a,b){this.id=a;this.c=b}function ea(a){this.id=a;this.a={P:"",R:"",m:"",A:"",N:"",V:""};this.i={};this.c=this.b=null;this.version=0}function fa(){this.b={};this.a=[]}function ga(a,b){a.b=JSON.parse(b.emoji_use);b.highlight_words?a.a=(b.highlight_words||"").split(",").filter(function(a){return""!==a.trim()}):b.highlights&&(a.a=b.highlights)}
-function ha(a){this.id=a;this.a={T:"",m:"",A:""};this.c=this.b=null;this.version=0;this.f=!1}function p(){this.g=null;this.i={};this.B={};this.b={};this.c={};this.a=null;this.w={};this.f={}}function q(a,b){return a.c[b]||a.w[b]||null}function y(a,b){return a.i[b]||a.b[b]||a.B[b]||null}"undefined"!==typeof module&&(module.K.Z=p);function ia(a,b){this.j=a.user||a.bot_id;this.g=a.username;this.id=a.ts;this.b=b||parseFloat(a.ts);this.text=a.text||"";this.f=a.attachments||[];this.l=!!a.edited;this.c=a.removed||!1;this.i="me_message"===a.subtype||a.isMeMessage;this.a={};this.version=this.b;var c=this;a.reactions&&a.reactions.forEach(function(a){c.a[a.name]=[];a.users.forEach(function(b){c.a[a.name].push(b)})})}
-function ja(a,b,c){b?(a.text=b.text||"",b.attachments&&(a.f=b.attachments),a.l=!!b.edited,a.c=!!b.removed,b.reactions&&(a.a={},b.reactions.forEach(function(b){a.a[b.name]=[];b.users.forEach(function(c){a.a[b.name].push(c)})}))):a.c=!0;a.version=c}function z(a,b,c){this.id="string"===typeof a?a:a.id;this.a=[];this.b=b;c&&B(this,c)}function ka(a,b,c,d){var f=!1;a.a[b]&&(1===a.a[b].length&&a.a[b][0]===c?(delete a.a[b],f=!0):a.a[b]=a.a[b].filter(function(a){return a!==c?!1:f=!0}));f&&(a.version=d)}
-function B(a,b){var c=0;b.forEach(function(a){c=Math.max(this.push(a),c)}.bind(a));la(a)}
-z.prototype.push=function(a){var b=parseFloat(a.ts);if(a.type&&"message"!==a.type)if("reaction_added"===a.type){var c=C(this,a.item.ts);if(c){var d=a.reaction;a=a.user;c.a[d]||(c.a[d]=[]);c.a[d].push(a);c.version=b}}else if("reaction_removed"===a.type)(c=C(this,a.item.ts))&&ka(c,a.reaction,a.user,b);else return 0;else{var c=!1,d=a.ts,f=a;"message_changed"===a.subtype&&a.previous_message?(d=a.previous_message.ts,f=a.message):"message_deleted"===a.subtype&&a.previous_message&&(d=a.previous_message.ts,
-f=null);for(var e=0,l=this.a.length;e<l;e++)if(this.a[e].id===d){ja(this.a[e],f,b);c=!0;break}c||this.a.push(new ia(a,b))}for(;this.a.length>this.b;)this.a.shift();return b};function ma(a){for(var b=D.b[E.id],c=0,d=b.a.length;c<d&&a>=b.a[c].b;c++)if(b.a[c].b===a)return b.a[c];return null}function C(a,b){for(var c=0,d=a.a.length;c<d;c++)if(a.a[c].id==b)return a.a[c];return null}function la(a){a.a.sort(function(a,c){return a.b-c.b})}"undefined"!==typeof module&&(module.K.$=z);var F={},G;function na(){var a;if(!a){for(var b=0,c=navigator.languages.length;b<c;b++)if(F.hasOwnProperty(navigator.languages[b])){a=navigator.languages[b];break}a||(a="en")}G=F[a];console.log("Loading language pack: "+a);if(G.h)for(b in G.h)document.getElementById(b).textContent=G.h[b]};F.fr={J:"Utilisateur inconnu",I:"Channel inconnu",F:"Nouveau message",D:"Reseau",l:"edit&eacute;",u: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()},h:{fileUploadCancel:"Annuler",neterror:"Impossible de se connecter au chat !"}};F.en={J:"Unknown member",I:"Unknown channel",F:"New message",D:"Network",l:"edited",u: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()},h:{fileUploadCancel:"Cancel",neterror:"Cannot connect to chat !"}};var H=null,I=null,L=0;
-function oa(){var a=document.createDocumentFragment(),b=D.a.a?Object.keys(D.a.a.i):[];b.sort(function(a,b){return a[0]!==b[0]?a[0]-b[0]:y(D.a,a).name.localeCompare(y(D.a,b).name)});b.forEach(function(b){b=y(D.a,b);if(!b.b){var c=document.createElement("li"),f=document.createElement("a");c.id=b.id;f.href="#"+b.id;"D"===b.id[0]?c.className="slack-context-room slack-ims":"G"===b.id[0]?c.className="slack-context-room slack-group":"C"===b.id[0]&&(c.className="slack-context-room slack-channel");f.textContent=
-b.name;c.appendChild(f);c&&a.appendChild(c)}});b=D.a.c?Object.keys(D.a.c):[];b.sort(function(a,b){return D.a.c[a].name.localeCompare(D.a.c[b].name)});b.forEach(function(b){b=q(D.a,b);if(!b.g){b=b.b;var c=document.createElement("li"),f=document.createElement("a");c.id=b.id;f.href="#"+b.id;c.className="slack-context-room slack-ims";f.textContent=b.c.name;c.appendChild(f);b.c.f||c.classList.add("away");c&&a.appendChild(c)}});document.getElementById("chanList").textContent="";document.getElementById("chanList").appendChild(a);
-M();N();pa(function(a){document.getElementById("slackCtx").style.backgroundImage="url("+a+")"})}function O(a){a?document.body.classList.remove("no-network"):document.body.classList.add("no-network");N()}
-function P(){if(H){document.body.classList.add("replyingTo");var a=document.getElementById("replyToContainer"),b=document.createElement("a");b.addEventListener("click",function(){H=null;P()});b.className="replyto-close";b.textContent="x";a.textContent="";a.appendChild(b);a.appendChild(Q("reply_"+E.id,H,!0))}else document.body.classList.remove("replyingTo"),document.getElementById("replyToContainer").textContent="";R()}
-function S(){if(I){document.body.classList.add("replyingTo");var a=document.getElementById("replyToContainer"),b=document.createElement("a");b.addEventListener("click",function(){I=null;S()});b.className="replyto-close";b.textContent="x";a.textContent="";a.appendChild(b);a.appendChild(Q("edit_"+E.id,I,!0));document.getElementById("msgInput").value=I.text}else document.body.classList.remove("replyingTo"),document.getElementById("replyToContainer").textContent="";R()}
-function qa(a,b,c,d){var f=T(c);if(f){for(var e=document.createElement("li"),l=document.createElement("a"),g=document.createElement("span"),h=document.createElement("span"),m=[],k=0,n=d.length;k<n;k++){var u=q(D.a,d[k]);u&&m.push(u.name)}m.sort();h.textContent=m.join(", ");g.appendChild(f);g.className="emoji-small";l.href="javascript:toggleReaction('"+a+"', '"+b+"', '"+c+"')";l.appendChild(g);l.appendChild(h);e.className="slackmsg-reaction-item";e.appendChild(l);return e}return null}
-window.toggleReaction=function(a,b,c){var d=D.b[a];if(d&&(d=C(d,b))){var f=D.a.a.id;d.a[c]&&-1!==d.a[c].indexOf(f)?(d=new XMLHttpRequest,d.open("DELETE","api/reaction?room="+a+"&msg="+b+"&reaction="+encodeURIComponent(c),!0),d.send(null)):U(a,b,c)}};
-function V(a,b,c){var d=document.createElement("div"),f=document.createElement("div"),e=document.createElement("div"),l=document.createElement("div"),g=document.createElement("img"),h=document.createElement("span"),m=document.createElement("ul"),k=document.createElement("li"),n=document.createElement("ul"),u=document.createElement("ul"),r=q(D.a,b.j);d.id=a+"_"+b.b;d.className="slackmsg-item";e.className="slackmsg-ts";l.className="slackmsg-msg";g.className="slackmsg-author-img";h.className="slackmsg-author-name";
-m.className="slackmsg-hover";k.className="slackmsg-hover-reply";e.innerHTML=G.u(b.b);l.innerHTML=W(b.text);h.textContent=r?r.name:b.g||"?";g.src=r?r.a.m:"";m.appendChild(k);if("makeEmoji"in window){var w=document.createElement("li"),v=window.makeEmoji("arrow_heading_down"),x=window.makeEmoji("smile"),A=window.makeEmoji("pencil2"),r=window.makeEmoji("x");w.className="slackmsg-hover-reaction";x?(w.classList.add("emoji-small"),w.appendChild(x)):w.style.backgroundImage='url("smile.svg")';v?(k.classList.add("emoji-small"),
-k.appendChild(v)):k.style.backgroundImage='url("repl.svg")';m.appendChild(w);b.j===D.a.a.id&&(k=document.createElement("li"),k.className="slackmsg-hover-edit",A?k.classList.add("emoji-small"):k.style.backgroundImage='url("edit.svg")',k.appendChild(A),m.appendChild(k),k=document.createElement("li"),k.className="slackmsg-hover-remove",r?k.classList.add("emoji-small"):k.style.backgroundImage='url("remove.svg")',k.appendChild(r),m.appendChild(k))}else k.style.backgroundImage='url("repl.svg")',b.j===D.a.a.id&&
-(k=document.createElement("li"),k.className="slackmsg-hover-edit",k.style.backgroundImage='url("edit.svg")',m.appendChild(k),k=document.createElement("li"),k.className="slackmsg-hover-remove",k.style.backgroundImage='url("remove.svg")',m.appendChild(k));d.appendChild(g);f.appendChild(h);f.appendChild(l);f.appendChild(e);f.appendChild(n);b.l&&(e=document.createElement("div"),e.textContent=G.l,e.className="slackmsg-edited",f.appendChild(e));f.appendChild(u);f.className="slackmsg-content";n.className=
-"slackmsg-attachments";u.className="slackmsg-reactions";if(!0!==c){if(b.a)for(var t in b.a)(c=qa(a,b.id,t,b.a[t]))&&u.appendChild(c);b.f.forEach(function(a){var b=document.createElement("li"),c=document.createElement("div"),d=document.createElement("div"),e=document.createElement("a"),f=document.createElement("div"),g=document.createElement("img"),v=document.createElement("a"),h=document.createElement("div"),l=document.createElement("div"),w=document.createElement("img"),k=document.createElement("img"),
-t=document.createElement("div"),x=document.createElement("img"),r=document.createElement("span"),m=document.createElement("span");b.className="slackmsg-attachment";var A="#e3e4e6";a.color&&("#"===a.color[0]?A=a.color[0]:"good"===a.color?A="#2fa44f":"warning"===a.color?A="#de9e31":"danger"===a.color&&(A="#d50200"));c.style.borderColor=A;d.className="slackmsg-attachment-pretext";a.pretext?d.innerHTML=W(a.pretext):d.classList.add("hidden");e.target="_blank";a.title?(e.innerHTML=W(a.title),a.title_link&&
-(e.href=a.title_link),e.className="slackmsg-attachment-title"):e.className="hidden slackmsg-attachment-title";v.target="_blank";f.className="slackmsg-author";a.author_name?(v.innerHTML=W(a.author_name),v.href=a.author_link||"",v.className="slackmsg-author-name",g.className="slackmsg-author-img",a.author_icon?g.src=a.author_icon:g.classList.add("hidden")):f.classList.add("hidden");l.innerHTML=W(a.text||"");l.a="slackmsg-attachment-text";w.className="slackmsg-attachment-thumb";a.thumb_url?w.src=a.thumb_url:
-w.classList.add("hidden");k.className="slackmsg-attachment-img";a.image_url?k.src=a.image_url:k.classList.add("hidden");t.className="slackmsg-attachment-footer";r.className="slackmsg-attachment-footer-text";x.className="slackmsg-attachment-footer-icon";a.footer?(r.innerHTML=W(a.footer),a.footer_icon?x.src=a.footer_icon:x.classList.add("hidden")):(x.classList.add("hidden"),r.classList.add("hidden"));m.className="slackmsg-ts";a.ts?m.innerHTML=G.u(a.ts):m.classList.add("hidden");f.appendChild(g);f.appendChild(v);
-h.appendChild(l);h.appendChild(w);t.appendChild(x);t.appendChild(r);t.appendChild(m);c.appendChild(e);c.appendChild(f);c.appendChild(h);c.appendChild(k);c.appendChild(t);b.appendChild(d);b.appendChild(c);b&&n.appendChild(b)})}d.appendChild(f);d.appendChild(m);return d}
-function T(a){a:{for(var b=a,c={};!c[b];){if(a=D.a.f[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 ra(a){return a.replace(/:([^ \t:]+):/g,function(b,c){var d=T(c);if(d){var f=document.createElement("span");f.className=b===a?"emoji-medium":"emoji-small";f.appendChild(d);return f.outerHTML}return b})}
-function W(a){a=a.split(/\r?\n/g);for(var b=0,c=a.length;b<c;b++){for(var d=a[b].trim(),f="",e={},l=!1,g=0,d=d.replace(RegExp("<([@#]?)([^>]*)>","g"),function(a,b,c){c=c.split("|");if("@"===b)c[1]?"@"!==c[1][0]&&(c[1]="@"+c[1]):(a=q(D.a,c[0]),c[1]=a?"@"+a.name:G.J),c[0]="#"+c[0],c[2]="slackmsg-link slackmsg-link-user";else if("#"===b)c[1]?"#"!==c[1][0]&&(c[1]="#"+c[1]):(a=y(D.a,c[0]),c[1]=a?"#"+a.name:G.I),c[0]="#"+c[0],c[2]="slackmsg-link slackmsg-link-chan";else if(-1!==c[0].indexOf("://"))c[1]||
-(c[1]=c[0]),c[2]="slackmsg-link";else return a;return'<a href="'+c[0]+'" class="'+c[2]+'"'+(b?"":' target="_blank"')+">"+c[1]+"</a>"}),d=ra(d),h=d.length,m=function(a,b,c){for(;a[b];){var d=a[b];if(("A"<=d&&"Z">=d||"a"<=d&&"z">=d||"0"<=d&&"9">=d||-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(d))&&
-a[b]!=c&&a[b+1]==c)return!0;b++}return!1},k=function(a){return Object.keys(e).length?'<span class="'+Object.keys(a).join(" ")+'">':""};g<h&&(" "===d[g]||"\t"===d[g]);)g++;"&gt;"===d.substr(g,4)&&(l=!0,g+=4);for(;g<h;g++){var n=d[g];if("<"===n){do f+=d[g++];while(">"!==d[g-1]);g--}else if(!e["slackmsg-style-bold"]&&"*"===n&&d[g+1]&&m(d,g,n))Object.keys(e).length&&(f+="</span>"),e["slackmsg-style-bold"]=!0,f+=k(e);else if(!e["slackmsg-style-strike"]&&"~"===n&&d[g+1]&&m(d,g,n))Object.keys(e).length&&
-(f+="</span>"),e["slackmsg-style-strike"]=!0,f+=k(e);else if(!e["slackmsg-style-code"]&&"`"===n&&d[g+1]&&m(d,g,n))Object.keys(e).length&&(f+="</span>"),e["slackmsg-style-code"]=!0,f+=k(e);else if(!e["slackmsg-style-italic"]&&"_"===n&&d[g+1]&&m(d,g,n))Object.keys(e).length&&(f+="</span>"),e["slackmsg-style-italic"]=!0,f+=k(e);else{var u=!1,f=f+n;do{if(e["slackmsg-style-bold"]&&"*"!==n&&"*"===d[g+1])delete e["slackmsg-style-bold"],u=!0;else if(e["slackmsg-style-strike"]&&"~"!==n&&"~"===d[g+1])delete e["slackmsg-style-strike"],
-u=!0;else if(e["slackmsg-style-code"]&&"`"!==n&&"`"===d[g+1])delete e["slackmsg-style-code"],u=!0;else if(e["slackmsg-style-italic"]&&"_"!==n&&"_"===d[g+1])delete e["slackmsg-style-italic"],u=!0;else break;n=d[++g]}while(g<h);u&&(f+="</span>"+k(e))}}e&&(f+="</span>");a[b]=l?'<span class="slackmsg-style-quote">'+f+"</span>":f}return a.join("<br/>")}function Q(a,b,c){b.i?(a=V(a,b,c),a.classList.add("slackmsg-me_message")):a=V(a,b,c);b.l&&a.classList.add("slackmsg-edited");return a}
-function N(){var a=0,b=0,c="";if(X)c="!"+G.D+" - ",document.getElementById("linkFavicon").href="favicon_err.png";else{for(var d in Y)Y.hasOwnProperty(d)&&(a+=Y[d].C,b+=Y[d].s);b?c="(!"+b+") - ":a&&(c="("+a+") - ");document.getElementById("linkFavicon").href=b||a?"favicon.png?h="+b+"&m="+a:"favicon_ok.png"}c+=D.a.g.name;document.title=c}
-function sa(){if("Notification"in window)if("granted"===Notification.permission){var a=Date.now();if(L+3E4<a){var b=new Notification(G.F);L=a;setTimeout(function(){b.close()},5E3)}}else"denied"!==Notification.permission&&Notification.requestPermission()}
-function ta(){var a=document.createDocumentFragment(),b=E.id,c=null,d=0,f=null;D.b[b]&&D.b[b].a.forEach(function(e){if(!e.c){var g=Q(b,e);c&&c.j===e.j&&e.j?(g.classList.add("slackmsg-same-author"),30>Math.abs(d-e.b)?f.classList.add("slackmsg-same-ts"):d=e.b):d=e.b;c=e;f=g;a.appendChild(g)}});var e=document.getElementById("chatWindow");e.textContent="";e.appendChild(a);e.scrollTop=e.scrollHeight-e.clientHeight}
-function ua(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=a.target;c!==a.currentTarget&&c&&!c.classList.contains("slackmsg-hover");){if(c.parentElement&&c.parentElement.classList.contains("slackmsg-hover")){if(a=b(a,c)){a=parseFloat(a.split("_")[1]);var d=ma(a);d&&c.classList.contains("slackmsg-hover-reply")?(I&&(I=null,S()),H!==d&&(H=d,P())):d&&c.classList.contains("slackmsg-hover-reaction")?va.H(document.body,
-function(a){a&&U(E.id,d.id,a)}):d&&c.classList.contains("slackmsg-hover-edit")?(H&&(H=null,P()),I!==d&&(I=d,S())):d&&c.classList.contains("slackmsg-hover-remove")&&(H&&(H=null,P()),I&&(I=null,S()),wa(d))}break}c=c.parentElement}}function R(){document.getElementById("msgInput").focus()}function M(){var a=document.location.hash.substr(1),b=y(D.a,a),a=q(D.a,a);b&&b!==E?xa(b):a&&a.b&&xa(a.b)}
-document.addEventListener("DOMContentLoaded",function(){na();document.getElementById("chatWindow").addEventListener("click",ua);window.addEventListener("hashchange",function(){document.location.hash&&"#"===document.location.hash[0]&&M()});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),ya(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&&za(a.value)&&(a.value="",H&&(H=null,P()),I&&(I=null,P()));R();return!1});window.addEventListener("blur",function(){window.hasFocus=!1});window.addEventListener("focus",function(){window.hasFocus=
-!0;L=0;E&&Aa();R()});window.hasFocus=!0;(function(){var a=document.getElementById("emojiButton");if("makeEmoji"in window){var b=window.makeEmoji("smile");b?a.innerHTML="<span class='emoji-small'>"+b.outerHTML+"</span>":a.style.backgroundImage='url("smile.svg")';(b=window.makeEmoji("paperclip"))?document.getElementById("attachFile").innerHTML="<span class='emoji-small'>"+b.outerHTML+"</span>":document.getElementById("attachFile").style.backgroundImage='url("public/paperclip.svg")';a.addEventListener("click",
-function(){va.H(document.body,function(a){a&&(document.getElementById("msgInput").value+=":"+a+":");R()})})}else a.classList.add("hidden")})();Z()});var va=function(){function a(a,b){for(var c=a.target;c!==h&&c&&"LI"!==c.nodeName;)c=c.parentElement;c&&"LI"===c.nodeName&&c.id&&"emojibar-"===c.id.substr(0,9)?b(c.id.substr(9)):b(null)}function b(){if(!c())return!1;J&&J(null);return!0}function c(){return h.parentElement?(h.parentElement.removeChild(m),h.parentElement.removeChild(h),!0):!1}function d(a){var b=0,c;a=void 0===a?r.value:a;if(g()){var d=window.searchEmojis(a);c=f(d);for(var h in w)w[h].visible&&(w[h].visible=!1,n.removeChild(w[h].h));
-h=0;for(var k=c.length;h<k;h++){var l=c[h].name,t=w[l];if(!t){var t=w,x=l,K=l,l=window.makeEmoji(d[l]),m=document.createElement("span");m.appendChild(l);m.className="emoji-medium";l=e(K,m);t=t[x]=l}t.visible||(t.visible=!0,n.appendChild(t.h));b++}}for(h in v)v[h].visible&&(v[h].visible=!1,u.removeChild(v[h].h));c=f(D.a.f);h=0;for(k=c.length;h<k;h++)l=c[h].name,""!==a&&l.substr(0,a.length)!==a||"alias:"===D.a.f[l].substr(0,6)||(t=v[l],t||(d=v,x=t=l,l=D.a.f[l],K=document.createElement("span"),m=document.createElement("span"),
-K.className="emoji emoji-custom",K.style.backgroundImage='url("'+l+'")',m.appendChild(K),m.className="emoji-medium",l=e(x,m),t=d[t]=l),t.visible||(t.visible=!0,u.appendChild(t.h)),b++);return b}function f(a){var b=D.a.a.c.b,c=[],d;for(d in a)c.push({name:d,G:0,count:b[d]||0});return c=c.sort(function(a,b){var c=b.count-a.count;return c?c:a.G-b.G})}function e(a,b){var c=document.createElement("li");c.appendChild(b);c.className="emojibar-list-item";c.id="emojibar-"+a;return{visible:!1,h:c}}function l(a){var b=
-document.createElement("img"),c=document.createElement("div");b.src=a;c.appendChild(b);c.className="emojibar-header";return c}function g(){return"searchEmojis"in window}var h=document.createElement("div"),m=document.createElement("div"),k=document.createElement("div"),n=document.createElement("ul"),u=document.createElement("ul"),r=document.createElement("input"),w={},v={},x=document.createElement("div"),A=document.createElement("span"),t=document.createElement("span"),J;m.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()});m.className="emojibar-overlay";h.className="emojibar";k.className="emojibar-emojis";x.className="emojibar-detail";A.className="emojibar-detail-img";t.className="emojibar-detail-name";n.className=u.className="emojibar-list";r.className="emojibar-search";x.appendChild(A);x.appendChild(t);k.appendChild(l(window.emojiProviderHeader));k.appendChild(n);k.appendChild(l("emojicustom.png"));
-k.appendChild(u);h.appendChild(k);h.appendChild(x);h.appendChild(r);r.addEventListener("keyup",function(){d()});h.addEventListener("mousemove",function(b){a(b,function(a){var b=a?w[a]||v[a]:null;b?(A.innerHTML=b.h.outerHTML,t.textContent=":"+a+":"):(A.textContent="",t.textContent="")})});h.addEventListener("click",function(b){a(b,function(a){a&&c()&&J&&J(a)})});return{isSupported:g,H:function(a,b){return g()?(J=b,a.appendChild(m),a.appendChild(h),r.value="",d(),r.focus(),!0):!1},search:d,close:b}}();var D,Y={};
-function Ba(a,b){if(a!==E||!window.hasFocus){var c=new RegExp("<@"+D.a.a.id),d=!1,f=!1;Y[a.id]||(Y[a.id]={s:0,C:0});b.forEach(function(b){var e;if(!(e="D"===a.id[0]||b.text.match(c)))a:{b=b.text;e=D.a.a.c.a;for(var g=0,h=e.length;g<h;g++)if(-1!==b.indexOf(e[g])){console.log("Found highlight "+e[g]+" in "+b);e=!0;break a}e=!1}e?(f|=!Y[a.id].s,Y[a.id].s++,d=!0):Y[a.id].C++});N();document.getElementById(a.id).classList.add("unread");d&&document.getElementById(a.id).classList.add("unreadHi");f&&!window.hasFocus&&
-sa()}}function Aa(){var a=E;Y[a.id]&&(Y[a.id]={s:0,C:0},N());a=document.getElementById(a.id);a.classList.remove("unread");a.classList.remove("unreadHi")}D=new function(){this.f=this.c=0;this.a=new p;this.b={}};var pa=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 f=0;f+k<=m;f+=k)e(a,b[c],d,f),c++,c===b.length&&(b.sort(function(a,b){return a.o?b.o?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].o){c(a[e].src,function(c){a[e].o=c;b(a,d)});return}var g=[];a.forEach(function(a){a.o&&g.push(a.o)});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.src=window.URL.createObjectURL(c.response)}else b(null)};
-c.open("GET",a,!0);c.send(null)}function d(){var a=g.createLinearGradient(0,0,0,m);a.addColorStop(0,"#4D394B");a.addColorStop(1,"#201820");g.fillStyle=a;g.fillRect(0,0,h,m);return g.getImageData(0,0,h,m)}function f(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 e(a,b,c,d){var e=Math.floor(d);a=[a.data[e*h*4+0],a.data[e*h*4+1],a.data[e*h*4+2]];g.fillStyle=
-"#"+(1.1*a[0]<<16|1.1*a[1]<<8|1.1*a[2]).toString(16);g.beginPath();g.moveTo(c+k/2,d+n);g.lineTo(c-n+k,d+k/2);g.lineTo(c+k/2,d-n+k);g.lineTo(c+n,d+k/2);g.closePath();g.fill();g.putImageData(f(g.getImageData(c+n,d+n,u,u),b),c+n,d+n)}var l=document.createElement("canvas"),g=l.getContext("2d"),h=l.width=250,m=l.height=290,k=(h-40)/3,n=.1*k,u=Math.floor(k-2*n),r=.5*u;return function(c){var e=d(),f=[],g;for(g in D.a.c)D.a.c[g].g||f.push({src:"api/avatar?user="+g});b(f,function(b){a(e,b);c(l.toDataURL())})}}();var X=0,E=null;function Ca(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){X&&(X=0,O(!0));c=b.response;try{c=JSON.parse(c)}catch(f){c=null}}else X?(X+=Math.floor((X||5)/2),X=Math.min(60,X)):(X=5,O(!1));a(d,c)}else X&&(X=0,O(!0)),Ca(a)};b.open("GET","api?v="+D.c+"&uv="+D.f,!0);b.send(null)}
-function Da(a,b){if(a){if(b){var c=D;b.v&&(c.c=b.v);b.userV&&(c.f=b.userV);if(b["static"]){var d=c.a,f=b["static"];if(f.bots)for(var e=0,l=f.bots.length;e<l;e++){var g=d.w[f.bots[e].id];g||(g=d.w[f.bots[e].id]=new ha(f.bots[e].id));var h=f.bots[e];g.g=h.deleted;g.name=h.name;g.a.T=h.icons.image_36;g.a.m=h.icons.image_48;g.a.A=h.icons.image_72}if(f.users)for(e=0,l=f.users.length;e<l;e++)(g=d.c[f.users[e].id])||(g=d.c[f.users[e].id]=new ea(f.users[e].id)),h=f.users[e],g.name=h.name,g.g=h.deleted,g.status=
-h.status,void 0!==h.presence&&(g.f="away"!==h.presence),void 0!==h.isPresent&&(g.f=h.isPresent),g.a.P=h.profile.image_24,g.a.R=h.profile.image_32,g.a.m=h.profile.image_48,g.a.A=h.profile.image_72,g.a.N=h.profile.image_192,g.a.V=h.profile.image_512;if(f.ims)for(e=0,l=f.ims.length;e<l;e++)if(h=q(d,f.ims[e].user))h.b||(d.b[f.ims[e].id]=h.b=new da(f.ims[e].id,h)),g=h.b,g.f=parseFloat(f.ims[e].last_read),g.b=h.g;if(f.channels)for(e=0,l=f.channels.length;e<l;e++){(g=d.i[f.channels[e].id])||(g=d.i[f.channels[e].id]=
-new ba(f.channels[e].id));var h=f.channels[e],m=d;g.name=h.name;g.b=h.is_archived;g.f=parseFloat(h.last_read);g.a={};if(h.members)for(var k=0,n=h.members.length;k<n;k++){var u=q(m,h.members[k]);g.a[u.id]=u;u.i[g.id]=g}}e=0;for(l=f.groups.length;e<l;e++){(g=d.B[f.groups[e].id])||(g=d.B[f.groups[e].id]=new ca(f.groups[e].id));h=d;m=f.groups[e];k=[];g.a={};n=0;for(u=m.members.length;n<u;n++){var r=q(h,m.members[n]);g.a[m.members[n]]=r;r.i[g.id]=g;k.push(r.name)}g.name=k.join(", ");g.b=m.is_archived||
-!1===m.is_open;g.f=parseFloat(m.last_read)}f.emojis&&(d.f=f.emojis);d.g||(d.g=new aa(f.team.id));e=d.g;l=f.team;e.name=l.name;e.a.S=l.icon.image_34;e.a.U=l.icon.image_44;e.a.W=l.icon.image_68;e.a.X=l.icon.image_88;e.a.L=l.icon.image_102;e.a.M=l.icon.image_132;e.a.O=l.icon.image_230;e.a.Y=l.icon.image_default;f.self&&(d.a=q(d,f.self.id),d.a.c||(d.a.c=new fa),ga(d.a.c,f.self.prefs));oa()}if(b.user)for(var w in b.user)(d=q(c.a,w))?(f=b.user[w],void 0!==f.presence&&(d.f=f.presence),(f=document.getElementById(d.b.id))&&
-(d.f?f.classList.remove("away"):f.classList.add("away"))):c.f=c.c=-1;if(b.live){for(var v in b.live)(w=c.b[v])?B(w,b.live[v]):c.b[v]=new z(v,250,b.live[v]);for(var x in b.live)(v=y(c.a,x))?v.b||(Ba(v,b.live[x]),E&&b.live[E.id]&&ta()):c.f=c.c=0}}Z()}else setTimeout(Z,1E3*X)}function Z(){Ca(Da)}
-function xa(a){E&&document.getElementById(E.id).classList.remove("selected");document.getElementById(a.id).classList.add("selected");document.body.classList.remove("no-room-selected");E=a;a=E.name||(E.c?E.c.name:void 0);if(!a){a=[];for(var b in E.a)a.push(E.a[b].name);a=a.join(", ")}document.getElementById("currentRoomTitle").textContent=a;ta();R();document.getElementById("fileUploadContainer").classList.add("hidden");Aa();H&&(H=null,P());I&&(I=null,P());E.f&&!D.b[E.id]&&(b=new XMLHttpRequest,b.open("GET",
-"api/hist?room="+E.id,!0),b.send(null))}function ya(a,b,c){var d=E;new FileReader;var f=new FormData,e=new XMLHttpRequest;f.append("file",b);f.append("filename",a);e.onreadystatechange=function(){4===e.readyState&&(204===e.status?c(null):c(e.statusText))};e.open("POST","api/file?room="+d.id);e.send(f)}
-function Ea(a,b){var c=E;if("me"==a){if(H)return!1;var d=new XMLHttpRequest;d.open("POST","api/msg?room="+c.id+"&me&text="+encodeURIComponent(b),!0);d.send(null);return!0}if("shrug"==a)return b.length&&(b+=" "),za(b+"\u00af_(\u30c4)_/\u00af",!0);console.log("Unknown command "+a);return!1}
-function za(a,b){if(I){var c=new XMLHttpRequest;c.open("PUT","api/msg?room="+E.id+"&ts="+I.id+"&text="+encodeURIComponent(a),!0);c.send(null);return!0}if("/"===a[0]&&!0!==b)return c=a.indexOf(" "),Ea(a.substr(1,-1===c?void 0:c-1),(-1===c?"":a.substr(c)).trim());var c=E,d=H,f=new XMLHttpRequest,e="api/msg?room="+c.id+"&text="+encodeURIComponent(a);if(d){var l=q(D.a,d.j),g="Message";"C"===c.id[0]?g="Channel message":"D"===c.id[0]?g="Direct message":"G"===c.id[0]&&(g="Group message");e+="&attachments="+
-encodeURIComponent(JSON.stringify([{fallback:d.text,author_name:"<@"+l.id+"|"+l.name+">",author_icon:l.a.m,text:d.text,footer:g,ts:d.b}]))}f.open("POST",e,!0);f.send(null);return!0}function wa(a){var b=new XMLHttpRequest;b.open("DELETE","api/msg?room="+E.id+"&ts="+a.id,!0);b.send(null)}function U(a,b,c){var d=new XMLHttpRequest;d.open("POST","api/reaction?room="+a+"&msg="+b+"&reaction="+encodeURIComponent(c),!0);d.send(null)};
+function aa(a){this.id=a;this.a={T:"",V:"",X:"",Y:"",M:"",N:"",P:"",Z:""};this.version=0}function ba(a){this.id=a;this.a={};this.version=0}function ca(a){this.id=a;this.a={};this.version=0}function da(a,b){this.id=a;this.c=b;this.version=0}function ea(a){this.id=a;this.a={R:"",S:"",m:"",A:"",O:"",W:""};this.i={};this.c=this.b=null;this.version=0}function fa(){this.b={};this.a=[]}
+function ga(a,b){a.b=JSON.parse(b.emoji_use);b.highlight_words?a.a=(b.highlight_words||"").split(",").filter(function(a){return""!==a.trim()}):b.highlights&&(a.a=b.highlights);a.version=Math.max(a.version,0)}function ha(a){this.id=a;this.a={U:"",m:"",A:""};this.c=this.b=null;this.version=0;this.f=!1}function p(){this.f=null;this.h={};this.w={};this.C={};this.b={};this.a=null;this.i={};this.c={};this.D=0}function r(a,b){return a.b[b]||a.i[b]||null}
+function y(a,b){return a.h[b]||a.C[b]||a.w[b]||null}"undefined"!==typeof module&&(module.L.$=p);function ia(a,b){this.j=a.user||a.bot_id;this.h=a.username;this.id=a.ts;this.b=parseFloat(a.ts);this.text=a.text||"";this.f=a.attachments||[];this.l=!!a.edited;this.c=a.removed||!1;this.i="me_message"===a.subtype||a.isMeMessage;this.a={};this.version=b;var c=this;a.reactions&&a.reactions.forEach(function(a){c.a[a.name]=[];a.users.forEach(function(b){c.a[a.name].push(b)})})}
+function ja(a,b,c){b?(a.text=b.text||"",b.attachments&&(a.f=b.attachments),a.l=!!b.edited,a.c=!!b.removed,b.reactions&&(a.a={},b.reactions.forEach(function(b){a.a[b.name]=[];b.users.forEach(function(c){a.a[b.name].push(c)})}))):a.c=!0;a.version=c}function z(a,b,c,e){this.id="string"===typeof a?a:a.id;this.a=[];this.b=b;c&&C(this,c,e)}
+function ka(a,b,c,e){var f=!1;a.a[b]&&(1===a.a[b].length&&a.a[b][0]===c?(delete a.a[b],f=!0):a.a[b]=a.a[b].filter(function(a){return a!==c?!1:f=!0}));f&&(a.version=e)}function C(a,b,c){var e=0;b.forEach(function(a){e=Math.max(this.push(a,c),e)}.bind(a));la(a)}
+z.prototype.push=function(a,b){if(a.type&&"message"!==a.type)if("reaction_added"===a.type){var c=D(this,a.item.ts);if(c){var e=a.reaction,f=a.user;c.a[e]||(c.a[e]=[]);c.a[e].push(f);c.version=b}}else if("reaction_removed"===a.type)(c=D(this,a.item.ts))&&ka(c,a.reaction,a.user,b);else return 0;else{c=!1;e=a.ts;f=a;"message_changed"===a.subtype&&a.previous_message?(e=a.previous_message.ts,f=a.message):"message_deleted"===a.subtype&&a.previous_message&&(e=a.previous_message.ts,f=null);for(var d=0,m=
+this.a.length;d<m;d++)if(this.a[d].id===e){ja(this.a[d],f,b);c=!0;break}c||this.a.push(new ia(a,b))}for(;this.a.length>this.b;)this.a.shift();return b};function ma(a){for(var b=E.b[F.id],c=0,e=b.a.length;c<e&&a>=b.a[c].b;c++)if(b.a[c].b===a)return b.a[c];return null}function D(a,b){for(var c=0,e=a.a.length;c<e;c++)if(a.a[c].id==b)return a.a[c];return null}function la(a){a.a.sort(function(a,c){return a.b-c.b})}"undefined"!==typeof module&&(module.L.aa=z);var G={},H;function na(){var a;if(!a){for(var b=0,c=navigator.languages.length;b<c;b++)if(G.hasOwnProperty(navigator.languages[b])){a=navigator.languages[b];break}a||(a="en")}H=G[a];console.log("Loading language pack: "+a);if(H.g)for(b in H.g)document.getElementById(b).textContent=H.g[b]};G.fr={K:"Utilisateur inconnu",J:"Channel inconnu",G:"Nouveau message",F:"Reseau",l:"edit&eacute;",u: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()},g:{fileUploadCancel:"Annuler",neterror:"Impossible de se connecter au chat !"}};G.en={K:"Unknown member",J:"Unknown channel",G:"New message",F:"Network",l:"edited",u: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()},g:{fileUploadCancel:"Cancel",neterror:"Cannot connect to chat !"}};var I=null,J=null,K=0;
+function oa(){var a=document.createDocumentFragment(),b=E.a.a?Object.keys(E.a.a.i):[];b.sort(function(a,b){return a[0]!==b[0]?a[0]-b[0]:y(E.a,a).name.localeCompare(y(E.a,b).name)});b.forEach(function(b){b=y(E.a,b);if(!b.b){var c=document.createElement("li"),f=document.createElement("a");c.id=b.id;f.href="#"+b.id;"D"===b.id[0]?c.className="slack-context-room slack-ims":"G"===b.id[0]?c.className="slack-context-room slack-group":"C"===b.id[0]&&(c.className="slack-context-room slack-channel");F===b&&
+c.classList.add("selected");f.textContent=b.name;c.appendChild(f);c&&a.appendChild(c)}});b=E.a.b?Object.keys(E.a.b):[];b.sort(function(a,b){return E.a.b[a].name.localeCompare(E.a.b[b].name)});b.forEach(function(b){b=r(E.a,b);if(!b.h){b=b.b;var c=document.createElement("li"),f=document.createElement("a");c.id=b.id;f.href="#"+b.id;c.className="slack-context-room slack-ims";f.textContent=b.c.name;c.appendChild(f);b.c.f||c.classList.add("away");F===b&&c.classList.add("selected");c&&a.appendChild(c)}});
+document.getElementById("chanList").textContent="";document.getElementById("chanList").appendChild(a);L();M();pa(function(a){document.getElementById("slackCtx").style.backgroundImage="url("+a+")"})}function N(a){a?document.body.classList.remove("no-network"):document.body.classList.add("no-network");M()}
+function O(){if(I){document.body.classList.add("replyingTo");var a=document.getElementById("replyToContainer"),b=document.createElement("a");b.addEventListener("click",function(){I=null;O()});b.className="replyto-close";b.textContent="x";a.textContent="";a.appendChild(b);a.appendChild(P("reply_"+F.id,I,!0))}else document.body.classList.remove("replyingTo"),document.getElementById("replyToContainer").textContent="";Q()}
+function R(){if(J){document.body.classList.add("replyingTo");var a=document.getElementById("replyToContainer"),b=document.createElement("a");b.addEventListener("click",function(){J=null;R()});b.className="replyto-close";b.textContent="x";a.textContent="";a.appendChild(b);a.appendChild(P("edit_"+F.id,J,!0));document.getElementById("msgInput").value=J.text}else document.body.classList.remove("replyingTo"),document.getElementById("replyToContainer").textContent="";Q()}
+function qa(a,b,c,e){var f=S(c);if(f){for(var d=document.createElement("li"),m=document.createElement("a"),k=document.createElement("span"),g=document.createElement("span"),h=[],l=0,n=e.length;l<n;l++){var t=r(E.a,e[l]);t&&h.push(t.name)}h.sort();g.textContent=h.join(", ");k.appendChild(f);k.className="emoji-small";m.href="javascript:toggleReaction('"+a+"', '"+b+"', '"+c+"')";m.appendChild(k);m.appendChild(g);d.className="slackmsg-reaction-item";d.appendChild(m);return d}return null}
+window.toggleReaction=function(a,b,c){var e=E.b[a];if(e&&(e=D(e,b))){var f=E.a.a.id;e.a[c]&&-1!==e.a[c].indexOf(f)?(e=new XMLHttpRequest,e.open("DELETE","api/reaction?room="+a+"&msg="+b+"&reaction="+encodeURIComponent(c),!0),e.send(null)):T(a,b,c)}};
+function U(a,b,c){var e=document.createElement("div"),f=document.createElement("div"),d=document.createElement("div"),m=document.createElement("div"),k=document.createElement("img"),g=document.createElement("span"),h=document.createElement("ul"),l=document.createElement("li"),n=document.createElement("ul"),t=document.createElement("ul"),q=r(E.a,b.j);e.id=a+"_"+b.b;e.className="slackmsg-item";d.className="slackmsg-ts";m.className="slackmsg-msg";k.className="slackmsg-author-img";g.className="slackmsg-author-name";
+h.className="slackmsg-hover";l.className="slackmsg-hover-reply";d.innerHTML=H.u(b.b);m.innerHTML=V(b.text);g.textContent=q?q.name:b.h||"?";k.src=q?q.a.m:"";h.appendChild(l);if("makeEmoji"in window){var u=document.createElement("li"),w=window.makeEmoji("arrow_heading_down"),A=window.makeEmoji("smile"),x=window.makeEmoji("pencil2"),q=window.makeEmoji("x");u.className="slackmsg-hover-reaction";A?(u.classList.add("emoji-small"),u.appendChild(A)):u.style.backgroundImage='url("smile.svg")';w?(l.classList.add("emoji-small"),
+l.appendChild(w)):l.style.backgroundImage='url("repl.svg")';h.appendChild(u);b.j===E.a.a.id&&(l=document.createElement("li"),l.className="slackmsg-hover-edit",x?l.classList.add("emoji-small"):l.style.backgroundImage='url("edit.svg")',l.appendChild(x),h.appendChild(l),l=document.createElement("li"),l.className="slackmsg-hover-remove",q?l.classList.add("emoji-small"):l.style.backgroundImage='url("remove.svg")',l.appendChild(q),h.appendChild(l))}else l.style.backgroundImage='url("repl.svg")',b.j===E.a.a.id&&
+(l=document.createElement("li"),l.className="slackmsg-hover-edit",l.style.backgroundImage='url("edit.svg")',h.appendChild(l),l=document.createElement("li"),l.className="slackmsg-hover-remove",l.style.backgroundImage='url("remove.svg")',h.appendChild(l));e.appendChild(k);f.appendChild(g);f.appendChild(m);f.appendChild(d);f.appendChild(n);b.l&&(d=document.createElement("div"),d.textContent=H.l,d.className="slackmsg-edited",f.appendChild(d));f.appendChild(t);f.className="slackmsg-content";n.className=
+"slackmsg-attachments";t.className="slackmsg-reactions";if(!0!==c){if(b.a)for(var v in b.a)(c=qa(a,b.id,v,b.a[v]))&&t.appendChild(c);b.f.forEach(function(a){var b=document.createElement("li"),c=document.createElement("div"),e=document.createElement("div"),d=document.createElement("a"),f=document.createElement("div"),m=document.createElement("img"),k=document.createElement("a"),g=document.createElement("div"),w=document.createElement("div"),h=document.createElement("img"),l=document.createElement("img"),
+B=document.createElement("div"),q=document.createElement("img"),A=document.createElement("span"),x=document.createElement("span");b.className="slackmsg-attachment";var v="#e3e4e6";a.color&&("#"===a.color[0]?v=a.color[0]:"good"===a.color?v="#2fa44f":"warning"===a.color?v="#de9e31":"danger"===a.color&&(v="#d50200"));c.style.borderColor=v;e.className="slackmsg-attachment-pretext";a.pretext?e.innerHTML=V(a.pretext):e.classList.add("hidden");d.target="_blank";a.title?(d.innerHTML=V(a.title),a.title_link&&
+(d.href=a.title_link),d.className="slackmsg-attachment-title"):d.className="hidden slackmsg-attachment-title";k.target="_blank";f.className="slackmsg-author";a.author_name?(k.innerHTML=V(a.author_name),k.href=a.author_link||"",k.className="slackmsg-author-name",m.className="slackmsg-author-img",a.author_icon?m.src=a.author_icon:m.classList.add("hidden")):f.classList.add("hidden");w.innerHTML=V(a.text||"");w.a="slackmsg-attachment-text";h.className="slackmsg-attachment-thumb";a.thumb_url?h.src=a.thumb_url:
+h.classList.add("hidden");l.className="slackmsg-attachment-img";a.image_url?l.src=a.image_url:l.classList.add("hidden");B.className="slackmsg-attachment-footer";A.className="slackmsg-attachment-footer-text";q.className="slackmsg-attachment-footer-icon";a.footer?(A.innerHTML=V(a.footer),a.footer_icon?q.src=a.footer_icon:q.classList.add("hidden")):(q.classList.add("hidden"),A.classList.add("hidden"));x.className="slackmsg-ts";a.ts?x.innerHTML=H.u(a.ts):x.classList.add("hidden");f.appendChild(m);f.appendChild(k);
+g.appendChild(w);g.appendChild(h);B.appendChild(q);B.appendChild(A);B.appendChild(x);c.appendChild(d);c.appendChild(f);c.appendChild(g);c.appendChild(l);c.appendChild(B);b.appendChild(e);b.appendChild(c);b&&n.appendChild(b)})}e.appendChild(f);e.appendChild(h);return e}
+function S(a){a:{for(var b=a,c={};!c[b];){if(a=E.a.c[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 ra(a){return a.replace(/:([^ \t:]+):/g,function(b,c){var e=S(c);if(e){var f=document.createElement("span");f.className=b===a?"emoji-medium":"emoji-small";f.appendChild(e);return f.outerHTML}return b})}
+function V(a){a=a.split(/\r?\n/g);for(var b=0,c=a.length;b<c;b++){for(var e=a[b].trim(),f="",d={},m=!1,k=0,e=e.replace(RegExp("<([@#]?)([^>]*)>","g"),function(a,b,c){c=c.split("|");if("@"===b)c[1]?"@"!==c[1][0]&&(c[1]="@"+c[1]):(a=r(E.a,c[0]),c[1]=a?"@"+a.name:H.K),c[0]="#"+c[0],c[2]="slackmsg-link slackmsg-link-user";else if("#"===b)c[1]?"#"!==c[1][0]&&(c[1]="#"+c[1]):(a=y(E.a,c[0]),c[1]=a?"#"+a.name:H.J),c[0]="#"+c[0],c[2]="slackmsg-link slackmsg-link-chan";else if(-1!==c[0].indexOf("://"))c[1]||
+(c[1]=c[0]),c[2]="slackmsg-link";else return a;return'<a href="'+c[0]+'" class="'+c[2]+'"'+(b?"":' target="_blank"')+">"+c[1]+"</a>"}),e=ra(e),g=e.length,h=function(a,b,c){for(;a[b];){var e=a[b];if(("A"<=e&&"Z">=e||"a"<=e&&"z">=e||"0"<=e&&"9">=e||-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(e))&&
+a[b]!=c&&a[b+1]==c)return!0;b++}return!1},l=function(a){return Object.keys(d).length?'<span class="'+Object.keys(a).join(" ")+'">':""};k<g&&(" "===e[k]||"\t"===e[k]);)k++;"&gt;"===e.substr(k,4)&&(m=!0,k+=4);for(;k<g;k++){var n=e[k];if("<"===n){do f+=e[k++];while(">"!==e[k-1]);k--}else if(!d["slackmsg-style-bold"]&&"*"===n&&e[k+1]&&h(e,k,n))Object.keys(d).length&&(f+="</span>"),d["slackmsg-style-bold"]=!0,f+=l(d);else if(!d["slackmsg-style-strike"]&&"~"===n&&e[k+1]&&h(e,k,n))Object.keys(d).length&&
+(f+="</span>"),d["slackmsg-style-strike"]=!0,f+=l(d);else if(!d["slackmsg-style-code"]&&"`"===n&&e[k+1]&&h(e,k,n))Object.keys(d).length&&(f+="</span>"),d["slackmsg-style-code"]=!0,f+=l(d);else if(!d["slackmsg-style-italic"]&&"_"===n&&e[k+1]&&h(e,k,n))Object.keys(d).length&&(f+="</span>"),d["slackmsg-style-italic"]=!0,f+=l(d);else{var t=!1,f=f+n;do{if(d["slackmsg-style-bold"]&&"*"!==n&&"*"===e[k+1])delete d["slackmsg-style-bold"],t=!0;else if(d["slackmsg-style-strike"]&&"~"!==n&&"~"===e[k+1])delete d["slackmsg-style-strike"],
+t=!0;else if(d["slackmsg-style-code"]&&"`"!==n&&"`"===e[k+1])delete d["slackmsg-style-code"],t=!0;else if(d["slackmsg-style-italic"]&&"_"!==n&&"_"===e[k+1])delete d["slackmsg-style-italic"],t=!0;else break;n=e[++k]}while(k<g);t&&(f+="</span>"+l(d))}}d&&(f+="</span>");a[b]=m?'<span class="slackmsg-style-quote">'+f+"</span>":f}return a.join("<br/>")}function P(a,b,c){b.i?(a=U(a,b,c),a.classList.add("slackmsg-me_message")):a=U(a,b,c);b.l&&a.classList.add("slackmsg-edited");return a}
+function M(){var a=0,b=0,c="";if(W)c="!"+H.F+" - ",document.getElementById("linkFavicon").href="favicon_err.png";else{for(var e in X)X.hasOwnProperty(e)&&(a+=X[e].B,b+=X[e].s);b?c="(!"+b+") - ":a&&(c="("+a+") - ");document.getElementById("linkFavicon").href=b||a?"favicon.png?h="+b+"&m="+a:"favicon_ok.png"}c+=E.a.f.name;document.title=c}
+function sa(){if("Notification"in window)if("granted"===Notification.permission){var a=Date.now();if(K+3E4<a){var b=new Notification(H.G);K=a;setTimeout(function(){b.close()},5E3)}}else"denied"!==Notification.permission&&Notification.requestPermission()}
+function Y(){var a=document.createDocumentFragment(),b=F.id,c=null,e=0,f=null;E.b[b]&&E.b[b].a.forEach(function(d){if(!d.c){var k=P(b,d);c&&c.j===d.j&&d.j?(k.classList.add("slackmsg-same-author"),30>Math.abs(e-d.b)?f.classList.add("slackmsg-same-ts"):e=d.b):e=d.b;c=d;f=k;a.appendChild(k)}});var d=document.getElementById("chatWindow");d.textContent="";d.appendChild(a);d.scrollTop=d.scrollHeight-d.clientHeight}
+function ta(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=a.target;c!==a.currentTarget&&c&&!c.classList.contains("slackmsg-hover");){if(c.parentElement&&c.parentElement.classList.contains("slackmsg-hover")){if(a=b(a,c)){a=parseFloat(a.split("_")[1]);var e=ma(a);e&&c.classList.contains("slackmsg-hover-reply")?(J&&(J=null,R()),I!==e&&(I=e,O())):e&&c.classList.contains("slackmsg-hover-reaction")?ua.I(document.body,
+function(a){a&&T(F.id,e.id,a)}):e&&c.classList.contains("slackmsg-hover-edit")?(I&&(I=null,O()),J!==e&&(J=e,R())):e&&c.classList.contains("slackmsg-hover-remove")&&(I&&(I=null,O()),J&&(J=null,R()),va(e))}break}c=c.parentElement}}function Q(){document.getElementById("msgInput").focus()}function L(){var a=document.location.hash.substr(1),b=y(E.a,a),a=r(E.a,a);b&&b!==F?wa(b):a&&a.b&&wa(a.b)}
+document.addEventListener("DOMContentLoaded",function(){na();document.getElementById("chatWindow").addEventListener("click",ta);window.addEventListener("hashchange",function(){document.location.hash&&"#"===document.location.hash[0]&&L()});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),xa(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();F&&document.getElementById("fileUploadContainer").classList.remove("hidden");return!1});document.getElementById("msgForm").addEventListener("submit",function(a){a.preventDefault();a=document.getElementById("msgInput");F&&a.value&&ya(a.value)&&(a.value="",I&&(I=null,O()),J&&(J=null,O()));Q();return!1});window.addEventListener("blur",function(){window.hasFocus=!1});window.addEventListener("focus",function(){window.hasFocus=
+!0;K=0;F&&za();Q()});window.hasFocus=!0;(function(){var a=document.getElementById("emojiButton");if("makeEmoji"in window){var b=window.makeEmoji("smile");b?a.innerHTML="<span class='emoji-small'>"+b.outerHTML+"</span>":a.style.backgroundImage='url("smile.svg")';(b=window.makeEmoji("paperclip"))?document.getElementById("attachFile").innerHTML="<span class='emoji-small'>"+b.outerHTML+"</span>":document.getElementById("attachFile").style.backgroundImage='url("public/paperclip.svg")';a.addEventListener("click",
+function(){ua.I(document.body,function(a){a&&(document.getElementById("msgInput").value+=":"+a+":");Q()})})}else a.classList.add("hidden")})();Z()});var ua=function(){function a(a,b){for(var c=a.target;c!==g&&c&&"LI"!==c.nodeName;)c=c.parentElement;c&&"LI"===c.nodeName&&c.id&&"emojibar-"===c.id.substr(0,9)?b(c.id.substr(9)):b(null)}function b(){if(!c())return!1;B&&B(null);return!0}function c(){return g.parentElement?(g.parentElement.removeChild(h),g.parentElement.removeChild(g),!0):!1}function e(a){var b=0,c;a=void 0===a?q.value:a;if(k()){var e=window.searchEmojis(a);c=f(e);for(var g in u)u[g].visible&&(u[g].visible=!1,n.removeChild(u[g].g));
+g=0;for(var m=c.length;g<m;g++){var h=c[g].name,l=u[h];if(!l){var l=u,B=h,x=h,h=window.makeEmoji(e[h]),v=document.createElement("span");v.appendChild(h);v.className="emoji-medium";h=d(x,v);l=l[B]=h}l.visible||(l.visible=!0,n.appendChild(l.g));b++}}for(g in w)w[g].visible&&(w[g].visible=!1,t.removeChild(w[g].g));c=f(E.a.c);g=0;for(m=c.length;g<m;g++)h=c[g].name,""!==a&&h.substr(0,a.length)!==a||"alias:"===E.a.c[h].substr(0,6)||(l=w[h],l||(e=w,B=l=h,h=E.a.c[h],x=document.createElement("span"),v=document.createElement("span"),
+x.className="emoji emoji-custom",x.style.backgroundImage='url("'+h+'")',v.appendChild(x),v.className="emoji-medium",h=d(B,v),l=e[l]=h),l.visible||(l.visible=!0,t.appendChild(l.g)),b++);return b}function f(a){var b=E.a.a.c.b,c=[],e;for(e in a)c.push({name:e,H:0,count:b[e]||0});return c=c.sort(function(a,b){var c=b.count-a.count;return c?c:a.H-b.H})}function d(a,b){var c=document.createElement("li");c.appendChild(b);c.className="emojibar-list-item";c.id="emojibar-"+a;return{visible:!1,g:c}}function m(a){var b=
+document.createElement("img"),c=document.createElement("div");b.src=a;c.appendChild(b);c.className="emojibar-header";return c}function k(){return"searchEmojis"in window}var g=document.createElement("div"),h=document.createElement("div"),l=document.createElement("div"),n=document.createElement("ul"),t=document.createElement("ul"),q=document.createElement("input"),u={},w={},A=document.createElement("div"),x=document.createElement("span"),v=document.createElement("span"),B;h.addEventListener("click",
+function(a){var c=g.getBoundingClientRect();(a.screenY<c.top||a.screenY>c.bottom||a.screenX<c.left||a.screenX>c.right)&&b()});h.className="emojibar-overlay";g.className="emojibar";l.className="emojibar-emojis";A.className="emojibar-detail";x.className="emojibar-detail-img";v.className="emojibar-detail-name";n.className=t.className="emojibar-list";q.className="emojibar-search";A.appendChild(x);A.appendChild(v);l.appendChild(m(window.emojiProviderHeader));l.appendChild(n);l.appendChild(m("emojicustom.png"));
+l.appendChild(t);g.appendChild(l);g.appendChild(A);g.appendChild(q);q.addEventListener("keyup",function(){e()});g.addEventListener("mousemove",function(b){a(b,function(a){var b=a?u[a]||w[a]:null;b?(x.innerHTML=b.g.outerHTML,v.textContent=":"+a+":"):(x.textContent="",v.textContent="")})});g.addEventListener("click",function(b){a(b,function(a){a&&c()&&B&&B(a)})});return{isSupported:k,I:function(a,b){return k()?(B=b,a.appendChild(h),a.appendChild(g),q.value="",e(),q.focus(),!0):!1},search:e,close:b}}();var E,X={};
+function Aa(a,b){if(a!==F||!window.hasFocus){var c=new RegExp("<@"+E.a.a.id),e=!1,f=!1;X[a.id]||(X[a.id]={s:0,B:0});b.forEach(function(b){var d;if(!(d="D"===a.id[0]||b.text.match(c)))a:{b=b.text;d=E.a.a.c.a;for(var k=0,g=d.length;k<g;k++)if(-1!==b.indexOf(d[k])){console.log("Found highlight "+d[k]+" in "+b);d=!0;break a}d=!1}d?(f|=!X[a.id].s,X[a.id].s++,e=!0):X[a.id].B++});M();document.getElementById(a.id).classList.add("unread");e&&document.getElementById(a.id).classList.add("unreadHi");f&&!window.hasFocus&&
+sa()}}function za(){var a=F;X[a.id]&&(X[a.id]={s:0,B:0},M());a=document.getElementById(a.id);a.classList.remove("unread");a.classList.remove("unreadHi")}E=new function(){this.c=0;this.a=new p;this.b={}};var pa=function(){function a(a,b){b.sort(function(){return Math.random()-.5});for(var c=0,e=20;e<g-40;e+=l)for(var f=0;f+l<=h;f+=l)d(a,b[c],e,f),c++,c===b.length&&(b.sort(function(a,b){return a.o?b.o?Math.random()-.5:-1:1}),c=0)}function b(a,e){for(var d=0,g=a.length;d<g;d++)if(void 0===a[d].o){c(a[d].src,function(c){a[d].o=c;b(a,e)});return}var f=[];a.forEach(function(a){a.o&&f.push(a.o)});e(f)}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=q;c=c.getContext("2d");c.drawImage(a,0,0,q,q);for(var c=c.getImageData(0,0,q,q),e=0,d=0;d<c.width*c.height*4;d+=4)c.data[d]=c.data[d+1]=c.data[d+2]=(c.data[d]+c.data[d+1]+c.data[d+2])/3,c.data[d+3]=50,e+=c.data[d];if(50>e/(c.height*c.width))for(d=0;d<c.width*c.height*4;d+=4)c.data[d]=c.data[d+1]=c.data[d+2]=255-c.data[d];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 e(){var a=k.createLinearGradient(0,0,0,h);a.addColorStop(0,"#4D394B");a.addColorStop(1,"#201820");k.fillStyle=a;k.fillRect(0,0,g,h);return k.getImageData(0,0,g,h)}function f(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 g=b.data[4*(d*b.width+e)]/255,f=4*((d+c)*a.width+e+c);a.data[f]*=g;a.data[f+1]*=g;a.data[f+2]*=g}return a}function d(a,b,c,d){var e=Math.floor(d);a=[a.data[e*g*4+0],a.data[e*g*4+1],a.data[e*g*4+2]];k.fillStyle=
+"#"+(1.1*a[0]<<16|1.1*a[1]<<8|1.1*a[2]).toString(16);k.beginPath();k.moveTo(c+l/2,d+n);k.lineTo(c-n+l,d+l/2);k.lineTo(c+l/2,d-n+l);k.lineTo(c+n,d+l/2);k.closePath();k.fill();k.putImageData(f(k.getImageData(c+n,d+n,t,t),b),c+n,d+n)}var m=document.createElement("canvas"),k=m.getContext("2d"),g=m.width=250,h=m.height=290,l=(g-40)/3,n=.1*l,t=Math.floor(l-2*n),q=.5*t,u;return function(c){if(u)c(u);else{var d=e(),f=[],g;for(g in E.a.b)E.a.b[g].h||f.push({src:"api/avatar?user="+g});b(f,function(b){a(d,b);
+u=m.toDataURL();c(u)})}}}();var W=0,F=null;function Ba(a){var b=new XMLHttpRequest;b.timeout=6E4;b.onreadystatechange=function(){if(4===b.readyState)if(b.status){var c=null,e=2===Math.floor(b.status/100);if(e){W&&(W=0,N(!0));c=b.response;try{c=JSON.parse(c)}catch(f){c=null}}else W?(W+=Math.floor((W||5)/2),W=Math.min(60,W)):(W=5,N(!1));a(e,c)}else W&&(W=0,N(!0)),Ba(a)};b.open("GET","api?v="+E.c,!0);b.send(null)}
+function Ca(a,b){if(a){if(b){var c=E,e=Date.now();b.v&&(c.c=b.v);if(b["static"]){var f=c.a,d=b["static"];if(d.bots)for(var m=0,k=d.bots.length;m<k;m++){var g=f.i[d.bots[m].id];g||(g=f.i[d.bots[m].id]=new ha(d.bots[m].id));var h=d.bots[m];void 0!==h.deleted&&(g.h=h.deleted);void 0!==h.name&&(g.name=h.name);h.icons&&(g.a.U=h.icons.image_36,g.a.m=h.icons.image_48,g.a.A=h.icons.image_72);void 0!==h.presence&&(g.f="away"!==h.presence);void 0!==h.isPresent&&(g.f=h.isPresent);g.version=Math.max(g.version,
+0)}if(d.users)for(m=0,k=d.users.length;m<k;m++)(g=f.b[d.users[m].id])||(g=f.b[d.users[m].id]=new ea(d.users[m].id)),h=d.users[m],void 0!==h.name&&(g.name=h.name),void 0!==h.deleted&&(g.h=h.deleted),void 0!==h.status&&(g.status=h.status),void 0!==h.presence&&(g.f="away"!==h.presence),void 0!==h.isPresent&&(g.f=h.isPresent),h.profile&&(g.a.R=h.profile.image_24,g.a.S=h.profile.image_32,g.a.m=h.profile.image_48,g.a.A=h.profile.image_72,g.a.O=h.profile.image_192,g.a.W=h.profile.image_512),g.version=Math.max(g.version,
+0);if(d.ims)for(m=0,k=d.ims.length;m<k;m++)if(h=r(f,d.ims[m].user))h.b||(f.C[d.ims[m].id]=h.b=new da(d.ims[m].id,h)),g=h.b,g.f=parseFloat(d.ims[m].last_read),g.b=h.h,g.version=Math.max(g.version,0);if(d.channels)for(m=0,k=d.channels.length;m<k;m++){(g=f.h[d.channels[m].id])||(g=f.h[d.channels[m].id]=new ba(d.channels[m].id));var h=d.channels[m],l=f;void 0!==h.name&&(g.name=h.name);void 0!==h.is_archived&&(g.b=h.is_archived);void 0!==h.last_read&&(g.f=parseFloat(h.last_read));if(h.members&&(g.a={},
+h.members))for(var n=0,t=h.members.length;n<t;n++){var q=r(l,h.members[n]);g.a[q.id]=q;q.i[g.id]=g}g.version=Math.max(g.version,0)}m=0;for(k=d.groups.length;m<k;m++){(g=f.w[d.groups[m].id])||(g=f.w[d.groups[m].id]=new ca(d.groups[m].id));h=f;l=d.groups[m];n=[];if(l.members){g.a={};t=0;for(q=l.members.length;t<q;t++){var u=r(h,l.members[t]);g.a[l.members[t]]=u;u.i[g.id]=g;n.push(u.name)}g.name=n.join(", ")}void 0!==l.is_archived&&(g.b=l.is_archived||!1===l.is_open);void 0!==l.last_read&&(g.f=parseFloat(l.last_read));
+g.version=Math.max(g.version,0)}d.emojis&&(f.c=d.emojis);f.f||(f.f=new aa(d.team.id));m=f.f;k=d.team;void 0!==k.name&&(m.name=k.name);k.icon&&(m.a.T=k.icon.image_34,m.a.V=k.icon.image_44,m.a.X=k.icon.image_68,m.a.Y=k.icon.image_88,m.a.M=k.icon.image_102,m.a.N=k.icon.image_132,m.a.P=k.icon.image_230,m.a.Z=k.icon.image_default);m.version=Math.max(m.version,0);f.D=Math.max(f.D,0);d.self&&(f.a=r(f,d.self.id),f.a.c||(f.a.c=new fa),ga(f.a.c,d.self.prefs));oa()}if(b.live){for(var w in b.live)(f=c.b[w])?
+C(f,b.live[w],e):c.b[w]=new z(w,250,b.live[w],e);for(var A in b.live)(e=y(c.a,A))&&!e.b&&(Aa(e,b.live[A]),F&&b.live[F.id]&&Y())}}Z()}else setTimeout(Z,1E3*W)}function Z(){Ba(Ca)}
+function wa(a){F&&document.getElementById(F.id).classList.remove("selected");document.getElementById(a.id).classList.add("selected");document.body.classList.remove("no-room-selected");F=a;a=F.name||(F.c?F.c.name:void 0);if(!a){a=[];for(var b in F.a)a.push(F.a[b].name);a=a.join(", ")}document.getElementById("currentRoomTitle").textContent=a;Y();Q();document.getElementById("fileUploadContainer").classList.add("hidden");za();I&&(I=null,O());J&&(J=null,O());F.f&&!E.b[F.id]&&(b=new XMLHttpRequest,b.open("GET",
+"api/hist?room="+F.id,!0),b.send(null))}function xa(a,b,c){var e=F;new FileReader;var f=new FormData,d=new XMLHttpRequest;f.append("file",b);f.append("filename",a);d.onreadystatechange=function(){4===d.readyState&&(204===d.status?c(null):c(d.statusText))};d.open("POST","api/file?room="+e.id);d.send(f)}
+function Da(a,b){var c=F;if("me"==a){if(I)return!1;var e=new XMLHttpRequest;e.open("POST","api/msg?room="+c.id+"&me&text="+encodeURIComponent(b),!0);e.send(null);return!0}if("shrug"==a)return b.length&&(b+=" "),ya(b+"\u00af_(\u30c4)_/\u00af",!0);console.log("Unknown command "+a);return!1}
+function ya(a,b){if(J){var c=new XMLHttpRequest;c.open("PUT","api/msg?room="+F.id+"&ts="+J.id+"&text="+encodeURIComponent(a),!0);c.send(null);return!0}if("/"===a[0]&&!0!==b)return c=a.indexOf(" "),Da(a.substr(1,-1===c?void 0:c-1),(-1===c?"":a.substr(c)).trim());var c=F,e=I,f=new XMLHttpRequest,d="api/msg?room="+c.id+"&text="+encodeURIComponent(a);if(e){var m=r(E.a,e.j),k="Message";"C"===c.id[0]?k="Channel message":"D"===c.id[0]?k="Direct message":"G"===c.id[0]&&(k="Group message");d+="&attachments="+
+encodeURIComponent(JSON.stringify([{fallback:e.text,author_name:"<@"+m.id+"|"+m.name+">",author_icon:m.a.m,text:e.text,footer:k,ts:e.b}]))}f.open("POST",d,!0);f.send(null);return!0}function va(a){var b=new XMLHttpRequest;b.open("DELETE","api/msg?room="+F.id+"&ts="+a.id,!0);b.send(null)}function T(a,b,c){var e=new XMLHttpRequest;e.open("POST","api/reaction?room="+a+"&msg="+b+"&reaction="+encodeURIComponent(c),!0);e.send(null)};

+ 1 - 1
srv/public/style.css

@@ -7,7 +7,7 @@ body { display: flex; margin: 0; padding: 0; font-family: Lato, sans-serif; }
 .slack-context-channellist { padding-left: 0; list-style: none; }
 .slack-context-room { position: relative; }
 .slack-context-room > a { display: block; padding: 3px 0 3px 1.5em; text-decoration: none; color: #AB9BA9; margin-right: 15px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; }
-.slack-context-room > a:hover { background-color: #3e313c; }
+.slack-context-room > a:hover { background-color: rgba(10, 5, 10, .6); }
 .slack-context-room.selected > a { background-color: #4c9689; color: #fff; border-top-right-radius: 3px; border-bottom-right-radius: 3px; }
 .slack-context-room.slack-ims { font-style: italic; }
 .slack-context-room.slack-ims::before { content: " "; position: absolute; display: inline-block; height: 6px; width: 6px; border: 2px solid #4c9689; background: #4c9689; top: 0; bottom: 0; margin: auto auto auto 7px; border-radius: 5px; }

+ 0 - 1
srv/src/httpServ.js

@@ -261,7 +261,6 @@ Server.prototype.onRequest = function(req, res) {
         } else if (req.urlObj.match(["api"])) {
             res.slack.onRequest(
                 (req.urlObj.queryTokens.v ? req.urlObj.queryTokens.v[0] : 0) || 0
-                ,(req.urlObj.queryTokens.uv ? req.urlObj.queryTokens.uv[0] : undefined) || undefined
                 , (slack, newData) => {
                 if (!res.ended) {
                     try {

+ 12 - 20
srv/src/slack.js

@@ -68,12 +68,12 @@ Slack.prototype.onUserInterract = function(t) {
     this.lastPing = Math.max(t, this.lastPing);
 }
 
-Slack.prototype.onRequest = function(knownVersion, knownUserVersion, cb) {
+Slack.prototype.onRequest = function(knownVersion, cb) {
     this.lastCb = cb;
     if (this.connected === false) {
-        this.connect(knownVersion, knownUserVersion);
+        this.connect(knownVersion);
     } else {
-        this.waitForEvent(knownVersion, knownUserVersion);
+        this.waitForEvent(knownVersion);
     }
 };
 
@@ -96,7 +96,7 @@ function httpsRequest(url, cb) {
     });
 }
 
-Slack.prototype.connect = function(knownVersion, knownUserVersion) {
+Slack.prototype.connect = function(knownVersion) {
     var _this = this;
 
     this.connected = undefined;
@@ -123,9 +123,9 @@ Slack.prototype.connect = function(knownVersion, knownUserVersion) {
         }
         _this.getEmojis((emojis) => {
             body.emojis = emojis;
-            _this.data.updateStatic(body);
+            _this.data.updateStatic(body, Date.now());
             _this.connectRtm(body.url);
-            _this.waitForEvent(knownVersion, knownUserVersion);
+            _this.waitForEvent(knownVersion);
         });
     });
 };
@@ -139,7 +139,7 @@ Slack.prototype.getEmojis = function(cb) {
     });
 };
 
-Slack.prototype.waitForEvent = function(knownVersion, knownUserVersion) {
+Slack.prototype.waitForEvent = function(knownVersion) {
     var tick = 0
         ,_this = this
         ,interval;
@@ -155,17 +155,8 @@ Slack.prototype.waitForEvent = function(knownVersion, knownUserVersion) {
                 ,updatedLive = _this.getLiveUpdates(knownVersion)
                 ,updated;
 
-            if (knownUserVersion !== undefined) {
-                var updatedUsers = _this.data.getUserStream(knownUserVersion);
-                if (updatedUsers) {
-                    updated = {
-                        "userV": updatedUsers.version
-                        ,"user": updatedUsers.stream
-                    };
-                }
-            }
             if (updatedCtx || updatedLive) {
-                updated = updated || {};
+                updated = {};
                 updated["static"] = updatedCtx;
                 updated["live"] = updatedLive;
                 updated["v"] = Math.max(_this.data.liveV, _this.data.staticV);
@@ -212,7 +203,7 @@ Slack.prototype.onMessage = function(msg, t) {
         var channelId = msg["channel"] || msg["channel_id"] || msg["item"]["channel"]
             ,histo = this.history[channelId];
         if (histo) {
-            this.data.liveV = Math.max(this.data.liveV, histo.push(msg));
+            this.data.liveV = Math.max(this.data.liveV, histo.push(msg, t));
             histo.resort();
         } else if (this.data.getChannel(msg["channel"])) {
             this.fetchHistory(msg["channel"]);
@@ -422,12 +413,13 @@ Slack.prototype.fetchHistory = function(targetId) {
         +"&count=" +HISTORY_LENGTH,
     (status, resp) => {
         if (status === 200 && resp && resp.ok) {
-            var history = _this.history[targetId];
+            var history = _this.history[targetId]
+                ,now = Date.now();
             if (!history) {
                 history = _this.history[targetId] = new SlackHistory(targetId, HISTORY_LENGTH);
                 history.isNew = true;
             }
-            this.data.liveV = Math.max(history.pushAll(resp.messages), this.data.liveV);
+            this.data.liveV = Math.max(history.pushAll(resp.messages, Date.now()), this.data.liveV);
         }
     });
 };

+ 148 - 137
srv/src/slackData.js

@@ -30,24 +30,31 @@ function SlackTeam(teamId) {
         ,image_230: ""
         ,image_default: ""
     };
+    /** @type {number} */
+    this.version = 0;
 }
 
-SlackTeam.prototype.update = function(teamData) {
-    this.name = teamData["name"];
-    this.domain = teamData["domain"];
-    this.callApp = teamData["prefs"]["calling_app_id"];
-    this.callAppName = teamData["prefs"]["calling_app_name"];
-    this.fileUploadPermission = teamData["prefs"]["disable_file_uploads"];
-    this.fileEditPermission = teamData["prefs"]["disable_file_editing"];
-    this.fileDeletePermission = teamData["prefs"]["disable_file_deleting"];
-    this.icons.image_34 = teamData["icon"]["image_34"];
-    this.icons.image_44 = teamData["icon"]["image_44"];
-    this.icons.image_68 = teamData["icon"]["image_68"];
-    this.icons.image_88 = teamData["icon"]["image_88"];
-    this.icons.image_102 = teamData["icon"]["image_102"];
-    this.icons.image_132 = teamData["icon"]["image_132"];
-    this.icons.image_230 = teamData["icon"]["image_230"];
-    this.icons.image_default = teamData["icon"]["image_default"];
+SlackTeam.prototype.update = function(teamData, t) {
+    if (teamData["name"] !== undefined) this.name = teamData["name"];
+    if (teamData["domain"] !== undefined) this.domain = teamData["domain"];
+    if (teamData["prefs"]) {
+        this.callApp = teamData["prefs"]["calling_app_id"];
+        this.callAppName = teamData["prefs"]["calling_app_name"];
+        this.fileUploadPermission = teamData["prefs"]["disable_file_uploads"];
+        this.fileEditPermission = teamData["prefs"]["disable_file_editing"];
+        this.fileDeletePermission = teamData["prefs"]["disable_file_deleting"];
+    }
+    if (teamData["icon"]) {
+        this.icons.image_34 = teamData["icon"]["image_34"];
+        this.icons.image_44 = teamData["icon"]["image_44"];
+        this.icons.image_68 = teamData["icon"]["image_68"];
+        this.icons.image_88 = teamData["icon"]["image_88"];
+        this.icons.image_102 = teamData["icon"]["image_102"];
+        this.icons.image_132 = teamData["icon"]["image_132"];
+        this.icons.image_230 = teamData["icon"]["image_230"];
+        this.icons.image_default = teamData["icon"]["image_default"];
+    }
+    this.version = Math.max(this.version, t);
 }
 
 /**
@@ -82,24 +89,28 @@ function SlackChan(chanId) {
     this.purposeTs;
     /** @type {SlackUser|SlackBot|undefined} */
     this.purposeCreator;
+    /** @type {number} */
+    this.version = 0;
 }
 
 /**
  * @param {*} chanData
  * @param {SlackData} slackData
 **/
-SlackChan.prototype.update = function(chanData, slackData) {
-    this.name = chanData["name"];
-    this.created = chanData["created"];
-    this.creator = slackData.getMember(chanData["creator"]);
-    this.archived = chanData["is_archived"];
-    this.isMember = chanData["is_member"];
-    this.lastRead = parseFloat(chanData["last_read"]);
-    this.members = {};
-    if (chanData["members"]) for (var i =0, nbMembers = chanData["members"].length; i < nbMembers; i++) {
-        var member = slackData.getMember(chanData["members"][i]);
-        this.members[member.id] = member;
-        member.channels[this.id] = this;
+SlackChan.prototype.update = function(chanData, slackData, t) {
+    if (chanData["name"] !== undefined) this.name = chanData["name"];
+    if (chanData["created"] !== undefined) this.created = chanData["created"];
+    if (chanData["creator"] !== undefined) this.creator = slackData.getMember(chanData["creator"]);
+    if (chanData["is_archived"] !== undefined) this.archived = chanData["is_archived"];
+    if (chanData["is_member"] !== undefined) this.isMember = chanData["is_member"];
+    if (chanData["last_read"] !== undefined) this.lastRead = parseFloat(chanData["last_read"]);
+    if (chanData["members"]) {
+        this.members = {};
+        if (chanData["members"]) for (var i =0, nbMembers = chanData["members"].length; i < nbMembers; i++) {
+            var member = slackData.getMember(chanData["members"][i]);
+            this.members[member.id] = member;
+            member.channels[this.id] = this;
+        }
     }
     if (chanData["topic"]) {
         this.topic = chanData["topic"]["value"];
@@ -111,6 +122,7 @@ SlackChan.prototype.update = function(chanData, slackData) {
         this.purposeCreator = slackData.getMember(chanData["purpose"]["creator"]);
         this.purposeTs = chanData["purpose"]["last_set"];
     }
+    this.version = Math.max(this.version, t);
 }
 
 /**
@@ -144,27 +156,31 @@ function SlackGroup(id) {
     this.purposeTs;
     /** @type {SlackUser|SlackBot|undefined} */
     this.purposeCreator;
+    /** @type {number} version */
+    this.version = 0;
 }
 
 /**
  * @param {SlackData} slack
  * @param {*} groupData
 **/
-SlackGroup.prototype.update = function(slack, groupData) {
+SlackGroup.prototype.update = function(slack, groupData, t) {
     var memberNames = [];
-    /** @type {Object.<string, SlackUser|SlackBot>} */
-    this.members = {};
-    for (var i =0, nbMembers = groupData["members"].length; i < nbMembers; i++) {
-        var member = slack.getMember(groupData["members"][i]);
-        this.members[groupData["members"][i]] = member;
-        member.channels[this.id] = this;
-        memberNames.push(member.name);
+    if (groupData["members"]) {
+        /** @type {Object.<string, SlackUser|SlackBot>} */
+        this.members = {};
+        for (var i =0, nbMembers = groupData["members"].length; i < nbMembers; i++) {
+            var member = slack.getMember(groupData["members"][i]);
+            this.members[groupData["members"][i]] = member;
+            member.channels[this.id] = this;
+            memberNames.push(member.name);
+        }
+        this.name = memberNames.join(", ");
     }
-    this.name = memberNames.join(", ");
-    this.created = groupData["created"];
-    this.creator = slack.getMember(groupData["creator"]);
-    this.archived = groupData["is_archived"] || groupData["is_open"] === false;
-    this.lastRead = parseFloat(groupData["last_read"]);
+    if (groupData["created"] !== undefined) this.created = groupData["created"];
+    if (groupData["creator"] !== undefined) this.creator = slack.getMember(groupData["creator"]);
+    if (groupData["is_archived"] !== undefined) this.archived = groupData["is_archived"] || groupData["is_open"] === false;
+    if (groupData["last_read"] !== undefined) this.lastRead = parseFloat(groupData["last_read"]);
     if (groupData["topic"]) {
         this.topic = groupData["topic"]["value"];
         this.topicCreator = slack.getMember(groupData["topic"]["creator"]);
@@ -175,6 +191,7 @@ SlackGroup.prototype.update = function(slack, groupData) {
         this.purposeCreator = slack.getMember(groupData["purpose"]["creator"]);
         this.purposeTs = groupData["purpose"]["last_set"];
     }
+    this.version = Math.max(this.version, t);
 }
 
 /**
@@ -193,16 +210,19 @@ function SlackIms(id, user) {
     this.lastRead;
     /** @type {boolean} */
     this.archived;
+    /** @type {number} */
+    this.version = 0;
 }
 
 /**
  * @param {SlackUser|SlackBot} user
  * @param {*} imsData
 **/
-SlackIms.prototype.update = function(user, imsData) {
+SlackIms.prototype.update = function(user, imsData, t) {
     this.created = imsData["created"];
     this.lastRead = parseFloat(imsData["last_read"]);
     this.archived = user.deleted;
+    this.version = Math.max(this.version, t);
 }
 
 /**
@@ -251,24 +271,30 @@ function SlackUser(id) {
 /**
  * @param {*} userData
 **/
-SlackUser.prototype.update = function(userData) {
-    this.name = userData["name"];
-    this.deleted = userData["deleted"];
-    this.status = userData["status"];
-    this.realName = userData["real_name"] || userData["profile"]["real_name"];
+SlackUser.prototype.update = function(userData, t) {
+    if (userData["name"] !== undefined) this.name = userData["name"];
+    if (userData["deleted"] !== undefined) this.deleted = userData["deleted"];
+    if (userData["status"] !== undefined) this.status = userData["status"];
+    if (userData["real_name"] !== undefined)
+        this.realName = userData["real_name"];
+    else if (userData["profile"] && userData["profile"]["real_name"] !== undefined)
+        this.realName = userData["profile"]["real_name"];
     if (userData["presence"] !== undefined)
         this.presence = userData["presence"] !== 'away';
     if (userData["isPresent"] !== undefined)
         this.presence = userData["isPresent"];
-    this.icons.image_24 = userData["profile"]["image_24"];
-    this.icons.image_32 = userData["profile"]["image_32"];
-    this.icons.image_48 = userData["profile"]["image_48"];
-    this.icons.image_72 = userData["profile"]["image_72"];
-    this.icons.image_192 = userData["profile"]["image_192"];
-    this.icons.image_512 = userData["profile"]["image_512"];
-    this.email = userData["profile"]["email"];
-    this.firstName = userData["profile"]["first_name"];
-    this.lastName = userData["profile"]["last_name"];
+    if (userData["profile"]) {
+        this.icons.image_24 = userData["profile"]["image_24"];
+        this.icons.image_32 = userData["profile"]["image_32"];
+        this.icons.image_48 = userData["profile"]["image_48"];
+        this.icons.image_72 = userData["profile"]["image_72"];
+        this.icons.image_192 = userData["profile"]["image_192"];
+        this.icons.image_512 = userData["profile"]["image_512"];
+        this.email = userData["profile"]["email"];
+        this.firstName = userData["profile"]["first_name"];
+        this.lastName = userData["profile"]["last_name"];
+    }
+    this.version = Math.max(this.version, t);
 }
 
 SlackUser.prototype.setPresence = function(presenceStr, t) {
@@ -276,18 +302,6 @@ SlackUser.prototype.setPresence = function(presenceStr, t) {
     this.version = Math.max(t, this.version);
 }
 
-SlackUser.prototype.getUserStream = function() {
-    var res = {
-        "presence": this.presence
-    };
-    return res;
-}
-
-SlackUser.prototype.onUserStream = function(userStream) {
-    if (userStream["presence"] !== undefined)
-        this.presence = userStream["presence"];
-}
-
 /**
  * @constructor
 **/
@@ -302,7 +316,7 @@ function SelfPreferences() {
 /**
  * @param {*} prefs
 **/
-SelfPreferences.prototype.update = function(prefs) {
+SelfPreferences.prototype.update = function(prefs, t) {
     this.favoriteEmojis = /** @type {Object<string,number>} */ (JSON.parse(prefs["emoji_use"]));
     if (prefs["highlight_words"])
         this.highlights = (prefs["highlight_words"]||"").split(',').filter(function(i) {
@@ -310,6 +324,7 @@ SelfPreferences.prototype.update = function(prefs) {
         });
     else if (prefs["highlights"])
         this.highlights = prefs["highlights"];
+    this.version = Math.max(this.version, t);
 }
 
 /**
@@ -345,13 +360,20 @@ function SlackBot(id) {
 }
 
 /** @param {*} botData */
-SlackBot.prototype.update = function(botData) {
-    this.deleted = botData["deleted"];
-    this.name = botData["name"];
-    this.appId = botData["app_id"];
-    this.icons.image_36 = botData["icons"]["image_36"]
-    this.icons.image_48 = botData["icons"]["image_48"]
-    this.icons.image_72 = botData["icons"]["image_72"]
+SlackBot.prototype.update = function(botData, t) {
+    if (botData["deleted"] !== undefined) this.deleted = botData["deleted"];
+    if (botData["name"] !== undefined) this.name = botData["name"];
+    if (botData["app_id"] !== undefined) this.appId = botData["app_id"];
+    if (botData["icons"]) {
+        this.icons.image_36 = botData["icons"]["image_36"]
+        this.icons.image_48 = botData["icons"]["image_48"]
+        this.icons.image_72 = botData["icons"]["image_72"]
+    }
+    if (botData["presence"] !== undefined)
+        this.presence = botData["presence"] !== 'away';
+    if (botData["isPresent"] !== undefined)
+        this.presence = botData["isPresent"];
+    this.version = Math.max(this.version, t);
 }
 
 SlackBot.prototype.setPresence = function(presenceStr, t) {
@@ -359,13 +381,6 @@ SlackBot.prototype.setPresence = function(presenceStr, t) {
     this.version = Math.max(t, this.version);
 }
 
-SlackBot.prototype.getUserStream = function() {
-    var res = {
-        "presence": this.presence
-    };
-    return res;
-}
-
 /**
  * @constructor
 **/
@@ -402,8 +417,8 @@ function SlackData(slack) {
 /**
  * @return {Object}
 **/
-SlackTeam.prototype.toStatic = function() {
-    return {
+SlackTeam.prototype.toStatic = function(t) {
+    return t >= this.version ? {} : {
         "id": this.id
         ,"name": this.name
         ,"domain": this.domain
@@ -421,7 +436,9 @@ SlackTeam.prototype.toStatic = function() {
 /**
  * @return {Object}
 **/
-SlackChan.prototype.toStatic = function() {
+SlackChan.prototype.toStatic = function(t) {
+    if (t >= this.version)
+        return null;
     var res = {
         "id": this.id
         ,"name": this.name
@@ -450,8 +467,8 @@ SlackChan.prototype.toStatic = function() {
 /**
  * @return {Object}
 **/
-SlackUser.prototype.toStatic = function() {
-    return {
+SlackUser.prototype.toStatic = function(t) {
+    return t >= this.version ? null : {
         "id": this.id
         ,"name": this.name
         ,"deleted": this.deleted
@@ -473,7 +490,9 @@ SlackUser.prototype.toStatic = function() {
     };
 };
 
-SlackGroup.prototype.toStatic = function() {
+SlackGroup.prototype.toStatic = function(t) {
+    if (t >= this.version)
+        return null;
     var res = {
         "id": this.id
         ,"members": []
@@ -502,8 +521,8 @@ SlackGroup.prototype.toStatic = function() {
     return res;
 };
 
-SlackIms.prototype.toStatic = function() {
-    return {
+SlackIms.prototype.toStatic = function(t) {
+    return t >= this.version ? null: {
         "id": this.id
         ,"created": this.created
         ,"user": this.user.id
@@ -511,12 +530,13 @@ SlackIms.prototype.toStatic = function() {
     };
 }
 
-SlackBot.prototype.toStatic = function() {
-    return {
+SlackBot.prototype.toStatic = function(t) {
+    return t >= this.version ? null : {
         "id": this.id
         ,"deleted": this.deleted
         ,"name": this.name
         ,"app_id": this.appId
+        ,"isPresent": this.presence
         ,"icons": {
             "image_36": this.icons.image_36
             ,"image_48": this.icons.image_48
@@ -528,52 +548,52 @@ SlackBot.prototype.toStatic = function() {
 /**
  * @param {*} data
 **/
-SlackData.prototype.updateStatic = function(data) {
+SlackData.prototype.updateStatic = function(data, t) {
     if (data["bots"]) for (var i =0, nbBots = data["bots"].length; i < nbBots; i++) {
         var botObj = this.bots[data["bots"][i]["id"]];
         if (!botObj)
             botObj = this.bots[data["bots"][i]["id"]] = new SlackBot(data["bots"][i]["id"]);
-        botObj.update(data["bots"][i]);
+        botObj.update(data["bots"][i], t);
     }
     if (data["users"]) for (var i =0, nbUsers = data["users"].length; i < nbUsers; i++) {
         var userObj = this.users[data["users"][i]["id"]];
         if (!userObj)
             userObj = this.users[data["users"][i]["id"]] = new SlackUser(data["users"][i]["id"]);
-        userObj.update(data["users"][i]);
+        userObj.update(data["users"][i], t);
     }
     if (data["ims"]) for (var i =0, nbIms = data["ims"].length; i < nbIms; i++) {
         var user = this.getMember(data["ims"][i]["user"]);
         if (user) {
             if (!user.ims)
                 this.ims[data["ims"][i]["id"]] = user.ims = new SlackIms(data["ims"][i]["id"], user);
-            user.ims.update(user, data["ims"][i]);
+            user.ims.update(user, data["ims"][i], t);
         }
     }
     if (data["channels"]) for (var i =0, nbChan = data["channels"].length; i < nbChan; i++) {
         var chanObj = this.channels[data["channels"][i]["id"]];
         if (!chanObj)
             chanObj = this.channels[data["channels"][i]["id"]] = new SlackChan(data["channels"][i]["id"]);
-        chanObj.update(data["channels"][i], this);
+        chanObj.update(data["channels"][i], this, t);
     }
     for (var i =0, nbGroups = data["groups"].length; i < nbGroups; i++) {
         var groupObj = this.groups[data["groups"][i]["id"]];
         if (!groupObj)
             groupObj = this.groups[data["groups"][i]["id"]] = new SlackGroup(data["groups"][i]["id"]);
-        groupObj.update(this, data["groups"][i]);
+        groupObj.update(this, data["groups"][i], t);
     }
     if (data["emojis"]) this.emojis = data["emojis"];
     if (!this.team) this.team = new SlackTeam(data["team"]["id"]);
-    this.team.update(data["team"]);
-    this.staticV = parseFloat(data["latest_event_ts"]);
+    this.team.update(data["team"], t);
+    this.staticV = Math.max(this.staticV, t);
     if (data["self"]) {
         this.self = this.getMember(data["self"]["id"]);
         if (!this.self.prefs) this.self.prefs = new SelfPreferences();
-        this.self.prefs.update(data["self"]["prefs"]);
+        this.self.prefs.update(data["self"]["prefs"], t);
     }
 };
 
-SelfPreferences.prototype.toStatic = function() {
-    return {
+SelfPreferences.prototype.toStatic = function(t) {
+    return this.version > t ? null : {
         "emoji_use": JSON.stringify(this.favoriteEmojis)
         ,"highlights": this.highlights
     };
@@ -611,9 +631,9 @@ SlackData.prototype.getChannel = function(chanId) {
 };
 
 /** @return {Object} */
-SlackData.prototype.buildStatic = function() {
+SlackData.prototype.buildStatic = function(t) {
     var res = {
-        "team": this.team.toStatic()
+        "team": this.team.toStatic(t)
         ,"channels": []
         ,"groups": []
         ,"ims": []
@@ -621,22 +641,33 @@ SlackData.prototype.buildStatic = function() {
         ,"bots": []
         ,"self": {
             "id": this.self.id
-            ,"prefs": this.self.prefs.toStatic()
+            ,"prefs": this.self.prefs.toStatic(t)
         }
         ,"emojis": this.emojis
     };
     for (var chanId in this.channels) {
-        res["channels"].push(this.channels[chanId].toStatic());
+        var chan = this.channels[chanId].toStatic(t);
+        if (chan)
+            res["channels"].push(chan);
     }
     for (var userId in this.users) {
-        res["users"].push(this.users[userId].toStatic());
-        res["ims"].push(this.users[userId].ims.toStatic());
+        var user = this.users[userId].toStatic(t)
+            ,ims = this.users[userId].ims.toStatic(t);
+
+        if (user)
+            res["users"].push(user);
+        if (ims)
+            res["ims"].push(ims);
     }
     for (var botId in this.bots) {
-        res["bots"].push(this.bots[botId].toStatic());
+        var bot = this.bots[botId].toStatic(t);
+        if (bot)
+            res["bots"].push(bot);
     }
     for (var groupId in this.groups) {
-        res["groups"].push(this.groups[groupId].toStatic());
+        var group = this.groups[groupId].toStatic(t);
+        if (group)
+            res["groups"].push(group);
     }
     return res;
 };
@@ -647,9 +678,10 @@ SlackData.prototype.buildStatic = function() {
 **/
 SlackData.prototype.onMessage = function(msg, t) {
     if (msg["type"] === "presence_change") {
-        var member = this.users[msg["user"]];
+        var member = this.getMember(msg["user"]);
         if (member)
             member.setPresence(msg["presence"], t);
+        this.staticV = Math.max(this.staticV, t);
     }
 }
 
@@ -658,30 +690,9 @@ SlackData.prototype.onMessage = function(msg, t) {
  * @return {Object|undefined}
 **/
 SlackData.prototype.getUpdates = function(knownVersion) {
-    return (this.staticV > knownVersion) ? this.buildStatic() : undefined;
-};
-
-SlackData.prototype.getUserStream = function(knownVersion) {
-    var res
-        ,v = 0;
-
-    for (var i in this.users) {
-        var user = this.users[i];
-        if (user.version > knownVersion) {
-            res = res || {};
-            res[i] = user.getUserStream();
-            v = Math.max(v, user.version);
-        }
-    }
-    for (var i in this.bots) {
-        var bot = this.bots[i];
-        if (bot.version > knownVersion) {
-            res = res || {};
-            res[i] = bot.getUserStream();
-            v = Math.max(v, user.version);
-        }
-    }
-    return res ? { stream: res, version: v } : undefined;
+    if (this.staticV > knownVersion)
+        return this.buildStatic(knownVersion);
+    return undefined;
 };
 
 /** @suppress {undefinedVars,checkTypes} */

+ 13 - 14
srv/src/slackHistory.js

@@ -15,7 +15,7 @@ function SlackMessage(e, ts) {
     this.id = e["ts"];
 
     /** @const @type {number} **/
-    this.ts = ts || parseFloat(e["ts"]);
+    this.ts = parseFloat(e["ts"]);
 
     /** @type {string} */
     this.text = e["text"] || "";
@@ -45,7 +45,7 @@ function SlackMessage(e, ts) {
     this.reactions = {};
 
     /** @type {number} */
-    this.version = this.ts;
+    this.version = ts;
 
     var _this = this;
     e["reactions"] && e["reactions"].forEach(function(r) {
@@ -86,8 +86,9 @@ SlackMessage.prototype.update = function(e, ts) {
  * @param {SlackChan|SlackGroup|SlackIms|string} room or roomId
  * @param {number} keepMessages number of messages to keep in memory
  * @param {Array|undefined} evts
+ * @param {number|undefined} now
 **/
-function SlackHistory(room, keepMessages, evts) {
+function SlackHistory(room, keepMessages, evts, now) {
     /** @type {string} */
     this.id = typeof room === "string" ? room : room.id;
     /** @type {Array.<SlackMessage>} */
@@ -98,7 +99,7 @@ function SlackHistory(room, keepMessages, evts) {
     /** @const @type {number} */
     this.keepMessages = keepMessages;
 
-    if (evts) this.pushAll(evts);
+    if (evts) this.pushAll(evts, now);
 }
 
 /** @return {*} */
@@ -171,11 +172,11 @@ SlackMessage.prototype.hasReactionForUser = function(reaction, userId) {
  * @param {Array} evts
  * @return {number} biggest ts
 **/
-SlackHistory.prototype.pushAll = function(evts) {
+SlackHistory.prototype.pushAll = function(evts, t) {
     var result = 0;
 
     evts.forEach(function(e) {
-        result = Math.max(this.push(e), result);
+        result = Math.max(this.push(e, t), result);
     }.bind(this));
     this.resort();
     return result;
@@ -184,9 +185,7 @@ SlackHistory.prototype.pushAll = function(evts) {
 /**
  * @return {number} ts
 **/
-SlackHistory.prototype.push = function(ev) {
-    var ts = parseFloat(ev["ts"]);
-
+SlackHistory.prototype.push = function(ev, t) {
     if (!ev["type"] || ev["type"] === "message") {
         var exists = false
             ,targetId = ev["ts"]
@@ -201,23 +200,23 @@ SlackHistory.prototype.push = function(ev) {
         }
         for (var i =0, nbMsg = this.messages.length; i < nbMsg; i++) {
             if (this.messages[i].id === targetId) {
-                this.messages[i].update(modifArg, ts);
+                this.messages[i].update(modifArg, t);
                 exists = true;
                 break;
             }
         }
         if (!exists)
-            this.messages.push(new SlackMessage(ev, ts));
+            this.messages.push(new SlackMessage(ev, t));
     } else if (ev["type"] === "reaction_added") {
-        this.addReaction(ev["reaction"], ev["user"], ev["item"]["ts"], ts);
+        this.addReaction(ev["reaction"], ev["user"], ev["item"]["ts"], t);
     } else if (ev["type"] === "reaction_removed") {
-        this.removeReaction(ev["reaction"], ev["user"], ev["item"]["ts"], ts);
+        this.removeReaction(ev["reaction"], ev["user"], ev["item"]["ts"], t);
     } else {
         return 0;
     }
     while (this.messages.length > this.keepMessages)
         this.messages.shift();
-    return ts;
+    return t;
 }
 
 /**