!function(e){!function t(e,o,n){function s(i,a){if(!o[i]){if(!e[i]){var l="function"==typeof require&&require;if(!a&&l)return l(i,!0);if(r)return r(i,!0);throw new Error("Cannot find module '"+i+"'")}var c=o[i]={exports:{}};e[i][0].call(c.exports,function(t){var o=e[i][1][t];return s(o?o:t)},c,c.exports,t,e,o,n)}return o[i].exports}for(var r="function"==typeof require&&require,i=0;ie?this._legacy_add_donors(e):void 0):void 0})},o.prototype._legacy_parse_donors=function(e){var t=0;if(null!=e)for(var o=e.trim().split(/\W+/),n=0;n50)return"Each user you unmod counts as a single message. To avoid being globally banned, please limit yourself to 50 at a time and wait between uses.";for(var n=t.length;t.length;){var s=t.shift();e.room.tmiRoom.sendMessage("/unmod "+s)}return"Sent unmod command for "+n+" users."},t.chat_commands.massunmod.help="Usage: /ffz massunmod \nBroadcaster only. Unmod all the users in the provided list.",t.chat_commands.massmod=function(e,t){if(t=t.join(" ").trim(),!t.length)return"You must provide a list of users to mod.";t=t.split(/\W*,\W*/);var o=this.get_user();if(!o||!o.login==e.id)return"You must be the broadcaster to use massmod.";if(t.length>50)return"Each user you mod counts as a single message. To avoid being globally banned, please limit yourself to 50 at a time and wait between uses.";for(var n=t.length;t.length;){var s=t.shift();e.room.tmiRoom.sendMessage("/mod "+s)}return"Sent mod command for "+n+" users."},t.chat_commands.massmod.help="Usage: /ffz massmod \nBroadcaster only. Mod all the users in the provided list."},{}],3:[function(e,t){var o='',n="true"==localStorage.ffzDebugMode&&document.body.classList.contains("ffz-dev");t.exports={DEBUG:n,SERVER:n?"//localhost:8000/":"//cdn.frankerfacez.com/",SVGPATH:o,ZREKNARF:''+o+"",CHAT_BUTTON:''+o+""}},{}],4:[function(){var t=e.FrankerFaceZ;t.chat_commands.developer_mode=function(e,t){var o,t=t&&t.length?t[0].toLowerCase():null;return"y"==t||"yes"==t||"true"==t||"on"==t?o=!0:("n"==t||"no"==t||"false"==t||"off"==t)&&(o=!1),void 0===o?"Developer Mode is currently "+("true"==localStorage.ffzDebugMode?"enabled.":"disabled."):(localStorage.ffzDebugMode=o,"Developer Mode is now "+(o?"enabled":"disabled")+". Please refresh your browser.")},t.chat_commands.developer_mode.help="Usage: /ffz developer_mode \nEnable or disable Developer Mode. When Developer Mode is enabled, the script will be reloaded from //localhost:8000/script.js instead of from the CDN."},{}],5:[function(){var t=e.FrankerFaceZ;t.prototype.setup_chatview=function(){this.log("Hooking the Ember Chat view.");var e=App.__container__.resolve("view:chat");this._modify_cview(e),e.create().destroy();for(var t in Ember.View.views)if(Ember.View.views.hasOwnProperty(t)){var o=Ember.View.views[t];o instanceof e&&(this.log("Adding UI link manually to Chat view.",o),o.$(".textarea-contain").append(this.build_ui_link(o)))}},t.prototype._modify_cview=function(e){var t=this;e.reopen({didInsertElement:function(){this._super(),this.$()&&this.$(".textarea-contain").append(t.build_ui_link(this))},willClearRender:function(){this._super(),this.$(".ffz-ui-toggle").remove()},ffzUpdateLink:Ember.observer("controller.currentRoom",function(){t.update_ui_link()})})}},{}],6:[function(){var t=e.FrankerFaceZ,o=function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")};t.prototype.setup_line=function(){this.log("Hooking the Ember Line controller.");var e=App.__container__.resolve("controller:line"),o=this;e.reopen({tokenizedMessage:function(){var e=o._emoticonize(this,this._super()),t=o.get_user();return t&&this.get("model.from")==t.login||(e=o._mentionize(this,e)),e}.property("model.message","isModeratorOrHigher","controllers.emoticons.emoticons.[]")}),this.log("Hooking the Ember Line view.");var e=App.__container__.resolve("view:line");e.reopen({didInsertElement:function(){this._super();var e=this.get("element"),t=this.get("context.model.from");e.setAttribute("data-room",this.get("context.parentController.content.id")),e.setAttribute("data-sender",t),o.render_badge(this),"false"!=localStorage.ffzCapitalize&&o.capitalize(this,t)}});var n=this.get_user();n&&n.name&&(t.capitalization[n.login]=[n.name,Date.now()]),this.mention_words=localStorage.ffzMentionize?JSON.parse(localStorage.ffzMentionize):[]},t.capitalization={},t._cap_fetching=0,t.get_capitalization=function(e,o){if(e=e.toLowerCase(),"jtv"==e||"twitchnotify"==e)return e;var n=t.capitalization[e];return n&&Date.now()-n[1]<36e5?n[0]:(t._cap_fetching<5&&(t._cap_fetching++,Twitch.api.get("users/"+e).always(function(n){var s=n.display_name||e;t.capitalization[e]=[s,Date.now()],t._cap_fetching--,"function"==typeof o&&o(s)})),n?n[0]:e)},t.prototype.capitalize=function(e,o){var n=t.get_capitalization(o,this.capitalize.bind(this,e));n&&e.$(".from").text(n)},t.chat_commands.capitalization=function(e,t){var o,t=t&&t.length?t[0].toLowerCase():null;return"y"==t||"yes"==t||"true"==t||"on"==t?o=!0:("n"==t||"no"==t||"false"==t||"off"==t)&&(o=!1),void 0===o?"Chat Name Capitalization is currently "+("false"!=localStorage.ffzCapitalize?"enabled.":"disabled."):(localStorage.ffzCapitalize=o,"Chat Name Capitalization is now "+(o?"enabled.":"disabled."))},t.chat_commands.capitalization.help="Usage: /ffz capitalization \nEnable or disable Chat Name Capitalization. This setting does not work with BetterTTV.",t._regex_cache={},t.get_regex=function(e){return t._regex_cache[e]=t._regex_cache[e]||RegExp("\\b"+o(e)+"\\b","i")},t.prototype._mentionize=function(e,o){return this.mention_words?("string"==typeof o&&(o=[o]),_.each(this.mention_words,function(e){var n={mentionedUser:e,own:!1};o=_.compact(_.flatten(_.map(o,function(o){if(_.isObject(o))return o;var s=o.split(t.get_regex(e)),r=[];return s.forEach(function(e,t){r.push(e),t!==s.length-1&&r.push(n)}),r})))}),o):o},t.chat_commands.mentionize=function(e,t){return t&&t.length&&(this.mention_words=t.join(" ").trim().split(/\W*,\W*/),1==this.mention_words.length&&"disable"==this.mention_words[0]&&(this.mention_words=[]),localStorage.ffzMentionize=JSON.stringify(this.mention_words)),this.mention_words.length?"The following words will be treated as mentions: "+this.mention_words.join(", "):"There are no words set that will be treated as mentions."},t.chat_commands.mentionize.help="Usage: /ffz mentionize \nSet a list of words that will also be treated as mentions and be displayed specially in chat.",t.prototype._emoticonize=function(e,t){var o=e.get("parentController.model.id"),n=e.get("model.from"),s=this,r=this.getEmotes(n,o),i=[];return _.each(r,function(e){var o=s.emote_sets[e];o&&_.each(o.emotes,function(e){_.any(t,function(t){return _.isString(t)&&t.match(e.regex)})&&i.push(e)})}),i.length?("string"==typeof t&&(t=[t]),_.each(i,function(e){var o={isEmoticon:!0,cls:e.klass,emoticonSrc:e.url,altText:e.hidden?"???":e.name};t=_.compact(_.flatten(_.map(t,function(t){if(_.isObject(t))return t;var n=t.split(e.regex),s=[];return n.forEach(function(e,t){s.push(e),t!==n.length-1&&s.push(o)}),s})))}),t):t}},{}],7:[function(t){var o=e.FrankerFaceZ,n=/\.([\w\-_]+)\s*?\{content:\s*?"([^"]+)";\s*?background-image:\s*?url\("([^"]+)"\);\s*?height:\s*?(\d+)px;\s*?width:\s*?(\d+)px;\s*?margin:([^;}]+);?([^}]*)\}/gm,s=/[^\n}]*\.badges\s+\.moderator\s*{\s*background-image:\s*url\(\s*['"]([^'"]+)['"][^}]+(?:}|$)/,r=/^_([^_]+)_\d+$/,i=t("../constants"),a=t("../utils"),l=function(e){return e.moderator_badge?'.chat-line[data-room="'+e.id+'"] .badges .moderator { background-image:url("'+e.moderator_badge+'") !important; }':""};o.prototype.setup_room=function(){this.rooms={},this.log("Creating room style element.");var e=this._room_style=document.createElement("style");e.id="ffz-room-css",document.head.appendChild(e),this.log("Hooking the Ember Room model.");var t=App.__container__.resolve("model:room");this._modify_room(t);var o=t.instances;for(var n in o)if(o.hasOwnProperty(n)){var s=o[n];this.add_room(s.id,s),this._modify_room(s)}},o.chat_commands={},o.prototype.room_message=function(e,t){var o=t.split("\n");if(this.has_bttv)for(var n=0;no?this._legacy_add_room(e,t,o):void 0)})},o.prototype._legacy_load_room_css=function(e,t,o){var i=e,a=i.match(r);a&&a[1]&&(i=a[1]);var l={id:e,menu_sets:[i],sets:[i],moderator_badge:null,css:null};return o&&(o=o.replace(n,"").trim()),o&&(o=o.replace(s,function(e,t){return l.moderator_badge||"modicon.png"!==t.substr(-11)?e:(l.moderator_badge=t,"")})),l.css=o||null,this._load_room_json(e,t,l)}},{"../constants":3,"../utils":23}],8:[function(){var t=e.FrankerFaceZ;t.prototype.setup_router=function(){this.log("Hooking the Ember router.");var e=this;App.__container__.lookup("router:main").reopen({ffzTransition:function(){e.track_page()}.on("didTransition")})}},{}],9:[function(){var t=e.FrankerFaceZ;t.prototype.setup_viewers=function(){this.log("Hooking the Ember Viewers controller.");var e=App.__container__.resolve("controller:viewers");this._modify_viewers(e)},t.prototype._modify_viewers=function(e){var o=this;e.reopen({lines:function(){var e=this._super(),n=[],s={},r=null,i=App.__container__.lookup("controller:channel"),a=this.get("parentController.model.id"),l=i&&i.get("id");if(l){var c=i.get("display_name");c&&(t.capitalization[l]=[c,Date.now()])}a!=l&&(l=null);for(var u=0;uo?this._legacy_load_set(e,t,o):"function"==typeof t&&t(!1))})},o.prototype._legacy_load_css=function(e,t,o){var r={},i={id:e,emotes:r,extra_css:null},a=this;o=o.replace(n,function(e,t,o,n,s,i,c,u){s=parseInt(s),i=parseInt(i),c=l(c,s);var d="."===n.substr(n.lastIndexOf("/")+1,1),h=++a._last_emote_id,m={id:h,hidden:d,name:o,height:s,width:i,url:n,margins:c,extra_css:u};return r[h]=m,""}).trim(),o&&o.replace(s,function(e,t){i.icon||"modicon.png"!==t.substr(-11)||(i.icon=t)}),this._load_set_json(e,t,i)}},{"./constants":3,"./utils":23}],11:[function(){var t=e.FrankerFaceZ,o=/(\sdata-sender="[^"]*"(?=>))/;t.prototype.find_bttv=function(t,o){return this.has_bttv=!1,e.BTTVLOADED?this.setup_bttv(o||0):void(o>=6e4?this.log("BetterTTV was not detected after 60 seconds."):setTimeout(this.find_bttv.bind(this,t,(o||0)+t),t))},t.prototype.setup_bttv=function(e){this.log("BetterTTV was detected after "+e+"ms. Hooking."),this.has_bttv=!0,this.track("setCustomVariable","3","BetterTTV",BetterTTV.info.versionString());var t=BetterTTV.chat.helpers.sendMessage,n=this;BetterTTV.chat.helpers.sendMessage=function(e){var o=e.split(" ",1)[0].toLowerCase();return"/ffz"!==o?t(e):void n.run_command(e.substr(5),BetterTTV.chat.store.currentRoom)};var s,r=BetterTTV.chat.handlers.privmsg;BetterTTV.chat.handlers.privmsg=function(e,t){s=e;var o=r(e,t);return s=null,o};var i=BetterTTV.chat.templates.privmsg;BetterTTV.chat.templates.privmsg=function(e,t,r,a,l){n.bttv_badges(l);var c=i(e,t,r,a,l);return c.replace(o,'$1 data-room="'+s+'"')};var a,l=BetterTTV.chat.templates.message;BetterTTV.chat.templates.message=function(e,t,o,n){a=e;var s=l(e,t,o,n);return a=null,s};var c=BetterTTV.chat.templates.emoticonize;BetterTTV.chat.templates.emoticonize=function(e,t){var o=c(e,t),r=n.getEmotes(a,s),t=[];return _.each(r,function(e){var s=n.emote_sets[e];s&&_.each(s.emotes,function(e){_.any(o,function(t){return _.isString(t)&&t.match(e.regex)})&&t.push(e)})}),t.length?(_.each(t,function(e){var t=[''+e.name+''],n=o;if(o=[],!n||!n.length)return o;for(var s=0;s=6e4?this.log("Emote Menu for Twitch was not detected after 60 seconds."):setTimeout(this.find_emote_menu.bind(this,t,(o||0)+t),t))},t.prototype.setup_emote_menu=function(e){this.log("Emote Menu for Twitch was detected after "+e+"ms. Registering emote enumerator."),emoteMenu.registerEmoteGetter("FrankerFaceZ",this._emote_menu_enumerator.bind(this))},t.prototype._emote_menu_enumerator=function(){for(var e=this.get_user(),o=e?e.login:null,n=App.__container__.lookup("controller:chat"),s=n?n.get("currentRoom.id"):null,r=this.getEmotes(o,s),i=[],a=0;a=6e4?this.log('Twitch application not detected in "'+location.toString()+'". Aborting.'):setTimeout(this.initialize.bind(this,t,(o||0)+t),t)))},o.prototype.setup_ember=function(t){var n=e.performance&&performance.now?performance.now():Date.now();this.log("Found Twitch application after "+(t||0)+' ms in "'+location+'". Initializing FrankerFaceZ version '+o.version_info),this.users={};for(var s in localStorage)"ffz_"==s.substr(0,4)&&localStorage.removeItem(s);this.ws_create(),this.setup_emoticons(),this.setup_badges(),this.setup_piwik(),this.setup_router(),this.setup_room(),this.setup_line(),this.setup_chatview(),this.setup_viewers(),this.setup_css(),this.setup_menu(),this.find_bttv(10),this.find_emote_menu(10),this.check_ff();var r=e.performance&&performance.now?performance.now():Date.now(),i=r-n;this.log("Initialization complete in "+i+"ms")}},{"./badges":1,"./commands":2,"./debug":4,"./ember/chatview":5,"./ember/line":6,"./ember/room":7,"./ember/router":8,"./ember/viewers":9,"./emoticons":10,"./ext/betterttv":11,"./ext/emote_menu":12,"./featurefriday":14,"./shims":15,"./socket":16,"./tracking":17,"./ui/menu":18,"./ui/menu_button":19,"./ui/notifications":20,"./ui/styles":21,"./ui/viewer_count":22}],14:[function(t){var o=e.FrankerFaceZ,n=t("./constants");o.prototype.feature_friday=null,o.prototype.check_ff=function(e){e||this.log("Checking for Feature Friday data..."),jQuery.ajax(n.SERVER+"script/event.json",{cache:!1,dataType:"json",context:this}).done(function(e){return this._load_ff(e)}).fail(function(t){return 404==t.status?this._load_ff(null):(e=e||0,e++,10>e?setTimeout(this.check_ff.bind(this,e),250):this._load_ff(null))})},o.ws_commands.reload_ff=function(){this.check_ff()},o.prototype._feature_friday_ui=function(e,t,o){if(this.feature_friday&&this.feature_friday.channel!=e){this._emotes_for_sets(t,o,[this.feature_friday.set],"Feature Friday");var n=App.__container__.lookup("controller:channel");if(!n||n.get("id")!=this.feature_friday.channel){var s=this.feature_friday,r=this,i=document.createElement("div"),a=document.createElement("a");i.className="chat-menu-content",i.style.textAlign="center";var l=s.display_name+(s.live?" is live now!":"");a.className="button primary",a.classList.toggle("live",s.live),a.classList.toggle("blue",this.has_bttv&&BetterTTV.settings.get("showBlueButtons")),a.href="http://www.twitch.tv/"+s.channel,a.title=l,a.target="_new",a.innerHTML=""+l+"",a.addEventListener("click",function(){r.track("trackLink",this.href,"link")}),i.appendChild(a),t.appendChild(i)}}},o.prototype._load_ff=function(e){if(this.feature_friday){this.global_sets.removeObject(this.feature_friday.set);var t=this.emote_sets[this.feature_friday.set];t&&(t.global=!1),this.feature_friday=null,this.update_ui_link()}e&&e.set&&e.channel&&(this.feature_friday={set:e.set,channel:e.channel,live:!1,display_name:o.get_capitalization(e.channel,this._update_ff_name.bind(this))},this.global_sets.push(e.set),this.load_set(e.set,this._update_ff_set.bind(this)),this._update_ff_live())},o.prototype._update_ff_live=function(){if(this.feature_friday){var e=this;Twitch.api.get("streams/"+this.feature_friday.channel).done(function(t){e.feature_friday.live=null!=t.stream,e.update_ui_link()}).always(function(){e.feature_friday.timer=setTimeout(e._update_ff_live.bind(e),12e4)})}},o.prototype._update_ff_set=function(e,t){t&&(t.global=!0)},o.prototype._update_ff_name=function(e){this.feature_friday&&(this.feature_friday.display_name=e)}},{"./constants":3}],15:[function(){Array.prototype.equals=function(e){if(!e)return!1;if(this.length!=e.length)return!1;for(var t=0,o=this.length;o>t;t++)if(this[t]instanceof Array&&e[t]instanceof Array){if(!this[t].equals(e[t]))return!1}else if(this[t]!=e[t])return!1;return!0}},{}],16:[function(){var t=e.FrankerFaceZ;t.prototype._ws_open=!1,t.prototype._ws_delay=0,t.ws_commands={},t.prototype.ws_create=function(){var e,o=this;this._ws_last_req=0,this._ws_callbacks={},this._ws_pending=this._ws_pending||[];try{e=this._ws_sock=new WebSocket("ws://ffz.stendec.me/")}catch(n){return this._ws_exists=!1,this.log("Error Creating WebSocket: "+n)}this._ws_exists=!0,e.onopen=function(){o._ws_open=!0,o._ws_delay=0,o.log("Socket connected.");var e=o.get_user();e&&o.ws_send("setuser",e.login);for(var t in o.rooms)o.ws_send("sub",t);var n=o._ws_pending;o._ws_pending=[];for(var s=0;s0){s=!0;break}}e.classList.toggle("no-emotes",!s),e.classList.toggle("live",a),e.classList.toggle("dark",r),e.classList.toggle("blue",i)}}},{"../constants":3}],20:[function(){var t=e.FrankerFaceZ;t.prototype.show_notification=function(t){e.noty({text:t,theme:"ffzTheme",layout:"bottomCenter",closeWith:["button"]}).show()},t.ws_commands.message=function(e){this.show_notification(e)}},{}],21:[function(t){var o=e.FrankerFaceZ,n=t("../constants");o.prototype.setup_css=function(){this.log("Injecting main FrankerFaceZ CSS.");var e=this._main_style=document.createElement("link");e.id="ffz-ui-css",e.setAttribute("rel","stylesheet"),e.setAttribute("href",n.SERVER+"script/style.css"),document.head.appendChild(e),jQuery.noty.themes.ffzTheme={name:"ffzTheme",style:function(){this.$bar.removeClass().addClass("noty_bar").addClass("ffz-noty").addClass(this.options.type)},callback:{onShow:function(){},onClose:function(){}}}}},{"../constants":3}],22:[function(t){var o=e.FrankerFaceZ,n=t("../constants"),s=t("../utils");o.ws_commands.viewers=function(e){var t=e[0],o=e[1],r=App.__container__.lookup("controller:channel"),i=r&&r.get&&r.get("id");if(i===t){var a=document.querySelector(".channel-stats .ffz.stat"),l=n.ZREKNARF+" "+s.number_commas(o);if(a)a.innerHTML=l;else{var c=document.querySelector(".channel-stats");if(!c)return;a=document.createElement("span"),a.className="ffz stat",a.title="Viewers with FrankerFaceZ",a.innerHTML=l,c.appendChild(a),jQuery(a).tipsy()}}}},{"../constants":3,"../utils":23}],23:[function(t,o){e.FrankerFaceZ,t("./constants");o.exports={update_css:function(e,t,o){var n=e.innerHTML,s="/*BEGIN "+t+"*/",r="/*END "+t+"*/",i=n.indexOf(s),a=n.indexOf(r),l=-1!==i&&-1!==a&&a>i;(l||o)&&(l&&(n=n.substr(0,i)+n.substr(a+r.length)),o&&(n+=s+o+r),e.innerHTML=n)},number_commas:function(e){var t=e.toString().split(".");return t[0]=t[0].replace(/\B(?=(\d{3})+(?!\d))/g,","),t.join(".")}}},{"./constants":3}]},{},[13]),e.ffz=new FrankerFaceZ}(window);