diff --git a/Gruntfile.coffee b/Gruntfile.coffee
index a1f61a960..e826243a3 100644
--- a/Gruntfile.coffee
+++ b/Gruntfile.coffee
@@ -20,10 +20,13 @@ module.exports = (grunt) ->
'src/General/Config.coffee'
'src/General/Globals.coffee'
'src/General/lib/*.coffee'
- 'src/General/Get.coffee'
+ 'src/General/Header.coffee'
'src/General/Build.coffee'
+ 'src/General/Get.coffee'
+ 'src/General/UI.coffee'
'src/Filtering/**/*'
'src/Quotelinks/**/*'
+ 'src/Linkification/**/*'
'src/Posting/**/*'
'src/Images/**/*'
'src/Menu/**/*'
@@ -45,7 +48,7 @@ module.exports = (grunt) ->
files:
'builds/crx/manifest.json': 'src/General/meta/manifest.json'
'builds/crx/script.js': [
- 'src/banner.js'
+ 'src/General/meta/banner.js'
'tmp-<%= pkg.type %>/script.js'
]
@@ -70,7 +73,7 @@ module.exports = (grunt) ->
copy:
crx:
- src: 'src/img/*.png'
+ src: 'src/General/img/*.png'
dest: 'builds/crx/'
expand: true
flatten: true
diff --git a/builds/4chan-X.js b/builds/4chan-X.js
index cc36717b5..2e308eea4 100644
--- a/builds/4chan-X.js
+++ b/builds/4chan-X.js
@@ -814,159 +814,6 @@
return __slice.call(root.querySelectorAll(selector));
};
- Build = {
- spoilerRange: {},
- shortFilename: function(filename, isReply) {
- var threshold;
-
- threshold = isReply ? 30 : 40;
- if (filename.length - 4 > threshold) {
- return "" + filename.slice(0, threshold - 5) + "(...)." + filename.slice(-3);
- } else {
- return filename;
- }
- },
- postFromObject: function(data, boardID) {
- var o;
-
- o = {
- postID: data.no,
- threadID: data.resto || data.no,
- boardID: boardID,
- name: data.name,
- capcode: data.capcode,
- tripcode: data.trip,
- uniqueID: data.id,
- email: data.email ? encodeURI(data.email.replace(/"/g, '"')) : '',
- subject: data.sub,
- flagCode: data.country,
- flagName: data.country_name,
- date: data.now,
- dateUTC: data.time,
- comment: data.com,
- isSticky: !!data.sticky,
- isClosed: !!data.closed
- };
- if (data.ext || data.filedeleted) {
- o.file = {
- name: data.filename + data.ext,
- timestamp: "" + data.tim + data.ext,
- url: "//images.4chan.org/" + boardID + "/src/" + data.tim + data.ext,
- height: data.h,
- width: data.w,
- MD5: data.md5,
- size: data.fsize,
- turl: "//thumbs.4chan.org/" + boardID + "/thumb/" + data.tim + "s.jpg",
- theight: data.tn_h,
- twidth: data.tn_w,
- isSpoiler: !!data.spoiler,
- isDeleted: !!data.filedeleted
- };
- }
- return Build.post(o);
- },
- post: function(o, isArchived) {
- /*
- This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS).
- @license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
- */
-
- var a, boardID, capcode, capcodeClass, capcodeStart, closed, comment, container, date, dateUTC, email, emailEnd, emailStart, ext, file, fileDims, fileHTML, fileInfo, fileSize, fileThumb, filename, flag, flagCode, flagName, href, imgSrc, isClosed, isOP, isSticky, name, postID, quote, shortFilename, spoilerRange, staticPath, sticky, subject, threadID, tripcode, uniqueID, userID, _i, _len, _ref;
-
- postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, comment = o.comment, file = o.file;
- isOP = postID === threadID;
- staticPath = '//static.4chan.org';
- if (email) {
- emailStart = '';
- emailEnd = '';
- } else {
- emailStart = '';
- emailEnd = '';
- }
- subject = "" + (subject || '') + "";
- userID = !capcode && uniqueID ? (" (ID: ") + ("" + uniqueID + ") ") : '';
- switch (capcode) {
- case 'admin':
- case 'admin_highlight':
- capcodeClass = " capcodeAdmin";
- capcodeStart = " ## Admin";
- capcode = ("
";
- break;
- case 'mod':
- capcodeClass = " capcodeMod";
- capcodeStart = " ## Mod";
- capcode = ("
";
- break;
- case 'developer':
- capcodeClass = " capcodeDeveloper";
- capcodeStart = " ## Developer";
- capcode = ("
";
- break;
- default:
- capcodeClass = '';
- capcodeStart = '';
- capcode = '';
- }
- flag = flagCode ? ("
") : '';
- if (file != null ? file.isDeleted : void 0) {
- fileHTML = isOP ? ("
") + ("
") + " " : ("") + ("
") + " ";
- } else if (file) {
- ext = file.name.slice(-3);
- if (!file.twidth && !file.theight && ext === 'gif') {
- file.twidth = file.width;
- file.theight = file.height;
- }
- fileSize = $.bytesToString(file.size);
- fileThumb = file.turl;
- if (file.isSpoiler) {
- fileSize = "Spoiler Image, " + fileSize;
- if (!isArchived) {
- fileThumb = '//static.4chan.org/image/spoiler';
- if (spoilerRange = Build.spoilerRange[boardID]) {
- fileThumb += ("-" + boardID) + Math.floor(1 + spoilerRange * Math.random());
- }
- fileThumb += '.png';
- file.twidth = file.theight = 100;
- }
- }
- if (boardID.ID !== 'f') {
- imgSrc = ("") + ("
");
- }
- a = $.el('a', {
- innerHTML: file.name
- });
- filename = a.textContent.replace(/%22/g, '"');
- a.textContent = Build.shortFilename(filename);
- shortFilename = a.innerHTML;
- a.textContent = filename;
- filename = a.innerHTML.replace(/'/g, ''');
- fileDims = ext === 'pdf' ? 'PDF' : "" + file.width + "x" + file.height;
- fileInfo = ("File: " + file.timestamp + "") + ("-(" + fileSize + ", " + fileDims + (file.isSpoiler ? '' : ", " + shortFilename + "")) + ")";
- fileHTML = "" + fileInfo + "
" + imgSrc + "
";
- } else {
- fileHTML = '';
- }
- tripcode = tripcode ? " " + tripcode + "" : '';
- sticky = isSticky ? '
' : '';
- closed = isClosed ? '
' : '';
- container = $.el('div', {
- id: "pc" + postID,
- className: "postContainer " + (isOP ? 'op' : 'reply') + "Container",
- innerHTML: (isOP ? '' : ">>
") + ("") + ("
") + ("
") + ("" + (name || '') + "") + tripcode + capcodeStart + capcode + userID + flag + sticky + closed + ("
" + subject) + ("" + date) + ("No.") + ("" + postID + "") + '' + '
' + (isOP ? fileHTML : '') + ("
") + ("
") + ("" + subject + " ") + ("
") + emailStart + ("" + (name || '') + "") + tripcode + capcodeStart + emailEnd + capcode + userID + flag + sticky + closed + ' ' + ("
" + date + " ") + "
" + ("No.") + ("" + postID + "") + '' + '
' + (isOP ? '' : fileHTML) + ("
" + (comment || '') + "
") + '
'
- });
- _ref = $$('.quotelink', container);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quote = _ref[_i];
- href = quote.getAttribute('href');
- if (href[0] === '/') {
- continue;
- }
- quote.href = "/" + boardID + "/res/" + href;
- }
- return container;
- }
- };
-
Board = (function() {
Board.prototype.toString = function() {
return this.ID;
@@ -1548,6 +1395,517 @@
})();
+ Polyfill = {
+ init: function() {
+ return Polyfill.visibility();
+ },
+ visibility: function() {
+ var event, prefix, property;
+
+ if ('visibilityState' in document || !(prefix = ('webkitVisibilityState' in document ? 'webkit' : 'mozVisibilityState' in document ? 'moz' : void 0))) {
+ return;
+ }
+ property = prefix + 'VisibilityState';
+ event = prefix + 'visibilitychange';
+ d.visibilityState = d[property];
+ d.hidden = d.visibilityState === 'hidden';
+ return $.on(d, event, function() {
+ d.visibilityState = d[property];
+ d.hidden = d.visibilityState === 'hidden';
+ return $.event('visibilitychange');
+ });
+ }
+ };
+
+ Header = {
+ init: function() {
+ var barFixedToggler, barPositionToggler, customNavToggler, editCustomNav, footerToggler, headerToggler,
+ _this = this;
+
+ this.menu = new UI.Menu('header');
+ this.menuButton = $.el('span', {
+ className: 'menu-button',
+ innerHTML: ''
+ });
+ barFixedToggler = $.el('label', {
+ innerHTML: ' Fixed Header'
+ });
+ headerToggler = $.el('label', {
+ innerHTML: ' Auto-hide header'
+ });
+ barPositionToggler = $.el('label', {
+ innerHTML: ' Bottom header'
+ });
+ customNavToggler = $.el('label', {
+ innerHTML: ' Custom board navigation'
+ });
+ footerToggler = $.el('label', {
+ innerHTML: " Hide bottom board list"
+ });
+ editCustomNav = $.el('a', {
+ textContent: 'Edit custom board navigation',
+ href: 'javascript:;'
+ });
+ this.barFixedToggler = barFixedToggler.firstElementChild;
+ this.barPositionToggler = barPositionToggler.firstElementChild;
+ this.headerToggler = headerToggler.firstElementChild;
+ this.footerToggler = footerToggler.firstElementChild;
+ this.customNavToggler = customNavToggler.firstElementChild;
+ $.on(this.menuButton, 'click', this.menuToggle);
+ $.on(this.barFixedToggler, 'change', this.toggleBarFixed);
+ $.on(this.barPositionToggler, 'change', this.toggleBarPosition);
+ $.on(this.headerToggler, 'change', this.toggleBarVisibility);
+ $.on(this.footerToggler, 'change', this.toggleFooterVisibility);
+ $.on(this.customNavToggler, 'change', this.toggleCustomNav);
+ $.on(editCustomNav, 'click', this.editCustomNav);
+ this.setBarFixed(Conf['Fixed Header']);
+ this.setBarVisibility(Conf['Header auto-hide']);
+ $.sync('Fixed Header', Header.setBarFixed);
+ $.sync('Bottom Header', Header.setBarPosition);
+ $.sync('Header auto-hide', Header.setBarVisibility);
+ this.addShortcut(Header.menuButton);
+ $.event('AddMenuEntry', {
+ type: 'header',
+ el: $.el('span', {
+ textContent: 'Header'
+ }),
+ order: 107,
+ subEntries: [
+ {
+ el: barFixedToggler
+ }, {
+ el: headerToggler
+ }, {
+ el: barPositionToggler
+ }, {
+ el: footerToggler
+ }, {
+ el: customNavToggler
+ }, {
+ el: editCustomNav
+ }
+ ]
+ });
+ $.on(window, 'load hashchange', Header.hashScroll);
+ $.on(d, 'CreateNotification', this.createNotification);
+ $.asap((function() {
+ return d.body;
+ }), function() {
+ if (!Main.isThisPageLegit()) {
+ return;
+ }
+ $.asap((function() {
+ return $.id('boardNavMobile') || d.readyState === 'complete';
+ }), Header.setBoardList);
+ $.prepend(d.body, _this.bar);
+ $.add(d.body, Header.hover);
+ return _this.setBarPosition(Conf['Bottom Header']);
+ });
+ return $.ready(function() {
+ var a, cs;
+
+ _this.footer = $.id('boardNavDesktopFoot');
+ if (a = $("a[href*='/" + g.BOARD + "/']", $.id('boardNavDesktopFoot'))) {
+ a.className = 'current';
+ }
+ cs = $.id('settingsWindowLink');
+ cs.textContent = 'Catalog Settings';
+ if (g.VIEW === 'catalog') {
+ _this.addShortcut(cs);
+ }
+ Header.setFooterVisibility(Conf['Bottom Board List']);
+ return $.sync('Bottom Board List', Header.setFooterVisibility);
+ });
+ },
+ bar: $.el('div', {
+ id: 'header-bar'
+ }),
+ notify: $.el('div', {
+ id: 'notifications'
+ }),
+ shortcuts: $.el('span', {
+ id: 'shortcuts'
+ }),
+ hover: $.el('div', {
+ id: 'hoverUI'
+ }),
+ toggle: $.el('div', {
+ id: 'scroll-marker'
+ }),
+ setBoardList: function() {
+ var a, boardList, btn, fourchannav, fullBoardList;
+
+ fourchannav = $.id('boardNavDesktop');
+ if (a = $("a[href*='/" + g.BOARD + "/']", fourchannav)) {
+ a.className = 'current';
+ }
+ boardList = $.el('span', {
+ id: 'board-list',
+ innerHTML: "[ - ] " + fourchannav.innerHTML + ""
+ });
+ fullBoardList = $('#full-board-list', boardList);
+ btn = $('.hide-board-list-button', fullBoardList);
+ $.on(btn, 'click', Header.toggleBoardList);
+ $.rm($('#navtopright', fullBoardList));
+ $.add(boardList, fullBoardList);
+ $.add(Header.bar, [boardList, Header.shortcuts, Header.notify, Header.toggle]);
+ Header.setCustomNav(Conf['Custom Board Navigation']);
+ Header.generateBoardList(Conf['boardnav']);
+ $.sync('Custom Board Navigation', Header.setCustomNav);
+ return $.sync('boardnav', Header.generateBoardList);
+ },
+ generateBoardList: function(text) {
+ var as, list, nodes;
+
+ list = $('#custom-board-list', Header.bar);
+ $.rmAll(list);
+ if (!text) {
+ return;
+ }
+ as = $$('#full-board-list a', Header.bar);
+ nodes = text.match(/[\w@]+(-(all|title|replace|full|index|catalog|text:"[^"]+"))*|[^\w@]+/g).map(function(t) {
+ var a, board, m, _i, _len;
+
+ if (/^[^\w@]/.test(t)) {
+ return $.tn(t);
+ }
+ if (/^toggle-all/.test(t)) {
+ a = $.el('a', {
+ className: 'show-board-list-button',
+ textContent: (t.match(/-text:"(.+)"/) || [null, '+'])[1],
+ href: 'javascript:;'
+ });
+ $.on(a, 'click', Header.toggleBoardList);
+ return a;
+ }
+ board = /^current/.test(t) ? g.BOARD.ID : t.match(/^[^-]+/)[0];
+ for (_i = 0, _len = as.length; _i < _len; _i++) {
+ a = as[_i];
+ if (a.textContent === board) {
+ a = a.cloneNode(true);
+ if (/-title/.test(t)) {
+ a.textContent = a.title;
+ } else if (/-replace/.test(t)) {
+ if ($.hasClass(a, 'current')) {
+ a.textContent = a.title;
+ }
+ } else if (/-full/.test(t)) {
+ a.textContent = "/" + board + "/ - " + a.title;
+ } else if (/-(index|catalog|text)/.test(t)) {
+ if (m = t.match(/-(index|catalog)/)) {
+ a.setAttribute('data-only', m[1]);
+ a.href = "//boards.4chan.org/" + board + "/";
+ if (m[1] === 'catalog') {
+ a.href += 'catalog';
+ }
+ }
+ if (m = t.match(/-text:"(.+)"/)) {
+ a.textContent = m[1];
+ }
+ } else if (board === '@') {
+ $.addClass(a, 'navSmall');
+ }
+ return a;
+ }
+ }
+ return $.tn(t);
+ });
+ return $.add(list, nodes);
+ },
+ toggleBoardList: function() {
+ var bar, custom, full, showBoardList;
+
+ bar = Header.bar;
+ custom = $('#custom-board-list', bar);
+ full = $('#full-board-list', bar);
+ showBoardList = !full.hidden;
+ custom.hidden = !showBoardList;
+ return full.hidden = showBoardList;
+ },
+ setBarPosition: function(bottom) {
+ Header.barPositionToggler.checked = bottom;
+ if (bottom) {
+ $.rmClass(doc, 'top');
+ $.addClass(doc, 'bottom');
+ return $.after(Header.bar, Header.notify);
+ } else {
+ $.rmClass(doc, 'bottom');
+ $.addClass(doc, 'top');
+ return $.add(Header.bar, Header.notify);
+ }
+ },
+ toggleBarPosition: function() {
+ $.event('CloseMenu');
+ Header.setBarPosition(this.checked);
+ Conf['Bottom Header'] = this.checked;
+ return $.set('Bottom Header', this.checked);
+ },
+ setBarFixed: function(fixed) {
+ Header.barFixedToggler.checked = fixed;
+ if (fixed) {
+ $.addClass(doc, 'fixed');
+ return $.addClass(Header.bar, 'dialog');
+ } else {
+ $.rmClass(doc, 'fixed');
+ return $.rmClass(Header.bar, 'dialog');
+ }
+ },
+ toggleBarFixed: function() {
+ $.event('CloseMenu');
+ Header.setBarFixed(this.checked);
+ Conf['Fixed Header'] = this.checked;
+ return $.set('Fixed Header', this.checked);
+ },
+ setBarVisibility: function(hide) {
+ Header.headerToggler.checked = hide;
+ $.event('CloseMenu');
+ (hide ? $.addClass : $.rmClass)(Header.bar, 'autohide');
+ return (hide ? $.addClass : $.rmClass)(doc, 'autohide');
+ },
+ toggleBarVisibility: function(e) {
+ var hide, message;
+
+ if (e.type === 'mousedown' && e.button !== 0) {
+ return;
+ }
+ hide = this.nodeName === 'INPUT' ? this.checked : !$.hasClass(Header.bar, 'autohide');
+ Conf['Header auto-hide'] = hide;
+ $.set('Header auto-hide', hide);
+ Header.setBarVisibility(hide);
+ message = hide ? 'The header bar will automatically hide itself.' : 'The header bar will remain visible.';
+ return new Notification('info', message, 2);
+ },
+ setFooterVisibility: function(hide) {
+ Header.footerToggler.checked = hide;
+ return Header.footer.hidden = hide;
+ },
+ toggleFooterVisibility: function() {
+ var hide, message;
+
+ $.event('CloseMenu');
+ hide = this.nodeName === 'INPUT' ? this.checked : !!Header.footer.hidden;
+ Header.setFooterVisibility(hide);
+ $.set('Bottom Board List', hide);
+ message = hide ? 'The bottom navigation will now be hidden.' : 'The bottom navigation will remain visible.';
+ return new Notification('info', message, 2);
+ },
+ setCustomNav: function(show) {
+ var btn, cust, full, _ref;
+
+ Header.customNavToggler.checked = show;
+ cust = $('#custom-board-list', Header.bar);
+ full = $('#full-board-list', Header.bar);
+ btn = $('.hide-board-list-button', full);
+ return _ref = show ? [false, true] : [true, false], cust.hidden = _ref[0], full.hidden = _ref[1], _ref;
+ },
+ toggleCustomNav: function() {
+ $.cb.checked.call(this);
+ return Header.setCustomNav(this.checked);
+ },
+ editCustomNav: function() {
+ var settings;
+
+ Settings.open('Advanced');
+ settings = $.id('fourchanx-settings');
+ return $('input[name=boardnav]', settings).focus();
+ },
+ hashScroll: function() {
+ var hash, post;
+
+ if (!((hash = this.location.hash) && (post = $.id(hash.slice(1))))) {
+ return;
+ }
+ if ((Get.postFromRoot(post)).isHidden) {
+ return;
+ }
+ return Header.scrollToPost(post);
+ },
+ scrollToPost: function(post) {
+ var headRect, top;
+
+ top = post.getBoundingClientRect().top;
+ if (Conf['Fixed Header'] && !Conf['Bottom Header']) {
+ headRect = Header.bar.getBoundingClientRect();
+ top += -headRect.top - headRect.height;
+ }
+ return ($.engine === 'webkit' ? d.body : doc).scrollTop += top;
+ },
+ addShortcut: function(el) {
+ var shortcut;
+
+ shortcut = $.el('span', {
+ className: 'shortcut'
+ });
+ $.add(shortcut, [$.tn(' ['), el, $.tn(']')]);
+ return $.prepend(Header.shortcuts, shortcut);
+ },
+ menuToggle: function(e) {
+ return Header.menu.toggle(e, this, g);
+ },
+ createNotification: function(e) {
+ var cb, content, lifetime, notif, type, _ref;
+
+ _ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb;
+ notif = new Notification(type, content, lifetime);
+ if (cb) {
+ return cb(notif);
+ }
+ }
+ };
+
+ Build = {
+ spoilerRange: {},
+ shortFilename: function(filename, isReply) {
+ var threshold;
+
+ threshold = isReply ? 30 : 40;
+ if (filename.length - 4 > threshold) {
+ return "" + filename.slice(0, threshold - 5) + "(...)." + filename.slice(-3);
+ } else {
+ return filename;
+ }
+ },
+ postFromObject: function(data, boardID) {
+ var o;
+
+ o = {
+ postID: data.no,
+ threadID: data.resto || data.no,
+ boardID: boardID,
+ name: data.name,
+ capcode: data.capcode,
+ tripcode: data.trip,
+ uniqueID: data.id,
+ email: data.email ? encodeURI(data.email.replace(/"/g, '"')) : '',
+ subject: data.sub,
+ flagCode: data.country,
+ flagName: data.country_name,
+ date: data.now,
+ dateUTC: data.time,
+ comment: data.com,
+ isSticky: !!data.sticky,
+ isClosed: !!data.closed
+ };
+ if (data.ext || data.filedeleted) {
+ o.file = {
+ name: data.filename + data.ext,
+ timestamp: "" + data.tim + data.ext,
+ url: "//images.4chan.org/" + boardID + "/src/" + data.tim + data.ext,
+ height: data.h,
+ width: data.w,
+ MD5: data.md5,
+ size: data.fsize,
+ turl: "//thumbs.4chan.org/" + boardID + "/thumb/" + data.tim + "s.jpg",
+ theight: data.tn_h,
+ twidth: data.tn_w,
+ isSpoiler: !!data.spoiler,
+ isDeleted: !!data.filedeleted
+ };
+ }
+ return Build.post(o);
+ },
+ post: function(o, isArchived) {
+ /*
+ This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS).
+ @license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
+ */
+
+ var a, boardID, capcode, capcodeClass, capcodeStart, closed, comment, container, date, dateUTC, email, emailEnd, emailStart, ext, file, fileDims, fileHTML, fileInfo, fileSize, fileThumb, filename, flag, flagCode, flagName, href, imgSrc, isClosed, isOP, isSticky, name, postID, quote, shortFilename, spoilerRange, staticPath, sticky, subject, threadID, tripcode, uniqueID, userID, _i, _len, _ref;
+
+ postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, comment = o.comment, file = o.file;
+ isOP = postID === threadID;
+ staticPath = '//static.4chan.org';
+ if (email) {
+ emailStart = '';
+ emailEnd = '';
+ } else {
+ emailStart = '';
+ emailEnd = '';
+ }
+ subject = "" + (subject || '') + "";
+ userID = !capcode && uniqueID ? (" (ID: ") + ("" + uniqueID + ") ") : '';
+ switch (capcode) {
+ case 'admin':
+ case 'admin_highlight':
+ capcodeClass = " capcodeAdmin";
+ capcodeStart = " ## Admin";
+ capcode = ("
";
+ break;
+ case 'mod':
+ capcodeClass = " capcodeMod";
+ capcodeStart = " ## Mod";
+ capcode = ("
";
+ break;
+ case 'developer':
+ capcodeClass = " capcodeDeveloper";
+ capcodeStart = " ## Developer";
+ capcode = ("
";
+ break;
+ default:
+ capcodeClass = '';
+ capcodeStart = '';
+ capcode = '';
+ }
+ flag = flagCode ? ("
") : '';
+ if (file != null ? file.isDeleted : void 0) {
+ fileHTML = isOP ? ("") + ("
") + " " : ("") + ("
") + " ";
+ } else if (file) {
+ ext = file.name.slice(-3);
+ if (!file.twidth && !file.theight && ext === 'gif') {
+ file.twidth = file.width;
+ file.theight = file.height;
+ }
+ fileSize = $.bytesToString(file.size);
+ fileThumb = file.turl;
+ if (file.isSpoiler) {
+ fileSize = "Spoiler Image, " + fileSize;
+ if (!isArchived) {
+ fileThumb = '//static.4chan.org/image/spoiler';
+ if (spoilerRange = Build.spoilerRange[boardID]) {
+ fileThumb += ("-" + boardID) + Math.floor(1 + spoilerRange * Math.random());
+ }
+ fileThumb += '.png';
+ file.twidth = file.theight = 100;
+ }
+ }
+ if (boardID.ID !== 'f') {
+ imgSrc = ("") + ("
");
+ }
+ a = $.el('a', {
+ innerHTML: file.name
+ });
+ filename = a.textContent.replace(/%22/g, '"');
+ a.textContent = Build.shortFilename(filename);
+ shortFilename = a.innerHTML;
+ a.textContent = filename;
+ filename = a.innerHTML.replace(/'/g, ''');
+ fileDims = ext === 'pdf' ? 'PDF' : "" + file.width + "x" + file.height;
+ fileInfo = ("File: " + file.timestamp + "") + ("-(" + fileSize + ", " + fileDims + (file.isSpoiler ? '' : ", " + shortFilename + "")) + ")";
+ fileHTML = "" + fileInfo + "
" + imgSrc + "
";
+ } else {
+ fileHTML = '';
+ }
+ tripcode = tripcode ? " " + tripcode + "" : '';
+ sticky = isSticky ? '
' : '';
+ closed = isClosed ? '
' : '';
+ container = $.el('div', {
+ id: "pc" + postID,
+ className: "postContainer " + (isOP ? 'op' : 'reply') + "Container",
+ innerHTML: (isOP ? '' : ">>
") + ("") + ("
") + ("
") + ("" + (name || '') + "") + tripcode + capcodeStart + capcode + userID + flag + sticky + closed + ("
" + subject) + ("" + date) + ("No.") + ("" + postID + "") + '' + '
' + (isOP ? fileHTML : '') + ("
") + ("
") + ("" + subject + " ") + ("
") + emailStart + ("" + (name || '') + "") + tripcode + capcodeStart + emailEnd + capcode + userID + flag + sticky + closed + ' ' + ("
" + date + " ") + "
" + ("No.") + ("" + postID + "") + '' + '
' + (isOP ? '' : fileHTML) + ("
" + (comment || '') + "
") + '
'
+ });
+ _ref = $$('.quotelink', container);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ quote = _ref[_i];
+ href = quote.getAttribute('href');
+ if (href[0] === '/') {
+ continue;
+ }
+ quote.href = "/" + boardID + "/res/" + href;
+ }
+ return container;
+ }
+ };
+
Get = {
threadExcerpt: function(thread) {
var OP, excerpt, _ref;
@@ -1804,28 +2162,6 @@
}
};
- Polyfill = {
- init: function() {
- return Polyfill.visibility();
- },
- visibility: function() {
- var event, prefix, property;
-
- if ('visibilityState' in document || !(prefix = ('webkitVisibilityState' in document ? 'webkit' : 'mozVisibilityState' in document ? 'moz' : void 0))) {
- return;
- }
- property = prefix + 'VisibilityState';
- event = prefix + 'visibilitychange';
- d.visibilityState = d[property];
- d.hidden = d.visibilityState === 'hidden';
- return $.on(d, event, function() {
- d.visibilityState = d[property];
- d.hidden = d.visibilityState === 'hidden';
- return $.event('visibilitychange');
- });
- }
- };
-
UI = (function() {
var Menu, dialog, drag, dragend, dragstart, hover, hoverend, hoverstart, touchend, touchmove;
@@ -2555,76 +2891,6 @@
}
};
- Recursive = {
- recursives: {},
- init: function() {
- if (g.VIEW === 'catalog') {
- return;
- }
- return Post.prototype.callbacks.push({
- name: 'Recursive',
- cb: this.node
- });
- },
- node: function() {
- var i, obj, quote, recursive, _i, _j, _len, _len1, _ref, _ref1;
-
- if (this.isClone) {
- return;
- }
- _ref = this.quotes;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quote = _ref[_i];
- if (obj = Recursive.recursives[quote]) {
- _ref1 = obj.recursives;
- for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
- recursive = _ref1[i];
- recursive.apply(null, [this].concat(__slice.call(obj.args[i])));
- }
- }
- }
- },
- add: function() {
- var args, obj, post, recursive, _base, _name;
-
- recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
- obj = (_base = Recursive.recursives)[_name = post.fullID] || (_base[_name] = {
- recursives: [],
- args: []
- });
- obj.recursives.push(recursive);
- return obj.args.push(args);
- },
- rm: function(recursive, post) {
- var i, obj, rec, _i, _len, _ref;
-
- if (!(obj = Recursive.recursives[post.fullID])) {
- return;
- }
- _ref = obj.recursives;
- for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
- rec = _ref[i];
- if (rec === recursive) {
- obj.recursives.splice(i, 1);
- obj.args.splice(i, 1);
- }
- }
- },
- apply: function() {
- var ID, args, fullID, post, recursive, _ref;
-
- recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
- fullID = post.fullID;
- _ref = g.posts;
- for (ID in _ref) {
- post = _ref[ID];
- if (post.quotes.contains(fullID)) {
- recursive.apply(null, [post].concat(__slice.call(args)));
- }
- }
- }
- };
-
PostHiding = {
init: function() {
if (g.VIEW === 'catalog' || !Conf['Reply Hiding Buttons'] && !Conf['Reply Hiding Link']) {
@@ -2903,28 +3169,71 @@
}
};
- QuoteStrikeThrough = {
+ Recursive = {
+ recursives: {},
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Reply Hiding Buttons'] && !Conf['Reply Hiding Link'] && !Conf['Filter']) {
+ if (g.VIEW === 'catalog') {
return;
}
return Post.prototype.callbacks.push({
- name: 'Strike-through Quotes',
+ name: 'Recursive',
cb: this.node
});
},
node: function() {
- var boardID, postID, quotelink, _i, _len, _ref, _ref1, _ref2;
+ var i, obj, quote, recursive, _i, _j, _len, _len1, _ref, _ref1;
if (this.isClone) {
return;
}
- _ref = this.nodes.quotelinks;
+ _ref = this.quotes;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quotelink = _ref[_i];
- _ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, postID = _ref1.postID;
- if ((_ref2 = g.posts["" + boardID + "." + postID]) != null ? _ref2.isHidden : void 0) {
- $.addClass(quotelink, 'filtered');
+ quote = _ref[_i];
+ if (obj = Recursive.recursives[quote]) {
+ _ref1 = obj.recursives;
+ for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
+ recursive = _ref1[i];
+ recursive.apply(null, [this].concat(__slice.call(obj.args[i])));
+ }
+ }
+ }
+ },
+ add: function() {
+ var args, obj, post, recursive, _base, _name;
+
+ recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
+ obj = (_base = Recursive.recursives)[_name = post.fullID] || (_base[_name] = {
+ recursives: [],
+ args: []
+ });
+ obj.recursives.push(recursive);
+ return obj.args.push(args);
+ },
+ rm: function(recursive, post) {
+ var i, obj, rec, _i, _len, _ref;
+
+ if (!(obj = Recursive.recursives[post.fullID])) {
+ return;
+ }
+ _ref = obj.recursives;
+ for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
+ rec = _ref[i];
+ if (rec === recursive) {
+ obj.recursives.splice(i, 1);
+ obj.args.splice(i, 1);
+ }
+ }
+ },
+ apply: function() {
+ var ID, args, fullID, post, recursive, _ref;
+
+ recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
+ fullID = post.fullID;
+ _ref = g.posts;
+ for (ID in _ref) {
+ post = _ref[ID];
+ if (post.quotes.contains(fullID)) {
+ recursive.apply(null, [post].concat(__slice.call(args)));
}
}
}
@@ -3157,455 +3466,646 @@
}
};
- FappeTyme = {
+ QuoteBacklink = {
init: function() {
- var el, input;
+ var format;
- if (!Conf['Fappe Tyme'] || g.VIEW === 'catalog' || g.BOARD === 'f') {
+ if (g.VIEW === 'catalog' || !Conf['Quote Backlinks']) {
return;
}
- el = $.el('label', {
- innerHTML: " Fappe Tyme",
- title: 'Fappe Tyme'
- });
- FappeTyme.input = input = el.firstElementChild;
- $.on(input, 'change', FappeTyme.toggle);
- $.event('AddMenuEntry', {
- type: 'header',
- el: el,
- order: 97
+ format = Conf['backlink'].replace(/%id/g, "' + id + '");
+ this.funk = Function('id', "return '" + format + "'");
+ this.containers = {};
+ Post.prototype.callbacks.push({
+ name: 'Quote Backlinking Part 1',
+ cb: this.firstNode
});
return Post.prototype.callbacks.push({
- name: 'Fappe Tyme',
- cb: this.node
+ name: 'Quote Backlinking Part 2',
+ cb: this.secondNode
});
},
- node: function() {
- if (this.file) {
+ firstNode: function() {
+ var a, clone, container, containers, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
+
+ if (this.isClone || !this.quotes.length) {
return;
}
- return $.addClass(this.nodes.root, "noFile");
+ a = $.el('a', {
+ href: "/" + this.board + "/res/" + this.thread + "#p" + this,
+ className: this.isHidden ? 'filtered backlink' : 'backlink',
+ textContent: (QuoteBacklink.funk(this.ID)) + (Conf['Mark Quotes of You'] && this.info.yours ? QuoteYou.text : '')
+ });
+ _ref = this.quotes;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ quote = _ref[_i];
+ containers = [QuoteBacklink.getContainer(quote)];
+ if ((post = g.posts[quote]) && post.nodes.backlinkContainer) {
+ _ref1 = post.clones;
+ for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
+ clone = _ref1[_j];
+ containers.push(clone.nodes.backlinkContainer);
+ }
+ }
+ for (_k = 0, _len2 = containers.length; _k < _len2; _k++) {
+ container = containers[_k];
+ link = a.cloneNode(true);
+ if (Conf['Quote Previewing']) {
+ $.on(link, 'mouseover', QuotePreview.mouseover);
+ }
+ if (Conf['Quote Inlining']) {
+ $.on(link, 'click', QuoteInline.toggle);
+ }
+ $.add(container, [$.tn(' '), link]);
+ }
+ }
},
- toggle: function() {
- $.event('CloseMenu');
- return (this.checked ? $.addClass : $.rmClass)(doc, 'fappeTyme');
+ secondNode: function() {
+ var container;
+
+ if (this.isClone && (this.origin.isReply || Conf['OP Backlinks'])) {
+ this.nodes.backlinkContainer = $('.container', this.nodes.info);
+ return;
+ }
+ if (!(this.isReply || Conf['OP Backlinks'])) {
+ return;
+ }
+ container = QuoteBacklink.getContainer(this.fullID);
+ this.nodes.backlinkContainer = container;
+ return $.add(this.nodes.info, container);
+ },
+ getContainer: function(id) {
+ var _base;
+
+ return (_base = this.containers)[id] || (_base[id] = $.el('span', {
+ className: 'container'
+ }));
}
};
- ImageExpand = {
+ QuoteCT = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
+ if (g.VIEW === 'catalog' || !Conf['Mark Cross-thread Quotes']) {
return;
}
- this.EAI = $.el('a', {
- className: 'expand-all-shortcut',
- textContent: 'EAI',
- title: 'Expand All Images',
- href: 'javascript:;'
- });
- $.on(this.EAI, 'click', ImageExpand.cb.toggleAll);
- Header.addShortcut(this.EAI);
+ if (Conf['Comment Expansion']) {
+ ExpandComment.callbacks.push(this.node);
+ }
+ this.text = '\u00A0(Cross-thread)';
return Post.prototype.callbacks.push({
- name: 'Image Expansion',
+ name: 'Mark Cross-thread Quotes',
cb: this.node
});
},
node: function() {
- var thumb, _ref;
+ var board, boardID, quotelink, quotelinks, quotes, thread, threadID, _i, _len, _ref, _ref1;
- if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ if (this.isClone && this.thread === this.context.thread) {
return;
}
- thumb = this.file.thumb;
- $.on(thumb.parentNode, 'click', ImageExpand.cb.toggle);
- if (this.isClone && $.hasClass(thumb, 'expanding')) {
- ImageExpand.contract(this);
- ImageExpand.expand(this);
+ if (!(quotes = this.quotes).length) {
return;
}
- if (ImageExpand.on && !this.isHidden) {
- return ImageExpand.expand(this);
- }
- },
- cb: {
- toggle: function(e) {
- if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
- return;
+ quotelinks = this.nodes.quotelinks;
+ _ref = this.isClone ? this.context : this, board = _ref.board, thread = _ref.thread;
+ for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
+ quotelink = quotelinks[_i];
+ _ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, threadID = _ref1.threadID;
+ if (!threadID) {
+ continue;
}
- e.preventDefault();
- return ImageExpand.toggle(Get.postFromNode(this));
- },
- toggleAll: function() {
- var ID, file, func, post, _i, _len, _ref, _ref1;
-
- $.event('CloseMenu');
- if (ImageExpand.on = $.hasClass(ImageExpand.EAI, 'expand-all-shortcut')) {
- ImageExpand.EAI.className = 'contract-all-shortcut';
- ImageExpand.EAI.title = 'Contract All Images';
- func = ImageExpand.expand;
- } else {
- ImageExpand.EAI.className = 'expand-all-shortcut';
- ImageExpand.EAI.title = 'Expand All Images';
- func = ImageExpand.contract;
+ if (this.isClone) {
+ quotelink.textContent = quotelink.textContent.replace(QuoteCT.text, '');
}
- _ref = g.posts;
- for (ID in _ref) {
- post = _ref[ID];
- _ref1 = [post].concat(post.clones);
- for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
- post = _ref1[_i];
- file = post.file;
- if (!(file && file.isImage && doc.contains(post.nodes.root))) {
- continue;
- }
- if (ImageExpand.on && (!Conf['Expand spoilers'] && file.isSpoiler || Conf['Expand from here'] && file.thumb.getBoundingClientRect().top < 0)) {
- continue;
- }
- $.queueTask(func, post);
- }
- }
- },
- setFitness: function() {
- var checked;
-
- checked = this.checked;
- (checked ? $.addClass : $.rmClass)(doc, this.name.toLowerCase().replace(/\s+/g, '-'));
- if (this.name !== 'Fit height') {
- return;
- }
- if (checked) {
- $.on(window, 'resize', ImageExpand.resize);
- if (!ImageExpand.style) {
- ImageExpand.style = $.addStyle(null);
- }
- return ImageExpand.resize();
- } else {
- return $.off(window, 'resize', ImageExpand.resize);
+ if (boardID === this.board.ID && threadID !== thread.ID) {
+ $.add(quotelink, $.tn(QuoteCT.text));
}
}
- },
- toggle: function(post) {
- var headRect, rect, root, thumb, top;
-
- thumb = post.file.thumb;
- if (!(post.file.isExpanded || $.hasClass(thumb, 'expanding'))) {
- ImageExpand.expand(post);
- return;
- }
- ImageExpand.contract(post);
- rect = post.nodes.root.getBoundingClientRect();
- if (!(rect.top <= 0 || rect.left <= 0)) {
- return;
- }
- top = rect.top;
- if (Conf['Fixed Header'] && !Conf['Bottom Header']) {
- headRect = Header.bar.getBoundingClientRect();
- top += -headRect.top - headRect.height;
- }
- root = doc;
- if (rect.top < 0) {
- root.scrollTop += top;
- }
- if (rect.left < 0) {
- return root.scrollLeft = 0;
- }
- },
- contract: function(post) {
- $.rmClass(post.nodes.root, 'expanded-image');
- $.rmClass(post.file.thumb, 'expanding');
- return post.file.isExpanded = false;
- },
- expand: function(post, src) {
- var img, thumb;
-
- thumb = post.file.thumb;
- if (post.isHidden || post.file.isExpanded || $.hasClass(thumb, 'expanding')) {
- return;
- }
- $.addClass(thumb, 'expanding');
- if (post.file.fullImage) {
- $.asap((function() {
- return post.file.fullImage.naturalHeight;
- }), function() {
- return ImageExpand.completeExpand(post);
- });
- return;
- }
- post.file.fullImage = img = $.el('img', {
- className: 'full-image',
- src: src || post.file.URL
- });
- $.on(img, 'error', ImageExpand.error);
- $.asap((function() {
- return post.file.fullImage.naturalHeight;
- }), function() {
- return ImageExpand.completeExpand(post);
- });
- return $.after(thumb, img);
- },
- completeExpand: function(post) {
- var prev, thumb;
-
- thumb = post.file.thumb;
- if (!$.hasClass(thumb, 'expanding')) {
- return;
- }
- post.file.isExpanded = true;
- if (!post.nodes.root.parentNode) {
- $.addClass(post.nodes.root, 'expanded-image');
- $.rmClass(post.file.thumb, 'expanding');
- return;
- }
- prev = post.nodes.root.getBoundingClientRect();
- return $.queueTask(function() {
- var curr, root;
-
- $.addClass(post.nodes.root, 'expanded-image');
- $.rmClass(post.file.thumb, 'expanding');
- if (!(prev.top + prev.height <= 0)) {
- return;
- }
- root = doc;
- curr = post.nodes.root.getBoundingClientRect();
- return root.scrollTop += curr.height - prev.height + curr.top - prev.top;
- });
- },
- error: function() {
- var URL, post, src, timeoutID;
-
- post = Get.postFromNode(this);
- $.rm(this);
- delete post.file.fullImage;
- if (!($.hasClass(post.file.thumb, 'expanding') || $.hasClass(post.nodes.root, 'expanded-image'))) {
- return;
- }
- ImageExpand.contract(post);
- src = this.src.split('/');
- if (src[2] === 'images.4chan.org') {
- if (URL = Redirect.image(src[3], src[5])) {
- setTimeout(ImageExpand.expand, 10000, post, URL);
- return;
- }
- if (g.DEAD || post.isDead || post.file.isDead) {
- return;
- }
- }
- timeoutID = setTimeout(ImageExpand.expand, 10000, post);
- return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", {
- onload: function() {
- var postObj, _i, _len, _ref;
-
- if (this.status !== 200) {
- return;
- }
- _ref = JSON.parse(this.response).posts;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- postObj = _ref[_i];
- if (postObj.no === post.ID) {
- break;
- }
- }
- if (postObj.no !== post.ID) {
- clearTimeout(timeoutID);
- return post.kill();
- } else if (postObj.filedeleted) {
- clearTimeout(timeoutID);
- return post.kill(true);
- }
- }
- });
- },
- menu: {
- init: function() {
- var conf, createSubEntry, el, key, subEntries, _ref;
-
- if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
- return;
- }
- el = $.el('span', {
- textContent: 'Image Expansion',
- className: 'image-expansion-link'
- });
- createSubEntry = ImageExpand.menu.createSubEntry;
- subEntries = [];
- _ref = Config.imageExpansion;
- for (key in _ref) {
- conf = _ref[key];
- subEntries.push(createSubEntry(key, conf));
- }
- return $.event('AddMenuEntry', {
- type: 'header',
- el: el,
- order: 105,
- subEntries: subEntries
- });
- },
- createSubEntry: function(type, config) {
- var input, label;
-
- label = $.el('label', {
- innerHTML: " " + type
- });
- input = label.firstElementChild;
- if (type === 'Fit width' || type === 'Fit height') {
- $.on(input, 'change', ImageExpand.cb.setFitness);
- }
- if (config) {
- label.title = config[1];
- input.checked = Conf[type];
- $.event('change', null, input);
- $.on(input, 'change', $.cb.checked);
- }
- return {
- el: label
- };
- }
- },
- resize: function() {
- return ImageExpand.style.textContent = ":root.fit-height .full-image {max-height:" + doc.clientHeight + "px}";
- },
- menuToggle: function(e) {
- return ImageExpand.opmenu.toggle(e, this, g);
}
};
- ImageHover = {
+ QuoteInline = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Image Hover']) {
+ if (g.VIEW === 'catalog' || !Conf['Quote Inlining']) {
return;
}
+ if (Conf['Comment Expansion']) {
+ ExpandComment.callbacks.push(this.node);
+ }
return Post.prototype.callbacks.push({
- name: 'Image Hover',
+ name: 'Quote Inlining',
cb: this.node
});
},
node: function() {
- var _ref;
+ var link, _i, _len, _ref;
- if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ link = _ref[_i];
+ $.on(link, 'click', QuoteInline.toggle);
+ }
+ },
+ toggle: function(e) {
+ var boardID, context, postID, threadID, _ref;
+
+ if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
return;
}
- return $.on(this.file.thumb, 'mouseover', ImageHover.mouseover);
+ e.preventDefault();
+ _ref = Get.postDataFromLink(this), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
+ context = Get.contextFromLink(this);
+ if ($.hasClass(this, 'inlined')) {
+ QuoteInline.rm(this, boardID, threadID, postID, context);
+ } else {
+ if ($.x("ancestor::div[@id='p" + postID + "']", this)) {
+ return;
+ }
+ QuoteInline.add(this, boardID, threadID, postID, context);
+ }
+ return this.classList.toggle('inlined');
+ },
+ findRoot: function(quotelink, isBacklink) {
+ if (isBacklink) {
+ return quotelink.parentNode.parentNode;
+ } else {
+ return $.x('ancestor-or-self::*[parent::blockquote][1]', quotelink);
+ }
+ },
+ add: function(quotelink, boardID, threadID, postID, context) {
+ var inline, isBacklink, post;
+
+ isBacklink = $.hasClass(quotelink, 'backlink');
+ inline = $.el('div', {
+ id: "i" + postID,
+ className: 'inline'
+ });
+ $.after(QuoteInline.findRoot(quotelink, isBacklink), inline);
+ Get.postClone(boardID, threadID, postID, inline, context);
+ if (!((post = g.posts["" + boardID + "." + postID]) && context.thread === post.thread)) {
+ return;
+ }
+ if (isBacklink && Conf['Forward Hiding']) {
+ $.addClass(post.nodes.root, 'forwarded');
+ post.forwarded++ || (post.forwarded = 1);
+ }
+ if (!Unread.posts) {
+ return;
+ }
+ return Unread.readSinglePost(post);
+ },
+ rm: function(quotelink, boardID, threadID, postID, context) {
+ var el, inlined, isBacklink, post, root, _ref;
+
+ isBacklink = $.hasClass(quotelink, 'backlink');
+ root = QuoteInline.findRoot(quotelink, isBacklink);
+ root = $.x("following-sibling::div[@id='i" + postID + "'][1]", root);
+ $.rm(root);
+ if (!(el = root.firstElementChild)) {
+ return;
+ }
+ post = g.posts["" + boardID + "." + postID];
+ post.rmClone(el.dataset.clone);
+ if (Conf['Forward Hiding'] && isBacklink && context.thread === g.threads["" + boardID + "." + threadID] && !--post.forwarded) {
+ delete post.forwarded;
+ $.rmClass(post.nodes.root, 'forwarded');
+ }
+ while (inlined = $('.inlined', el)) {
+ _ref = Get.postDataFromLink(inlined), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
+ QuoteInline.rm(inlined, boardID, threadID, postID, context);
+ $.rmClass(inlined, 'inlined');
+ }
+ }
+ };
+
+ QuoteOP = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Mark OP Quotes']) {
+ return;
+ }
+ if (Conf['Comment Expansion']) {
+ ExpandComment.callbacks.push(this.node);
+ }
+ this.text = '\u00A0(OP)';
+ return Post.prototype.callbacks.push({
+ name: 'Mark OP Quotes',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var boardID, op, postID, quotelink, quotelinks, quotes, _i, _j, _len, _len1, _ref;
+
+ if (this.isClone && this.thread === this.context.thread) {
+ return;
+ }
+ if (!(quotes = this.quotes).length) {
+ return;
+ }
+ quotelinks = this.nodes.quotelinks;
+ if (this.isClone && quotes.contains(this.thread.fullID)) {
+ for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
+ quotelink = quotelinks[_i];
+ quotelink.textContent = quotelink.textContent.replace(QuoteOP.text, '');
+ }
+ }
+ op = (this.isClone ? this.context : this).thread.fullID;
+ if (!quotes.contains(op)) {
+ return;
+ }
+ for (_j = 0, _len1 = quotelinks.length; _j < _len1; _j++) {
+ quotelink = quotelinks[_j];
+ _ref = Get.postDataFromLink(quotelink), boardID = _ref.boardID, postID = _ref.postID;
+ if (("" + boardID + "." + postID) === op) {
+ $.add(quotelink, $.tn(QuoteOP.text));
+ }
+ }
+ }
+ };
+
+ QuotePreview = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Quote Previewing']) {
+ return;
+ }
+ if (Conf['Comment Expansion']) {
+ ExpandComment.callbacks.push(this.node);
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Quote Previewing',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var link, _i, _len, _ref;
+
+ _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ link = _ref[_i];
+ $.on(link, 'mouseover', QuotePreview.mouseover);
+ }
},
mouseover: function(e) {
- var el, post;
+ var boardID, clone, origin, post, postID, posts, qp, quote, quoterID, threadID, _i, _j, _len, _len1, _ref, _ref1;
- post = Get.postFromNode(this);
- el = $.el('img', {
- id: 'ihover',
- src: post.file.URL
+ if ($.hasClass(this, 'inlined')) {
+ return;
+ }
+ _ref = Get.postDataFromLink(this), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
+ qp = $.el('div', {
+ id: 'qp',
+ className: 'dialog'
});
- el.setAttribute('data-fullid', post.fullID);
- $.add(Header.hover, el);
+ $.add(Header.hover, qp);
+ Get.postClone(boardID, threadID, postID, qp, Get.contextFromLink(this));
UI.hover({
root: this,
- el: el,
+ el: qp,
latestEvent: e,
endEvents: 'mouseout click',
+ cb: QuotePreview.mouseout,
asapTest: function() {
- return el.naturalHeight;
+ return qp.firstElementChild;
}
});
- return $.on(el, 'error', ImageHover.error);
- },
- error: function() {
- var URL, post, src, timeoutID,
- _this = this;
-
- if (!doc.contains(this)) {
+ if (!(origin = g.posts["" + boardID + "." + postID])) {
return;
}
- post = g.posts[this.dataset.fullid];
- src = this.src.split('/');
- if (src[2] === 'images.4chan.org') {
- if (URL = Redirect.image(src[3], src[5].replace(/\?.+$/, ''))) {
- this.src = URL;
- return;
- }
- if (g.DEAD || post.isDead || post.file.isDead) {
- return;
+ if (Conf['Quote Highlighting']) {
+ posts = [origin].concat(origin.clones);
+ posts.pop();
+ for (_i = 0, _len = posts.length; _i < _len; _i++) {
+ post = posts[_i];
+ $.addClass(post.nodes.post, 'qphl');
}
}
- timeoutID = setTimeout((function() {
- return _this.src = post.file.URL + '?' + Date.now();
- }), 3000);
- return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", {
- onload: function() {
- var postObj, _i, _len, _ref;
-
- if (this.status !== 200) {
- return;
- }
- _ref = JSON.parse(this.response).posts;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- postObj = _ref[_i];
- if (postObj.no === post.ID) {
- break;
- }
- }
- if (postObj.no !== post.ID) {
- clearTimeout(timeoutID);
- return post.kill();
- } else if (postObj.filedeleted) {
- clearTimeout(timeoutID);
- return post.kill(true);
- }
+ quoterID = $.x('ancestor::*[@id][1]', this).id.match(/\d+$/)[0];
+ clone = Get.postFromRoot(qp.firstChild);
+ _ref1 = clone.nodes.quotelinks.concat(__slice.call(clone.nodes.backlinks));
+ for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
+ quote = _ref1[_j];
+ if (quote.hash.slice(2) === quoterID) {
+ $.addClass(quote, 'forwardlink');
}
- });
+ }
+ },
+ mouseout: function() {
+ var clone, post, root, _i, _len, _ref;
+
+ if (!(root = this.el.firstElementChild)) {
+ return;
+ }
+ clone = Get.postFromRoot(root);
+ post = clone.origin;
+ post.rmClone(root.dataset.clone);
+ if (!Conf['Quote Highlighting']) {
+ return;
+ }
+ _ref = [post].concat(post.clones);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ post = _ref[_i];
+ $.rmClass(post.nodes.post, 'qphl');
+ }
}
};
- ImageReplace = {
+ QuoteStrikeThrough = {
init: function() {
- if (g.VIEW === 'catalog') {
+ if (g.VIEW === 'catalog' || !Conf['Reply Hiding Buttons'] && !Conf['Reply Hiding Link'] && !Conf['Filter']) {
return;
}
return Post.prototype.callbacks.push({
- name: 'Image Replace',
+ name: 'Strike-through Quotes',
cb: this.node
});
},
node: function() {
- var URL, img, style, thumb, type, _ref, _ref1;
+ var boardID, postID, quotelink, _i, _len, _ref, _ref1, _ref2;
- if (this.isClone || this.isHidden || this.thread.isHidden || !((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ if (this.isClone) {
return;
}
- _ref1 = this.file, thumb = _ref1.thumb, URL = _ref1.URL;
- if (!(Conf["Replace " + ((type = (URL.match(/\w{3}$/))[0].toUpperCase()) === 'PEG' ? 'JPG' : type)] && !/spoiler/.test(thumb.src))) {
- return;
+ _ref = this.nodes.quotelinks;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ quotelink = _ref[_i];
+ _ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, postID = _ref1.postID;
+ if ((_ref2 = g.posts["" + boardID + "." + postID]) != null ? _ref2.isHidden : void 0) {
+ $.addClass(quotelink, 'filtered');
+ }
}
- if (this.file.isSpoiler) {
- style = thumb.style;
- style.maxHeight = style.maxWidth = this.isReply ? '125px' : '250px';
- }
- img = $.el('img');
- $.on(img, 'load', function() {
- return thumb.src = URL;
- });
- return img.src = URL;
}
};
- RevealSpoilers = {
+ /*
+ <3 aeosynth
+ */
+
+
+ QuoteThreading = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Reveal Spoilers']) {
+ var input;
+
+ if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
return;
}
+ this.enabled = true;
+ this.controls = $.el('span', {
+ innerHTML: ''
+ });
+ input = $('input', this.controls);
+ $.on(input, 'change', QuoteThreading.toggle);
+ $.event('AddMenuEntry', {
+ type: 'header',
+ el: this.controls,
+ order: 98
+ });
+ $.on(d, '4chanXInitFinished', this.setup);
return Post.prototype.callbacks.push({
- name: 'Reveal Spoilers',
+ name: 'Quote Threading',
+ cb: this.node
+ });
+ },
+ setup: function() {
+ var ID, post, posts;
+
+ $.off(d, '4chanXInitFinished', QuoteThreading.setup);
+ posts = g.posts;
+ for (ID in posts) {
+ post = posts[ID];
+ if (post.cb) {
+ post.cb.call(post);
+ }
+ }
+ return QuoteThreading.hasRun = true;
+ },
+ node: function() {
+ var ID, fullID, keys, len, post, posts, qid, quote, quotes, uniq, _i, _len;
+
+ if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) {
+ return;
+ }
+ quotes = this.quotes, ID = this.ID, fullID = this.fullID;
+ posts = g.posts;
+ if (!(post = posts[fullID]) || post.isHidden) {
+ return;
+ }
+ uniq = {};
+ len = ("" + g.BOARD).length + 1;
+ for (_i = 0, _len = quotes.length; _i < _len; _i++) {
+ quote = quotes[_i];
+ qid = quote;
+ if (!(qid.slice(len) < ID)) {
+ continue;
+ }
+ if (qid in posts) {
+ uniq[qid.slice(len)] = true;
+ }
+ }
+ keys = Object.keys(uniq);
+ if (keys.length !== 1) {
+ return;
+ }
+ this.threaded = "" + g.BOARD + "." + keys[0];
+ return this.cb = QuoteThreading.nodeinsert;
+ },
+ nodeinsert: function() {
+ var bottom, height, posts, qpost, qroot, threadContainer, top, _ref;
+
+ posts = g.posts;
+ qpost = posts[this.threaded];
+ delete this.threaded;
+ delete this.cb;
+ if (this.thread.OP === qpost) {
+ return false;
+ }
+ if (QuoteThreading.hasRun) {
+ height = doc.clientHeight;
+ _ref = qpost.nodes.root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top;
+ if (!(Unread.posts.contains(qpost) || ((bottom < height) && (top > 0)))) {
+ return false;
+ }
+ }
+ qroot = qpost.nodes.root;
+ if (!$.hasClass(qroot, 'threadOP')) {
+ $.addClass(qroot, 'threadOP');
+ threadContainer = $.el('div', {
+ className: 'threadContainer'
+ });
+ $.after(qroot, threadContainer);
+ } else {
+ threadContainer = qroot.nextSibling;
+ }
+ $.add(threadContainer, this.nodes.root);
+ return true;
+ },
+ toggle: function() {
+ var container, containers, node, nodes, replies, reply, thread, _i, _j, _len, _len1;
+
+ thread = $('.thread');
+ replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread);
+ QuoteThreading.enabled = this.checked;
+ if (this.checked) {
+ nodes = (function() {
+ var _i, _len, _results;
+
+ _results = [];
+ for (_i = 0, _len = replies.length; _i < _len; _i++) {
+ reply = replies[_i];
+ _results.push(Get.postFromNode(reply));
+ }
+ return _results;
+ })();
+ for (_i = 0, _len = nodes.length; _i < _len; _i++) {
+ node = nodes[_i];
+ QuoteThreading.node(node);
+ }
+ } else {
+ replies.sort(function(a, b) {
+ var aID, bID;
+
+ aID = Number(a.id.slice(2));
+ bID = Number(b.id.slice(2));
+ return aID - bID;
+ });
+ $.add(thread, replies);
+ containers = $$('.threadContainer', thread);
+ for (_j = 0, _len1 = containers.length; _j < _len1; _j++) {
+ container = containers[_j];
+ $.rm(container);
+ }
+ Unread.update(true);
+ }
+ },
+ kb: function() {
+ var control;
+
+ control = $.id('threadingControl');
+ return control.click();
+ }
+ };
+
+ QuoteYou = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Mark Quotes of You'] || !Conf['Quick Reply']) {
+ return;
+ }
+ this.text = '\u00A0(You)';
+ return Post.prototype.callbacks.push({
+ name: 'Mark Quotes of You',
cb: this.node
});
},
node: function() {
- var thumb, _ref;
+ var quotelink, quotelinks, quotes, _i, _len;
- if (this.isClone || !((_ref = this.file) != null ? _ref.isSpoiler : void 0)) {
+ if (this.isClone) {
return;
}
- thumb = this.file.thumb;
- thumb.removeAttribute('style');
- return thumb.src = this.file.thumbURL;
+ if (this.info.yours) {
+ $.addClass(this.nodes.root, 'yourPost');
+ }
+ if (Conf['Highlight Own Posts']) {
+ $.addClass(doc, 'highlight-own');
+ }
+ if (!(quotes = this.quotes).length) {
+ return;
+ }
+ quotelinks = this.nodes.quotelinks;
+ for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
+ quotelink = quotelinks[_i];
+ if (QR.db.get(Get.postDataFromLink(quotelink))) {
+ $.add(quotelink, $.tn(QuoteYou.text));
+ }
+ }
+ }
+ };
+
+ Quotify = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Resurrect Quotes']) {
+ return;
+ }
+ if (Conf['Comment Expansion']) {
+ ExpandComment.callbacks.push(this.node);
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Resurrect Quotes',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var deadlink, _i, _len, _ref;
+
+ _ref = $$('.deadlink', this.nodes.comment);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ deadlink = _ref[_i];
+ if (this.isClone) {
+ if ($.hasClass(deadlink, 'quotelink')) {
+ this.nodes.quotelinks.push(deadlink);
+ }
+ } else {
+ Quotify.parseDeadlink.call(this, deadlink);
+ }
+ }
+ },
+ parseDeadlink: function(deadlink) {
+ var a, boardID, m, post, postID, quote, quoteID, redirect, _ref;
+
+ if (deadlink.parentNode.className === 'prettyprint') {
+ $.replace(deadlink, __slice.call(deadlink.childNodes));
+ return;
+ }
+ quote = deadlink.textContent;
+ if (!(postID = (_ref = quote.match(/\d+$/)) != null ? _ref[0] : void 0)) {
+ return;
+ }
+ boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID;
+ quoteID = "" + boardID + "." + postID;
+ if (post = g.posts[quoteID]) {
+ if (!post.isDead) {
+ a = $.el('a', {
+ href: "/" + boardID + "/" + post.thread + "/res/#p" + postID,
+ className: 'quotelink',
+ textContent: quote
+ });
+ } else {
+ a = $.el('a', {
+ href: "/" + boardID + "/" + post.thread + "/res/#p" + postID,
+ className: 'quotelink deadlink',
+ target: '_blank',
+ textContent: "" + quote + "\u00A0(Dead)"
+ });
+ a.setAttribute('data-boardid', boardID);
+ a.setAttribute('data-threadid', post.thread.ID);
+ a.setAttribute('data-postid', postID);
+ }
+ } else if (redirect = Redirect.to({
+ boardID: boardID,
+ threadID: 0,
+ postID: postID
+ })) {
+ a = $.el('a', {
+ href: redirect,
+ className: 'deadlink',
+ target: '_blank',
+ textContent: "" + quote + "\u00A0(Dead)"
+ });
+ if (Redirect.post(boardID, postID)) {
+ $.addClass(a, 'quotelink');
+ a.setAttribute('data-boardid', boardID);
+ a.setAttribute('data-postid', postID);
+ }
+ }
+ if (__indexOf.call(this.quotes, quoteID) < 0) {
+ this.quotes.push(quoteID);
+ }
+ if (!a) {
+ deadlink.textContent = "" + quote + "\u00A0(Dead)";
+ return;
+ }
+ $.replace(deadlink, a);
+ if ($.hasClass(a, 'quotelink')) {
+ return this.nodes.quotelinks.push(a);
+ }
}
};
@@ -3895,3081 +4395,6 @@
}
};
- ArchiveLink = {
- init: function() {
- var div, entry, type, _i, _len, _ref;
-
- if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Archive Link']) {
- return;
- }
- div = $.el('div', {
- textContent: 'Archive'
- });
- entry = {
- type: 'post',
- el: div,
- order: 90,
- open: function(_arg) {
- var ID, board, redirect, thread;
-
- ID = _arg.ID, thread = _arg.thread, board = _arg.board;
- redirect = Redirect.to({
- postID: ID,
- threadID: thread.ID,
- boardID: board.ID
- });
- return redirect !== ("//boards.4chan.org/" + board + "/");
- },
- subEntries: []
- };
- _ref = [['Post', 'post'], ['Name', 'name'], ['Tripcode', 'tripcode'], ['E-mail', 'email'], ['Subject', 'subject'], ['Filename', 'filename'], ['Image MD5', 'MD5']];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- type = _ref[_i];
- entry.subEntries.push(this.createSubEntry(type[0], type[1]));
- }
- return $.event('AddMenuEntry', entry);
- },
- createSubEntry: function(text, type) {
- var el, open;
-
- el = $.el('a', {
- textContent: text,
- target: '_blank'
- });
- open = type === 'post' ? function(_arg) {
- var ID, board, thread;
-
- ID = _arg.ID, thread = _arg.thread, board = _arg.board;
- el.href = Redirect.to({
- postID: ID,
- threadID: thread.ID,
- boardID: board.ID
- });
- return true;
- } : function(post) {
- var value;
-
- value = Filter[type](post);
- if (!value) {
- return false;
- }
- el.href = Redirect.to({
- boardID: post.board.ID,
- type: type,
- value: value,
- isSearch: true
- });
- return true;
- };
- return {
- el: el,
- open: open
- };
- }
- };
-
- DeleteLink = {
- init: function() {
- var div, fileEl, fileEntry, postEl, postEntry;
-
- if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Delete Link']) {
- return;
- }
- div = $.el('div', {
- className: 'delete-link',
- textContent: 'Delete'
- });
- postEl = $.el('a', {
- className: 'delete-post',
- href: 'javascript:;'
- });
- fileEl = $.el('a', {
- className: 'delete-file',
- href: 'javascript:;'
- });
- postEntry = {
- el: postEl,
- open: function() {
- postEl.textContent = 'Post';
- $.on(postEl, 'click', DeleteLink["delete"]);
- return true;
- }
- };
- fileEntry = {
- el: fileEl,
- open: function(_arg) {
- var file;
-
- file = _arg.file;
- if (!file || file.isDead) {
- return false;
- }
- fileEl.textContent = 'File';
- $.on(fileEl, 'click', DeleteLink["delete"]);
- return true;
- }
- };
- return $.event('AddMenuEntry', {
- type: 'post',
- el: div,
- order: 40,
- open: function(post) {
- var node;
-
- if (post.isDead) {
- return false;
- }
- DeleteLink.post = post;
- node = div.firstChild;
- node.textContent = 'Delete';
- DeleteLink.cooldown.start(post, node);
- return true;
- },
- subEntries: [postEntry, fileEntry]
- });
- },
- "delete": function() {
- var fileOnly, form, link, m, post, pwd;
-
- post = DeleteLink.post;
- if (DeleteLink.cooldown.counting === post) {
- return;
- }
- $.off(this, 'click', DeleteLink["delete"]);
- this.textContent = "Deleting " + this.textContent + "...";
- pwd = (m = d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : $.id('delPassword').value;
- fileOnly = $.hasClass(this, 'delete-file');
- form = {
- mode: 'usrdel',
- onlyimgdel: fileOnly,
- pwd: pwd
- };
- form[post.ID] = 'delete';
- link = this;
- return $.ajax($.id('delform').action.replace("/" + g.BOARD + "/", "/" + post.board + "/"), {
- onload: function() {
- return DeleteLink.load(link, post, fileOnly, this.response);
- },
- onerror: function() {
- return DeleteLink.error(link);
- }
- }, {
- cred: true,
- form: $.formData(form)
- });
- },
- load: function(link, post, fileOnly, html) {
- var msg, s, tmpDoc;
-
- tmpDoc = d.implementation.createHTMLDocument('');
- tmpDoc.documentElement.innerHTML = html;
- if (tmpDoc.title === '4chan - Banned') {
- s = 'Banned!';
- } else if (msg = tmpDoc.getElementById('errmsg')) {
- s = msg.textContent;
- $.on(link, 'click', DeleteLink["delete"]);
- } else {
- if (tmpDoc.title === 'Updating index...') {
- (post.origin || post).kill(fileOnly);
- }
- s = 'Deleted';
- }
- return link.textContent = s;
- },
- error: function(link) {
- link.textContent = 'Connection error, please retry.';
- return $.on(link, 'click', DeleteLink["delete"]);
- },
- cooldown: {
- start: function(post, node) {
- var length, seconds, _ref;
-
- if (!((_ref = QR.db) != null ? _ref.get({
- boardID: post.board.ID,
- threadID: post.thread.ID,
- postID: post.ID
- }) : void 0)) {
- delete DeleteLink.cooldown.counting;
- return;
- }
- DeleteLink.cooldown.counting = post;
- length = post.board.ID === 'q' ? 600 : 30;
- seconds = Math.ceil((length * $.SECOND - (Date.now() - post.info.date)) / $.SECOND);
- return DeleteLink.cooldown.count(post, seconds, length, node);
- },
- count: function(post, seconds, length, node) {
- if (DeleteLink.cooldown.counting !== post) {
- return;
- }
- if (!((0 <= seconds && seconds <= length))) {
- if (DeleteLink.cooldown.counting === post) {
- node.textContent = 'Delete';
- delete DeleteLink.cooldown.counting;
- }
- return;
- }
- setTimeout(DeleteLink.cooldown.count, 1000, post, seconds - 1, length, node);
- return node.textContent = "Delete (" + seconds + ")";
- }
- }
- };
-
- DownloadLink = {
- init: function() {
- var a;
-
- if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Download Link']) {
- return;
- }
- a = $.el('a', {
- className: 'download-link',
- textContent: 'Download file'
- });
- return $.event('AddMenuEntry', {
- type: 'post',
- el: a,
- order: 70,
- open: function(_arg) {
- var file;
-
- file = _arg.file;
- if (!file) {
- return false;
- }
- a.href = file.URL;
- a.download = file.name;
- return true;
- }
- });
- }
- };
-
- Menu = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Menu']) {
- return;
- }
- this.menu = new UI.Menu('post');
- return Post.prototype.callbacks.push({
- name: 'Menu',
- cb: this.node
- });
- },
- node: function() {
- var button;
-
- button = Menu.makeButton(this);
- if (this.isClone) {
- $.replace($('.menu-button', this.nodes.info), button);
- return;
- }
- return $.add(this.nodes.info, [$.tn('\u00A0'), button]);
- },
- makeButton: (function() {
- var a;
-
- a = null;
- return function(post) {
- var clone;
-
- a || (a = $.el('a', {
- className: 'menu-button',
- innerHTML: '[]',
- href: 'javascript:;'
- }));
- clone = a.cloneNode(true);
- clone.setAttribute('data-postid', post.fullID);
- if (post.isClone) {
- clone.setAttribute('data-clone', true);
- }
- $.on(clone, 'click', Menu.toggle);
- return clone;
- };
- })(),
- toggle: function(e) {
- var post;
-
- post = this.dataset.clone ? Get.postFromNode(this) : g.posts[this.dataset.postid];
- return Menu.menu.toggle(e, this, post);
- }
- };
-
- ReportLink = {
- init: function() {
- var a;
-
- if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Report Link']) {
- return;
- }
- a = $.el('a', {
- className: 'report-link',
- href: 'javascript:;',
- textContent: 'Report this post'
- });
- $.on(a, 'click', ReportLink.report);
- return $.event('AddMenuEntry', {
- type: 'post',
- el: a,
- order: 10,
- open: function(post) {
- ReportLink.post = post;
- return !post.isDead;
- }
- });
- },
- report: function() {
- var id, post, set, url;
-
- post = ReportLink.post;
- url = "//sys.4chan.org/" + post.board + "/imgboard.php?mode=report&no=" + post;
- id = Date.now();
- set = "toolbar=0,scrollbars=0,location=0,status=1,menubar=0,resizable=1,width=685,height=200";
- return window.open(url, id, set);
- }
- };
-
- PSAHiding = {
- init: function() {
- var entry;
-
- if (!Conf['Announcement Hiding']) {
- return;
- }
- entry = {
- type: 'header',
- el: $.el('a', {
- textContent: 'Show announcement',
- className: 'show-announcement',
- href: 'javascript:;'
- }),
- order: 50,
- open: function() {
- var _ref;
-
- if ((_ref = $.id('globalMessage')) != null ? _ref.hidden : void 0) {
- return true;
- }
- return false;
- }
- };
- $.event('AddMenuEntry', entry);
- $.on(entry.el, 'click', PSAHiding.toggle);
- $.addClass(doc, 'hide-announcement');
- return $.on(d, '4chanXInitFinished', this.setup);
- },
- setup: function() {
- var btn, psa;
-
- $.off(d, '4chanXInitFinished', PSAHiding.setup);
- if (!(psa = $.id('globalMessage'))) {
- $.rmClass(doc, 'hide-announcement');
- return;
- }
- PSAHiding.btn = btn = $.el('a', {
- innerHTML: '[ - ]',
- title: 'Hide announcement.',
- className: 'hide-announcement',
- href: 'javascript:;'
- });
- $.on(btn, 'click', PSAHiding.toggle);
- $.get('hiddenPSAs', [], function(item) {
- PSAHiding.sync(item['hiddenPSAs']);
- $.before(psa, btn);
- return $.rmClass(doc, 'hide-announcement');
- });
- return $.sync('hiddenPSAs', PSAHiding.sync);
- },
- toggle: function(e) {
- var hide, text;
-
- hide = $.hasClass(this, 'hide-announcement');
- text = PSAHiding.trim($.id('globalMessage'));
- return $.get('hiddenPSAs', [], function(_arg) {
- var hiddenPSAs, i;
-
- hiddenPSAs = _arg.hiddenPSAs;
- if (hide) {
- hiddenPSAs.push(text);
- hiddenPSAs = hiddenPSAs.slice(-5);
- } else {
- $.event('CloseMenu');
- i = hiddenPSAs.indexOf(text);
- hiddenPSAs.splice(i, 1);
- }
- PSAHiding.sync(hiddenPSAs);
- return $.set('hiddenPSAs', hiddenPSAs);
- });
- },
- sync: function(hiddenPSAs) {
- var hr, psa, _ref;
-
- psa = $.id('globalMessage');
- psa.hidden = PSAHiding.btn.hidden = (_ref = PSAHiding.trim(psa), __indexOf.call(hiddenPSAs, _ref) >= 0) ? true : false;
- if ((hr = psa.nextElementSibling) && hr.nodeName === 'HR') {
- return hr.hidden = psa.hidden;
- }
- },
- trim: function(psa) {
- return psa.textContent.replace(/\W+/g, '').toLowerCase();
- }
- };
-
- CatalogLinks = {
- init: function() {
- var el, input;
-
- if (!Conf['Catalog Links']) {
- return;
- }
- el = $.el('label', {
- id: 'toggleCatalog',
- href: 'javascript:;',
- innerHTML: "Catalog Links",
- title: "Turn catalog links " + (Conf['Header catalog links'] ? 'off' : 'on') + "."
- });
- input = $('input', el);
- $.on(input, 'change', this.toggle);
- $.sync('Header catalog links', CatalogLinks.set);
- $.event('AddMenuEntry', {
- type: 'header',
- el: el,
- order: 95
- });
- return $.on(d, '4chanXInitFinished', function() {
- return CatalogLinks.set(Conf['Header catalog links']);
- });
- },
- toggle: function() {
- var useCatalog;
-
- $.event('CloseMenu');
- $.set('Header catalog links', useCatalog = this.checked);
- return CatalogLinks.set(useCatalog);
- },
- set: function(useCatalog) {
- var a, board, path, _i, _len, _ref;
-
- path = useCatalog ? 'catalog' : '';
- _ref = $$("#board-list a[href*=\"boards.4chan.org\"],\n#boardNavDesktop a[href*=\"boards.4chan.org\"],\n#boardNavDesktopFoot a[href*=\"boards.4chan.org\"]");
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- a = _ref[_i];
- board = a.pathname.split('/')[1];
- if (['f', 'status', '4chan'].contains(board) || !board) {
- continue;
- }
- if (Conf['External Catalog']) {
- a.href = useCatalog ? CatalogLinks.external(board) : "//boards.4chan.org/" + board + "/";
- } else {
- a.pathname = "/" + board + "/" + path;
- }
- a.title = useCatalog ? "" + a.title + " - Catalog" : a.title.replace(/\ -\ Catalog$/, '');
- }
- return this.title = "Turn catalog links " + (useCatalog ? 'off' : 'on') + ".";
- },
- external: function(board) {
- return (['a', 'c', 'g', 'co', 'k', 'm', 'o', 'p', 'v', 'vg', 'w', 'cm', '3', 'adv', 'an', 'cgl', 'ck', 'diy', 'fa', 'fit', 'int', 'jp', 'mlp', 'lit', 'mu', 'n', 'po', 'sci', 'toy', 'trv', 'tv', 'vp', 'x', 'q'].contains(board) ? "http://catalog.neet.tv/" + board : ['d', 'e', 'gif', 'h', 'hr', 'hc', 'r9k', 's', 'pol', 'soc', 'u', 'i', 'ic', 'hm', 'r', 'w', 'wg', 'wsg', 't', 'y'].contains(board) ? "http://4index.gropes.us/" + board : "//boards.4chan.org/" + board + "/catalog");
- }
- };
-
- IDColor = {
- init: function() {
- if (!Conf['Color User IDs']) {
- return;
- }
- return Post.prototype.callbacks.push({
- name: 'Reveal Spoilers',
- cb: this.node
- });
- },
- node: function(post) {
- var str, uid;
-
- if (!(uid = $('.hand', this.nodes.uniqueID))) {
- return;
- }
- str = this.info.uniqueID;
- if (uid.nodeName === 'SPAN') {
- return uid.style.cssText = IDColor.apply.call(str);
- }
- },
- ids: {},
- compute: function(str) {
- var hash, rgb;
-
- hash = this.hash(str);
- rgb = [(hash >> 24) & 0xFF, (hash >> 16) & 0xFF, (hash >> 8) & 0xFF];
- rgb[3] = ((rgb[0] * 0.299) + (rgb[1] * 0.587) + (rgb[2] * 0.114)) > 125;
- this.ids[str] = rgb;
- return rgb;
- },
- apply: function() {
- var rgb;
-
- rgb = IDColor.ids[this] || IDColor.compute(this);
- return ("background-color: rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "); color: ") + (rgb[3] ? "black;" : "white; border-radius: 3px; padding: 0px 2px;");
- },
- hash: function(str) {
- var i, j, msg;
-
- msg = 0;
- i = 0;
- j = str.length;
- while (i < j) {
- msg = ((msg << 5) - msg) + str.charCodeAt(i);
- ++i;
- }
- return msg;
- }
- };
-
- Emoji = {
- init: function() {
- var css, icon, name, pos, _ref;
-
- if (!Conf['Emoji']) {
- return;
- }
- pos = Conf['emojiPos'];
- css = ["a.useremail[href]:last-of-type::" + pos + " {\n vertical-align: top;\n margin-" + (pos === "before" ? "right" : "left") + ": 5px;\n}\n"];
- this.icons["PlanNine"] = Emoji.icons["Plan9"];
- this.icons['Sage'] = Emoji.sage[Conf['sageEmoji']];
- _ref = this.icons;
- for (name in _ref) {
- icon = _ref[name];
- if (!this.icons.hasOwnProperty(name)) {
- continue;
- }
- css.push("a.useremail[href*='" + name + "']:last-of-type::" + pos + ",\na.useremail[href*='" + (name.toLowerCase()) + "']:last-of-type::" + pos + ",\na.useremail[href*='" + (name.toUpperCase()) + "']:last-of-type::" + pos + " {\n content: url('data:image/png;base64," + icon + "');\n}\n");
- }
- return $.addStyle(css.join(""), 'emoji');
- },
- sage: {
- '4chan SS': 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAYAAACZ3F9/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAa9JREFUKFOdkt0rg2EUwM95b2zlL0CRRLngksznXrJsNtYW1tjYhM3mY6+IXZAbikhTKJp8XZAp81UmWYhIRHHhUi60e7s6ntdCa2449es8PfU7z+k5B6AbyuE/wQlc4BcO2d06unAUBCgFE0hianOd3NHIcy8NPwrUf9NBPZcOEi7ayXZiea/1V7+ljaXeYAfOgg2So2TOwQWGnwQafOgi962TnMFmatozUeNu4yetASspVvgXiUvii5K5Nm6z56ol3Hdtpy+cwSYy+HRUt1nLsoEato0kXyh6wTac+24brThWv6MNOYNW9prlG/uxmbRrFaT0VrCspZoNPSUNJNyCBcoiLZuhLH0o9U6UrAfGKCz7RlLM81Q8XUwqr4oKPLIQmnA8IupBigacVy7yrya/2JouhryJHJJNykg+UxLGOtz6+SQNpEiMcduls4Wvoli9WklVKz+ol5SU4U6ngql8Qj2eRI+GyajBhSRH4r3cUxhSeRVhsYBmWUWiyM+UMDmDUI2nsfuSC1I27nLgYZJlP8jhjJ3PY8iE+L8tWx4kQC6MQA5b1D9HNiRCFhx8AF/e2qh92VnKAAAAAElFTkSuQmCC',
- 'appchan': 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAABa1BMVEUAAACqrKiCgYIAAAAAAAAAAACHmX5pgl5NUEx/hnx4hXRSUVMiIyKwrbFzn19SbkZ1d3OvtqtpaWhcX1ooMyRsd2aWkZddkEV8vWGcpZl+kHd7jHNdYFuRmI4bHRthaV5WhUFsfGZReUBFZjdJazpGVUBnamYfHB9TeUMzSSpHgS1cY1k1NDUyOC8yWiFywVBoh1lDSEAZHBpucW0ICQgUHhBjfFhCRUA+QTtEQUUBAQFyo1praWspKigWFRZHU0F6j3E9Oz5VWFN0j2hncWONk4sAAABASDxJWkJKTUgAAAAvNC0fJR0DAwMAAAA9QzoWGhQAAAA8YytvrFOJsnlqyT9oqExqtkdrsExpsUsqQx9rpVJDbzBBbi5utk9jiFRuk11iqUR64k5Wf0JIZTpadk5om1BkyjmF1GRNY0FheFdXpjVXhz86XSp2yFJwslR3w1NbxitbtDWW5nNnilhFXTtYqDRwp1dSijiJ7H99AAAAUnRSTlMAJTgNGQml71ypu3cPEN/RDh8HBbOwQN7wVg4CAQZ28vs9EDluXjo58Ge8xwMy0P3+rV8cT73sawEdTv63NAa3rQwo4cUdAl3hWQSWvS8qqYsjEDiCzAAAAIVJREFUeNpFx7GKAQAYAOD/A7GbZVAWZTBZFGQw6LyCF/MIkiTdcOmWSzYbJVE2u1KX0J1v+8QDv/EkyS0yXF/NgeEILiHfyc74mICTQltqYXBeAWU9HGxU09YqqEvAElGjyZYjPyLqitjzHSEiGkrsfMWr0VLe+oy/djGP//YwfbeP8bN3Or0bkqEVblAAAAAASUVORK5CYII='
- },
- icons: {
- 'Plan9': 'iVBORw0KGgoAAAANSUhEUgAAAAwAAAAPCAYAAAGn5h7fAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAzE15J1s7QAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAACAElEQVQoz3WSz4sSARTHvzMjygpqYg3+KIhkE83DKtKlf0C9SrTRuZNEx0VowU6CuSeJNlwwpEO2kJ6SQBiIUAzFjRDF4wrjKosnGx3HmdehFDfpe/2+z/s++D5gU7IsEwRByICIiAEAIiIAYAFAXsjYVr/fLxMRNVvN+prJ5/OA3+/XERFNf02JyeVyDx0OxyvLNQsnimLKfcf9KRQKXQAAnE6nlf5qMpnQycnbP/kAoKoqsSwLAJhOp+AAwOv1otvtpqxWq73dbt/r9XqvEQ6HUalUEvF4XLd5IpvNZqlerzd5nlf6/f6tTCZjBACk0+nb+XxeW4UrikLJZPImAGA0Gq0NIqJyuSyyANDr9Q5Wu1utFvR6/SULAI1G4+vK8Pv90DTtGwsAJpPpaGUYDAZ0Op3PHAAEg8H3tVqtbrtu21sqyxuRSOQJk0ql9IvF4r7b7f7pcrlejkaj57IsH58Pzp8dvjhc/lsBk0gkbLFYrFqtVvd27+4qOk733ePxPDCbzVBVFfP5fCiK4rvhxfDN/qP9wSasGwwGMv1HiqJQsVg8ZlfTHMepkiR1t05gGJBGmM/nMBqNj9nN9kql0lNN064ARISzH2cQBAGz2ewLu2na7XYLwzBbvxYIBBCNRrFj3BmsAZ/PZ+J5/kOhUIAkSVeA8XiMZqt5efrx9OA3GfcgvyVno9cAAAAASUVORK5CYII=',
- 'Neko': 'iVBORw0KGgoAAAANSUhEUgAAABMAAAARCAMAAAAIRmf1AAACoFBMVEUAAABnUFZoUVddU1T6+PvFwLzn4eFXVlT/+vZpZGCgm5dKU1Cfnpz//flbWljr5uLp5OCalpNZWFb//f3r6+n28ff9+PRaVVH59Pr//vr38vj57/Dp7eyjn5zq8O5aVVJbYV9nVFhjUFRiWFlZVlFgZGOboJzm5uZhamfz9/bt8fDw6+drb26bl5j/8/lkX1z06uldWFS5r61UT0tfWlbDwr3Ew76moqNRTU7Mx8P75OpeY19pWl1XW1qzr6x5eHaLiojv7+1UT0xIU0uzqadVS0nV0MxkZGT5+PPk497///ra29Xq5eFtY2H28e2hnJignJlUUE1dXV2vrqxkY2FkYF/m3d5vZmfDuruhl5aZlJHx8O75+PZWVVP29vT/9fTj3trv6ubh5eRdXFqTkpBOTUtqZmX88/RMQ0T78vPEvr7HwcHDwsDq6ef///3Gx8H++fXEv7tZWVedmZZXXVudnJp0c3FZU1f79fnb1dlXUVVjXWFrZmy8t7359/qLj455e3q4s69vamZjX1zy4+avpaReWFz/+f1NR0vu6Ozp4+f48/lnYmi8ur3Iw7/69fHz7+xbV1SZmJZVUk1ZV1zq5ez++f/c196uqbDn4uj9+P7z7vRVVVXt6ORiXl/OycXHw8CPi4ihoJ5aWF3/+v/k3+axrLOsp67LzMZYU1m2sq9dWF5WUU1WUk/Au7eYlJGqpqObmphYVV749f7p5Or38fPu6OpiXFz38fH79vLz7urv6+hhYF5cWWKal6D//f/Z09Xg29exraqbl5RqaW6kpKTq5uPv7Of/+PDj29D//vP18Ozs5+OloJymoZ1ZVVJZWVlkYF2hnpmblIyspJmVjYKQi4enop5STUlRTUpcWUhqY1BgWT9ZUjhcV1NiXVkkhke3AAAABHRSTlMA5vjapJ+a9wAAAP9JREFUGBk9wA1EAwEAhuHv3dTQAkLiUlJFJWF0QDLFYDRXIMkomBgxNIYxhOk4wwCqQhQjxgxSGIsALFA5BiYbMZHajz1oJlx51sBJpf6Gd3zONcrqm/r1W8ByK0r+XV1LXyOLLnjW6hMGpu0u1IzPSdO17DgrGC6AadrVodGcDQYbhguP6wAvAaC0BRZQalkUQ8UQDz5tAof0XbejOFcV5xiUoCfjj3O/nf0ZbqAMPYmzU18KSDaRQ08qnfw+B2JNdAEQt2O5vctUGjhoIBU4ygPsj2Vh5zYopDK73hsirdkPTwGCbSHpiYFwYVVC/17pCFSBeUmoqwYQuZtWxx+BVEz0LeVKIQAAAABJRU5ErkJggg==',
- 'Madotsuki': 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAMAAADTRh9nAAAALVBMVEUAAAC3iopWLTtWPkHnvqUcBxx5GCZyAAARERGbdXJrRUyGRUyYbY23coZFGDRFGEYfAAAAAXRSTlMAQObYZgAAAGhJREFUeF5Vy1kOQyEMQ1Fshzd12P9y61AixLX4yJFo1cvVUfT23GaflF0HPLln6bhnZVKCcrIWGqpCUcKYSP3JSIRySKTtULPNwMaD8/NC8tsyqsd1hR+6qeqIDHc3LD0B3KdtV1f2A+LJBBIHSgcEAAAAAElFTkSuQmCC',
- 'Sega': 'iVBORw0KGgoAAAANSUhEUgAAACwAAAALBAMAAAD2A3K8AAAAMFBMVEUAAACMjpOChImytLmdnqMrKzDIyM55dnkODQ94foQ7PkXm5Olsb3VUUVVhZmw8Sl6klHLxAAAAAXRSTlMAQObYZgAAANFJREFUGJVjYIACRiUlJUUGDHBk4syTkxQwhO3/rQ/4ZYsuymi3YEFUqAhC4LCJZJGIi1uimKKjk3KysbOxsaMnAwNLyqoopaXhttf2it1anrJqke1pr1DlBAZhicLnM5YXZ4RWlIYoezx0zrjYqG6czCDsYRzxIko6Q/qFaKy0690Ij0MxN8K2MIhJXF+hsfxJxuwdpYGVaUU3Mm5bqgKFOZOFit3Vp23J3pgsqLxFUXpLtlD5bgcGBs45794dn6mkOVFQUOjNmXPPz8ysOcAAANw6SHLtrqolAAAAAElFTkSuQmCC',
- 'Sakamoto': 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAYAAADwMZRfAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAxVJREFUOE+Nk19IU1EYwK+GQQTVQ39egh6ibKlzw91z7rn3bvfOmddNszl1bjKXc5rJJGmBUr7Yg9qTD0IalFgRBEYg6EDQQB+GovQyQgiaUZsoLcgHMcr069w7MgcGXfi453zn+37fv3MYZt/n99e76tzVj4JN/hP79fvXnV3hnNabwUBjoOHcgTYOu/JQspgTzsqKgn9BfD4vkWTzur287PqLVy+zM+yePB7KsRXLywTjnSpnZctBkPCdW8ccDuU55vBO8RXbkC/oP5ph19V5+7LIky0OY1BKbZEbLcFSt7u6pN7jLmltCVrr3DV5jY3+KovFEsccB1KJNVpefe10BqS2tqqO4/AuphBB4L/LkrRqNgtJs1lMypLls1kU38mytMLz/E8VIlutqVqX6/weZG52OttRXjbE0cP/FYLRlpVjDXuQ/r77x2XZPKkCHA4HBAIBkCQpAygIAvh8Pu2MZgO0Lz+QSa/sQfwN9RfpVN66XC6Ynp6GhYUFGBwczAC1t7fD0tISxONx6O7upgHILmsqvLcHodOggfiV/v5+SCaT4HQ6IRaLgdfr1bIRRREmJyfBZrNBNBqF+fl5sNsdgE2GiAbp6bmbdbXC7qWQbxMTE7C2tgY6nQ5SqRSEw2ENopaoZpCXlwdTU1NaoECgCbgiU6y8QH+ECYWaTymK7TWdys7MzIwGaWtrg42NDejo6AB1WjU1NZo+FArB2NgYrK6uQrAlCASxn2z6wkuMp87VIAhkE2MEAwMDkEgkYHx8HBYXF0HtkQpRy1BLiEQisLy8rPVNKSsFjEzrXH4+z1hlS4xDhKadNu7t7YPR0VHweDzAEVWfHru6HxkZgeHhYVAURYNjkylVWKArZjjMzqmdVi+QCsLUkQiEjvDvncEkvU7/qQ0Vgukeo48Go87IiCJnZNmipxiz7wXEbVDnbUxQOgM12h9n6qTq6NvapRdtkwaP0XK8RmPuYSbxYfaQ/sJJhjfknuFRURUi7AMOozcCwl94hLZp5F+EioDQVwqYI6jomZU1NFtM+rOSxZjVazcyvwHr/p/Kws1jegAAAABJRU5ErkJggg==',
- 'Baka': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA0pJREFUOE91k3tI01EUx39JOpA0H4jNx0pbD3XTalISWf8YFlEgldqDsBLLyqjEKBCiLLWiggh6/KEV1WZ7OaelLZvDdDafNW1JFraWe/32+01FrUZ9uy4ylLpw4Z5z7/nc77n3HIqaMRIjZJyEcNX+uFCFeGmI/GZciEIsCFJUTvoAzDz+1y7K76MSwhX5hXl6z+WSbrzU2KB8YEGDwgrTaxZ3b7xHcaHhR3xw7Z5/UviB1ReP5XSg3+TAqYJOxMzWISFIC0GQDomhTVA9skCnsaAwp/vnMq66dBokNuBR9uFd7T9Z1zCunjci0qcRJUVdoJ3DYOhRnC/qBZ+jQbfeCc+37yjY2UEg0iwvJE0k9l8Z+8xqHmTgot0QLdQgTaQFQ2AsOzlHvOu1S5pwOLsHHo8HjHMCq2MazNvTlByKHyrJLDvdR25jMWRxYx5HjeMH2r1BDOOeguRua4OI14jx8a8YH5tA+al3EHKlW6mYOapb2oZBOOwMbEMseAE12L+jjUh3w+VipyAZ65oxn1NP/GMYGR6Ftn4Qsf7qa9S82Y/l/X122G0uL2TbxmZEz1WhXW8mUol8moXu+SCi/OoQ6VsDh3UUwyQ1k9GOaI5MTkX4yWTGHutvgI1F28sviAlRgxeoRm62HvsyW8En9pZ1TYgi6TntoyQtFm86rVgUoJZRvDnKMmXVAGxWmkAYOBwudBqGcHCvHulrGpGT2Uy+z4yT+QYsCXtCUpp8GxbKhx8gDK0ro+KjJGvzdjfDZnN6VdisLD5/JjArQ2zW66PJOj2lEZtStaBphkwah7K6kMJ/GEulp1bMWhAmMbTozOQRaWRtfoZVgjo4iRra4SYgGi26TwjxVeDKhR7Y7U606ixICq9tr7hd7+OthRWL7yUnJ1WPmXotqLhpRICPHCePtuFV6xdUPTAhcWEtRHEqfHpPyto4hPXLXnzflSEJnFaN3OCKDcsFsrEntR9RUmxARLAUgT5iBPuJsXWDBj0dZjRU9yNV+PTbpjTp9OA/pOSk24nRkXf1J462oPxcJ65f6ULlHSMulepRerYDgvj7A0cKpNz/tyTZqbzXO4t0ZZGQJ34RH11lFHIlA8LIqreCCMUZRY3cd2bwL/5/RmjNSXqtAAAAAElFTkSuQmCC',
- 'Ponyo': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAuNJREFUOE+Nk3tI01EUx39BTytConQTt1am07m5abi5KT5S8z2dj1yOEMUC7aUgIoimlmUEWX9kBZGWaamEmE6U1BI1XNPNGTrnHs33IwuSXrL4NgcJ0mNdOHDh3PPhnPP9XoKwcroJYvMQiRSicHCQKCgUyZC9/T5rNet5KUFs0zCZbZMsFmZ9fTEjEEBDp4/KSSSb/4JoGIyWaTYbiykpWEhOxhSHAzWD0aqkUGhWAcVkW58xlvuPhfh4zItEmOHxYDR3MhcdDaNAsKJydAz5IySKRNjEUmy88vjOVaU8F0iPCqCNjEBHkC/UYaGYFwqxmJoKLYOhkxPElg0QsbNtTlmox9yjRD9UCbnoOR+J/lwRWtOCcdXfDc2BPpg0d7CQlIQZPh9KKlVkAQjJ2x2zmOSsQu7hpzUJfBhLjsNQmADjxcT10Bcl4rE4EHc5LjBEhEPn7f1WTqXSLQB/s1Tp7vslsoIkyPPiMJAbi86McBguiaHKjoEqR4jJy2K0nAxApzMN5iUGrclrKVaz2fUvuF4tRbxDKA90w5VjTFyLZKHpTBSq4/1QnxGB2qxoVIZx0JopRCPHFSNOThfWZzfrXDcZEowH4iA05ATg68hDtBaL0HAuCm3lJ9Bfcx2fFNUoi/DCjRgfNHHd1wCZA2TyXjNkE6F0cBDpPFiojeNi8EkJdFoN3vXch0nbBJOhDd907dANv8JITxNqziag3ZsJbUDAwLin50Q9QWwl1qSYoNOVvUcOoqOqAAa9Fu9H2/F9+B5WZLcwOyxFX18flLI+VASyMGVeoJHD+Tzq5BS1PoaKRrNT8127P74swsq4FCa9FKvqBqwaOiz3hdEuLKueYSyECT2LNW0eIfo3E/WmEbvnG1MUJnWdpWhDGDvxQXZHo+RR0uW2tnv+auPX+TvtJm7zKpaen/4y2yjBUlcxlvtvmvT16ZWDpQeoVv3/60F/NrHjTf4ugazIXtJ8ivjnz/sJ+yGQRjcqUdIAAAAASUVORK5CYII=',
- 'Rabite': 'iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAD/0lEQVR4Xl2MXUxbdQDFz/9+9Lb3tkBLCxTKhzgoOOZAsokbJmZxDFHnd+LL4hKVzBgfNCY++ODbjDEaZowvErOM6HRu6hKZY2rIAOkCY4OSDTpFaAsrlJa2t5+39+NvjT7tnJzknIfzI98Nf/C6TuXdguWBd1q9rcb8/CwsZiu2Ywm4nDVo3VWLZCKDaDwJq9mCg31PgjAMKKUwmcyYvTbek9iJRDm6M/XswEDjwNz6plWW6wdZhjUAintFCEEhn0N04zYskljaDLaj8ar49oUrsYR6mrFJNj322w46H8y+mitM/ZJKZmyE4XAvjJSsazpyuSzslVZIkgWKOvvRgQ6Xrdlhqmds7o7bFZoLkctreKxf7GtuCE7IyUQjBQcQ8j/lvxCGQJZz0IoCVpamTtzfIh9nwiaIrCQyjNg8mq11oDLUhNXRJfT1Ozr3tS/PqpnQ80qRgjAmKIqBfK4ItbSLKoOZqR/6neLkENlSUAIhlktvEf+sD2rkm8nWTHtvZCGMVON1ePuaoBER31/MXGly1wSqq9Uug6FluYyWXJiPqFXmjd4Dh9oF9ZKKimYXRtYCx8lmMIDIxlIPGz591av0mtanF7FcCEN6iMXeox2wOJ0QJAmUAoRQaIqCnWAQY1/ewKNGNeQuYXkm0d2NC2e+wvmRr/Hx+6+8PHayrbDyyQBNDb9As3PHKDWG6MTM23RoeJAWsqeoWvyUUv0UHf7pBB0fe4OeeXe3/vmHbx3+8dwIGJ4IsFpMMFe0fbtAn+nwZePr1u4MBK8XIALG/Rt479wYrs2vgeNNAMNgMbiNzybuoKVvn+Gs9kbr6qpBfJfGYHFIkJUCoGwfqcoMX/b27EGhwgOjoCADDlP+CA51ugFFRzoB8FYNaQ1oqKD44+eNL+wNj7zJGQSIhe8+jgQ9thk+27v/KRY6L4FSCkVOwtlQj6P73Qgt/o1ERoKt4iUkE7+jrZMHyzIoK9cOBFfT4LbWAk+0a7ZLnvqHcTNdACgFScfAcjxEdy00VQclHGo7dqGeYxHbvIo6hwhSghCehb3G5p6eW7VxXC5/xGWToMgrKKoaCnIalI9CIARasQAqloMI/x4BWrLLYwE1AEPTwCGHaGjz7pw/leZUNV8wNm9BLy6CxsvxZ1kMbaY4TKIIXlNBsynoVjvAC4CuAoYOVi+CMfLYCUfg95tPHuzZB0YtKzsb58RMucWE/fZmhCbdOP9rNnLnxko6GVoB8lFwyVVw8b/AyeulHoJyN4Rb19dTFyeqBlu6njvfsWcvOJvLs7DMmw/7bvpeE4pU2OIcgcqmp4fGAgt2Txwvqr7lTp5V7LquZxXC6+BqEvGcY5pyjaM1tffJbk89NE3FP5VQ6y7a+paZAAAAAElFTkSuQmCC',
- 'Arch': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABCFBMVEUAAAAA//8rqtVAqtUQj88tpdIYks46otwVldUbktEaldMjldM2qNcXk9IWktQZkdIYlc8mnNUXlNEZktEZlNIYktIWlNMXktE7o9klmdMXktFHqdkXk9EWk9EYk9IlmtQXlNEXktAWk9AWlNEYlNFDptkZldMYk9E4otg/p9kXktEXk9AXlNA4otclmdQXk9IYktEXlNEwn9YXk9IXk9FFp9o3otgXk9FPrdwXk9E2otdCptkXk9E/ptkcldIXk9Edl9IXk9EjmdUXk9EXk9EXk9EbldIcldIjmdMmmtQsndUvntYyn9YyoNYzoNc0odc1odc2odc6pNg7pNg9pdlDp9pJqttOrdzlYlFbAAAARXRSTlMAAQYMEBEVFhgcHR0mLS8zNTY3PT4/RU1kdXp6e3+Cg4WIiYqMjZGXl5mbnqSnrbS3zMzV3OPk7Ozv8fT29vf4+fz8/f7SyXIjAAAAmUlEQVR4XlXI1WLCUBQF0YM3SHB3a1B3l7Bx1///E6ANkDtva0jKbCW2XIH1z2hiZEZ4uUgxo7JedTQye/KN/Sb5tbJ+7V9OXd1n+O+38257TL+tah3mADAwSMM7wzQWF4Hff6ubQIZIAIb6vxEF4CZyATXhZa4HwEnEA+2QgoiyQDnIEWkjVSBBZBqXbCRlKYo8+Rwkyx54AOYfFe7HhFa7AAAAAElFTkSuQmCC',
- 'CentOS': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAB5lBMVEUAAADy8tng4Ovs9tnk5O3c7bX44LLduNO1tdDh7r/eutj43q2kocX23az07N+qqsvUqcmXl7331ZXJj7r40o/Pn8T42qP63KjNw9n21p3Y387Ml7732JzR55z05MSxtMLGn8TC4Hx8eqt8e62Af6/B4HnG4oPC4HzH44fBf7LCgbOkoMTcsrmtn8PWqcfFtKrj4Jvs2ZOz2FnMqLXT3KfY5p60Z6NUU5XRuqHzwWSywqDn3JaiiLWahrWhkry5zJjRmqm1Z6P1wmb1y319fK632mK5cKi5nH+73Gu73Gy73W283W+9eK17e6y1yZS3aqRZWJdcW5ldXJplXZppaKBwb6VwcKV5eKswL306OYNPTpGkfK+m0kGpUJWq1EnEqIuXK3+Xh7ahP4qhkryMfK6BgK+CdpGMaKKMa6O9ea2+eq6+oYW/eq+NbqWVlL2Wlr7AjanA4HnA4HrBkqbBlafB33rCgbLCmKjCxIzC1mSs1UytV5mtxIWt1lCuz2evWpuvXJywxYzHjrvH4oXIjrrN2HXO5pTO5pXUlYnUlYvVl5Hb0G7e0XTg03rhr5fpzHPpzXTp0Hvtz3/wrDHytknyt0zyuE3yuVHzvVr0wGP1x3T1yHf1yXe0ZaL2zYP30o730pD31ZeRIcF5AAAAQ3RSTlMAFBkbHEhJS0xMTk5UWWBsd4SEiIiPkJCVlZaam6CjpK29wMPDxMTFxcnK193e3+Dg4uTn5+fo6e/v8/P4+fn7/P7+J4XBAAAAAOBJREFUeF5Vj1OvAwEYBb/yGlu717atLW0b17Zt2/6nze42TTpvMw8nOZCAmwUpiIY6c5IiLi9tPX64GairqszHQ4X2VB64v1Cs6PxMPJSdHM777s6/jyaMRGiRLyyrb88OpjZ3CzAXrm1sqzSNNeN7kVBPNgB7cG51abE5l9cXDces7emQ1uadHhutFUg6gpPKkSIqQGavwz7r7O/+/3t/rSdjI9XDM3qz4fr3B/3iA0aJTG9x71+9oR/PLDwUe2wm19bly+fTIxHyEETatbPewGEw6Mk/tKZCEqSQQUlIHB/QNBEjjVN1AAAAAElFTkSuQmCC',
- 'Debian': 'iVBORw0KGgoAAAANSUhEUgAAAA0AAAAQCAYAAADNo/U5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAZ5JREFUOE+Nkk0oBHEYxv8fu5GQj3JwcaDkIAc5IpR87M7MKnIVJVKclaIQ5Sy5OLkgR7n5OigcSNpmd2c2Vyfl4KT8/muWiVU79TTv+7zv837NCBF6PG1X+NpZyEYSD9mIc+tHnBPe23B9xKrCuTmbQA/JKfABrhBswa1hH4A38IwfOxPdX1qcjiCQxO5NyrjKV70TnSbeRPwJvGN3i4yyqnEucPY8ZZX9GSEgGK+RvFfyjk2VKZxzBNG8wJWWgh/xtDOeUXZ7Slr6TrSLYL9N4SMgYTTcwdc2ArvJcElhSVcM6mCNSV8n9hA59yTU5UWMG6HIbLhIWlglgWiC2L4Z79qTdo40D6ISuOWwKCWHyk9Fv8ldpUHOuGTuynwSBUynddPdlbEosVpP9Eu4FnOsRzUYNTsdmZN/d5LDiqM0w+2CMdAFFsFGWgfXxZnheqe/z+0puwEM0HHYV3Z9Sgz8TEz7GkQvpuJ/36ggj2AaHLrSlkULWV5x+h2E8xkZL16YVjGNaAUscfZ/f6c/k9ywLKI2MMcRWl0RLy007idmRbQJ7RIfDAAAAABJRU5ErkJggg==',
- 'Fedora': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABPlBMVEUAAAApQXIpQXIpQXIqQ3UpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIqQ3QpQXIpQXIqRHYpQXIpQXIqQ3QqRHYpQXI8brT///8uTYMpQnM5Zqg5ZqnS1+I4ZaY4ZactSn8uRnYrQ3MrRXgsRHUsR3s8bbM8brMtSX4wUosxVI01XZw2X50vUIguToQvR3c6X5o6aKs6aq08Un8qQnM9VIFDWINJXohKcKlXapEqQ3UvUIc2X55bhcBdcJVgcpdhfapmd5tuk8dxgqJ1hKR5jbB6iah/m8Shudq3v9C4wNG/x9bFy9nFzNnFzNrIz9zK0NzK0t/O2+3P1eA2YaDU2eTb3+jb4Oje4urj6fHm6e/s7/Tz9fj3+fz7/P38/f3+/v83YaEa/NNxAAAAHnRSTlMABAoVGyY1SVlpeIuQsLfDzdHW4+3y8/b39/n6+vr4+ns8AAAAyklEQVR4XiWN5XrDMAxF75KOknYdZJS0klNmHjMzMzO9/wvMcH7I37mSJShsJ+5NjMT6umDoHyXDcI/2qJadh++P3cle1de+9yPe3/bTY92wzfzr7wGtP3JrAI72BZGVtcAdQlwHy+JS1pDbBE9qamZF3BYrjQxPEXwKc6dC8bXFm0QIpmt8kn0Rn093q82UCtK8oXZckwFJzuulV8bHkajPyXdbnJnARfDHs0trz+JQ+5AFvzp/L0+cL2qPAINUPrq5OC6p/64F/AMnrST+Dq/r7QAAAABJRU5ErkJggg==',
- 'FreeBSD': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAABIAAAASABGyWs+AAAABmJLR0QA/wD/AP+gvaeTAAADXklEQVQYGQXBS2wUZQDA8f83j33M9rF9d7u4loaWklaDpkSo9KDGaIKUaGxshD2YSPRiuDVeTDyhBxosJCoa40ktpAkPDcUqAYVIpUSUPrAulEdD2bbb7e7ObGcfM/P5+4kwKDvq6yJ1FYYcvb+YAkqAHo/HQ7FYrFIoCiurq9ZXJ06YSOkA+kBzfX06bys3zHxS9EL0tXDVyZfefacqV+X/ZSJx5+qLbx98LhaL9RiGEZWlEsWC/Thd9q6Pf3vs2u6Orc83rFsvTwwfLf5obgywT1Vjh2Hh+rbNsnTssJdNLedK5aIrpSuldKVXKsnH4+Pyn6FDXn5tMef9O+3NvdkvP1V4+EYw2AoQ+KSx8dRYS6NXXnwovaItXduSrrkinWxGOmZWJi9OyOK9m1LmsjIz9IH8QUMOd3WfAQwNKCy2tJwbHB5+XasPaxIHmc4g7WWEZ1MquBiRFlJTf1E7+Tl/H/8asavPzTY1nWd2ZkMDRPeBeHPz5ojwsilEQCBvTSKunCF3M8FSNkBGVTHDYYrLj8jVNhDZ2SMa2zo3MTamaIC/u6Ojr3DtrOrvP0BpdATnyBeIhTxpR5ABUlKSUlXS1dWstbVxdz6hPL0l1quGqkLaKwNvVcjEXNRd/4mit4Z19DjefBEPyCKxgQJQcF28dBrHNDGTSZSezsjeff0hraa2Vs2vrvit81O4vj9xLJcC4ADrQA7YAGqBGsAql/EtLdFQE/L7dF1XZmdnSrbPMJfXoLDmolQK8gJyQBowgQhQDRQBD+hsraVhd4e5MH+/oExfvWLJ9q3/3S7qMpNH2hsS40kFS4EUUAMA2IANRIBXv4uzuO67c2PykqkA5YmZ6bN18YPi0Yoknxc4AsJPCMLVAk2BLKDosCWqs/PZaulkuxk9fekcUBAAQGDks5FT0W++3NuYuC0DVUL4DIEdlIQDAj0IRkigaMjArkFx0tf523sffrQHyKsAgHPhwoXLL+yP9/kePNhk5ExUTyKFkJVAUAiCFZrQup4Rv9ftuLV/6ONBYBVABQAArMvJ5MXW7duD6P62sD8UrPAFRU1TpeCpCnGvPZr7WW///v0jpw+VC9ZdAAABAAAAAMLo7drWrmQyPWG/r8tnaGIjaM05ujr16x/ZBFh5AACA/wGZnIuw4Z4A3AAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxMi0wNy0wNFQxMDowOTo0OS0wNDowMOPVpFwAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTItMDctMDRUMTA6MDk6NDktMDQ6MDCSiBzgAAAAAElFTkSuQmCC',
- 'Gentoo': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAB9VBMVEUAAAD///+AgICqqv+AgIC/v9+Ojqqii9GAgKptYZKQkOmPj/ddUYBgW4eVjeCTgfiWjO5wbJaZkvPBvepkXomYkNldV4Bzbpl6dJ+Uj7ynoO6Vi+1qZI63se2mnudjXYjOy+GCfaqZjvWlm/Pc2e+Oh7NeWIOWjfeXjeW1sd+gl+diXIfp5/KHgKnn5/F2cZx6c6ZgWoXc2e6dltrAvNu0scrX1eTOyujCvup4c5qpovVpY43///+6uPPJyPXq6fvm5vrz8/z8/P7+/v/d3PixqvmxrPSyrfe0sPO0sfS3tMve2/3r6vy6ufPz8/3d3fi3tM63tPO4tsu5tsu5tvO6tfe6t/Vva5KRjKy7tvW7t/W9vPO/vM+/vvPCwfPEw/TFwvTFxOfGxfTGxvTHxvTIx/TJx/aTiOrNzPXNzfXQzfnRzuHS0fbS0vbT0uHU0e/U0uTU0/bW0+zW1ffX1vfY1/jZ2Pjb2/jc2uSTiemVkLSlnvbe3PTe3vng3fzg3f3g4Pnh4Pnh4fri4enj4/nk5Prl5Prm4/ymn/bn5vro5/rp6O/p6funoPWsqs3t7Pvt7fXv7vzv7v3w7/nx7/3y8f3y8v3z8vytqPWuqPX09P319P319P719f339v739/34+P35+f37+/+uqev9/f6vqvSwrPQAR0dcAAAAPHRSTlMAAQIDBAgJCwwVFyAsNUFHSVBneH+Bh4mVmZmanKCxsrK2tr3ExtDW19rb4ODl5u3t7u/w8/T6+/z9/f4MkNJ1AAAA8ElEQVR4XjXNw5aDURSE0YrRtm3b54+dtm3btm3bz9k3Wek9+2pSYFwT8ibzE93hwAtdJqK3nZo4J9hFXbP+vFHOthV6gnGzstZq94wdCs4UCCDymQ2v7X0LdYoSQ0MIENRYzJbRlPTTHu73ZNAL8vivmVui98PpzuqffX0mIPHJGtOQenukteJ+aS3b9htNpDnT9TeZH1bHAwBRMhGpd6e6uNrLoRgxBKmsX47nBlp678ojpEA40fejcmW4e/No0V8IIPfj6eKgbEJ3ZUnzgE1OqWp9Q3VeWRAsg51f1dZ8c31RmAsc+N5JGbG+zvj3BzDCPrzMDC9SAAAAAElFTkSuQmCC',
- 'Mint': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAACVVBMVEUAAADh4eEAAAAAAAAAAAAAAAAAAAAsLCyXl5dgYGCnp6eTk5N3d3fBwcGqqqq8vLzNzc3Ozs7Ozs7Pz8/Pz9DQ0NHR0dLS0tLS0tPT09Pf3t/Pz8/i4eLb29vZ2drZ2tna2dra2trf3t/u7O/u7e/u7O/r6+vt7O/w7/Lw8PDy8fTz8fXz8fbx8fHz8/P19fb49/j49/n6+vuPxlmWyGOx437h9NDr9eD6/fj////+/v75/vTA5Jv6/fb7/fnL5bDL5q+AxjeDxUCEzTyGxUaGzjyHxkiHzz6J0D+Kxk6K0kCLyE2M00WNy06P00mSz1OUyF+W2FGX1FiY0F6Z02CZ21ac0Wiez2yfz2+f2mOh4GCi4GOi4WKi4mOk12+k3Wul32um1Hin0nun4G6n5Gin5Wmo23Op2Huq1n+q43Cr526s4Hit23+v6XSw34Cw34Gw6nWx4IKy4IOy44Cy63ez146z34az4IWz4YW03Y217nu38H2625e645G74pK83pu98Iq984W+4ZjA4px0tzDA5ZrB8ZDC5p7D55/E947F6KHF+JHH4qvH6qTI46/K5LLL5LN1tzLL5bN1uTDL57DM5bPM6qzM66/N5rTP6LbP6bTR6rfS573T67vT7LrV7r3X68XX7MHX773Y77/Y9rvZ8cHa7cjd88bi88/j8tTk8djk9tHm8trn89vo89zo9N3p9N3p9d7p9tvq9d/s+93s/dzy+erz+O73+vT4/PX5/fT5/fX5/vN1uzB3vTD6/ff6/fh5uTj8/fv9/vr9/vx8wjV/xDmrMRH0AAAAOXRSTlMAAAECAwQJDzk/RUlNU3F0kpSVlpeYmpucnaKjpKWqqqqtu8LExMTEzdTU1NXY4evy8vP+/v7+/v6LaR1mAAABD0lEQVR4XiXI03bEABAA0KltW9kaW3eSZW3btm3btm3b/q4mp/fxgqKOtpamhrqaqoqykrQYABh+PVMU9fjE5Xp8o54kgPHN0EBHU2N5YXZykiua0HHd2759VF2Sk5IYE5GGsmCEWLV1kVWwt5O+3x/qpgsy8k4ja+cJl2/v5C22tlgCAHtw9TQSa4s+AzfPSm0BRNl9SydhWJzLC567KrNhgrNwHIJ5qTz/2f9w7Jw/DNqIjVr04exW0AEOXcN3Ab7enr9eDW2VTJgehONyc2Z8XP5YdD0Tcuhcc4/r45OjGX51TEjYPbh8THRPvbz+CHusgSZlT7rP8PkCwfQKaQUi9Igr6JsRBMFiWZgb/AHKElRzKopZJQAAAABJRU5ErkJggg==',
- 'Osx': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABrVBMVEUAAAD///////+qqqr///+ZmZn///+qqqqAgID///////+tra339/eAgICoqKjx8fGMjIzm5ubh4eGPj4/g4ODIyMiAgICSkpKLi4vS1tbPz8+Xl5eMjIypqanIyMjW1tZ2dnbR0dGamprFxcV3d3d+fn60tbV3d3dcXFx3d3epqal7fHxxcXF+foCnp6hYWFhyc3Ojo6SMjI5fX196enp+fn6Li4xERERqamqgoKFpaWmFhoeen6A/Pz9QUFCWlpeSk5SUlZWUlZaOjo+Tk5RHR0cuLi5YWFgwMDAeHh40NDQ3Nzc6OjpcXF1rbG0XFxdSU1NVVVVXV1dZWVlbW1tnZ2lwcHABAQEEBAQXFxchISI+P0BISUpaW1xHR0kNDg4qKyszNDU1NTY9Pj8NDQ1cXF4XFxhSU1QSEhIDAwMrKywtLS4uLi4wMDFHSElISEggISE0NDVJSktNTU1FRUVWVlhGRkYEBAVBQUE0NTZQUVJQUVMFBQUqKitWV1lXV1daWlpaWlw+Pj8bGxtcXV9dXV1fX19fYGFgYGBkZGRlZmhpaWlsbGxwcHB2dna844Y9AAAAV3RSTlMAAQIDAwUFBggMDhkeICMkKCgqMDIzPj9ERFBib4CCg4iMjZCcnp+jqamrw83W1tvb3ePl6Ojp6+vs7u7v8PHy9PT09PT3+vr7/f39/f39/v7+/v7+/v50ou7NAAAA30lEQVR4XkXIY3vDYABG4SepMdq2bRSz/capzdm2fvOuDO397Rw0Ly4tz2QAQPbcxuZ2E/STJwfxPhWgG355fRrVAIVb1zeP9UDLfiSwkAcADe8fn7tFxWuEXFRDoer/OgoMTRBCumj8yJwPBo8Zhpk14U856/HI8n0ZUtpZ1udrSzfVneA4roNKjdrwpcMRilb8d8G60+lKnrpWcn9bO+B23w2O8Tzfq4aiNSZJqzn5O4Kw16h06fPZ+VUlUHfo97+VAEb7rSh2UgDd4/U+TBlQY7FMj5gBIGvcarVVfQPVPTG94D0j9QAAAABJRU5ErkJggg==',
- 'Rhel': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABj1BMVEUAAAD///////8AAAD///////8AAAD///8AAAD///////8AAAD///8AAAD+/v4AAAAAAAAAAAArKysAAAD///////8AAAAAAAAAAAAAAAD///8AAAAAAAAAAAD///8AAAD///8AAAAAAAAAAAAAAAB5eXn+/v5JSUnKysrS0tJ5eXmqqqqxsrL+/v4ZCgknJyeHh4eIiIjo6OgZCAdOTk7t7e3///8GCwwPAAArKyv19fX29vb9/f0EAAD////+/v4AAAAGBgYHAAAJAAAMAAANAQAPAQAVAQFyCQV9fX2pIRzmEQjn5+cBAAAFAAAAAADnEQjvEgn////uEQjyEgnsEQjzEgnxEgljBwPaEAj9EwnwEglHBQJHBQNNBQIBAAB3CQR5CQSHCgWLCgWRCgWTCwadDAWmDAapDAa/DgfKDwjWEAgGAADh4eHiEQjmEQjmEQkKAADoEQgLAQDtEQgMAQDuEQnvEQjvEQkPAQAfAgEuAwEvAwE8BAL1Egn3Egn4Egn6Egk+BAL+/v5CBQJrB0muAAAAT3RSTlMAAAMEBAkYGhsbMTRLUmpvcHeIjLe6vcHCxM3P0NbW3Ojp6u/w9ff5+fn6+vr6+/v7+/v8/Pz9/f39/f39/f7+/v7+/v7+/v7+/v7+/v7+Q8UoNAAAAO5JREFUeF4tiwVPA0EYRL9SXIsWl+LuxfcOd2Z3764quLu788NZNrxkksmbDP2R7vH6GioLs+iffEzNXd4+TqPErUUpVqMOvwgdzMPn1rv5vPsVeufBTaBK/bH2FPvkEUuIG5jIIc+sHYn/HJ3dC/Hxuo4y8s44dzwBbFkisHN8bVIdXs6jb+H97aCwbHEIqgcml64CD7YllNkAVQC940MLYe5YzvIeQAXNrd19Roc5MdzfdQLUUKaUYyuG9I8y1g4gj6hIak4X5cBIT2MquZJrJdOqpY11ZpAiqVwbY/C7KY1cRCrZxX4pWXVuiuq/hs49kg4OyP4AAAAASUVORK5CYII=',
- 'Sabayon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABvFBMVEUAAAAcUaYdVKwAAAAAAAUABAwWRY4YSZYhZtIhaNYHDx0KCgoFDBcKCgoRMmYSNm0fXL0fXb8AAAAYS5gaTp8fXLwgXsEGBgYFBQUZSpgZTZ4JFSgODg4IEiIOJkwOKVIkW7EnXbQLGzUTExMKGC8LHjwMIkITExMiIiIPEBEPJ00QEhMXOXAaPncOJEgoXbApXbEcHBwwMDAEAgAfHRgQDgo3NC8AAAAHBwcKCgoLCwsJCQkaGhofHx8lJSUwMDA0NDQ4ODiRkZEICQocHBweHh4GBgYHCg8mJiYnJycpKSkrKystLS0uLi4ICAgODg43NzcRERF1dXUUFBSjo6O1tbUbGxsEBAMLGS8MDA0iIiIjIyMkJCQNDQ0NHTYKCQkoKCgPDw8QEBArMDkKCgkRERIREhMxMTEyMjISIz00Njk1NTU2NjYCAgIVFRU5OTo5P0c8PD0+Pj4/QURAQEBHR0dKSkpMTExSUlJiYmJlZWVnZ2cWFhZ2dnZ4eHh8fHx9fX2FhYUXFxeVlZWXl5eYmJiZmZmcnJwZGRmlpaWrq6usrKyvr68KFiq/v7/FxcXY2Nji4uLn5+ft7e0yif9uAAAAN3RSTlMAAAApKSkqKioqg4OEhISEhoa1tra3t7y9vr7S09PT09TU+Pj5+fn5+/v7+/v7+/v7/v7+/v7+70RY/wAAAPpJREFUeF4dyWNjw2AUBeC7dfYyorM6rx1exKltzLZt2/rDa/J8OgBVVlFDX39jcTZoUqCse251a2dvu6ccUtWlanLQ4Vpel+ThlWq1l3wEz58tx4dOt1dMlAJk9A5gMjG75LHwo46hzkwosGOMbejumoRvubC9EOrMviT0E0Us9fvN9dA6zxJCNv6+ECGsb6oNWsgmpZT9/UTUZo3Em6AW34guTL4jiAudiCM1kLcw8/SmHERfT1/eueBiDqR1GK1n9w+K8nglxYxd6QAML4ztXoQuj8YFgWcgqdJp8qzty26vaboCNIxBCshyQDKov0aXr29v1ufq1PwPx5Q7bCoh6eoAAAAASUVORK5CYII=',
- 'Slackware': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AcEDi0qZWWDgAAAAx1JREFUOMt9kktoXHUchb/ffc1M7rySSdJMOknFPMRitLgoNKKI8ZHGKkgrjU8SitidimSh2UkXoQmoO1dGQSxJjdvOtqSaqlR0USEGSjVJGxuSmWR6M3fu4/93YX0g4rc9HA6cc4Q7DI+fpzz7PA8++2mxvZAeBZ4xhHtFcJRmXWsWvb36/OLcyxf5B/KHeYHy7DmGx1+YSDjmWTdlobTGMAStQGkNoLXS4tXDq7u7tUcWz49tA8jR8QUuzB5n5NTCV13F9JEo1JJwTLKuzU61QiOMcd0UDb+BncwQK3Rl15eNja3ui/Njq8aF2eMcO/XlBz0H8oO2ZUkum6A13WB99TtyzXlaCi24SaFa+ZFCzsG2DNnfkdbFjsI1APPhk+d6ujqznycdCxFozadYWvyMpx47wa+bPkGksKwUNnsk3TaCGASRXDZh5LpHXPPg4Rcni+3uYBxrtBbQghlscOVKmYHeEm0ZIZ9xyLffw41ND6VAa43SmjiMByzHYtjzwr9arfshxf5jOKlvKZfn8es77N2uks24PPfSFD/9Uvt7AtPKWmEU9d645eHYJo5tcKi/FX/zG+zmQxQH+rANk862DOW5N/hhaY64cJSa5xNFCgDDILZACMKYWAmh73HmzFsMlBQJ06LeiMinE1S3KzRCm5rXIIoUIoKIYCVM36urZFbEoiBLNMIhAE6/NsSB7h6SKZdL8xsUOnpx9j1KbTdARACIowArYe1ergfNT2i0mIbJys0GI6PT3N1/hJvrPxOFdRJNBQIy/FapI4Bpgohgcjuw+jq8jy8tV55MNBWI4ohS802CpizKv8q+FgALZAfYgSyAZtNro1oLaU1VvxCA029Oraxs7u/tKnXiNjn8HyKwur6lI++6vPK4V7IA7u+1Dyu1tr183ddNbkHuXP8/zEIYeFqiLRl6YO/p0bHJdflT/PD9qZa1W+ry99fcvlAlcZwUpuUAglIRYVgnDEIOlna4q0M/NPnuO1/PzMwg/045O/XeibUt5/Xangx6viSVFpK2jtMpvdyWCz+5ryf10clX3/amp6eZmJjgd441URWWJY8BAAAAAElFTkSuQmCC',
- 'Trisquel': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABjFBMVEX///8AAAAAAAAAAAAAADMAAGYAAAAAHFUAGWYAF10AImYAIGAAHloAHGMAKGsAGmYAJmYAJGEAKnUAJ1gAMXYAJnEAJGQAI2EAK28AK3cAGTEAMHgALXEALXgALG0AFUAAI2oAK3EAMngANoYALXMANIAAM4IANIIAL3gANIcANokANoQANYQAOY0ANIYANooAN4kAN40AOY0APZMANIUAOY0AO5AAPZUAPJAAP5MAPpQAQJUAOYsAPpYANoUAPpoAPpUAM4AAQJkAPZIAPJEAQpgAN4cAPpQAPZUAPJEAO4oAOosAOo8AQJoAOYsAO44AQpsAO48AQp0AP5UAQpoARJwAQ58ARaAAQZgAQ54AQ50AQpgARaIARqMARaMARaIAR6QARaIARaEASakARKEAR6MASqsARKEASKcAR6MARqYAR6UATbEATa8ARqUARKAAR6oARqMASKgATK8AR6QATbIATbAASq0AR6cASKgASqwAR6UASKcATa8ASqoASqwAS6wASKoAS60ATbHn4CTpAAAAhHRSTlMAAQIFBQUGCQoLDxAREhMUFBUYGhobHB0eHh8gIiIjJCQkJCYoLC0xMTE0NDo6Oz1BQUNHSUxOVFVVVldaWl5iY2RkZWZoamtsb3FycnR1ent9f4KDhIiJioyNkJGYm5+foqOkpqamqKmqrKytsLKzs7e4uLy8v8TFxcXGx8rO0NXY2eZc4XYcAAAA00lEQVR4XkWN1VoCUQAG/3NWtwh7CTsQJOyk7BaDxuxA6bbrxf32gt25m7kZqDRYxziooDV7+1AalMUavQh2AsEZoWvzigLun+T17/c8QiJZ7qu2QKiNmyZthdcR1/as353jIeU1GxMHo5XHdqPFeX8IaDMdHPYN6dRN7LR4qQewdTa35HWkyh+fbxERAMjwlAWJv3CPSKDQ+H7XvHdkV4Pua3Gtm4sPKIF/WV8dop4VKBw/NU33B3x1JbTt+XwhkJQoqRfWvHOy28uqH8JIdomR/R+s9yR3Cso77AAAAABJRU5ErkJggg==',
- 'Ubuntu': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABKVBMVEX////ojFzplGf1zbnqnHLvs5P10b3yuZv1xKrytZXvtJXys5LysI32waT0n3HxiVHwg0jxhk31kFn0h0zxf0P0hUrveTv2iU3yfkD1hEfyejv5eDLybSX0aR7zZxvyayH6ZxnxZBj4YhH7XAb5WALlUQLeTwHgUAHeTgHfTwD65NzdTQDdTQHdTgD31MfcTgLcTADcTQD////xt5/31Mf54dfmfE/dUAbeVQ/jcUDcTgHeWBnnflHohFvpjGbqkGztnX342Mz53dLgXiP65d399PHdUgrtoYLyu6Xzvaf76eLfXB/rkm/fWhvupojwrpTeVhTgYSfgYynzwa30xbL1ybnngFT31snngljhZS3539XhZzDiajbibDn77OX88Ovrl3X99vTjbz1fisGCAAAAMHRSTlMABgYGBwcHJiorMDA1NXGHjY2Nl5mZmZyfn6O5u8XHzc3X193j9fj4+vr6/f39/f08OUojAAAAx0lEQVR4Xi3HZVbDYBhGwQctWqzFPXiQ+36pu+LubvtfBKcN82/UEhld2vWXxyL6F92gbTPabse8hU/uHMx1SZoyyJWPTwq1Rs7GpYE9+Cg+OJcs1MHvU9y4fnrN31yUm18vMCIPjtw3QMndw4rs8ieVzAAcBlewpe1KM3uaBuD3Dda1BhWXAsi6AFY1a2SqifxZ+rnxWYcJDRkUS3fO1R5vwe+XZgw4D4L3RAJiknoXCVX3WeiUpJ5pIxTvVmg45pl5k4Ot/AGV2iqZBWgJJAAAAABJRU5ErkJggg==',
- 'Windows': 'iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA+pJREFUOE+F0n84FHYcB3CWSsL9ojo/6ik64c6PnTjmSS0limmrpBm2G002y++xzXRz6zE0R4nbw+RnTj/WD4sbanLkkAe55ccYlyNme4SrO9u9d13PI3/saZ+/vs/3831ez+f9eb5aWsuqy2mjRYeNUa7YmtjfTico7jNJ8z0eG24NB9vvnDrvufzpq89Npnr8VjMddNmuRh9rDfp36mFg91oM7qPIc5JdbDJq3An/JfCu7Hl53W2lpS220pP2OuniN299jAYbYizSENIoAgbCTdrTKtxOJVdvGo8psUwKy7Vxe4ez1YEVudGP8YEZzyveInFJ6mZRHHqYazDspw/pJwTIuERM5JIwmUdGdyo9K7/BszGzzg6fXzZHGJ8KvzQqXKOpoIeZLjofWR++BPWyCEnPY4xFGEKWQcLjMjKmr1MwfcMYwmz/Y4KOgNki0V5k1dkjUWCK93Kp2PMFFawos8cm1gZ2GqjLXktL4mbQPHLQ4B9ZDFE5+S356fQlyuJMqzH++HnTo6ui2OO1ko9Ul+4fxfd3d4F7k4YTReqpuFS88bGZUE2QNNDobuIq8Q5CduHb7lFJaTnvnym9ergjMWD/FG8zf+aKS3G9JO5C01Asah6wUXrvALKEDoitMMHhDKrKJdg8RU2s0EB2EWWur8dd7PDPFv6dUC0Gv3kAN36VPRGP/5k5NS6lljWxG0TDiSr1VKhoPwhevRMSqkwRxDObc/DavGtpP6zoi8XOyZfhnyNEvKANBU0P8VPfI/wyNCGXSn7wlEmyA9KrgmOKGth3eDVvPfyywq2dnUEv2R9qG2rLsH7xJXziKnWcI8tlTvEC7Mu8hROlImTU9aKqcwQ1vWOihWFu+sJknmph5CvxQh87c7bNh/NXo03hrMCosyvLmMNgMF7TQL6J1dsZIUVwjKqEO+cajp5vxPN439U/gKBt8PTcYHzL/BgHCyOf4unAISj6mFC2bYC82kB5Ls460NHRUVsDeYSXpGw7UgC7sAtwShDgzdM38W7BbURXtqpqhfmB8sEQuXwoCM/6faGQuGCxyxyKWhIm+PrSD495WL3cT0hhi8Whc3NbAs9KaOyCTvrJ8qkdX19XBeTUDU00+55USFzVU2yHstcaix0mUAjJkJeuRU868Ucmk0lcguiBnMAVxjbbdHV1yeq8+u4Hgo22huSG+iQXp83ftaxW3lsPZcs6KG5T8OwaAfJiPcxlrVRVRhvF02i0F/t5VbHZ7JWDfErKTLnhE3mFPuRFepg/uxqz6TqLv6euGj3ut87t/4ylvre3t3ZehOWWO1zjSFEqMVP4GfGb/DBykJcjmaZOoLsc+hcVY/LaAgcTQAAAAABJRU5ErkJggg==',
- 'OpenBSD': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAykIPu64pQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADTklEQVQ4y32RXUxTdxjGn3N6eujoKT3SUkuk3VoBGfVjgFXAsZ7WkipyYXQbuu3CzUXZmGRbssnFEseFkWzgcGzGXky9MWL8TsC4IeFgtK4oAqOnG5vMVl1pCMVWQD7b/y5M6jLdflfvxfPked/nBQA0NDSChqnGVrLuGkES742NhJAdhAKAuk9yyUs5Gry7RQMZAARCWgivpQiPe71P5DUfH0xaqTL7m/iiLkJmphawa+e4SM2PvUyC4yUIBu8CnAQKAK53rCA5OUtQtStVpJ4Gw/FOBddZVKhCfq4MP4n6+at+DUsJm/e0G9JZzYEvI2tHwlEYjDxomkZ+3nG8WroRtHihZVOhVlorDQzh0okhcByDP4ZGcf+X9XAsvY5/RsBa7Kq5H/CqLctKyl/g08S2i6fq8W/MS3P34T9wNDVYSeDX1eTD9xhiLXbtB/Akwmmv6Kr+ICFkLpGhtNSM3qsSstS3oX8lSsmsxS6ZVn3j6PvVVqhUcvC8AtPxVPxwygVKvngN89WOjgVprggGA4eenjB4nsXsTASpC63I0wVTZYPR11FoKRB8Ax54PCFk6BhMTk5CPR3GSbHouGzknr/bYFq9EAvfc9Tu1sLjHcXNKxLuTOTgzOlOe7IHBc/beAXWpWmXlz8a84nhcLQ+ecVzsAEQrMWuMX+f9HZF2YPZ28FVSNfoPWqOzMUmqYMAJm7+/OOzXQFwHGpyEV+vi+yvtxBC9pDmpgJC4tvI3mo9GTitIxvW24nT7ug67HY/3eDs2bbyrVsrY2day70rV6kRfDAHk5lDLJqAmmeRiD9GJDKHvwb74R8G0mkTPjrQTTG122xkTTbwaV2b1H4u16JQKXGr7yG2b8/H1MQ09IsTSEmRwzf4CCwzD+dmE1re8CI7wwi5XNlFf9vaTXX4dWJg4LLl7h05fpNGwNAMWpp9CIVYNO/tRCzGwpDFQaVMQTS2CKY0BWr3GVGWNSXKACDDaA4Mh976pq9f5Sy09GgKlmeAMIBKzUKpU+BFoxJecRhUfAbMxDi4eADfHVmE79v7q575gvvYeVvjZ58LD5mwsKUyX0hnf0feslnQCWD4zxnc6reKisxsfH2oscqcmTmK/+Ow252cna7K52r+Bky6PqmoT5HBAAAAAElFTkSuQmCC',
- 'Gnu': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAywUV5gQrwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADcElEQVQ4y43Tb0jjBRzH8c9v+7nNMebcUW21Cc78g/wcuhByIScoMRwoTBmFlZCmIJ14axqkgoYIkXIqKIVBEuJNUBEUPRlpqDC3Q2Ex0nTezun2YOaPLXNIv7Vvj7zgiOj1+PPk/eADjuNEuHN6ekqMw+H4IzMz8xChUCjV1NT0JbO7uxtfXFy8NZvNr21tbd0AAEQikY6I0m1tbQbx2NjYZiqV+vn29jY+PDw8xhYWFj45PDzcb25uhlQqfSTief6X0dFRpqKigvF4PPPipaWlY7lcXhCLxXJnZmY+ZTY2NnzX19ePGxsbHw0MDLivrq5mc3Jy2pPJZLVWq/2cdbvdDSzLholoNJ1OMy6Xq0Ymk5HNZktOTU29qMgA8HYqlaKDgwNKp9M0PT09BgAM/iGuqqoimUx2yPP8U5/P9wEAMB0dHRUKheJHiUTyeGhoqAUAnE7nR0qlsjcQCLwjlsvlz+bm5mQWi0VSWlr6bXV1tU6hUMj6+/vfN5lMN0xxcfG1zWZ7SETTSqWSGhoamPHxcajV6s+8Xu9Xou7u7t9VKtW00+mkSCTC6PV6aDQa8Dw/Wl9fP8UAQCgUosvLSyovL2eWl5dRUFBw7Ha7v9vc3By5K3g1EAg8FQSBiIguLi4IgBwA2LtEjuPuJxKJ62AwKFpdXf0eQBIvYVmW/cLlchEAWK1WAADT09NzX6PR/OTz+eKVlZUzKpVqTyqVvsnzfLCkpGSrtrb2t97eXnFeXl5ZKpWyZ2RkPPP7/UUnJyefGI3GU+zt7aU4jotOTk7mAUBfX1+b1Wq9kcvlBIAcDgctLCyQxWKhoqIi6uzs/BoAVlZW3qqpqbllZmdnf1hfX//Q4/HEzWbzX+3t7fcMBgMFg0EYjUYmEolAEAREo1Hk5+fT+fk5Mzg4GD86OpJ0dXXJGQBoaWl5Ra/XP6yrq3tQVlam2N7ehslkAsuySCaTUKvVSCQS2NnZSXAcJxYEQTEyMvKeIAhLDADY7fZ7BoPhm6ysLFpbWzuan5//WKvVvsHzPEWjUSYSiSA3N5d0Oh0TjUaf+/1+S2Nj46/4FwYAr7e2tnbF4/E/iYjC4TCFw+F0LBaj/f19mpiYeID/IAagAyABYLXb7cLZ2Rml02nyer3POY6rwv8hEr34u0IkEk1mZ2cTgGMA7768/RtL5JKsGzrLIgAAAABJRU5ErkJggg==',
- 'CrunchBang': 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAQCAQAAAC45EetAAAA8ElEQVR4XnWOsUpCYQBGz1TIHYu2Qix6g0DEtSeQu/UIISJtUS8gJq61F1wcdMohcBDxKUR8hsz1xA/y44/cs3znbB+RJ0Skl3pSkeFQbUs79VAPzrwPFRmN1Ja0Ug/16I93+1oi4lKte+zMXv32WuoAm43lXMrqzbFncgWw21lORf4+/PREKpAhYqZuPXZ+T/3yXbZEajV1JavUQ104sRcq0myqc5mnHurWqc/7yhExVwuPncl+C4Bu13L60ueAwcByOtLhgAIRCzU38fRGTmSxUBvSSD3Ui1NvQkXWa7Uq1dRD9R17HiqyRUSy1NP6B7e1Yu2GtlUKAAAAAElFTkSuQmCC',
- 'Yuno': 'iVBORw0KGgoAAAANSUhEUgAAABgAAAAPCAYAAAD+pA/bAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAABDtJREFUOE+FlHtMm1UYxrtsi8aEgCb+oTFmZur+WNS5RaPERU10C2qGaBgb6hgwLwMmHTIKlIKlQIHSQrmU24BSSmnpBVooUmihtEC5yKWDjVu5uOkcEca4lG5E93j6EQmELX7Jky/fOed9fu973vMdGu0xT3Cgz57yXMZLDdXcy821PFWLKmuA6HqLMqtLX5POl4iYb2ukWW8IOOFe/qfe3/M4n0eOjwyZD8//bldODOk37N1yDJgl+LVdjEGLFKO9KkzZm8hbje7mIrTXZ7sMtTydrJh15H8hHW11XvN/jGS7VudcD5w34ZZzeQYb67fwYO03LN4exo1+LWzNxbA05O5QuzbHqRYn+++CHDx4YK9WLfaedfQzV5em54g5Zbi8OIml+VFMDLWQ7GXoaSmFWZsDZVGCO2u0EbkhHTrhFqi9PmelSsQ8tAtSVch60dpUeGe4kxgZxegzVkBzlQ2NKBG2+iJIMqMok9r8OLRIMqApToSqmAWTmk9B2+o2YW79oshU7ABcuvAFrVGWXkVKpBYoSaBSxIS2mINpiwbjZiUMZRloVfJQyaXDKObBpimBScpHFe8KmmXpaKhK3arGrBVuVBclHN2CiPNin1OVs1tVJYlQlyZBxA6DviQVo6ZaOKd7sTplw53BVugruBBzfsRslw7rZPxaczWutSpQV/gzJPxo1JexyfaxKBBpuiEx+tw+CpKdEvGWTprGlhcwqbIzL5/DYKMYndpK3L1hxf3ZfkrzwybUZjPhnOqmvlcmutFF1jis9QSShOrcWNSXJ1MA0ou/NZWc8Ddfe4VGO3bk0JON1dyMMlK+gmxNrZCFhZF2Kng7YNO0awt4b7wLNp2EqtAsF6ImP56SG0B6siovTYpIjg15gapCVhAfJRUyIBFEo6k8AyuTtkcC/qvG/XbDexulWJvqgYH0o0nKhVHFJ40XwFQnWM5OCX+XMg86c3KvVMSMapCmPpSTIygTxGKZZOcOXhrr3Mp4uzkFuG6B3ajE3TELDDU8qEmsmvRATxquKkxAnSTFjwKEfv3JU9JC5unG6rQ1bTkbQ4Yq/DVgxOqwBWt2K9Yne3ZCZvrgHO2k5paHzOhSiVCZSkdNTgzy40JRlPgDhDHBCxUZdCs91G8fLeK87zOl6XSOICZYXMGNhDqX9fDP/mbK2DXVi/szm03eLpejl5pzOfqwOt4JBT8OeYwQt/4R/BR0OzXiLCM5LOCji/4nXt46rpywgG+zor5RxgSdupBzJdglSY+5ZZbl3XNY6mbn7W0Lcx06zBg1WBjtcC6OmG+OmRTrFrnIUZESZeVeCpwh8TpiPsQ47/tloM97T+/6m8mg55mT3tStyL54mhlwwtszNvjzD8/6HH8i7PvvPPRioZdRWuDBZUR6pEWG7I8P9Xs1Jsj36MfvvO5J/+rTw58dP7afJPfBgeef3XGz/gskFVpJc4HwGwAAAABJRU5ErkJggg=='
- }
- };
-
- ExpandComment = {
- init: function() {
- if (g.VIEW !== 'index' || !Conf['Comment Expansion']) {
- return;
- }
- if (g.BOARD.ID === 'g') {
- this.callbacks.push(Fourchan.code);
- }
- if (g.BOARD.ID === 'sci') {
- this.callbacks.push(Fourchan.math);
- }
- return Post.prototype.callbacks.push({
- name: 'Comment Expansion',
- cb: this.node
- });
- },
- node: function() {
- var a;
-
- if (a = $('.abbr > a', this.nodes.comment)) {
- return $.on(a, 'click', ExpandComment.cb);
- }
- },
- callbacks: [],
- cb: function(e) {
- var post;
-
- e.preventDefault();
- post = Get.postFromNode(this);
- return ExpandComment.expand(post);
- },
- expand: function(post) {
- var a;
-
- if (post.nodes.longComment && !post.nodes.longComment.parentNode) {
- $.replace(post.nodes.shortComment, post.nodes.longComment);
- post.nodes.comment = post.nodes.longComment;
- return;
- }
- if (!(a = $('.abbr > a', post.nodes.comment))) {
- return;
- }
- a.textContent = "Post No." + post + " Loading...";
- return $.cache("//api.4chan.org" + a.pathname + ".json", function() {
- return ExpandComment.parse(this, a, post);
- });
- },
- contract: function(post) {
- var a;
-
- if (!post.nodes.shortComment) {
- return;
- }
- a = $('.abbr > a', post.nodes.shortComment);
- a.textContent = 'here';
- $.replace(post.nodes.longComment, post.nodes.shortComment);
- return post.nodes.comment = post.nodes.shortComment;
- },
- parse: function(req, a, post) {
- var callback, clone, comment, href, postObj, posts, quote, spoilerRange, status, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
-
- status = req.status;
- if (![200, 304].contains(status)) {
- a.textContent = "Error " + req.statusText + " (" + status + ")";
- return;
- }
- posts = JSON.parse(req.response).posts;
- if (spoilerRange = posts[0].custom_spoiler) {
- Build.spoilerRange[g.BOARD] = spoilerRange;
- }
- for (_i = 0, _len = posts.length; _i < _len; _i++) {
- postObj = posts[_i];
- if (postObj.no === post.ID) {
- break;
- }
- }
- if (postObj.no !== post.ID) {
- a.textContent = "Post No." + post + " not found.";
- return;
- }
- comment = post.nodes.comment;
- clone = comment.cloneNode(false);
- clone.innerHTML = postObj.com;
- _ref = $$('.quotelink', clone);
- for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
- quote = _ref[_j];
- href = quote.getAttribute('href');
- if (href[0] === '/') {
- continue;
- }
- quote.href = "/" + post.board + "/res/" + href;
- }
- post.nodes.shortComment = comment;
- $.replace(comment, clone);
- post.nodes.comment = post.nodes.longComment = clone;
- post.parseComment();
- post.parseQuotes();
- _ref1 = ExpandComment.callbacks;
- for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
- callback = _ref1[_k];
- callback.call(post);
- }
- }
- };
-
- ExpandThread = {
- init: function() {
- if (g.VIEW !== 'index' || !Conf['Thread Expansion']) {
- return;
- }
- return Thread.prototype.callbacks.push({
- name: 'Thread Expansion',
- cb: this.node
- });
- },
- node: function() {
- var a, span;
-
- if (!(span = $('.summary', this.OP.nodes.root.parentNode))) {
- return;
- }
- a = $.el('a', {
- textContent: "+ " + span.textContent,
- className: 'summary',
- href: 'javascript:;'
- });
- $.on(a, 'click', ExpandThread.cbToggle);
- return $.replace(span, a);
- },
- cbToggle: function() {
- var op;
-
- op = Get.postFromRoot(this.previousElementSibling);
- return ExpandThread.toggle(op.thread);
- },
- toggle: function(thread) {
- var a, inlined, num, post, replies, reply, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
-
- threadRoot = thread.OP.nodes.root.parentNode;
- a = $('.summary', threadRoot);
- switch (thread.isExpanded) {
- case false:
- case void 0:
- thread.isExpanded = 'loading';
- _ref = $$('.thread > .postContainer', threadRoot);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- post = _ref[_i];
- ExpandComment.expand(Get.postFromRoot(post));
- }
- if (!a) {
- thread.isExpanded = true;
- return;
- }
- thread.isExpanded = 'loading';
- a.textContent = a.textContent.replace('+', '× Loading...');
- $.cache("//api.4chan.org/" + thread.board + "/res/" + thread + ".json", function() {
- return ExpandThread.parse(this, thread, a);
- });
- break;
- case 'loading':
- thread.isExpanded = false;
- if (!a) {
- return;
- }
- a.textContent = a.textContent.replace('× Loading...', '+');
- break;
- case true:
- thread.isExpanded = false;
- if (a) {
- a.textContent = a.textContent.replace('-', '+');
- num = (function() {
- if (thread.isSticky) {
- return 1;
- } else {
- switch (g.BOARD.ID) {
- case 'b':
- case 'vg':
- case 'q':
- return 3;
- case 't':
- return 1;
- default:
- return 5;
- }
- }
- })();
- replies = $$('.thread > .replyContainer', threadRoot).slice(0, -num);
- for (_j = 0, _len1 = replies.length; _j < _len1; _j++) {
- reply = replies[_j];
- if (Conf['Quote Inlining']) {
- while (inlined = $('.inlined', reply)) {
- inlined.click();
- }
- }
- $.rm(reply);
- }
- }
- _ref1 = $$('.thread > .postContainer', threadRoot);
- for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
- post = _ref1[_k];
- ExpandComment.contract(Get.postFromRoot(post));
- }
- }
- },
- parse: function(req, thread, a) {
- var link, node, nodes, post, posts, replies, reply, spoilerRange, status, _i, _len;
-
- if (a.textContent[0] === '+') {
- return;
- }
- status = req.status;
- if (![200, 304].contains(status)) {
- a.textContent = "Error " + req.statusText + " (" + status + ")";
- $.off(a, 'click', ExpandThread.cb.toggle);
- return;
- }
- thread.isExpanded = true;
- a.textContent = a.textContent.replace('× Loading...', '-');
- posts = JSON.parse(req.response).posts;
- if (spoilerRange = posts[0].custom_spoiler) {
- Build.spoilerRange[g.BOARD] = spoilerRange;
- }
- replies = posts.slice(1);
- posts = [];
- nodes = [];
- for (_i = 0, _len = replies.length; _i < _len; _i++) {
- reply = replies[_i];
- if (post = thread.posts[reply.no]) {
- nodes.push(post.nodes.root);
- continue;
- }
- node = Build.postFromObject(reply, thread.board);
- post = new Post(node, thread, thread.board);
- link = $('a[title="Highlight this post"]', node);
- link.href = "res/" + thread + "#p" + post;
- link.nextSibling.href = "res/" + thread + "#q" + post;
- posts.push(post);
- nodes.push(node);
- }
- Main.callbackNodes(Post, posts);
- $.after(a, nodes);
- return Fourchan.parseThread(thread.ID, 1, nodes.length);
- }
- };
-
- FileInfo = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['File Info Formatting']) {
- return;
- }
- this.funk = this.createFunc(Conf['fileInfo']);
- return Post.prototype.callbacks.push({
- name: 'File Info Formatting',
- cb: this.node
- });
- },
- node: function() {
- if (!this.file || this.isClone) {
- return;
- }
- return this.file.text.innerHTML = FileInfo.funk(FileInfo, this);
- },
- createFunc: function(format) {
- var code;
-
- code = format.replace(/%(.)/g, function(s, c) {
- if (c in FileInfo.formatters) {
- return "' + FileInfo.formatters." + c + ".call(post) + '";
- } else {
- return s;
- }
- });
- return Function('FileInfo', 'post', "return '" + code + "'");
- },
- convertUnit: function(size, unit) {
- var i;
-
- if (unit === 'B') {
- return "" + (size.toFixed()) + " Bytes";
- }
- i = 1 + ['KB', 'MB'].indexOf(unit);
- while (i--) {
- size /= 1024;
- }
- size = unit === 'MB' ? Math.round(size * 100) / 100 : size.toFixed();
- return "" + size + " " + unit;
- },
- escape: function(name) {
- return name.replace(/<|>/g, function(c) {
- return c === '<' && '<' || '>';
- });
- },
- formatters: {
- t: function() {
- return this.file.URL.match(/\d+\..+$/)[0];
- },
- T: function() {
- return "" + (FileInfo.formatters.t.call(this)) + "";
- },
- l: function() {
- return "" + (FileInfo.formatters.n.call(this)) + "";
- },
- L: function() {
- return "" + (FileInfo.formatters.N.call(this)) + "";
- },
- n: function() {
- var fullname, shortname;
-
- fullname = this.file.name;
- shortname = Build.shortFilename(this.file.name, this.isReply);
- if (fullname === shortname) {
- return FileInfo.escape(fullname);
- } else {
- return "" + (FileInfo.escape(shortname)) + "" + (FileInfo.escape(fullname)) + "";
- }
- },
- N: function() {
- return FileInfo.escape(this.file.name);
- },
- p: function() {
- if (this.file.isSpoiler) {
- return 'Spoiler, ';
- } else {
- return '';
- }
- },
- s: function() {
- return this.file.size;
- },
- B: function() {
- return FileInfo.convertUnit(this.file.sizeInBytes, 'B');
- },
- K: function() {
- return FileInfo.convertUnit(this.file.sizeInBytes, 'KB');
- },
- M: function() {
- return FileInfo.convertUnit(this.file.sizeInBytes, 'MB');
- },
- r: function() {
- if (this.file.isImage) {
- return this.file.dimensions;
- } else {
- return 'PDF';
- }
- }
- }
- };
-
- Fourchan = {
- init: function() {
- var board;
-
- if (g.VIEW === 'catalog') {
- return;
- }
- board = g.BOARD.ID;
- if (board === 'g') {
- $.globalEval("window.addEventListener('prettyprint', function(e) {\n var pre = e.detail;\n pre.innerHTML = prettyPrintOne(pre.innerHTML);\n}, false);");
- Post.prototype.callbacks.push({
- name: 'Parse /g/ code',
- cb: this.code
- });
- }
- if (board === 'sci') {
- $.globalEval("window.addEventListener('jsmath', function(e) {\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(e.detail);\n } else {\n // load jsMath and process whole document\n jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);\n jsMath.Autoload.LoadJsMath();\n }\n}, false);");
- return Post.prototype.callbacks.push({
- name: 'Parse /sci/ math',
- cb: this.math
- });
- }
- },
- code: function() {
- var pre, _i, _len, _ref;
-
- if (this.isClone) {
- return;
- }
- _ref = $$('.prettyprint', this.nodes.comment);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- pre = _ref[_i];
- $.event('prettyprint', pre, window);
- }
- },
- math: function() {
- if (this.isClone || !$('.math', this.nodes.comment)) {
- return;
- }
- return $.event('jsmath', this.nodes.post, window);
- },
- parseThread: function(threadID, offset, limit) {
- return $.event('4chanParsingDone', {
- threadId: threadID,
- offset: offset,
- limit: limit
- });
- }
- };
-
- Header = {
- init: function() {
- var barFixedToggler, barPositionToggler, customNavToggler, editCustomNav, footerToggler, headerToggler,
- _this = this;
-
- this.menu = new UI.Menu('header');
- this.menuButton = $.el('span', {
- className: 'menu-button',
- innerHTML: ''
- });
- barFixedToggler = $.el('label', {
- innerHTML: ' Fixed Header'
- });
- headerToggler = $.el('label', {
- innerHTML: ' Auto-hide header'
- });
- barPositionToggler = $.el('label', {
- innerHTML: ' Bottom header'
- });
- customNavToggler = $.el('label', {
- innerHTML: ' Custom board navigation'
- });
- footerToggler = $.el('label', {
- innerHTML: " Hide bottom board list"
- });
- editCustomNav = $.el('a', {
- textContent: 'Edit custom board navigation',
- href: 'javascript:;'
- });
- this.barFixedToggler = barFixedToggler.firstElementChild;
- this.barPositionToggler = barPositionToggler.firstElementChild;
- this.headerToggler = headerToggler.firstElementChild;
- this.footerToggler = footerToggler.firstElementChild;
- this.customNavToggler = customNavToggler.firstElementChild;
- $.on(this.menuButton, 'click', this.menuToggle);
- $.on(this.barFixedToggler, 'change', this.toggleBarFixed);
- $.on(this.barPositionToggler, 'change', this.toggleBarPosition);
- $.on(this.headerToggler, 'change', this.toggleBarVisibility);
- $.on(this.footerToggler, 'change', this.toggleFooterVisibility);
- $.on(this.customNavToggler, 'change', this.toggleCustomNav);
- $.on(editCustomNav, 'click', this.editCustomNav);
- this.setBarFixed(Conf['Fixed Header']);
- this.setBarVisibility(Conf['Header auto-hide']);
- $.sync('Fixed Header', Header.setBarFixed);
- $.sync('Bottom Header', Header.setBarPosition);
- $.sync('Header auto-hide', Header.setBarVisibility);
- this.addShortcut(Header.menuButton);
- $.event('AddMenuEntry', {
- type: 'header',
- el: $.el('span', {
- textContent: 'Header'
- }),
- order: 107,
- subEntries: [
- {
- el: barFixedToggler
- }, {
- el: headerToggler
- }, {
- el: barPositionToggler
- }, {
- el: footerToggler
- }, {
- el: customNavToggler
- }, {
- el: editCustomNav
- }
- ]
- });
- $.on(window, 'load hashchange', Header.hashScroll);
- $.on(d, 'CreateNotification', this.createNotification);
- $.asap((function() {
- return d.body;
- }), function() {
- if (!Main.isThisPageLegit()) {
- return;
- }
- $.asap((function() {
- return $.id('boardNavMobile') || d.readyState === 'complete';
- }), Header.setBoardList);
- $.prepend(d.body, _this.bar);
- $.add(d.body, Header.hover);
- return _this.setBarPosition(Conf['Bottom Header']);
- });
- return $.ready(function() {
- var a, cs;
-
- _this.footer = $.id('boardNavDesktopFoot');
- if (a = $("a[href*='/" + g.BOARD + "/']", $.id('boardNavDesktopFoot'))) {
- a.className = 'current';
- }
- cs = $.id('settingsWindowLink');
- cs.textContent = 'Catalog Settings';
- if (g.VIEW === 'catalog') {
- _this.addShortcut(cs);
- }
- Header.setFooterVisibility(Conf['Bottom Board List']);
- return $.sync('Bottom Board List', Header.setFooterVisibility);
- });
- },
- bar: $.el('div', {
- id: 'header-bar'
- }),
- notify: $.el('div', {
- id: 'notifications'
- }),
- shortcuts: $.el('span', {
- id: 'shortcuts'
- }),
- hover: $.el('div', {
- id: 'hoverUI'
- }),
- toggle: $.el('div', {
- id: 'scroll-marker'
- }),
- setBoardList: function() {
- var a, boardList, btn, fourchannav, fullBoardList;
-
- fourchannav = $.id('boardNavDesktop');
- if (a = $("a[href*='/" + g.BOARD + "/']", fourchannav)) {
- a.className = 'current';
- }
- boardList = $.el('span', {
- id: 'board-list',
- innerHTML: "[ - ] " + fourchannav.innerHTML + ""
- });
- fullBoardList = $('#full-board-list', boardList);
- btn = $('.hide-board-list-button', fullBoardList);
- $.on(btn, 'click', Header.toggleBoardList);
- $.rm($('#navtopright', fullBoardList));
- $.add(boardList, fullBoardList);
- $.add(Header.bar, [boardList, Header.shortcuts, Header.notify, Header.toggle]);
- Header.setCustomNav(Conf['Custom Board Navigation']);
- Header.generateBoardList(Conf['boardnav']);
- $.sync('Custom Board Navigation', Header.setCustomNav);
- return $.sync('boardnav', Header.generateBoardList);
- },
- generateBoardList: function(text) {
- var as, list, nodes;
-
- list = $('#custom-board-list', Header.bar);
- $.rmAll(list);
- if (!text) {
- return;
- }
- as = $$('#full-board-list a', Header.bar);
- nodes = text.match(/[\w@]+(-(all|title|replace|full|index|catalog|text:"[^"]+"))*|[^\w@]+/g).map(function(t) {
- var a, board, m, _i, _len;
-
- if (/^[^\w@]/.test(t)) {
- return $.tn(t);
- }
- if (/^toggle-all/.test(t)) {
- a = $.el('a', {
- className: 'show-board-list-button',
- textContent: (t.match(/-text:"(.+)"/) || [null, '+'])[1],
- href: 'javascript:;'
- });
- $.on(a, 'click', Header.toggleBoardList);
- return a;
- }
- board = /^current/.test(t) ? g.BOARD.ID : t.match(/^[^-]+/)[0];
- for (_i = 0, _len = as.length; _i < _len; _i++) {
- a = as[_i];
- if (a.textContent === board) {
- a = a.cloneNode(true);
- if (/-title/.test(t)) {
- a.textContent = a.title;
- } else if (/-replace/.test(t)) {
- if ($.hasClass(a, 'current')) {
- a.textContent = a.title;
- }
- } else if (/-full/.test(t)) {
- a.textContent = "/" + board + "/ - " + a.title;
- } else if (/-(index|catalog|text)/.test(t)) {
- if (m = t.match(/-(index|catalog)/)) {
- a.setAttribute('data-only', m[1]);
- a.href = "//boards.4chan.org/" + board + "/";
- if (m[1] === 'catalog') {
- a.href += 'catalog';
- }
- }
- if (m = t.match(/-text:"(.+)"/)) {
- a.textContent = m[1];
- }
- } else if (board === '@') {
- $.addClass(a, 'navSmall');
- }
- return a;
- }
- }
- return $.tn(t);
- });
- return $.add(list, nodes);
- },
- toggleBoardList: function() {
- var bar, custom, full, showBoardList;
-
- bar = Header.bar;
- custom = $('#custom-board-list', bar);
- full = $('#full-board-list', bar);
- showBoardList = !full.hidden;
- custom.hidden = !showBoardList;
- return full.hidden = showBoardList;
- },
- setBarPosition: function(bottom) {
- Header.barPositionToggler.checked = bottom;
- if (bottom) {
- $.rmClass(doc, 'top');
- $.addClass(doc, 'bottom');
- return $.after(Header.bar, Header.notify);
- } else {
- $.rmClass(doc, 'bottom');
- $.addClass(doc, 'top');
- return $.add(Header.bar, Header.notify);
- }
- },
- toggleBarPosition: function() {
- $.event('CloseMenu');
- Header.setBarPosition(this.checked);
- Conf['Bottom Header'] = this.checked;
- return $.set('Bottom Header', this.checked);
- },
- setBarFixed: function(fixed) {
- Header.barFixedToggler.checked = fixed;
- if (fixed) {
- $.addClass(doc, 'fixed');
- return $.addClass(Header.bar, 'dialog');
- } else {
- $.rmClass(doc, 'fixed');
- return $.rmClass(Header.bar, 'dialog');
- }
- },
- toggleBarFixed: function() {
- $.event('CloseMenu');
- Header.setBarFixed(this.checked);
- Conf['Fixed Header'] = this.checked;
- return $.set('Fixed Header', this.checked);
- },
- setBarVisibility: function(hide) {
- Header.headerToggler.checked = hide;
- $.event('CloseMenu');
- (hide ? $.addClass : $.rmClass)(Header.bar, 'autohide');
- return (hide ? $.addClass : $.rmClass)(doc, 'autohide');
- },
- toggleBarVisibility: function(e) {
- var hide, message;
-
- if (e.type === 'mousedown' && e.button !== 0) {
- return;
- }
- hide = this.nodeName === 'INPUT' ? this.checked : !$.hasClass(Header.bar, 'autohide');
- Conf['Header auto-hide'] = hide;
- $.set('Header auto-hide', hide);
- Header.setBarVisibility(hide);
- message = hide ? 'The header bar will automatically hide itself.' : 'The header bar will remain visible.';
- return new Notification('info', message, 2);
- },
- setFooterVisibility: function(hide) {
- Header.footerToggler.checked = hide;
- return Header.footer.hidden = hide;
- },
- toggleFooterVisibility: function() {
- var hide, message;
-
- $.event('CloseMenu');
- hide = this.nodeName === 'INPUT' ? this.checked : !!Header.footer.hidden;
- Header.setFooterVisibility(hide);
- $.set('Bottom Board List', hide);
- message = hide ? 'The bottom navigation will now be hidden.' : 'The bottom navigation will remain visible.';
- return new Notification('info', message, 2);
- },
- setCustomNav: function(show) {
- var btn, cust, full, _ref;
-
- Header.customNavToggler.checked = show;
- cust = $('#custom-board-list', Header.bar);
- full = $('#full-board-list', Header.bar);
- btn = $('.hide-board-list-button', full);
- return _ref = show ? [false, true] : [true, false], cust.hidden = _ref[0], full.hidden = _ref[1], _ref;
- },
- toggleCustomNav: function() {
- $.cb.checked.call(this);
- return Header.setCustomNav(this.checked);
- },
- editCustomNav: function() {
- var settings;
-
- Settings.open('Advanced');
- settings = $.id('fourchanx-settings');
- return $('input[name=boardnav]', settings).focus();
- },
- hashScroll: function() {
- var hash, post;
-
- if (!((hash = this.location.hash) && (post = $.id(hash.slice(1))))) {
- return;
- }
- if ((Get.postFromRoot(post)).isHidden) {
- return;
- }
- return Header.scrollToPost(post);
- },
- scrollToPost: function(post) {
- var headRect, top;
-
- top = post.getBoundingClientRect().top;
- if (Conf['Fixed Header'] && !Conf['Bottom Header']) {
- headRect = Header.bar.getBoundingClientRect();
- top += -headRect.top - headRect.height;
- }
- return ($.engine === 'webkit' ? d.body : doc).scrollTop += top;
- },
- addShortcut: function(el) {
- var shortcut;
-
- shortcut = $.el('span', {
- className: 'shortcut'
- });
- $.add(shortcut, [$.tn(' ['), el, $.tn(']')]);
- return $.prepend(Header.shortcuts, shortcut);
- },
- menuToggle: function(e) {
- return Header.menu.toggle(e, this, g);
- },
- createNotification: function(e) {
- var cb, content, lifetime, notif, type, _ref;
-
- _ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb;
- notif = new Notification(type, content, lifetime);
- if (cb) {
- return cb(notif);
- }
- }
- };
-
- Keybinds = {
- init: function() {
- var init;
-
- if (g.VIEW === 'catalog' || !Conf['Keybinds']) {
- return;
- }
- init = function() {
- var node, _i, _len, _ref;
-
- $.off(d, '4chanXInitFinished', init);
- $.on(d, 'keydown', Keybinds.keydown);
- _ref = $$('[accesskey]');
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- node = _ref[_i];
- node.removeAttribute('accesskey');
- }
- };
- return $.on(d, '4chanXInitFinished', init);
- },
- keydown: function(e) {
- var form, key, notification, notifications, op, target, thread, threadRoot, _i, _len;
-
- if (!(key = Keybinds.keyCode(e))) {
- return;
- }
- target = e.target;
- if (['INPUT', 'TEXTAREA'].contains(target.nodeName)) {
- if (!/(Esc|Alt|Ctrl|Meta)/.test(key)) {
- return;
- }
- }
- threadRoot = Nav.getThread();
- if (op = $('.op', threadRoot)) {
- thread = Get.postFromNode(op).thread;
- }
- switch (key) {
- case Conf['Toggle board list']:
- if (Conf['Custom Board Navigation']) {
- Header.toggleBoardList();
- }
- break;
- case Conf['Open empty QR']:
- Keybinds.qr(threadRoot);
- break;
- case Conf['Open QR']:
- Keybinds.qr(threadRoot, true);
- break;
- case Conf['Open settings']:
- Settings.open();
- break;
- case Conf['Close']:
- if (Settings.dialog) {
- Settings.close();
- } else if ((notifications = $$('.notification')).length) {
- for (_i = 0, _len = notifications.length; _i < _len; _i++) {
- notification = notifications[_i];
- $('.close', notification).click();
- }
- } else if (QR.nodes) {
- QR.close();
- }
- break;
- case Conf['Spoiler tags']:
- if (target.nodeName !== 'TEXTAREA') {
- return;
- }
- Keybinds.tags('spoiler', target);
- break;
- case Conf['Code tags']:
- if (target.nodeName !== 'TEXTAREA') {
- return;
- }
- Keybinds.tags('code', target);
- break;
- case Conf['Eqn tags']:
- if (target.nodeName !== 'TEXTAREA') {
- return;
- }
- Keybinds.tags('eqn', target);
- break;
- case Conf['Math tags']:
- if (target.nodeName !== 'TEXTAREA') {
- return;
- }
- Keybinds.tags('math', target);
- break;
- case Conf['Toggle sage']:
- if (QR.nodes) {
- Keybinds.sage();
- }
- break;
- case Conf['Submit QR']:
- if (QR.nodes && !QR.status()) {
- QR.submit();
- }
- break;
- case Conf['Watch']:
- ThreadWatcher.toggle(thread);
- break;
- case Conf['Update']:
- ThreadUpdater.update();
- break;
- case Conf['Expand image']:
- Keybinds.img(threadRoot);
- break;
- case Conf['Expand images']:
- Keybinds.img(threadRoot, true);
- break;
- case Conf['fappeTyme']:
- if (!$('#menu.left')) {
- Header.menuButton.click();
- }
- FappeTyme.input.click();
- break;
- case Conf['Front page']:
- window.location = "/" + g.BOARD + "/0#delform";
- break;
- case Conf['Open front page']:
- $.open("/" + g.BOARD + "/#delform");
- break;
- case Conf['Next page']:
- if (form = $('.next form')) {
- window.location = form.action;
- }
- break;
- case Conf['Previous page']:
- if (form = $('.prev form')) {
- window.location = form.action;
- }
- break;
- case Conf['Open catalog']:
- if (Conf['External Catalog']) {
- window.location = CatalogLinks.external(g.BOARD.ID);
- } else {
- window.location = "/" + g.BOARD + "/catalog";
- }
- break;
- case Conf['Next thread']:
- if (g.VIEW === 'thread') {
- return;
- }
- Nav.scroll(+1);
- break;
- case Conf['Previous thread']:
- if (g.VIEW === 'thread') {
- return;
- }
- Nav.scroll(-1);
- break;
- case Conf['Expand thread']:
- ExpandThread.toggle(thread);
- break;
- case Conf['Open thread']:
- Keybinds.open(thread);
- break;
- case Conf['Open thread tab']:
- Keybinds.open(thread, true);
- break;
- case Conf['Next reply']:
- Keybinds.hl(+1, threadRoot);
- break;
- case Conf['Previous reply']:
- Keybinds.hl(-1, threadRoot);
- break;
- case Conf['Hide']:
- if (g.VIEW === 'index') {
- ThreadHiding.toggle(thread);
- }
- break;
- default:
- return;
- }
- e.preventDefault();
- return e.stopPropagation();
- },
- keyCode: function(e) {
- var kc, key;
-
- key = (function() {
- switch (kc = e.keyCode) {
- case 8:
- return '';
- case 13:
- return 'Enter';
- case 27:
- return 'Esc';
- case 37:
- return 'Left';
- case 38:
- return 'Up';
- case 39:
- return 'Right';
- case 40:
- return 'Down';
- default:
- if ((48 <= kc && kc <= 57) || (65 <= kc && kc <= 90)) {
- return String.fromCharCode(kc).toLowerCase();
- } else {
- return null;
- }
- }
- })();
- if (key) {
- if (e.altKey) {
- key = 'Alt+' + key;
- }
- if (e.ctrlKey) {
- key = 'Ctrl+' + key;
- }
- if (e.metaKey) {
- key = 'Meta+' + key;
- }
- if (e.shiftKey) {
- key = 'Shift+' + key;
- }
- }
- return key;
- },
- qr: function(thread, quote) {
- if (!(Conf['Quick Reply'] && QR.postingIsEnabled)) {
- return;
- }
- QR.open();
- if (quote) {
- QR.quote.call($('input', $('.post.highlight', thread) || thread));
- }
- QR.nodes.com.focus();
- if (Conf['QR Shortcut']) {
- return $.rmClass($('.qr-shortcut'), 'disabled');
- }
- },
- tags: function(tag, ta) {
- var range, selEnd, selStart, value;
-
- value = ta.value;
- selStart = ta.selectionStart;
- selEnd = ta.selectionEnd;
- ta.value = value.slice(0, selStart) + ("[" + tag + "]") + value.slice(selStart, selEnd) + ("[/" + tag + "]") + value.slice(selEnd);
- range = ("[" + tag + "]").length + selEnd;
- ta.setSelectionRange(range, range);
- return $.event('input', null, ta);
- },
- sage: function() {
- var isSage;
-
- isSage = /sage/i.test(QR.nodes.email.value);
- return QR.nodes.email.value = isSage ? "" : "sage";
- },
- img: function(thread, all) {
- var post;
-
- if (all) {
- return ImageExpand.cb.toggleAll();
- } else {
- post = Get.postFromNode($('.post.highlight', thread) || $('.op', thread));
- return ImageExpand.toggle(post);
- }
- },
- open: function(thread, tab) {
- var url;
-
- if (g.VIEW !== 'index') {
- return;
- }
- url = "/" + thread.board + "/res/" + thread;
- if (tab) {
- return $.open(url);
- } else {
- return location.href = url;
- }
- },
- hl: function(delta, thread) {
- var headRect, next, postEl, rect, replies, reply, root, topMargin, _i, _len;
-
- if (Conf['Fixed Header'] && Conf['Bottom header']) {
- topMargin = 0;
- } else {
- headRect = Header.bar.getBoundingClientRect();
- topMargin = headRect.top + headRect.height;
- }
- if (postEl = $('.reply.highlight', thread)) {
- $.rmClass(postEl, 'highlight');
- rect = postEl.getBoundingClientRect();
- if (rect.bottom >= topMargin && rect.top <= doc.clientHeight) {
- root = postEl.parentNode;
- next = $.x('child::div[contains(@class,"post reply")]', delta === +1 ? root.nextElementSibling : root.previousElementSibling);
- if (!next) {
- this.focus(postEl);
- return;
- }
- if (!(g.VIEW === 'thread' || $.x('ancestor::div[parent::div[@class="board"]]', next) === thread)) {
- return;
- }
- rect = next.getBoundingClientRect();
- if (rect.top < 0 || rect.bottom > doc.clientHeight) {
- if (delta === -1) {
- window.scrollBy(0, rect.top - topMargin);
- } else {
- next.scrollIntoView(false);
- }
- }
- this.focus(next);
- return;
- }
- }
- replies = $$('.reply', thread);
- if (delta === -1) {
- replies.reverse();
- }
- for (_i = 0, _len = replies.length; _i < _len; _i++) {
- reply = replies[_i];
- rect = reply.getBoundingClientRect();
- if (delta === +1 && rect.top >= topMargin || delta === -1 && rect.bottom <= doc.clientHeight) {
- this.focus(reply);
- return;
- }
- }
- },
- focus: function(post) {
- return $.addClass(post, 'highlight');
- }
- };
-
- Redirect = {
- init: function() {
- return $.sync('archs', this.updateArchives);
- },
- updateArchives: function() {
- return $.get('archivers', {}, function(_arg) {
- var archivers;
-
- archivers = _arg.archivers;
- return Conf['archivers'] = archivers;
- });
- },
- image: function(boardID, filename) {
- switch (boardID) {
- case 'a':
- case 'gd':
- case 'jp':
- case 'm':
- case 'q':
- case 'tg':
- case 'vg':
- case 'vp':
- case 'vr':
- case 'wsg':
- return "//archive.foolz.us/" + boardID + "/full_image/" + filename;
- case 'u':
- return "//nsfw.foolz.us/" + boardID + "/full_image/" + filename;
- case 'po':
- return "//archive.thedarkcave.org/" + boardID + "/full_image/" + filename;
- case 'hr':
- case 'tv':
- return "http://archive.4plebs.org/" + boardID + "/full_image/" + filename;
- case 'ck':
- case 'fa':
- case 'lit':
- case 's4s':
- return "//fuuka.warosu.org/" + boardID + "/full_image/" + filename;
- case 'cgl':
- case 'g':
- case 'mu':
- case 'w':
- return "//rbt.asia/" + boardID + "/full_image/" + filename;
- case 'an':
- case 'k':
- case 'toy':
- case 'x':
- return "http://archive.heinessen.com/" + boardID + "/full_image/" + filename;
- case 'c':
- return "//archive.nyafuu.org/" + boardID + "/full_image/" + filename;
- }
- },
- post: function(boardID, postID) {
- var archive, name, _base, _ref;
-
- if (Redirect.post[boardID] == null) {
- _ref = this.archiver;
- for (name in _ref) {
- archive = _ref[name];
- if (archive.type === 'foolfuuka' && archive.boards.contains(boardID)) {
- Redirect.post[boardID] = archive.base;
- break;
- }
- }
- (_base = Redirect.post)[boardID] || (_base[boardID] = false);
- }
- if (Redirect.post[boardID]) {
- return "" + Redirect.post[boardID] + "/_/api/chan/post/?board=" + boardID + "&num=" + postID;
- } else {
- return null;
- }
- },
- select: function(board) {
- var archive, name, _ref, _results;
-
- _ref = this.archiver;
- _results = [];
- for (name in _ref) {
- archive = _ref[name];
- if (!archive.boards.contains(board)) {
- continue;
- }
- _results.push(name);
- }
- return _results;
- },
- to: function(data) {
- var arch, archive, boardID;
-
- boardID = data.boardID;
- if ((arch = Conf.archivers[boardID]) == null) {
- Conf.archivers[boardID] = arch = this.select(boardID)[0];
- $.set('archivers', Conf.archivers);
- }
- return (arch && (archive = this.archiver[arch]) ? Redirect.path(archive.base, archive.type, data) : data.threadID ? "//boards.4chan.org/" + boardID + "/" : null);
- },
- archiver: {
- 'Foolz': {
- base: 'https://archive.foolz.us',
- boards: ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'v', 'vg', 'vp', 'vr', 'wsg'],
- type: 'foolfuuka'
- },
- 'NSFWFoolz': {
- base: 'https://nsfw.foolz.us',
- boards: ['u'],
- type: 'foolfuuka'
- },
- 'TheDarkCave': {
- base: 'http://archive.thedarkcave.org',
- boards: ['c', 'int', 'out', 'po'],
- type: 'foolfuuka'
- },
- '4plebs': {
- base: 'http://archive.4plebs.org',
- boards: ['hr', 'tg', 'tv', 'x'],
- base: 'foolfuuka'
- },
- 'Warosu': {
- base: '//fuuka.warosu.org',
- boards: ['cgl', 'ck', 'fa', 'jp', 'lit', 's4s', 'q', 'tg'],
- type: 'fuuka'
- },
- 'InstallGentoo': {
- base: '//archive.installgentoo.net',
- boards: ['diy', 'g', 'sci'],
- type: 'fuuka'
- },
- 'RebeccaBlackTech': {
- base: '//rbt.asia',
- boards: ['an', 'cgl', 'g', 'mu', 'w'],
- type: 'fuuka_mail'
- },
- 'Heinessen': {
- base: 'http://archive.heinessen.com',
- boards: ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x'],
- type: 'fuuka'
- },
- 'Cliche': {
- base: '//www.cliché.net/4chan/cgi-board.pl',
- boards: ['e'],
- type: 'fuuka'
- },
- 'NyaFuu': {
- base: '//archive.nyafuu.org',
- boards: ['c', 'w'],
- type: 'fuuka'
- }
- },
- path: function(base, archiver, data) {
- var boardID, path, postID, threadID, type, value;
-
- if (data.isSearch) {
- boardID = data.boardID, type = data.type, value = data.value;
- type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type;
- value = encodeURIComponent(value);
- if (archiver === 'foolfuuka') {
- return "" + base + "/" + boardID + "/search/" + type + "/" + value;
- } else if (type === 'image') {
- return "" + base + "/" + boardID + "/?task=search2&search_media_hash=" + value;
- } else {
- return "" + base + "/" + boardID + "/?task=search2&search_" + type + "=" + value;
- }
- }
- boardID = data.boardID, threadID = data.threadID, postID = data.postID;
- path = threadID ? "" + boardID + "/thread/" + threadID : "" + boardID + "/post/" + postID;
- if (archiver === 'foolfuuka') {
- path += '/';
- }
- if (threadID && postID) {
- path += archiver === 'foolfuuka' ? "#" + postID : "#p" + postID;
- }
- return "" + base + "/" + path;
- }
- };
-
- RelativeDates = {
- INTERVAL: $.MINUTE / 2,
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Relative Post Dates']) {
- return;
- }
- $.on(d, 'visibilitychange ThreadUpdate', this.flush);
- this.flush();
- return Post.prototype.callbacks.push({
- name: 'Relative Post Dates',
- cb: this.node
- });
- },
- node: function() {
- var dateEl;
-
- if (this.isClone) {
- return;
- }
- dateEl = this.nodes.date;
- dateEl.title = dateEl.textContent;
- return RelativeDates.setUpdate(this);
- },
- relative: function(diff, now, date) {
- var days, months, number, rounded, unit, years;
-
- unit = (number = diff / $.DAY) >= 1 ? (years = now.getYear() - date.getYear(), months = now.getMonth() - date.getMonth(), days = now.getDate() - date.getDate(), years > 1 ? (number = years - (months < 0 || months === 0 && days < 0), 'year') : years === 1 && (months > 0 || months === 0 && days >= 0) ? (number = years, 'year') : (months = (months + 12) % 12) > 1 ? (number = months - (days < 0), 'month') : months === 1 && days >= 0 ? (number = months, 'month') : 'day') : (number = diff / $.HOUR) >= 1 ? 'hour' : (number = diff / $.MINUTE) >= 1 ? 'minute' : (number = Math.max(0, diff) / $.SECOND, 'second');
- rounded = Math.round(number);
- if (rounded !== 1) {
- unit += 's';
- }
- return "" + rounded + " " + unit + " ago";
- },
- stale: [],
- flush: function() {
- var now, update, _i, _len, _ref;
-
- if (d.hidden) {
- return;
- }
- now = new Date();
- _ref = RelativeDates.stale;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- update = _ref[_i];
- update(now);
- }
- RelativeDates.stale = [];
- clearTimeout(RelativeDates.timeout);
- return RelativeDates.timeout = setTimeout(RelativeDates.flush, RelativeDates.INTERVAL);
- },
- setUpdate: function(post) {
- var markStale, setOwnTimeout, update;
-
- setOwnTimeout = function(diff) {
- var delay;
-
- delay = diff < $.MINUTE ? $.SECOND - (diff + $.SECOND / 2) % $.SECOND : diff < $.HOUR ? $.MINUTE - (diff + $.MINUTE / 2) % $.MINUTE : diff < $.DAY ? $.HOUR - (diff + $.HOUR / 2) % $.HOUR : $.DAY - (diff + $.DAY / 2) % $.DAY;
- return setTimeout(markStale, delay);
- };
- update = function(now) {
- var date, diff, relative, singlePost, _i, _len, _ref;
-
- date = post.info.date;
- diff = now - date;
- relative = RelativeDates.relative(diff, now, date);
- _ref = [post].concat(post.clones);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- singlePost = _ref[_i];
- singlePost.nodes.date.firstChild.textContent = relative;
- }
- return setOwnTimeout(diff);
- };
- markStale = function() {
- return RelativeDates.stale.push(update);
- };
- return update(new Date());
- }
- };
-
- RemoveSpoilers = {
- init: function() {
- if (!Conf['Remove Spoilers']) {
- return;
- }
- if (Conf['Indicate Spoilers']) {
- this.wrapper = function(text) {
- return "[spoiler]" + text + "[/spoiler]";
- };
- }
- return Post.prototype.callbacks.push({
- name: 'Reveal Spoilers',
- cb: this.node
- });
- },
- wrapper: function(text) {
- return text;
- },
- node: function(post) {
- var spoiler, spoilers, _i, _len;
-
- spoilers = $$('s', this.nodes.comment);
- for (_i = 0, _len = spoilers.length; _i < _len; _i++) {
- spoiler = spoilers[_i];
- $.replace(spoiler, $.tn(RemoveSpoilers.wrapper(spoiler.textContent)));
- }
- }
- };
-
- Report = {
- init: function() {
- if (!/report/.test(location.search)) {
- return;
- }
- return $.ready(this.ready);
- },
- ready: function() {
- var field, form;
-
- form = $('form');
- field = $.id('recaptcha_response_field');
- $.on(field, 'keydown', function(e) {
- if (e.keyCode === 8 && !field.value) {
- return $.globalEval('Recaptcha.reload("t")');
- }
- });
- return $.on(form, 'submit', function(e) {
- var response;
-
- e.preventDefault();
- response = field.value.trim();
- if (!/\s/.test(response)) {
- field.value = "" + response + " " + response;
- }
- return form.submit();
- });
- }
- };
-
- Nav = {
- init: function() {
- var append, next, prev, span;
-
- switch (g.VIEW) {
- case 'index':
- if (!Conf['Index Navigation']) {
- return;
- }
- break;
- case 'thread':
- if (!Conf['Reply Navigation']) {
- return;
- }
- break;
- default:
- return;
- }
- span = $.el('span', {
- id: 'navlinks'
- });
- prev = $.el('a', {
- textContent: '▲',
- href: 'javascript:;'
- });
- next = $.el('a', {
- textContent: '▼',
- href: 'javascript:;'
- });
- $.on(prev, 'click', this.prev);
- $.on(next, 'click', this.next);
- $.add(span, [prev, $.tn(' '), next]);
- append = function() {
- $.off(d, '4chanXInitFinished', append);
- return $.add(d.body, span);
- };
- return $.on(d, '4chanXInitFinished', append);
- },
- prev: function() {
- if (g.VIEW === 'thread') {
- return window.scrollTo(0, 0);
- } else {
- return Nav.scroll(-1);
- }
- },
- next: function() {
- if (g.VIEW === 'thread') {
- return window.scrollTo(0, d.body.scrollHeight);
- } else {
- return Nav.scroll(+1);
- }
- },
- getThread: function(full) {
- var headRect, i, rect, thread, threads, topMargin, _i, _len;
-
- if (Conf['Bottom header']) {
- topMargin = 0;
- } else {
- headRect = Header.bar.getBoundingClientRect();
- topMargin = headRect.top + headRect.height;
- }
- threads = $$('.thread:not([hidden])');
- for (i = _i = 0, _len = threads.length; _i < _len; i = ++_i) {
- thread = threads[i];
- rect = thread.getBoundingClientRect();
- if (rect.bottom > topMargin) {
- if (full) {
- return [threads, thread, i, rect, topMargin];
- } else {
- return thread;
- }
- }
- }
- return $('.board');
- },
- scroll: function(delta) {
- var i, rect, thread, threads, top, topMargin, _ref, _ref1;
-
- _ref = Nav.getThread(true), threads = _ref[0], thread = _ref[1], i = _ref[2], rect = _ref[3], topMargin = _ref[4];
- top = rect.top - topMargin;
- if (!((delta === -1 && Math.ceil(top) < 0) || (delta === +1 && top > 1))) {
- i += delta;
- }
- top = ((_ref1 = threads[i]) != null ? _ref1.getBoundingClientRect().top : void 0) - topMargin;
- return window.scrollBy(0, top);
- }
- };
-
- Sauce = {
- init: function() {
- var link, links, _i, _len, _ref;
-
- if (g.VIEW === 'catalog' || !Conf['Sauce']) {
- return;
- }
- links = [];
- _ref = Conf['sauces'].split('\n');
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- link = _ref[_i];
- if (link[0] === '#') {
- continue;
- }
- links.push(this.createSauceLink(link.trim()));
- }
- if (!links.length) {
- return;
- }
- this.links = links;
- this.link = $.el('a', {
- target: '_blank'
- });
- return Post.prototype.callbacks.push({
- name: 'Sauce',
- cb: this.node
- });
- },
- createSauceLink: function(link) {
- var m, text;
-
- link = link.replace(/%(T?URL|MD5|board)/ig, function(parameter) {
- switch (parameter) {
- case '%TURL':
- return "' + encodeURIComponent(post.file.thumbURL) + '";
- case '%URL':
- return "' + encodeURIComponent(post.file.URL) + '";
- case '%MD5':
- return "' + encodeURIComponent(post.file.MD5) + '";
- case '%board':
- return "' + encodeURIComponent(post.board) + '";
- default:
- return parameter;
- }
- });
- text = (m = link.match(/;text:(.+)$/)) ? m[1] : link.match(/(\w+)\.\w+\//)[1];
- link = link.replace(/;text:.+$/, '');
- return Function('post', 'a', "a.href = '" + link + "';\na.textContent = '" + text + "';\nreturn a;");
- },
- node: function() {
- var link, nodes, _i, _len, _ref;
-
- if (this.isClone || !this.file) {
- return;
- }
- nodes = [];
- _ref = Sauce.links;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- link = _ref[_i];
- nodes.push($.tn('\u00A0'), link(this, Sauce.link.cloneNode(true)));
- }
- return $.add(this.file.info, nodes);
- }
- };
-
- Time = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Time Formatting']) {
- return;
- }
- this.funk = this.createFunc(Conf['time']);
- return Post.prototype.callbacks.push({
- name: 'Time Formatting',
- cb: this.node
- });
- },
- node: function() {
- if (this.isClone) {
- return;
- }
- return this.nodes.date.textContent = Time.funk(Time, this.info.date);
- },
- createFunc: function(format) {
- var code;
-
- code = format.replace(/%([A-Za-z])/g, function(s, c) {
- if (c in Time.formatters) {
- return "' + Time.formatters." + c + ".call(date) + '";
- } else {
- return s;
- }
- });
- return Function('Time', 'date', "return '" + code + "'");
- },
- day: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
- month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
- zeroPad: function(n) {
- if (n < 10) {
- return "0" + n;
- } else {
- return n;
- }
- },
- formatters: {
- a: function() {
- return Time.day[this.getDay()].slice(0, 3);
- },
- A: function() {
- return Time.day[this.getDay()];
- },
- b: function() {
- return Time.month[this.getMonth()].slice(0, 3);
- },
- B: function() {
- return Time.month[this.getMonth()];
- },
- d: function() {
- return Time.zeroPad(this.getDate());
- },
- e: function() {
- return this.getDate();
- },
- H: function() {
- return Time.zeroPad(this.getHours());
- },
- I: function() {
- return Time.zeroPad(this.getHours() % 12 || 12);
- },
- k: function() {
- return this.getHours();
- },
- l: function() {
- return this.getHours() % 12 || 12;
- },
- m: function() {
- return Time.zeroPad(this.getMonth() + 1);
- },
- M: function() {
- return Time.zeroPad(this.getMinutes());
- },
- p: function() {
- if (this.getHours() < 12) {
- return 'AM';
- } else {
- return 'PM';
- }
- },
- P: function() {
- if (this.getHours() < 12) {
- return 'am';
- } else {
- return 'pm';
- }
- },
- S: function() {
- return Time.zeroPad(this.getSeconds());
- },
- y: function() {
- return this.getFullYear() - 2000;
- }
- }
- };
-
- Favicon = {
- init: function() {
- return $.ready(function() {
- var href;
-
- Favicon.el = $('link[rel="shortcut icon"]', d.head);
- Favicon.el.type = 'image/x-icon';
- href = Favicon.el.href;
- Favicon.SFW = /ws\.ico$/.test(href);
- Favicon["default"] = href;
- return Favicon["switch"]();
- });
- },
- "switch": function() {
- switch (Conf['favicon']) {
- case 'ferongr':
- Favicon.unreadDead = 'data:image/gif;base64,R0lGODlhEAAQAOMHAOgLAnMFAL8AAOgLAukMA/+AgP+rq////////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
- Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAS1BMVEUAAAAAAAAAAAAJAAASAAAZAQAaAQAiAQAkAQAoFBQyAgAzAgA1AgA4AABBAgBXAwBzBQCEBgGvCAG/AADoCwLpDAP/gID/q6v///9zILr8AAAAA3RSTlMAx9dmesIgAAAAc0lEQVQY02WPgQ6DIBBDmTqnbE70Cvb/v3TAnW5OSKB9ybXg3HUBOAmEEH4FQtrSn4gxi+xjVC9SVOEiSvbZI8zSV+/Xo7icnryZ15GObMxvtWUkB/VJW57kHU7fUcHStm8FkncGE/mwP6CGzq/eauHwvT7sWQt3gZLW+AAAAABJRU5ErkJggg==';
- Favicon.unreadSFW = 'data:image/gif;base64,R0lGODlhEAAQAOMHAADX8QBwfgC2zADX8QDY8nnl8qLp8v///////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
- Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAASFBMVEUAAAAAAAAAAAAACAkAERMAGBsAGR0AISUALzQALzUAMTcANjwAP0cAVF8AcH4AeokAorYAtswA1/EA2PISIyV55fKi6fL////l+pZqAAAAA3RSTlMAx9dmesIgAAAAcklEQVQY02VPARLCIAxjsjnUWdcg6/9/ukIr00nvIMldEhrC/wHwA0BE3wBUtnICOStQnrNx5oqqzmzKx9vDPH1Nae3F9U4ig3OzjCIX51treYvMxou13EQmBPtHE14xLiawjgoPtfgOaKHP+9VrEXA8O1v7CmSPE3u0AAAAAElFTkSuQmCC';
- Favicon.unreadNSFW = 'data:image/gif;base64,R0lGODlhEAAQAOMHAFT+ACh5AEncAFT+AFX/Acz/su7/5v///////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
- Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAS1BMVEUAAAAAAAAAAAADCgAGEgAIGgAJGwALJAANJwASNwASOAATOgAVQQAWRAAeWwAgKBsoeQAwkQA/wABJ3ABU/gBV/wHM/7Lu/+b////r+K2AAAAAA3RSTlMAx9dmesIgAAAAc0lEQVQY02WPgQ6DIBBDmTonbk70Cvb/v3TAnW5OSKB9ybXg3HUBOAmEEH4FQtrSn4gxi+xjVC9SVOEiSvbZI8zSV+/Xo7icnryZ15GObMxvtWUmB/VJW0byDqfvqGBp20mB5J3Bi3zYH1BD38/eauHwvT7sEAt1Fb320QAAAABJRU5ErkJggg==';
- break;
- case 'xat-':
- Favicon.unreadDead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA2ElEQVQ4y61TQQrCMBDMQ8WDIEV6LbT2A4og2Hq0veo7fIAH04dY9N4xmyYlpGmI2MCQTWYy3Wy2DAD7B2wWAzWgcTgVeZKlZRxHNYFi2jM18oBh0IcKtC6ixf22WT4IFLs0owxswXu9egm0Ls6bwfCFfNsJYJKfqoEkd3vgUgFVLWObtzNgVKyruC+ljSzr5OEnBzjvjcQecaQhbZgBb4CmGQw+PoMkTUtdbd8VSEPakcGxPOcsoIgUKy0LecY29BmdBrqRfjIwZ93KLs5loHvBnL3cLH/jF+C/+z5dgUysAAAAAElFTkSuQmCC';
- Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACKkJGNkpN0d3d0eHdra2dGRkORZ1wAAACmaV6naV4PDw8LCwsLCwvyZWLyZWIeExEyFBTAWlr/eHj/enkAAAAKAAAoAAA4AAA4GhpMAACRAAD/AAD/enn/h4j/m5z/nJ3/0dL/0tL/0tP/09P///9VK8WFAAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uZfI0YOdiiMiJw+2CKIPkZzGtcbgKYIJaI26LAfQOzOqoYNA4Z49Nguv/gEEhw2/C5BUZgAAAABJRU5ErkJggg==';
- Favicon.unreadSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA30lEQVQ4y2P4//8/AyWYgSoGQMF/GJ7Y11VVUVoyKTM9ey4Ig9ggMWQ1YA1IBvzXm34YjkH8mPyJB+Nqlp8FYRAbmxoMF6ArSNrw6T0Qf8Amh9cFMEWVR/7/A+L/uORxhgEIt5/+/3/2lf//5wAxiI0uj+4CBlBgxVUvOwtydgXQZpDmi2/+/7/0GmIQSAwkB1IDUkuUAZeABlx+g2zAZ9wGlAOjChba+LwAUgNSi2HA5Am9VciBhSsQQWyoWgZiovEDsdGI1QBYQiLJAGQalpSxyWEzAJYWkGm8clTJjQCZ1hkoVG0CygAAAABJRU5ErkJggg==';
- Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACRjoqTkI13dXR4dXRpZ2tFQ0Zcb5EAAABee6ZefKcPDw8LCwsLCwtisPJisPIRFh4UJDJalMB4xP95xP8AAAABBQcHFx4KISoNLToaKzgaVW4ul8N5xP+Hy/+b1P+c1P/R7P/S6//S7P/T7P////9P0rk0AAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uUrk6MFOxRGRkwdbBNGHSE7jWmPwFMEEtEZdlgPonRmvoYNA4Z49Nguv/gEE3A2/sQ7iRgAAAABJRU5ErkJggg==';
- Favicon.unreadNSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA4ElEQVQ4y2P4//8/AyWYgSoGQMF/GJ7YNbGqrKRiUnp21lwQBrFBYshqwBqQDPifdsYYjkH8mInxB+OWx58FYRAbmxoMF6ArKPmU9B6IP2CTw+sCmKKe/5X/gPg/LnmcYQDCs/63/1/9fzYQzwGz0eXRXcAACqy4ZfFnQc7u+V/xD6T55v+LQHwJbBBIDCQHUgNSS5QBt4Cab/2/jDDgMx4DykrKJ8FCG58XQGpAajEMmNw7uQo5sHAFIogNVctATDR+IDYasRoAS0gkGYBMw5IyNjlsBsDSAjKNV44quREAx58Mr9vt5wQAAAAASUVORK5CYII=';
- Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACRipGTjZN2dHd2dHhna2pDRkVckV8AAABepl9ep18PDw8LCwsLCwt08mJ08mIRHhEYMhRpwFqM/3iM/3kAAAAECAIQIAgWLAseOBoePA86dB1mzDOM/3ma/4er/5ur/5zZ/9HZ/9La/9La/9P///85Jx7jAAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uZfI0YOdiiMiJw+2CKIPkZzGtcbgKYIJaI26LAfQOzOqoYNA4Z49Nguv/gEEhw2/C5BUZgAAAABJRU5ErkJggg==';
- break;
- case 'Mayhem':
- Favicon.unreadDead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABIUlEQVQ4jZ2ScWuDMBDFgw4pIkU0WsoQkWAYIkXZH4N9/+/V3dmfXSrKYIFHwt17j8vdGWNMIkgFuaDgzgQnwRs4EQs5KdolUQtagRN0givEDBTEOjgtGs0Zq8F7cKqqusVxrMQLaDUWcjBSrXkn8gs51tpJSWLk9b3HUa0aNIL5gPBR1/V4kJvR7lTwl8GmAm1Gf9+c3S+89qBHa8502AsmSrtBaEBPbIbj0ah2madlNAPEccdgJDfAtWifBjqWKShRBT6KoiH8QlEUn/qt0CCjnNdmPUwmFWzj9Oe6LpKuZXcwqq88z78Pch3aZU3dPwwc2sWlfZKCW5tWluV8kGvXClLm6dYN4/aUqfCbnEOzNDGhGZbNargvxCzvMGfRJD8UaDVvgkzo6QAAAABJRU5ErkJggg==';
- Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABj0lEQVQ4y42TQUorQRCGv+oekpj43pOhOyIiKoHBxTMkuAnEtWcwx/AY3sUbBIRcwCw8gCfIMkaTOOUiNdgGRRuKoav+v2qq/i4BakBmXweUwDoxLF5ZhVkC64rYBHYMUAIvwKuBMEwdaFiCNbAAngEC0NHkxBi73vsOsG92HGPsphigY1wOzfNhqhpC6AEd730RQuh9hQEOAY6A/jeAs3a7/f+bWB84ckCpqg+I8Osjgqo+AKUDViJS8LkGMcY+sJrNZssYY387LiIFsBLgL9AC/pgaArzZlF+sZgO4BG7sfgvcA3MxUtOStBIpX7cS3Klqd9OBTIEr4DlLOsuAmqpODXQOiHMuy/O8FkLoJth/6Uh2gQPg87Q3k+7leX6hqnpmPvM/GWfXWeWGqj5+oUS9LMs6wF7iHAwGJ9ZW5uxpup+UGwEtEVoijEYjKl66PJujmvIW3vsFwBiYqzJXZTweY5wSU6Bd7UP1KoECODUrJpOJAtPhcKjAtXGaYptWs57qWyv9Zn/it1a5knj5Dm3v4q8APeACAAAAAElFTkSuQmCC';
- Favicon.unreadSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABCElEQVQ4jZ2S4crCMAxF+0OGDJEPKYrIGKOsiJSx/fJRfSAfTJNyKqXfiuDg0C25N2RJjTGmEVrhTzhw7oStsIEtsVzT4o2Jo9ALThiEM8IdHIgNaHo8mjNWg6/ske8bohPo+63QOLzmooHp8fyAICBSQkVz0QKdsFQEV6WSW/D+7+BbgbIDHcb4Kp61XyjyI16zZ8JemGltQtDBSGxB4/GoN+7TpkkjDCsFArm0IYv3U0BbnYtf8BCy+JytsE0X6VyuKhPPK/GAJ14kvZZDZVV3pZIb8MZr6n4o4PDGKn0S5SdDmyq5PnXQsk+Xbhinp03FFzmHJw6xYRiWm9VxnohZ3vOcxdO8ARmXRvbWdtzQAAAAAElFTkSuQmCC';
- Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAkFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OztMTEyRkZHBwcH///9dzWZ0AAAAI3RSTlMEBggKDA4QEhQWFxkbHR8hIyUmKCosLjAxN1hbYc7P0dLc3mzWzBUAAAC+SURBVBjTNY3pcsIwEIM3ePERx/bG5IIe0NIrhVbv/3Y4Ydj9Ic030ogqpY3mDdGGi1EVsYuSvGE2Pkl0TFYAdLGuY1eMWGowzzN6kX41DYVpNbvdKlO4Jx5gSbi2VO+Vcq2jrc/jNLQhtM+n05PfkrKxG/oFHIEXqwqQsVRy7n+AtwLYL3sYR3wA755Jp3Vvv8cn8Js0GXmA7/P5TwzpiLn8MOALuEZNygkm5JTy/+vl4BRVbJvQ1NbWRSxXN64PGOBlhG0qAAAAAElFTkSuQmCC';
- Favicon.unreadNSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABCklEQVQ4jZ2S0WrDMAxF/TBCCKWMYhZKCSGYmFJMSNjD/mhf239qJXNcjBdTWODgRLpXKJKNMaYROuFTOHEehFb4gJZYrunwxsSXMApOmIQzwgOciE1oRjyaM1aDj+yR7xuiHvT9VmgcXnPRwO/9+wWCgEgJFc1FCwzCVhFclUpuw/u3g3cFyg50GPOjePZ+ocjPeM2RCXthpbUFwQAzsQ2Nx6PeuE+bJo0w7BQI5NKGLN5XAW11LX7BQ8jia7bCLl2kc7mqTLzuxAOeeJH0Wk6VVf0oldyEN15T948CDm+sMiZRfjK0pZIbUwcd+3TphnF62lR8kXN44hAbhmG5WQNnT8zynucsnuYJhFpBfkMzqD4AAAAASUVORK5CYII=';
- Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAkFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztMTExmzDORkZHBwcH///92I3mvAAAAI3RSTlMEBggKDA4QEhQWFxkbHR8hIyUmKCosLjAxN1hbYc7P0dLc3mzWzBUAAAC+SURBVBjTNY3pcsIwEIM3ePERx/bG5IIe0NIT0ur93w4nDLs/pPlGGlGltNG8IdpwMaoidlGSN8zGJ4mOyQqALtZ17IoRSw3meUYv0q+moTCtZrdbZQr3xAMsCdeW6r1SrnW09XmchjaE9vl0evJbUjZ2Q7+AI/BiVQEylkrO/TfwVgD7ZQ/jiA/g3TPptO7t9/gEfpImIw/wez7/iSEdMZcfBnwB16hJOcGEnFL+f70cnKKKbROa2tq6iOXqBuMXGTe4CAUbAAAAAElFTkSuQmCC';
- break;
- case 'Original':
- Favicon.unreadDead = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
- Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAAKAAAoAAAoKCg4AAA4ODg7OztMAACRAADBwcH/AAD///+WCcPSAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQmAUAxEb4Isk0rwp3EPR3ECcRQrh7C3/nAasPwzmCgYuPBy5AH/NALSImqAK+H1oJRqyJVHNAnZqDITVhj7/PrAciJ9il0BHs/jjU+fnB9sQ0IxX6OBO6Xr0xKAxANLZzUanCWzZQAAAABJRU5ErkJggg==';
- Favicon.unreadSFW = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAC6Xw////////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
- Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OzvBwcH///8uS/CdAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQ2AUAhEbwKWoftRGvdwBEewchM7d9BFbE6pbP4Mgj+R5MjjwgP+qQSkRtQAV8K3lVI2Q648oknIRpWZsMI4988HjgvpU+wO8HgeHzR9cjZYhoRiPkcDd0rXpyUAiRd5YjKC7MvNRgAAAABJRU5ErkJggg==';
- Favicon.unreadNSFW = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAGbMM////////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
- Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztmzDPBwcH///+rsf3XAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQ2AUAhEbwKWofRL4x6O4AhuopWb2P4F7E5prP4MgiaSHHlceMA/jYC0iBrgSnjdKaUacuURTUI2qsyEFcaxvD6wnkifYleAx/N449Mn5wfbkFDM52jgTun6tAQg8QAEvjQg42KY2AAAAABJRU5ErkJggg==';
- }
- if (Favicon.SFW) {
- Favicon.unread = Favicon.unreadSFW;
- return Favicon.unreadY = Favicon.unreadSFWY;
- } else {
- Favicon.unread = Favicon.unreadNSFW;
- return Favicon.unreadY = Favicon.unreadNSFWY;
- }
- },
- empty: 'data:image/gif;base64,R0lGODlhEAAQAJEAAAAAAP///9vb2////yH5BAEAAAMALAAAAAAQABAAAAIvnI+pq+D9DBAUoFkPFnbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw==',
- dead: 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAIALAAAAAAQABAAAAIvlI+pq+D9DAgUoFkPDlbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw=='
- };
-
- ThreadExcerpt = {
- init: function() {
- if (g.VIEW !== 'thread' || !Conf['Thread Excerpt']) {
- return;
- }
- return Thread.prototype.callbacks.push({
- name: 'Thread Excerpt',
- cb: this.node
- });
- },
- node: function() {
- return d.title = Get.threadExcerpt(this);
- }
- };
-
- ThreadStats = {
- init: function() {
- var sc;
-
- if (g.VIEW !== 'thread' || !Conf['Thread Stats']) {
- return;
- }
- this.dialog = sc = $.el('span', {
- innerHTML: "0 / 0",
- id: 'thread-stats'
- });
- this.postCountEl = $('#post-count', sc);
- this.fileCountEl = $('#file-count', sc);
- Header.addShortcut(sc);
- return Thread.prototype.callbacks.push({
- name: 'Thread Stats',
- cb: this.node
- });
- },
- node: function() {
- var ID, fileCount, post, postCount, _ref;
-
- postCount = 0;
- fileCount = 0;
- _ref = this.posts;
- for (ID in _ref) {
- post = _ref[ID];
- postCount++;
- if (post.file) {
- fileCount++;
- }
- }
- ThreadStats.thread = this;
- ThreadStats.update(postCount, fileCount);
- return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate);
- },
- onUpdate: function(e) {
- var fileCount, postCount, _ref;
-
- if (e.detail[404]) {
- return;
- }
- _ref = e.detail, postCount = _ref.postCount, fileCount = _ref.fileCount;
- return ThreadStats.update(postCount, fileCount);
- },
- update: function(postCount, fileCount) {
- var fileCountEl, postCountEl, thread;
-
- thread = ThreadStats.thread, postCountEl = ThreadStats.postCountEl, fileCountEl = ThreadStats.fileCountEl;
- postCountEl.textContent = postCount;
- fileCountEl.textContent = fileCount;
- (thread.postLimit && !thread.isSticky ? $.addClass : $.rmClass)(postCountEl, 'warning');
- return (thread.fileLimit && !thread.isSticky ? $.addClass : $.rmClass)(fileCountEl, 'warning');
- }
- };
-
- ThreadUpdater = {
- init: function() {
- var checked, conf, el, input, name, sc, settings, subEntries, _ref;
-
- if (g.VIEW !== 'thread' || !Conf['Thread Updater']) {
- return;
- }
- checked = Conf['Auto Update'] ? 'checked' : '';
- this.dialog = sc = $.el('span', {
- innerHTML: "",
- id: 'updater'
- });
- this.timer = $('#update-timer', sc);
- this.status = $('#update-status', sc);
- $.on(this.timer, 'click', ThreadUpdater.update);
- $.on(this.status, 'click', ThreadUpdater.update);
- this.checkPostCount = 0;
- Header.addShortcut(sc);
- subEntries = [];
- _ref = Config.updater.checkbox;
- for (name in _ref) {
- conf = _ref[name];
- checked = Conf[name] ? 'checked' : '';
- el = $.el('label', {
- title: "" + conf[1],
- innerHTML: " " + name
- });
- input = el.firstElementChild;
- $.on(input, 'change', $.cb.checked);
- if (input.name === 'Scroll BG') {
- $.on(input, 'change', ThreadUpdater.cb.scrollBG);
- ThreadUpdater.cb.scrollBG();
- }
- subEntries.push({
- el: el
- });
- }
- settings = $.el('span', {
- innerHTML: 'Interval'
- });
- $.on(settings, 'click', this.intervalShortcut);
- subEntries.push({
- el: settings
- });
- $.event('AddMenuEntry', {
- type: 'header',
- el: $.el('span', {
- textContent: 'Updater'
- }),
- order: 110,
- subEntries: subEntries
- });
- return Thread.prototype.callbacks.push({
- name: 'Thread Updater',
- cb: this.node
- });
- },
- node: function() {
- ThreadUpdater.thread = this;
- ThreadUpdater.root = this.OP.nodes.root.parentNode;
- ThreadUpdater.lastPost = +ThreadUpdater.root.lastElementChild.id.match(/\d+/)[0];
- ThreadUpdater.outdateCount = 0;
- ThreadUpdater.lastModified = '0';
- ThreadUpdater.cb.interval.call($.el('input', {
- value: Conf['Interval']
- }));
- $.on(window, 'online offline', ThreadUpdater.cb.online);
- $.on(d, 'QRPostSuccessful', ThreadUpdater.cb.post);
- $.on(d, 'visibilitychange', ThreadUpdater.cb.visibility);
- return ThreadUpdater.cb.online();
- },
- /*
- http://freesound.org/people/pierrecartoons1979/sounds/90112/
- cc-by-nc-3.0
- */
-
- beep: 'data:audio/wav;base64,UklGRjQDAABXQVZFZm10IBAAAAABAAEAgD4AAIA+AAABAAgAc21wbDwAAABBAAADAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkYXRhzAIAAGMms8em0tleMV4zIpLVo8nhfSlcPR102Ki+5JspVEkdVtKzs+K1NEhUIT7DwKrcy0g6WygsrM2k1NpiLl0zIY/WpMrjgCdbPhxw2Kq+5Z4qUkkdU9K1s+K5NkVTITzBwqnczko3WikrqM+l1NxlLF0zIIvXpsnjgydZPhxs2ay95aIrUEkdUdC3suK8N0NUIjq+xKrcz002WioppdGm091pK1w0IIjYp8jkhydXPxxq2K295aUrTkoeTs65suK+OUFUIzi7xqrb0VA0WSoootKm0t5tKlo1H4TYqMfkiydWQBxm16+85actTEseS8y7seHAPD9TIza5yKra01QyWSson9On0d5wKVk2H4DYqcfkjidUQB1j1rG75KsvSkseScu8seDCPz1TJDW2yara1FYxWSwnm9Sn0N9zKVg2H33ZqsXkkihSQR1g1bK65K0wSEsfR8i+seDEQTxUJTOzy6rY1VowWC0mmNWoz993KVc3H3rYq8TklSlRQh1d1LS647AyR0wgRMbAsN/GRDpTJTKwzKrX1l4vVy4lldWpzt97KVY4IXbUr8LZljVPRCxhw7W3z6ZISkw1VK+4sMWvXEhSPk6buay9sm5JVkZNiLWqtrJ+TldNTnquqbCwilZXU1BwpKirrpNgWFhTaZmnpquZbFlbVmWOpaOonHZcXlljhaGhpZ1+YWBdYn2cn6GdhmdhYGN3lp2enIttY2Jjco+bnJuOdGZlZXCImJqakHpoZ2Zug5WYmZJ/bGlobX6RlpeSg3BqaW16jZSVkoZ0bGtteImSk5KIeG5tbnaFkJKRinxxbm91gY2QkIt/c3BwdH6Kj4+LgnZxcXR8iI2OjIR5c3J0e4WLjYuFe3VzdHmCioyLhn52dHR5gIiKioeAeHV1eH+GiYqHgXp2dnh9hIiJh4J8eHd4fIKHiIeDfXl4eHyBhoeHhH96eHmA',
- cb: {
- online: function() {
- if (ThreadUpdater.online = navigator.onLine) {
- ThreadUpdater.outdateCount = 0;
- ThreadUpdater.set('timer', ThreadUpdater.getInterval());
- ThreadUpdater.update();
- ThreadUpdater.set('status', null, null);
- } else {
- ThreadUpdater.set('timer', null);
- ThreadUpdater.set('status', 'Offline', 'warning');
- }
- return ThreadUpdater.cb.autoUpdate();
- },
- post: function(e) {
- if (e.detail.threadID !== ThreadUpdater.thread.ID) {
- return;
- }
- ThreadUpdater.outdateCount = 0;
- if (ThreadUpdater.seconds > 2) {
- return setTimeout(ThreadUpdater.update, 1000);
- }
- },
- checkpost: function() {
- if (!(g.DEAD || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 10)) {
- return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * 500);
- }
- ThreadUpdater.checkPostCount = 0;
- delete ThreadUpdater.foundPost;
- return delete ThreadUpdater.postID;
- },
- visibility: function() {
- if (d.hidden) {
- return;
- }
- ThreadUpdater.outdateCount = 0;
- if (ThreadUpdater.seconds > ThreadUpdater.interval) {
- return ThreadUpdater.set('timer', ThreadUpdater.getInterval());
- }
- },
- scrollBG: function() {
- return ThreadUpdater.scrollBG = Conf['Scroll BG'] ? function() {
- return true;
- } : function() {
- return !d.hidden;
- };
- },
- autoUpdate: function() {
- if (ThreadUpdater.online) {
- return ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
- } else {
- return clearTimeout(ThreadUpdater.timeoutID);
- }
- },
- interval: function() {
- var val;
-
- val = +this.value;
- if (val < 1) {
- val = 1;
- }
- ThreadUpdater.interval = this.value = val;
- return $.cb.value.call(this);
- },
- load: function() {
- var klass, req, text, _ref;
-
- req = ThreadUpdater.req;
- switch (req.status) {
- case 200:
- g.DEAD = false;
- ThreadUpdater.parse(JSON.parse(req.response).posts);
- ThreadUpdater.lastModified = req.getResponseHeader('Last-Modified');
- ThreadUpdater.set('timer', ThreadUpdater.getInterval());
- break;
- case 404:
- g.DEAD = true;
- ThreadUpdater.set('timer', null);
- ThreadUpdater.set('status', '404', 'warning');
- clearTimeout(ThreadUpdater.timeoutID);
- ThreadUpdater.thread.kill();
- $.event('ThreadUpdate', {
- 404: true,
- thread: ThreadUpdater.thread
- });
- break;
- default:
- ThreadUpdater.outdateCount++;
- ThreadUpdater.set('timer', ThreadUpdater.getInterval());
- /*
- Status Code 304: Not modified
- By sending the `If-Modified-Since` header we get a proper status code, and no response.
- This saves bandwidth for both the user and the servers and avoid unnecessary computation.
- */
-
- _ref = [0, 304].contains(req.status) ? [null, null] : ["" + req.statusText + " (" + req.status + ")", 'warning'], text = _ref[0], klass = _ref[1];
- ThreadUpdater.set('status', text, klass);
- }
- if (ThreadUpdater.postID) {
- ThreadUpdater.cb.checkpost(this.status);
- }
- return delete ThreadUpdater.req;
- }
- },
- getInterval: function() {
- var i, j;
-
- i = ThreadUpdater.interval;
- j = Math.min(ThreadUpdater.outdateCount, 10);
- if (!d.hidden) {
- j = Math.min(j, 7);
- }
- return ThreadUpdater.seconds = Conf['Optional Increase'] ? Math.max(i, [0, 5, 10, 15, 20, 30, 60, 90, 120, 240, 300][j]) : i;
- },
- intervalShortcut: function() {
- var settings;
-
- Settings.open('Advanced');
- settings = $.id('fourchanx-settings');
- return $('input[name=Interval]', settings).focus();
- },
- set: function(name, text, klass) {
- var el, node;
-
- el = ThreadUpdater[name];
- if (node = el.firstChild) {
- node.data = text;
- } else {
- el.textContent = text;
- }
- if (klass !== void 0) {
- return el.className = klass;
- }
- },
- timeout: function() {
- var n;
-
- ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
- if (!(n = --ThreadUpdater.seconds)) {
- return ThreadUpdater.update();
- } else if (n <= -60) {
- ThreadUpdater.set('status', 'Retrying', null);
- return ThreadUpdater.update();
- } else if (n > 0) {
- return ThreadUpdater.set('timer', n);
- }
- },
- update: function() {
- var url;
-
- if (!ThreadUpdater.online) {
- return;
- }
- ThreadUpdater.seconds = 0;
- ThreadUpdater.set('timer', '...');
- if (ThreadUpdater.req) {
- ThreadUpdater.req.onloadend = null;
- ThreadUpdater.req.abort();
- }
- url = "//api.4chan.org/" + ThreadUpdater.thread.board + "/res/" + ThreadUpdater.thread + ".json";
- return ThreadUpdater.req = $.ajax(url, {
- onloadend: ThreadUpdater.cb.load
- }, {
- headers: {
- 'If-Modified-Since': ThreadUpdater.lastModified
- }
- });
- },
- updateThreadStatus: function(title, OP) {
- var icon, message, root, titleLC;
-
- titleLC = title.toLowerCase();
- if (ThreadUpdater.thread["is" + title] === !!OP[titleLC]) {
- return;
- }
- if (!(ThreadUpdater.thread["is" + title] = !!OP[titleLC])) {
- message = title === 'Sticky' ? 'The thread is not a sticky anymore.' : 'The thread is not closed anymore.';
- new Notification('info', message, 30);
- $.rm($("." + titleLC + "Icon", ThreadUpdater.thread.OP.nodes.info));
- return;
- }
- message = title === 'Sticky' ? 'The thread is now a sticky.' : 'The thread is now closed.';
- new Notification('info', message, 30);
- icon = $.el('img', {
- src: "//static.4chan.org/image/" + titleLC + ".gif",
- alt: title,
- title: title,
- className: "" + titleLC + "Icon"
- });
- root = $('[title="Quote this post"]', ThreadUpdater.thread.OP.nodes.info);
- if (title === 'Closed') {
- root = $('.stickyIcon', ThreadUpdater.thread.OP.nodes.info) || root;
- }
- return $.after(root, [$.tn(' '), icon]);
- },
- parse: function(postObjects) {
- var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, scroll, _i, _len, _ref;
-
- OP = postObjects[0];
- Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
- ThreadUpdater.updateThreadStatus('Sticky', OP);
- ThreadUpdater.updateThreadStatus('Closed', OP);
- ThreadUpdater.thread.postLimit = !!OP.bumplimit;
- ThreadUpdater.thread.fileLimit = !!OP.imagelimit;
- posts = [];
- index = [];
- files = [];
- count = 0;
- for (_i = 0, _len = postObjects.length; _i < _len; _i++) {
- postObject = postObjects[_i];
- num = postObject.no;
- index.push(num);
- if (postObject.fsize) {
- files.push(num);
- }
- if (num <= ThreadUpdater.lastPost) {
- continue;
- }
- count++;
- node = Build.postFromObject(postObject, ThreadUpdater.thread.board);
- posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
- }
- deletedPosts = [];
- deletedFiles = [];
- _ref = ThreadUpdater.thread.posts;
- for (ID in _ref) {
- post = _ref[ID];
- ID = +ID;
- if (post.isDead && index.contains(ID)) {
- post.resurrect();
- } else if (!index.contains(ID)) {
- post.kill();
- deletedPosts.push(post);
- } else if (post.file && !post.file.isDead && !files.contains(ID)) {
- post.kill(true);
- deletedFiles.push(post);
- }
- if (ThreadUpdater.postID) {
- if (ID === ThreadUpdater.postID) {
- ThreadUpdater.foundPost = true;
- }
- }
- }
- if (!count) {
- ThreadUpdater.set('status', null, null);
- ThreadUpdater.outdateCount++;
- } else {
- ThreadUpdater.set('status', "+" + count, 'new');
- ThreadUpdater.outdateCount = 0;
- if (Conf['Beep'] && d.hidden && Unread.posts && !Unread.posts.length) {
- if (!ThreadUpdater.audio) {
- ThreadUpdater.audio = $.el('audio', {
- src: ThreadUpdater.beep
- });
- }
- ThreadUpdater.audio.play();
- }
- ThreadUpdater.lastPost = posts[count - 1].ID;
- Main.callbackNodes(Post, posts);
- scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25;
- for (key in posts) {
- post = posts[key];
- if (!posts.hasOwnProperty(key)) {
- continue;
- }
- if (post.cb) {
- if (!post.cb.call(post)) {
- $.add(ThreadUpdater.root, post.nodes.root);
- }
- } else {
- $.add(ThreadUpdater.root, post.nodes.root);
- }
- }
- if (scroll) {
- if (Conf['Bottom Scroll']) {
- doc.scrollTop = d.body.clientHeight;
- } else {
- Header.scrollToPost(nodes[0]);
- }
- }
- $.queueTask(function() {
- var length, threadID;
-
- threadID = ThreadUpdater.thread.ID;
- length = $$('.thread > .postContainer', ThreadUpdater.root).length;
- return Fourchan.parseThread(threadID, length - count, length);
- });
- }
- return $.event('ThreadUpdate', {
- 404: false,
- thread: ThreadUpdater.thread,
- newPosts: posts,
- deletedPosts: deletedPosts,
- deletedFiles: deletedFiles,
- postCount: OP.replies + 1,
- fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead)
- });
- }
- };
-
- ThreadWatcher = {
- init: function() {
- if (!Conf['Thread Watcher']) {
- return;
- }
- this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', 'Thread Watcher
');
- $.on(d, 'QRPostSuccessful', this.cb.post);
- $.on(d, '4chanXInitFinished', this.ready);
- $.sync('WatchedThreads', this.refresh);
- return Thread.prototype.callbacks.push({
- name: 'Thread Watcher',
- cb: this.node
- });
- },
- node: function() {
- var favicon,
- _this = this;
-
- favicon = $.el('img', {
- className: 'favicon'
- });
- $.on(favicon, 'click', ThreadWatcher.cb.toggle);
- $.before($('input', this.OP.nodes.post), favicon);
- if (g.VIEW !== 'thread') {
- return;
- }
- return $.get('AutoWatch', 0, function(item) {
- if (item['AutoWatch'] !== _this.ID) {
- return;
- }
- ThreadWatcher.watch(_this);
- return $["delete"]('AutoWatch');
- });
- },
- ready: function() {
- $.off(d, '4chanXInitFinished', ThreadWatcher.ready);
- if (!Main.isThisPageLegit()) {
- return;
- }
- ThreadWatcher.refresh();
- return $.add(d.body, ThreadWatcher.dialog);
- },
- refresh: function(watched) {
- var ID, board, div, favicon, id, link, nodes, props, thread, x, _ref, _ref1;
-
- if (!watched) {
- $.get('WatchedThreads', {}, function(item) {
- return ThreadWatcher.refresh(item['WatchedThreads']);
- });
- return;
- }
- nodes = [$('.move', ThreadWatcher.dialog)];
- for (board in watched) {
- _ref = watched[board];
- for (id in _ref) {
- props = _ref[id];
- x = $.el('a', {
- textContent: '×',
- href: 'javascript:;'
- });
- $.on(x, 'click', ThreadWatcher.cb.x);
- link = $.el('a', props);
- link.title = link.textContent;
- div = $.el('div');
- $.add(div, [x, $.tn(' '), link]);
- nodes.push(div);
- }
- }
- $.rmAll(ThreadWatcher.dialog);
- $.add(ThreadWatcher.dialog, nodes);
- watched = watched[g.BOARD] || {};
- _ref1 = g.BOARD.threads;
- for (ID in _ref1) {
- thread = _ref1[ID];
- favicon = $('.favicon', thread.OP.nodes.post);
- favicon.src = ID in watched ? Favicon["default"] : Favicon.empty;
- }
- },
- cb: {
- toggle: function() {
- return ThreadWatcher.toggle(Get.postFromNode(this).thread);
- },
- x: function() {
- var thread;
-
- thread = this.nextElementSibling.pathname.split('/');
- return ThreadWatcher.unwatch(thread[1], thread[3]);
- },
- post: function(e) {
- var board, postID, threadID, _ref;
-
- _ref = e.detail, board = _ref.board, postID = _ref.postID, threadID = _ref.threadID;
- if (postID === threadID) {
- if (Conf['Auto Watch']) {
- return $.set('AutoWatch', threadID);
- }
- } else if (Conf['Auto Watch Reply']) {
- return ThreadWatcher.watch(board.threads[threadID]);
- }
- }
- },
- toggle: function(thread) {
- if ($('.favicon', thread.OP.nodes.post).src === Favicon.empty) {
- return ThreadWatcher.watch(thread);
- } else {
- return ThreadWatcher.unwatch(thread.board, thread.ID);
- }
- },
- unwatch: function(board, threadID) {
- return $.get('WatchedThreads', {}, function(item) {
- var watched;
-
- watched = item['WatchedThreads'];
- delete watched[board][threadID];
- if (!Object.keys(watched[board]).length) {
- delete watched[board];
- }
- ThreadWatcher.refresh(watched);
- return $.set('WatchedThreads', watched);
- });
- },
- watch: function(thread) {
- return $.get('WatchedThreads', {}, function(item) {
- var watched, _name;
-
- watched = item['WatchedThreads'];
- watched[_name = thread.board] || (watched[_name] = {});
- watched[thread.board][thread] = {
- href: "/" + thread.board + "/res/" + thread,
- textContent: Get.threadExcerpt(thread)
- };
- ThreadWatcher.refresh(watched);
- return $.set('WatchedThreads', watched);
- });
- }
- };
-
- Unread = {
- init: function() {
- if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon']) {
- return;
- }
- this.db = new DataBoard('lastReadPosts', this.sync);
- this.hr = $.el('hr', {
- id: 'unread-line'
- });
- this.posts = [];
- this.postsQuotingYou = [];
- return Thread.prototype.callbacks.push({
- name: 'Unread',
- cb: this.node
- });
- },
- node: function() {
- Unread.thread = this;
- Unread.title = d.title;
- Unread.lastReadPost = Unread.db.get({
- boardID: this.board.ID,
- threadID: this.ID,
- defaultValue: 0
- });
- $.on(d, '4chanXInitFinished', Unread.ready);
- $.on(d, 'ThreadUpdate', Unread.onUpdate);
- $.on(d, 'scroll visibilitychange', Unread.read);
- if (Conf['Unread Line']) {
- $.on(d, 'visibilitychange', Unread.setLine);
- }
- if (Conf['Scroll to Last Read Post']) {
- return $.on(window, 'load', Unread.scroll);
- }
- },
- ready: function() {
- var ID, post, posts, _ref;
-
- $.off(d, '4chanXInitFinished', Unread.ready);
- posts = [];
- _ref = Unread.thread.posts;
- for (ID in _ref) {
- post = _ref[ID];
- if (post.isReply) {
- posts.push(post);
- }
- }
- return Unread.addPosts(posts);
- },
- scroll: function() {
- var hash, post, posts, prevID, root;
-
- if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
- return;
- }
- if (Unread.posts.length) {
- prevID = 0;
- while (root = $.x('preceding-sibling::div[contains(@class,"postContainer")][1]', Unread.posts[0].nodes.root)) {
- post = Get.postFromRoot(root);
- if (prevID === post.ID) {
- break;
- }
- prevID = post.ID;
- if (!post.isHidden) {
- break;
- }
- }
- root.scrollIntoView(false);
- return;
- }
- posts = Object.keys(Unread.thread.posts);
- return Header.scrollToPost(Unread.thread.posts[posts[posts.length - 1]].nodes.root);
- },
- sync: function() {
- var lastReadPost;
-
- lastReadPost = Unread.db.get({
- boardID: Unread.thread.board.ID,
- threadID: Unread.thread.ID,
- defaultValue: 0
- });
- if (!(Unread.lastReadPost < lastReadPost)) {
- return;
- }
- Unread.lastReadPost = lastReadPost;
- Unread.readArray(Unread.posts);
- Unread.readArray(Unread.postsQuotingYou);
- Unread.setLine();
- return Unread.update();
- },
- addPosts: function(newPosts) {
- var ID, data, post, _i, _len;
-
- for (_i = 0, _len = newPosts.length; _i < _len; _i++) {
- post = newPosts[_i];
- ID = post.ID;
- if (ID <= Unread.lastReadPost || post.isHidden) {
- continue;
- }
- if (QR.db) {
- data = {
- boardID: post.board.ID,
- threadID: post.thread.ID,
- postID: post.ID
- };
- if (QR.db.get(data)) {
- continue;
- }
- }
- Unread.posts.push(post);
- Unread.addPostQuotingYou(post);
- }
- if (Conf['Unread Line']) {
- Unread.setLine(newPosts.contains(Unread.posts[0]));
- }
- Unread.read();
- return Unread.update();
- },
- addPostQuotingYou: function(post) {
- var quotelink, _i, _len, _ref;
-
- if (!QR.db) {
- return;
- }
- _ref = post.nodes.quotelinks;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quotelink = _ref[_i];
- if (QR.db.get(Get.postDataFromLink(quotelink))) {
- Unread.postsQuotingYou.push(post);
- }
- }
- },
- onUpdate: function(e) {
- if (e.detail[404]) {
- return Unread.update();
- } else {
- return Unread.addPosts(e.detail.newPosts);
- }
- },
- readSinglePost: function(post) {
- var i;
-
- if ((i = Unread.posts.indexOf(post)) === -1) {
- return;
- }
- Unread.posts.splice(i, 1);
- if (i === 0) {
- Unread.lastReadPost = post.ID;
- Unread.saveLastReadPost();
- }
- if ((i = Unread.postsQuotingYou.indexOf(post)) !== -1) {
- Unread.postsQuotingYou.splice(i, 1);
- }
- return Unread.update();
- },
- readArray: function(arr) {
- var i, post, _i, _len;
-
- for (i = _i = 0, _len = arr.length; _i < _len; i = ++_i) {
- post = arr[i];
- if (post.ID > Unread.lastReadPost) {
- break;
- }
- }
- return arr.splice(0, i);
- },
- read: $.debounce(50, function(e) {
- var ID, bottom, height, i, post, posts, read;
-
- if (d.hidden || !Unread.posts.length) {
- return;
- }
- height = doc.clientHeight;
- posts = Unread.posts;
- read = [];
- i = posts.length;
- while (post = posts[--i]) {
- bottom = post.nodes.root.getBoundingClientRect().bottom;
- if (bottom < height) {
- ID = post.ID;
- posts.remove(post);
- }
- }
- if (!ID) {
- return;
- }
- Unread.lastReadPost = ID;
- Unread.saveLastReadPost();
- Unread.readArray(Unread.postsQuotingYou);
- if (e) {
- return Unread.update();
- }
- }),
- saveLastReadPost: $.debounce(2 * $.SECOND, function() {
- return Unread.db.set({
- boardID: Unread.thread.board.ID,
- threadID: Unread.thread.ID,
- val: Unread.lastReadPost
- });
- }),
- setLine: function(force) {
- var post, root;
-
- if (!(d.hidden || force === true)) {
- return;
- }
- if (post = Unread.posts[0]) {
- root = post.nodes.root;
- if (root !== $('.thread > .replyContainer', root.parentNode)) {
- return $.before(root, Unread.hr);
- }
- } else {
- return $.rm(Unread.hr);
- }
- },
- update: function() {
- var count;
-
- count = Unread.posts.length;
- if (Conf['Unread Count']) {
- d.title = "" + (count || !Conf['Hide Unread Count at (0)'] ? "(" + count + ") " : '') + (g.DEAD ? "/" + g.BOARD + "/ - 404" : "" + Unread.title);
- }
- if (!Conf['Unread Favicon']) {
- return;
- }
- Favicon.el.href = g.DEAD ? Unread.postsQuotingYou.length ? Favicon.unreadDeadY : count ? Favicon.unreadDead : Favicon.dead : count ? Unread.postsQuotingYou.length ? Favicon.unreadY : Favicon.unread : Favicon["default"];
- return $.add(d.head, Favicon.el);
- }
- };
-
QR = {
init: function() {
var sc;
@@ -8298,619 +5723,2028 @@
}
};
- QuoteBacklink = {
+ FappeTyme = {
init: function() {
- var format;
+ var el, input;
- if (g.VIEW === 'catalog' || !Conf['Quote Backlinks']) {
+ if (!Conf['Fappe Tyme'] || g.VIEW === 'catalog' || g.BOARD === 'f') {
return;
}
- format = Conf['backlink'].replace(/%id/g, "' + id + '");
- this.funk = Function('id', "return '" + format + "'");
- this.containers = {};
- Post.prototype.callbacks.push({
- name: 'Quote Backlinking Part 1',
- cb: this.firstNode
+ el = $.el('label', {
+ innerHTML: " Fappe Tyme",
+ title: 'Fappe Tyme'
+ });
+ FappeTyme.input = input = el.firstElementChild;
+ $.on(input, 'change', FappeTyme.toggle);
+ $.event('AddMenuEntry', {
+ type: 'header',
+ el: el,
+ order: 97
});
return Post.prototype.callbacks.push({
- name: 'Quote Backlinking Part 2',
- cb: this.secondNode
+ name: 'Fappe Tyme',
+ cb: this.node
});
},
- firstNode: function() {
- var a, clone, container, containers, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
+ node: function() {
+ if (this.file) {
+ return;
+ }
+ return $.addClass(this.nodes.root, "noFile");
+ },
+ toggle: function() {
+ $.event('CloseMenu');
+ return (this.checked ? $.addClass : $.rmClass)(doc, 'fappeTyme');
+ }
+ };
- if (this.isClone || !this.quotes.length) {
+ ImageExpand = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
+ return;
+ }
+ this.EAI = $.el('a', {
+ className: 'expand-all-shortcut',
+ textContent: 'EAI',
+ title: 'Expand All Images',
+ href: 'javascript:;'
+ });
+ $.on(this.EAI, 'click', ImageExpand.cb.toggleAll);
+ Header.addShortcut(this.EAI);
+ return Post.prototype.callbacks.push({
+ name: 'Image Expansion',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var thumb, _ref;
+
+ if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ return;
+ }
+ thumb = this.file.thumb;
+ $.on(thumb.parentNode, 'click', ImageExpand.cb.toggle);
+ if (this.isClone && $.hasClass(thumb, 'expanding')) {
+ ImageExpand.contract(this);
+ ImageExpand.expand(this);
+ return;
+ }
+ if (ImageExpand.on && !this.isHidden) {
+ return ImageExpand.expand(this);
+ }
+ },
+ cb: {
+ toggle: function(e) {
+ if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
+ return;
+ }
+ e.preventDefault();
+ return ImageExpand.toggle(Get.postFromNode(this));
+ },
+ toggleAll: function() {
+ var ID, file, func, post, _i, _len, _ref, _ref1;
+
+ $.event('CloseMenu');
+ if (ImageExpand.on = $.hasClass(ImageExpand.EAI, 'expand-all-shortcut')) {
+ ImageExpand.EAI.className = 'contract-all-shortcut';
+ ImageExpand.EAI.title = 'Contract All Images';
+ func = ImageExpand.expand;
+ } else {
+ ImageExpand.EAI.className = 'expand-all-shortcut';
+ ImageExpand.EAI.title = 'Expand All Images';
+ func = ImageExpand.contract;
+ }
+ _ref = g.posts;
+ for (ID in _ref) {
+ post = _ref[ID];
+ _ref1 = [post].concat(post.clones);
+ for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
+ post = _ref1[_i];
+ file = post.file;
+ if (!(file && file.isImage && doc.contains(post.nodes.root))) {
+ continue;
+ }
+ if (ImageExpand.on && (!Conf['Expand spoilers'] && file.isSpoiler || Conf['Expand from here'] && file.thumb.getBoundingClientRect().top < 0)) {
+ continue;
+ }
+ $.queueTask(func, post);
+ }
+ }
+ },
+ setFitness: function() {
+ var checked;
+
+ checked = this.checked;
+ (checked ? $.addClass : $.rmClass)(doc, this.name.toLowerCase().replace(/\s+/g, '-'));
+ if (this.name !== 'Fit height') {
+ return;
+ }
+ if (checked) {
+ $.on(window, 'resize', ImageExpand.resize);
+ if (!ImageExpand.style) {
+ ImageExpand.style = $.addStyle(null);
+ }
+ return ImageExpand.resize();
+ } else {
+ return $.off(window, 'resize', ImageExpand.resize);
+ }
+ }
+ },
+ toggle: function(post) {
+ var headRect, rect, root, thumb, top;
+
+ thumb = post.file.thumb;
+ if (!(post.file.isExpanded || $.hasClass(thumb, 'expanding'))) {
+ ImageExpand.expand(post);
+ return;
+ }
+ ImageExpand.contract(post);
+ rect = post.nodes.root.getBoundingClientRect();
+ if (!(rect.top <= 0 || rect.left <= 0)) {
+ return;
+ }
+ top = rect.top;
+ if (Conf['Fixed Header'] && !Conf['Bottom Header']) {
+ headRect = Header.bar.getBoundingClientRect();
+ top += -headRect.top - headRect.height;
+ }
+ root = doc;
+ if (rect.top < 0) {
+ root.scrollTop += top;
+ }
+ if (rect.left < 0) {
+ return root.scrollLeft = 0;
+ }
+ },
+ contract: function(post) {
+ $.rmClass(post.nodes.root, 'expanded-image');
+ $.rmClass(post.file.thumb, 'expanding');
+ return post.file.isExpanded = false;
+ },
+ expand: function(post, src) {
+ var img, thumb;
+
+ thumb = post.file.thumb;
+ if (post.isHidden || post.file.isExpanded || $.hasClass(thumb, 'expanding')) {
+ return;
+ }
+ $.addClass(thumb, 'expanding');
+ if (post.file.fullImage) {
+ $.asap((function() {
+ return post.file.fullImage.naturalHeight;
+ }), function() {
+ return ImageExpand.completeExpand(post);
+ });
+ return;
+ }
+ post.file.fullImage = img = $.el('img', {
+ className: 'full-image',
+ src: src || post.file.URL
+ });
+ $.on(img, 'error', ImageExpand.error);
+ $.asap((function() {
+ return post.file.fullImage.naturalHeight;
+ }), function() {
+ return ImageExpand.completeExpand(post);
+ });
+ return $.after(thumb, img);
+ },
+ completeExpand: function(post) {
+ var prev, thumb;
+
+ thumb = post.file.thumb;
+ if (!$.hasClass(thumb, 'expanding')) {
+ return;
+ }
+ post.file.isExpanded = true;
+ if (!post.nodes.root.parentNode) {
+ $.addClass(post.nodes.root, 'expanded-image');
+ $.rmClass(post.file.thumb, 'expanding');
+ return;
+ }
+ prev = post.nodes.root.getBoundingClientRect();
+ return $.queueTask(function() {
+ var curr, root;
+
+ $.addClass(post.nodes.root, 'expanded-image');
+ $.rmClass(post.file.thumb, 'expanding');
+ if (!(prev.top + prev.height <= 0)) {
+ return;
+ }
+ root = doc;
+ curr = post.nodes.root.getBoundingClientRect();
+ return root.scrollTop += curr.height - prev.height + curr.top - prev.top;
+ });
+ },
+ error: function() {
+ var URL, post, src, timeoutID;
+
+ post = Get.postFromNode(this);
+ $.rm(this);
+ delete post.file.fullImage;
+ if (!($.hasClass(post.file.thumb, 'expanding') || $.hasClass(post.nodes.root, 'expanded-image'))) {
+ return;
+ }
+ ImageExpand.contract(post);
+ src = this.src.split('/');
+ if (src[2] === 'images.4chan.org') {
+ if (URL = Redirect.image(src[3], src[5])) {
+ setTimeout(ImageExpand.expand, 10000, post, URL);
+ return;
+ }
+ if (g.DEAD || post.isDead || post.file.isDead) {
+ return;
+ }
+ }
+ timeoutID = setTimeout(ImageExpand.expand, 10000, post);
+ return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", {
+ onload: function() {
+ var postObj, _i, _len, _ref;
+
+ if (this.status !== 200) {
+ return;
+ }
+ _ref = JSON.parse(this.response).posts;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ postObj = _ref[_i];
+ if (postObj.no === post.ID) {
+ break;
+ }
+ }
+ if (postObj.no !== post.ID) {
+ clearTimeout(timeoutID);
+ return post.kill();
+ } else if (postObj.filedeleted) {
+ clearTimeout(timeoutID);
+ return post.kill(true);
+ }
+ }
+ });
+ },
+ menu: {
+ init: function() {
+ var conf, createSubEntry, el, key, subEntries, _ref;
+
+ if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
+ return;
+ }
+ el = $.el('span', {
+ textContent: 'Image Expansion',
+ className: 'image-expansion-link'
+ });
+ createSubEntry = ImageExpand.menu.createSubEntry;
+ subEntries = [];
+ _ref = Config.imageExpansion;
+ for (key in _ref) {
+ conf = _ref[key];
+ subEntries.push(createSubEntry(key, conf));
+ }
+ return $.event('AddMenuEntry', {
+ type: 'header',
+ el: el,
+ order: 105,
+ subEntries: subEntries
+ });
+ },
+ createSubEntry: function(type, config) {
+ var input, label;
+
+ label = $.el('label', {
+ innerHTML: " " + type
+ });
+ input = label.firstElementChild;
+ if (type === 'Fit width' || type === 'Fit height') {
+ $.on(input, 'change', ImageExpand.cb.setFitness);
+ }
+ if (config) {
+ label.title = config[1];
+ input.checked = Conf[type];
+ $.event('change', null, input);
+ $.on(input, 'change', $.cb.checked);
+ }
+ return {
+ el: label
+ };
+ }
+ },
+ resize: function() {
+ return ImageExpand.style.textContent = ":root.fit-height .full-image {max-height:" + doc.clientHeight + "px}";
+ },
+ menuToggle: function(e) {
+ return ImageExpand.opmenu.toggle(e, this, g);
+ }
+ };
+
+ ImageHover = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Image Hover']) {
+ return;
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Image Hover',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var _ref;
+
+ if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ return;
+ }
+ return $.on(this.file.thumb, 'mouseover', ImageHover.mouseover);
+ },
+ mouseover: function(e) {
+ var el, post;
+
+ post = Get.postFromNode(this);
+ el = $.el('img', {
+ id: 'ihover',
+ src: post.file.URL
+ });
+ el.setAttribute('data-fullid', post.fullID);
+ $.add(Header.hover, el);
+ UI.hover({
+ root: this,
+ el: el,
+ latestEvent: e,
+ endEvents: 'mouseout click',
+ asapTest: function() {
+ return el.naturalHeight;
+ }
+ });
+ return $.on(el, 'error', ImageHover.error);
+ },
+ error: function() {
+ var URL, post, src, timeoutID,
+ _this = this;
+
+ if (!doc.contains(this)) {
+ return;
+ }
+ post = g.posts[this.dataset.fullid];
+ src = this.src.split('/');
+ if (src[2] === 'images.4chan.org') {
+ if (URL = Redirect.image(src[3], src[5].replace(/\?.+$/, ''))) {
+ this.src = URL;
+ return;
+ }
+ if (g.DEAD || post.isDead || post.file.isDead) {
+ return;
+ }
+ }
+ timeoutID = setTimeout((function() {
+ return _this.src = post.file.URL + '?' + Date.now();
+ }), 3000);
+ return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", {
+ onload: function() {
+ var postObj, _i, _len, _ref;
+
+ if (this.status !== 200) {
+ return;
+ }
+ _ref = JSON.parse(this.response).posts;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ postObj = _ref[_i];
+ if (postObj.no === post.ID) {
+ break;
+ }
+ }
+ if (postObj.no !== post.ID) {
+ clearTimeout(timeoutID);
+ return post.kill();
+ } else if (postObj.filedeleted) {
+ clearTimeout(timeoutID);
+ return post.kill(true);
+ }
+ }
+ });
+ }
+ };
+
+ ImageReplace = {
+ init: function() {
+ if (g.VIEW === 'catalog') {
+ return;
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Image Replace',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var URL, img, style, thumb, type, _ref, _ref1;
+
+ if (this.isClone || this.isHidden || this.thread.isHidden || !((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ return;
+ }
+ _ref1 = this.file, thumb = _ref1.thumb, URL = _ref1.URL;
+ if (!(Conf["Replace " + ((type = (URL.match(/\w{3}$/))[0].toUpperCase()) === 'PEG' ? 'JPG' : type)] && !/spoiler/.test(thumb.src))) {
+ return;
+ }
+ if (this.file.isSpoiler) {
+ style = thumb.style;
+ style.maxHeight = style.maxWidth = this.isReply ? '125px' : '250px';
+ }
+ img = $.el('img');
+ $.on(img, 'load', function() {
+ return thumb.src = URL;
+ });
+ return img.src = URL;
+ }
+ };
+
+ RevealSpoilers = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Reveal Spoilers']) {
+ return;
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Reveal Spoilers',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var thumb, _ref;
+
+ if (this.isClone || !((_ref = this.file) != null ? _ref.isSpoiler : void 0)) {
+ return;
+ }
+ thumb = this.file.thumb;
+ thumb.removeAttribute('style');
+ return thumb.src = this.file.thumbURL;
+ }
+ };
+
+ ArchiveLink = {
+ init: function() {
+ var div, entry, type, _i, _len, _ref;
+
+ if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Archive Link']) {
+ return;
+ }
+ div = $.el('div', {
+ textContent: 'Archive'
+ });
+ entry = {
+ type: 'post',
+ el: div,
+ order: 90,
+ open: function(_arg) {
+ var ID, board, redirect, thread;
+
+ ID = _arg.ID, thread = _arg.thread, board = _arg.board;
+ redirect = Redirect.to({
+ postID: ID,
+ threadID: thread.ID,
+ boardID: board.ID
+ });
+ return redirect !== ("//boards.4chan.org/" + board + "/");
+ },
+ subEntries: []
+ };
+ _ref = [['Post', 'post'], ['Name', 'name'], ['Tripcode', 'tripcode'], ['E-mail', 'email'], ['Subject', 'subject'], ['Filename', 'filename'], ['Image MD5', 'MD5']];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ type = _ref[_i];
+ entry.subEntries.push(this.createSubEntry(type[0], type[1]));
+ }
+ return $.event('AddMenuEntry', entry);
+ },
+ createSubEntry: function(text, type) {
+ var el, open;
+
+ el = $.el('a', {
+ textContent: text,
+ target: '_blank'
+ });
+ open = type === 'post' ? function(_arg) {
+ var ID, board, thread;
+
+ ID = _arg.ID, thread = _arg.thread, board = _arg.board;
+ el.href = Redirect.to({
+ postID: ID,
+ threadID: thread.ID,
+ boardID: board.ID
+ });
+ return true;
+ } : function(post) {
+ var value;
+
+ value = Filter[type](post);
+ if (!value) {
+ return false;
+ }
+ el.href = Redirect.to({
+ boardID: post.board.ID,
+ type: type,
+ value: value,
+ isSearch: true
+ });
+ return true;
+ };
+ return {
+ el: el,
+ open: open
+ };
+ }
+ };
+
+ DeleteLink = {
+ init: function() {
+ var div, fileEl, fileEntry, postEl, postEntry;
+
+ if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Delete Link']) {
+ return;
+ }
+ div = $.el('div', {
+ className: 'delete-link',
+ textContent: 'Delete'
+ });
+ postEl = $.el('a', {
+ className: 'delete-post',
+ href: 'javascript:;'
+ });
+ fileEl = $.el('a', {
+ className: 'delete-file',
+ href: 'javascript:;'
+ });
+ postEntry = {
+ el: postEl,
+ open: function() {
+ postEl.textContent = 'Post';
+ $.on(postEl, 'click', DeleteLink["delete"]);
+ return true;
+ }
+ };
+ fileEntry = {
+ el: fileEl,
+ open: function(_arg) {
+ var file;
+
+ file = _arg.file;
+ if (!file || file.isDead) {
+ return false;
+ }
+ fileEl.textContent = 'File';
+ $.on(fileEl, 'click', DeleteLink["delete"]);
+ return true;
+ }
+ };
+ return $.event('AddMenuEntry', {
+ type: 'post',
+ el: div,
+ order: 40,
+ open: function(post) {
+ var node;
+
+ if (post.isDead) {
+ return false;
+ }
+ DeleteLink.post = post;
+ node = div.firstChild;
+ node.textContent = 'Delete';
+ DeleteLink.cooldown.start(post, node);
+ return true;
+ },
+ subEntries: [postEntry, fileEntry]
+ });
+ },
+ "delete": function() {
+ var fileOnly, form, link, m, post, pwd;
+
+ post = DeleteLink.post;
+ if (DeleteLink.cooldown.counting === post) {
+ return;
+ }
+ $.off(this, 'click', DeleteLink["delete"]);
+ this.textContent = "Deleting " + this.textContent + "...";
+ pwd = (m = d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : $.id('delPassword').value;
+ fileOnly = $.hasClass(this, 'delete-file');
+ form = {
+ mode: 'usrdel',
+ onlyimgdel: fileOnly,
+ pwd: pwd
+ };
+ form[post.ID] = 'delete';
+ link = this;
+ return $.ajax($.id('delform').action.replace("/" + g.BOARD + "/", "/" + post.board + "/"), {
+ onload: function() {
+ return DeleteLink.load(link, post, fileOnly, this.response);
+ },
+ onerror: function() {
+ return DeleteLink.error(link);
+ }
+ }, {
+ cred: true,
+ form: $.formData(form)
+ });
+ },
+ load: function(link, post, fileOnly, html) {
+ var msg, s, tmpDoc;
+
+ tmpDoc = d.implementation.createHTMLDocument('');
+ tmpDoc.documentElement.innerHTML = html;
+ if (tmpDoc.title === '4chan - Banned') {
+ s = 'Banned!';
+ } else if (msg = tmpDoc.getElementById('errmsg')) {
+ s = msg.textContent;
+ $.on(link, 'click', DeleteLink["delete"]);
+ } else {
+ if (tmpDoc.title === 'Updating index...') {
+ (post.origin || post).kill(fileOnly);
+ }
+ s = 'Deleted';
+ }
+ return link.textContent = s;
+ },
+ error: function(link) {
+ link.textContent = 'Connection error, please retry.';
+ return $.on(link, 'click', DeleteLink["delete"]);
+ },
+ cooldown: {
+ start: function(post, node) {
+ var length, seconds, _ref;
+
+ if (!((_ref = QR.db) != null ? _ref.get({
+ boardID: post.board.ID,
+ threadID: post.thread.ID,
+ postID: post.ID
+ }) : void 0)) {
+ delete DeleteLink.cooldown.counting;
+ return;
+ }
+ DeleteLink.cooldown.counting = post;
+ length = post.board.ID === 'q' ? 600 : 30;
+ seconds = Math.ceil((length * $.SECOND - (Date.now() - post.info.date)) / $.SECOND);
+ return DeleteLink.cooldown.count(post, seconds, length, node);
+ },
+ count: function(post, seconds, length, node) {
+ if (DeleteLink.cooldown.counting !== post) {
+ return;
+ }
+ if (!((0 <= seconds && seconds <= length))) {
+ if (DeleteLink.cooldown.counting === post) {
+ node.textContent = 'Delete';
+ delete DeleteLink.cooldown.counting;
+ }
+ return;
+ }
+ setTimeout(DeleteLink.cooldown.count, 1000, post, seconds - 1, length, node);
+ return node.textContent = "Delete (" + seconds + ")";
+ }
+ }
+ };
+
+ DownloadLink = {
+ init: function() {
+ var a;
+
+ if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Download Link']) {
return;
}
a = $.el('a', {
- href: "/" + this.board + "/res/" + this.thread + "#p" + this,
- className: this.isHidden ? 'filtered backlink' : 'backlink',
- textContent: (QuoteBacklink.funk(this.ID)) + (Conf['Mark Quotes of You'] && this.info.yours ? QuoteYou.text : '')
+ className: 'download-link',
+ textContent: 'Download file'
});
- _ref = this.quotes;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quote = _ref[_i];
- containers = [QuoteBacklink.getContainer(quote)];
- if ((post = g.posts[quote]) && post.nodes.backlinkContainer) {
- _ref1 = post.clones;
- for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
- clone = _ref1[_j];
- containers.push(clone.nodes.backlinkContainer);
- }
- }
- for (_k = 0, _len2 = containers.length; _k < _len2; _k++) {
- container = containers[_k];
- link = a.cloneNode(true);
- if (Conf['Quote Previewing']) {
- $.on(link, 'mouseover', QuotePreview.mouseover);
- }
- if (Conf['Quote Inlining']) {
- $.on(link, 'click', QuoteInline.toggle);
- }
- $.add(container, [$.tn(' '), link]);
- }
- }
- },
- secondNode: function() {
- var container;
+ return $.event('AddMenuEntry', {
+ type: 'post',
+ el: a,
+ order: 70,
+ open: function(_arg) {
+ var file;
- if (this.isClone && (this.origin.isReply || Conf['OP Backlinks'])) {
- this.nodes.backlinkContainer = $('.container', this.nodes.info);
- return;
- }
- if (!(this.isReply || Conf['OP Backlinks'])) {
- return;
- }
- container = QuoteBacklink.getContainer(this.fullID);
- this.nodes.backlinkContainer = container;
- return $.add(this.nodes.info, container);
- },
- getContainer: function(id) {
- var _base;
-
- return (_base = this.containers)[id] || (_base[id] = $.el('span', {
- className: 'container'
- }));
+ file = _arg.file;
+ if (!file) {
+ return false;
+ }
+ a.href = file.URL;
+ a.download = file.name;
+ return true;
+ }
+ });
}
};
- QuoteCT = {
+ Menu = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Mark Cross-thread Quotes']) {
+ if (g.VIEW === 'catalog' || !Conf['Menu']) {
return;
}
- if (Conf['Comment Expansion']) {
- ExpandComment.callbacks.push(this.node);
- }
- this.text = '\u00A0(Cross-thread)';
+ this.menu = new UI.Menu('post');
return Post.prototype.callbacks.push({
- name: 'Mark Cross-thread Quotes',
+ name: 'Menu',
cb: this.node
});
},
node: function() {
- var board, boardID, quotelink, quotelinks, quotes, thread, threadID, _i, _len, _ref, _ref1;
+ var button;
- if (this.isClone && this.thread === this.context.thread) {
+ button = Menu.makeButton(this);
+ if (this.isClone) {
+ $.replace($('.menu-button', this.nodes.info), button);
return;
}
- if (!(quotes = this.quotes).length) {
- return;
- }
- quotelinks = this.nodes.quotelinks;
- _ref = this.isClone ? this.context : this, board = _ref.board, thread = _ref.thread;
- for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
- quotelink = quotelinks[_i];
- _ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, threadID = _ref1.threadID;
- if (!threadID) {
- continue;
- }
- if (this.isClone) {
- quotelink.textContent = quotelink.textContent.replace(QuoteCT.text, '');
- }
- if (boardID === this.board.ID && threadID !== thread.ID) {
- $.add(quotelink, $.tn(QuoteCT.text));
- }
- }
- }
- };
-
- QuoteInline = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Quote Inlining']) {
- return;
- }
- if (Conf['Comment Expansion']) {
- ExpandComment.callbacks.push(this.node);
- }
- return Post.prototype.callbacks.push({
- name: 'Quote Inlining',
- cb: this.node
- });
+ return $.add(this.nodes.info, [$.tn('\u00A0'), button]);
},
- node: function() {
- var link, _i, _len, _ref;
+ makeButton: (function() {
+ var a;
- _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- link = _ref[_i];
- $.on(link, 'click', QuoteInline.toggle);
- }
- },
+ a = null;
+ return function(post) {
+ var clone;
+
+ a || (a = $.el('a', {
+ className: 'menu-button',
+ innerHTML: '[]',
+ href: 'javascript:;'
+ }));
+ clone = a.cloneNode(true);
+ clone.setAttribute('data-postid', post.fullID);
+ if (post.isClone) {
+ clone.setAttribute('data-clone', true);
+ }
+ $.on(clone, 'click', Menu.toggle);
+ return clone;
+ };
+ })(),
toggle: function(e) {
- var boardID, context, postID, threadID, _ref;
+ var post;
- if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
- return;
- }
- e.preventDefault();
- _ref = Get.postDataFromLink(this), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
- context = Get.contextFromLink(this);
- if ($.hasClass(this, 'inlined')) {
- QuoteInline.rm(this, boardID, threadID, postID, context);
- } else {
- if ($.x("ancestor::div[@id='p" + postID + "']", this)) {
- return;
- }
- QuoteInline.add(this, boardID, threadID, postID, context);
- }
- return this.classList.toggle('inlined');
- },
- findRoot: function(quotelink, isBacklink) {
- if (isBacklink) {
- return quotelink.parentNode.parentNode;
- } else {
- return $.x('ancestor-or-self::*[parent::blockquote][1]', quotelink);
- }
- },
- add: function(quotelink, boardID, threadID, postID, context) {
- var inline, isBacklink, post;
-
- isBacklink = $.hasClass(quotelink, 'backlink');
- inline = $.el('div', {
- id: "i" + postID,
- className: 'inline'
- });
- $.after(QuoteInline.findRoot(quotelink, isBacklink), inline);
- Get.postClone(boardID, threadID, postID, inline, context);
- if (!((post = g.posts["" + boardID + "." + postID]) && context.thread === post.thread)) {
- return;
- }
- if (isBacklink && Conf['Forward Hiding']) {
- $.addClass(post.nodes.root, 'forwarded');
- post.forwarded++ || (post.forwarded = 1);
- }
- if (!Unread.posts) {
- return;
- }
- return Unread.readSinglePost(post);
- },
- rm: function(quotelink, boardID, threadID, postID, context) {
- var el, inlined, isBacklink, post, root, _ref;
-
- isBacklink = $.hasClass(quotelink, 'backlink');
- root = QuoteInline.findRoot(quotelink, isBacklink);
- root = $.x("following-sibling::div[@id='i" + postID + "'][1]", root);
- $.rm(root);
- if (!(el = root.firstElementChild)) {
- return;
- }
- post = g.posts["" + boardID + "." + postID];
- post.rmClone(el.dataset.clone);
- if (Conf['Forward Hiding'] && isBacklink && context.thread === g.threads["" + boardID + "." + threadID] && !--post.forwarded) {
- delete post.forwarded;
- $.rmClass(post.nodes.root, 'forwarded');
- }
- while (inlined = $('.inlined', el)) {
- _ref = Get.postDataFromLink(inlined), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
- QuoteInline.rm(inlined, boardID, threadID, postID, context);
- $.rmClass(inlined, 'inlined');
- }
+ post = this.dataset.clone ? Get.postFromNode(this) : g.posts[this.dataset.postid];
+ return Menu.menu.toggle(e, this, post);
}
};
- QuoteOP = {
+ ReportLink = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Mark OP Quotes']) {
+ var a;
+
+ if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Report Link']) {
return;
}
- if (Conf['Comment Expansion']) {
- ExpandComment.callbacks.push(this.node);
+ a = $.el('a', {
+ className: 'report-link',
+ href: 'javascript:;',
+ textContent: 'Report this post'
+ });
+ $.on(a, 'click', ReportLink.report);
+ return $.event('AddMenuEntry', {
+ type: 'post',
+ el: a,
+ order: 10,
+ open: function(post) {
+ ReportLink.post = post;
+ return !post.isDead;
+ }
+ });
+ },
+ report: function() {
+ var id, post, set, url;
+
+ post = ReportLink.post;
+ url = "//sys.4chan.org/" + post.board + "/imgboard.php?mode=report&no=" + post;
+ id = Date.now();
+ set = "toolbar=0,scrollbars=0,location=0,status=1,menubar=0,resizable=1,width=685,height=200";
+ return window.open(url, id, set);
+ }
+ };
+
+ Favicon = {
+ init: function() {
+ return $.ready(function() {
+ var href;
+
+ Favicon.el = $('link[rel="shortcut icon"]', d.head);
+ Favicon.el.type = 'image/x-icon';
+ href = Favicon.el.href;
+ Favicon.SFW = /ws\.ico$/.test(href);
+ Favicon["default"] = href;
+ return Favicon["switch"]();
+ });
+ },
+ "switch": function() {
+ switch (Conf['favicon']) {
+ case 'ferongr':
+ Favicon.unreadDead = 'data:image/gif;base64,R0lGODlhEAAQAOMHAOgLAnMFAL8AAOgLAukMA/+AgP+rq////////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
+ Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAS1BMVEUAAAAAAAAAAAAJAAASAAAZAQAaAQAiAQAkAQAoFBQyAgAzAgA1AgA4AABBAgBXAwBzBQCEBgGvCAG/AADoCwLpDAP/gID/q6v///9zILr8AAAAA3RSTlMAx9dmesIgAAAAc0lEQVQY02WPgQ6DIBBDmTqnbE70Cvb/v3TAnW5OSKB9ybXg3HUBOAmEEH4FQtrSn4gxi+xjVC9SVOEiSvbZI8zSV+/Xo7icnryZ15GObMxvtWUkB/VJW57kHU7fUcHStm8FkncGE/mwP6CGzq/eauHwvT7sWQt3gZLW+AAAAABJRU5ErkJggg==';
+ Favicon.unreadSFW = 'data:image/gif;base64,R0lGODlhEAAQAOMHAADX8QBwfgC2zADX8QDY8nnl8qLp8v///////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
+ Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAASFBMVEUAAAAAAAAAAAAACAkAERMAGBsAGR0AISUALzQALzUAMTcANjwAP0cAVF8AcH4AeokAorYAtswA1/EA2PISIyV55fKi6fL////l+pZqAAAAA3RSTlMAx9dmesIgAAAAcklEQVQY02VPARLCIAxjsjnUWdcg6/9/ukIr00nvIMldEhrC/wHwA0BE3wBUtnICOStQnrNx5oqqzmzKx9vDPH1Nae3F9U4ig3OzjCIX51treYvMxou13EQmBPtHE14xLiawjgoPtfgOaKHP+9VrEXA8O1v7CmSPE3u0AAAAAElFTkSuQmCC';
+ Favicon.unreadNSFW = 'data:image/gif;base64,R0lGODlhEAAQAOMHAFT+ACh5AEncAFT+AFX/Acz/su7/5v///////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
+ Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAS1BMVEUAAAAAAAAAAAADCgAGEgAIGgAJGwALJAANJwASNwASOAATOgAVQQAWRAAeWwAgKBsoeQAwkQA/wABJ3ABU/gBV/wHM/7Lu/+b////r+K2AAAAAA3RSTlMAx9dmesIgAAAAc0lEQVQY02WPgQ6DIBBDmTonbk70Cvb/v3TAnW5OSKB9ybXg3HUBOAmEEH4FQtrSn4gxi+xjVC9SVOEiSvbZI8zSV+/Xo7icnryZ15GObMxvtWUmB/VJW0byDqfvqGBp20mB5J3Bi3zYH1BD38/eauHwvT7sEAt1Fb320QAAAABJRU5ErkJggg==';
+ break;
+ case 'xat-':
+ Favicon.unreadDead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA2ElEQVQ4y61TQQrCMBDMQ8WDIEV6LbT2A4og2Hq0veo7fIAH04dY9N4xmyYlpGmI2MCQTWYy3Wy2DAD7B2wWAzWgcTgVeZKlZRxHNYFi2jM18oBh0IcKtC6ixf22WT4IFLs0owxswXu9egm0Ls6bwfCFfNsJYJKfqoEkd3vgUgFVLWObtzNgVKyruC+ljSzr5OEnBzjvjcQecaQhbZgBb4CmGQw+PoMkTUtdbd8VSEPakcGxPOcsoIgUKy0LecY29BmdBrqRfjIwZ93KLs5loHvBnL3cLH/jF+C/+z5dgUysAAAAAElFTkSuQmCC';
+ Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACKkJGNkpN0d3d0eHdra2dGRkORZ1wAAACmaV6naV4PDw8LCwsLCwvyZWLyZWIeExEyFBTAWlr/eHj/enkAAAAKAAAoAAA4AAA4GhpMAACRAAD/AAD/enn/h4j/m5z/nJ3/0dL/0tL/0tP/09P///9VK8WFAAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uZfI0YOdiiMiJw+2CKIPkZzGtcbgKYIJaI26LAfQOzOqoYNA4Z49Nguv/gEEhw2/C5BUZgAAAABJRU5ErkJggg==';
+ Favicon.unreadSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA30lEQVQ4y2P4//8/AyWYgSoGQMF/GJ7Y11VVUVoyKTM9ey4Ig9ggMWQ1YA1IBvzXm34YjkH8mPyJB+Nqlp8FYRAbmxoMF6ArSNrw6T0Qf8Amh9cFMEWVR/7/A+L/uORxhgEIt5/+/3/2lf//5wAxiI0uj+4CBlBgxVUvOwtydgXQZpDmi2/+/7/0GmIQSAwkB1IDUkuUAZeABlx+g2zAZ9wGlAOjChba+LwAUgNSi2HA5Am9VciBhSsQQWyoWgZiovEDsdGI1QBYQiLJAGQalpSxyWEzAJYWkGm8clTJjQCZ1hkoVG0CygAAAABJRU5ErkJggg==';
+ Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACRjoqTkI13dXR4dXRpZ2tFQ0Zcb5EAAABee6ZefKcPDw8LCwsLCwtisPJisPIRFh4UJDJalMB4xP95xP8AAAABBQcHFx4KISoNLToaKzgaVW4ul8N5xP+Hy/+b1P+c1P/R7P/S6//S7P/T7P////9P0rk0AAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uUrk6MFOxRGRkwdbBNGHSE7jWmPwFMEEtEZdlgPonRmvoYNA4Z49Nguv/gEE3A2/sQ7iRgAAAABJRU5ErkJggg==';
+ Favicon.unreadNSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA4ElEQVQ4y2P4//8/AyWYgSoGQMF/GJ7YNbGqrKRiUnp21lwQBrFBYshqwBqQDPifdsYYjkH8mInxB+OWx58FYRAbmxoMF6ArKPmU9B6IP2CTw+sCmKKe/5X/gPg/LnmcYQDCs/63/1/9fzYQzwGz0eXRXcAACqy4ZfFnQc7u+V/xD6T55v+LQHwJbBBIDCQHUgNSS5QBt4Cab/2/jDDgMx4DykrKJ8FCG58XQGpAajEMmNw7uQo5sHAFIogNVctATDR+IDYasRoAS0gkGYBMw5IyNjlsBsDSAjKNV44quREAx58Mr9vt5wQAAAAASUVORK5CYII=';
+ Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACRipGTjZN2dHd2dHhna2pDRkVckV8AAABepl9ep18PDw8LCwsLCwt08mJ08mIRHhEYMhRpwFqM/3iM/3kAAAAECAIQIAgWLAseOBoePA86dB1mzDOM/3ma/4er/5ur/5zZ/9HZ/9La/9La/9P///85Jx7jAAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uZfI0YOdiiMiJw+2CKIPkZzGtcbgKYIJaI26LAfQOzOqoYNA4Z49Nguv/gEEhw2/C5BUZgAAAABJRU5ErkJggg==';
+ break;
+ case 'Mayhem':
+ Favicon.unreadDead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABIUlEQVQ4jZ2ScWuDMBDFgw4pIkU0WsoQkWAYIkXZH4N9/+/V3dmfXSrKYIFHwt17j8vdGWNMIkgFuaDgzgQnwRs4EQs5KdolUQtagRN0givEDBTEOjgtGs0Zq8F7cKqqusVxrMQLaDUWcjBSrXkn8gs51tpJSWLk9b3HUa0aNIL5gPBR1/V4kJvR7lTwl8GmAm1Gf9+c3S+89qBHa8502AsmSrtBaEBPbIbj0ah2madlNAPEccdgJDfAtWifBjqWKShRBT6KoiH8QlEUn/qt0CCjnNdmPUwmFWzj9Oe6LpKuZXcwqq88z78Pch3aZU3dPwwc2sWlfZKCW5tWluV8kGvXClLm6dYN4/aUqfCbnEOzNDGhGZbNargvxCzvMGfRJD8UaDVvgkzo6QAAAABJRU5ErkJggg==';
+ Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABj0lEQVQ4y42TQUorQRCGv+oekpj43pOhOyIiKoHBxTMkuAnEtWcwx/AY3sUbBIRcwCw8gCfIMkaTOOUiNdgGRRuKoav+v2qq/i4BakBmXweUwDoxLF5ZhVkC64rYBHYMUAIvwKuBMEwdaFiCNbAAngEC0NHkxBi73vsOsG92HGPsphigY1wOzfNhqhpC6AEd730RQuh9hQEOAY6A/jeAs3a7/f+bWB84ckCpqg+I8Osjgqo+AKUDViJS8LkGMcY+sJrNZssYY387LiIFsBLgL9AC/pgaArzZlF+sZgO4BG7sfgvcA3MxUtOStBIpX7cS3Klqd9OBTIEr4DlLOsuAmqpODXQOiHMuy/O8FkLoJth/6Uh2gQPg87Q3k+7leX6hqnpmPvM/GWfXWeWGqj5+oUS9LMs6wF7iHAwGJ9ZW5uxpup+UGwEtEVoijEYjKl66PJujmvIW3vsFwBiYqzJXZTweY5wSU6Bd7UP1KoECODUrJpOJAtPhcKjAtXGaYptWs57qWyv9Zn/it1a5knj5Dm3v4q8APeACAAAAAElFTkSuQmCC';
+ Favicon.unreadSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABCElEQVQ4jZ2S4crCMAxF+0OGDJEPKYrIGKOsiJSx/fJRfSAfTJNyKqXfiuDg0C25N2RJjTGmEVrhTzhw7oStsIEtsVzT4o2Jo9ALThiEM8IdHIgNaHo8mjNWg6/ske8bohPo+63QOLzmooHp8fyAICBSQkVz0QKdsFQEV6WSW/D+7+BbgbIDHcb4Kp61XyjyI16zZ8JemGltQtDBSGxB4/GoN+7TpkkjDCsFArm0IYv3U0BbnYtf8BCy+JytsE0X6VyuKhPPK/GAJ14kvZZDZVV3pZIb8MZr6n4o4PDGKn0S5SdDmyq5PnXQsk+Xbhinp03FFzmHJw6xYRiWm9VxnohZ3vOcxdO8ARmXRvbWdtzQAAAAAElFTkSuQmCC';
+ Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAkFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OztMTEyRkZHBwcH///9dzWZ0AAAAI3RSTlMEBggKDA4QEhQWFxkbHR8hIyUmKCosLjAxN1hbYc7P0dLc3mzWzBUAAAC+SURBVBjTNY3pcsIwEIM3ePERx/bG5IIe0NIrhVbv/3Y4Ydj9Ic030ogqpY3mDdGGi1EVsYuSvGE2Pkl0TFYAdLGuY1eMWGowzzN6kX41DYVpNbvdKlO4Jx5gSbi2VO+Vcq2jrc/jNLQhtM+n05PfkrKxG/oFHIEXqwqQsVRy7n+AtwLYL3sYR3wA755Jp3Vvv8cn8Js0GXmA7/P5TwzpiLn8MOALuEZNygkm5JTy/+vl4BRVbJvQ1NbWRSxXN64PGOBlhG0qAAAAAElFTkSuQmCC';
+ Favicon.unreadNSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABCklEQVQ4jZ2S0WrDMAxF/TBCCKWMYhZKCSGYmFJMSNjD/mhf239qJXNcjBdTWODgRLpXKJKNMaYROuFTOHEehFb4gJZYrunwxsSXMApOmIQzwgOciE1oRjyaM1aDj+yR7xuiHvT9VmgcXnPRwO/9+wWCgEgJFc1FCwzCVhFclUpuw/u3g3cFyg50GPOjePZ+ocjPeM2RCXthpbUFwQAzsQ2Nx6PeuE+bJo0w7BQI5NKGLN5XAW11LX7BQ8jia7bCLl2kc7mqTLzuxAOeeJH0Wk6VVf0oldyEN15T948CDm+sMiZRfjK0pZIbUwcd+3TphnF62lR8kXN44hAbhmG5WQNnT8zynucsnuYJhFpBfkMzqD4AAAAASUVORK5CYII=';
+ Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAkFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztMTExmzDORkZHBwcH///92I3mvAAAAI3RSTlMEBggKDA4QEhQWFxkbHR8hIyUmKCosLjAxN1hbYc7P0dLc3mzWzBUAAAC+SURBVBjTNY3pcsIwEIM3ePERx/bG5IIe0NIT0ur93w4nDLs/pPlGGlGltNG8IdpwMaoidlGSN8zGJ4mOyQqALtZ17IoRSw3meUYv0q+moTCtZrdbZQr3xAMsCdeW6r1SrnW09XmchjaE9vl0evJbUjZ2Q7+AI/BiVQEylkrO/TfwVgD7ZQ/jiA/g3TPptO7t9/gEfpImIw/wez7/iSEdMZcfBnwB16hJOcGEnFL+f70cnKKKbROa2tq6iOXqBuMXGTe4CAUbAAAAAElFTkSuQmCC';
+ break;
+ case 'Original':
+ Favicon.unreadDead = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
+ Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAAKAAAoAAAoKCg4AAA4ODg7OztMAACRAADBwcH/AAD///+WCcPSAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQmAUAxEb4Isk0rwp3EPR3ECcRQrh7C3/nAasPwzmCgYuPBy5AH/NALSImqAK+H1oJRqyJVHNAnZqDITVhj7/PrAciJ9il0BHs/jjU+fnB9sQ0IxX6OBO6Xr0xKAxANLZzUanCWzZQAAAABJRU5ErkJggg==';
+ Favicon.unreadSFW = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAC6Xw////////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
+ Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OzvBwcH///8uS/CdAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQ2AUAhEbwKWoftRGvdwBEewchM7d9BFbE6pbP4Mgj+R5MjjwgP+qQSkRtQAV8K3lVI2Q648oknIRpWZsMI4988HjgvpU+wO8HgeHzR9cjZYhoRiPkcDd0rXpyUAiRd5YjKC7MvNRgAAAABJRU5ErkJggg==';
+ Favicon.unreadNSFW = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAGbMM////////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
+ Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztmzDPBwcH///+rsf3XAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQ2AUAhEbwKWofRL4x6O4AhuopWb2P4F7E5prP4MgiaSHHlceMA/jYC0iBrgSnjdKaUacuURTUI2qsyEFcaxvD6wnkifYleAx/N449Mn5wfbkFDM52jgTun6tAQg8QAEvjQg42KY2AAAAABJRU5ErkJggg==';
}
- this.text = '\u00A0(OP)';
- return Post.prototype.callbacks.push({
- name: 'Mark OP Quotes',
+ if (Favicon.SFW) {
+ Favicon.unread = Favicon.unreadSFW;
+ return Favicon.unreadY = Favicon.unreadSFWY;
+ } else {
+ Favicon.unread = Favicon.unreadNSFW;
+ return Favicon.unreadY = Favicon.unreadNSFWY;
+ }
+ },
+ empty: 'data:image/gif;base64,R0lGODlhEAAQAJEAAAAAAP///9vb2////yH5BAEAAAMALAAAAAAQABAAAAIvnI+pq+D9DBAUoFkPFnbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw==',
+ dead: 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAIALAAAAAAQABAAAAIvlI+pq+D9DAgUoFkPDlbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw=='
+ };
+
+ ThreadExcerpt = {
+ init: function() {
+ if (g.VIEW !== 'thread' || !Conf['Thread Excerpt']) {
+ return;
+ }
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Excerpt',
cb: this.node
});
},
node: function() {
- var boardID, op, postID, quotelink, quotelinks, quotes, _i, _j, _len, _len1, _ref;
-
- if (this.isClone && this.thread === this.context.thread) {
- return;
- }
- if (!(quotes = this.quotes).length) {
- return;
- }
- quotelinks = this.nodes.quotelinks;
- if (this.isClone && quotes.contains(this.thread.fullID)) {
- for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
- quotelink = quotelinks[_i];
- quotelink.textContent = quotelink.textContent.replace(QuoteOP.text, '');
- }
- }
- op = (this.isClone ? this.context : this).thread.fullID;
- if (!quotes.contains(op)) {
- return;
- }
- for (_j = 0, _len1 = quotelinks.length; _j < _len1; _j++) {
- quotelink = quotelinks[_j];
- _ref = Get.postDataFromLink(quotelink), boardID = _ref.boardID, postID = _ref.postID;
- if (("" + boardID + "." + postID) === op) {
- $.add(quotelink, $.tn(QuoteOP.text));
- }
- }
+ return d.title = Get.threadExcerpt(this);
}
};
- QuotePreview = {
+ ThreadStats = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Quote Previewing']) {
+ var sc;
+
+ if (g.VIEW !== 'thread' || !Conf['Thread Stats']) {
return;
}
- if (Conf['Comment Expansion']) {
- ExpandComment.callbacks.push(this.node);
- }
- return Post.prototype.callbacks.push({
- name: 'Quote Previewing',
+ this.dialog = sc = $.el('span', {
+ innerHTML: "0 / 0",
+ id: 'thread-stats'
+ });
+ this.postCountEl = $('#post-count', sc);
+ this.fileCountEl = $('#file-count', sc);
+ Header.addShortcut(sc);
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Stats',
cb: this.node
});
},
node: function() {
- var link, _i, _len, _ref;
+ var ID, fileCount, post, postCount, _ref;
- _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- link = _ref[_i];
- $.on(link, 'mouseover', QuotePreview.mouseover);
+ postCount = 0;
+ fileCount = 0;
+ _ref = this.posts;
+ for (ID in _ref) {
+ post = _ref[ID];
+ postCount++;
+ if (post.file) {
+ fileCount++;
+ }
}
+ ThreadStats.thread = this;
+ ThreadStats.update(postCount, fileCount);
+ return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate);
},
- mouseover: function(e) {
- var boardID, clone, origin, post, postID, posts, qp, quote, quoterID, threadID, _i, _j, _len, _len1, _ref, _ref1;
+ onUpdate: function(e) {
+ var fileCount, postCount, _ref;
- if ($.hasClass(this, 'inlined')) {
+ if (e.detail[404]) {
return;
}
- _ref = Get.postDataFromLink(this), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
- qp = $.el('div', {
- id: 'qp',
- className: 'dialog'
- });
- $.add(Header.hover, qp);
- Get.postClone(boardID, threadID, postID, qp, Get.contextFromLink(this));
- UI.hover({
- root: this,
- el: qp,
- latestEvent: e,
- endEvents: 'mouseout click',
- cb: QuotePreview.mouseout,
- asapTest: function() {
- return qp.firstElementChild;
- }
- });
- if (!(origin = g.posts["" + boardID + "." + postID])) {
- return;
- }
- if (Conf['Quote Highlighting']) {
- posts = [origin].concat(origin.clones);
- posts.pop();
- for (_i = 0, _len = posts.length; _i < _len; _i++) {
- post = posts[_i];
- $.addClass(post.nodes.post, 'qphl');
- }
- }
- quoterID = $.x('ancestor::*[@id][1]', this).id.match(/\d+$/)[0];
- clone = Get.postFromRoot(qp.firstChild);
- _ref1 = clone.nodes.quotelinks.concat(__slice.call(clone.nodes.backlinks));
- for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
- quote = _ref1[_j];
- if (quote.hash.slice(2) === quoterID) {
- $.addClass(quote, 'forwardlink');
- }
- }
+ _ref = e.detail, postCount = _ref.postCount, fileCount = _ref.fileCount;
+ return ThreadStats.update(postCount, fileCount);
},
- mouseout: function() {
- var clone, post, root, _i, _len, _ref;
+ update: function(postCount, fileCount) {
+ var fileCountEl, postCountEl, thread;
- if (!(root = this.el.firstElementChild)) {
- return;
- }
- clone = Get.postFromRoot(root);
- post = clone.origin;
- post.rmClone(root.dataset.clone);
- if (!Conf['Quote Highlighting']) {
- return;
- }
- _ref = [post].concat(post.clones);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- post = _ref[_i];
- $.rmClass(post.nodes.post, 'qphl');
- }
+ thread = ThreadStats.thread, postCountEl = ThreadStats.postCountEl, fileCountEl = ThreadStats.fileCountEl;
+ postCountEl.textContent = postCount;
+ fileCountEl.textContent = fileCount;
+ (thread.postLimit && !thread.isSticky ? $.addClass : $.rmClass)(postCountEl, 'warning');
+ return (thread.fileLimit && !thread.isSticky ? $.addClass : $.rmClass)(fileCountEl, 'warning');
}
};
- /*
- <3 aeosynth
- */
-
-
- QuoteThreading = {
+ ThreadUpdater = {
init: function() {
- var input;
+ var checked, conf, el, input, name, sc, settings, subEntries, _ref;
- if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
+ if (g.VIEW !== 'thread' || !Conf['Thread Updater']) {
return;
}
- this.enabled = true;
- this.controls = $.el('span', {
- innerHTML: ''
+ checked = Conf['Auto Update'] ? 'checked' : '';
+ this.dialog = sc = $.el('span', {
+ innerHTML: "",
+ id: 'updater'
+ });
+ this.timer = $('#update-timer', sc);
+ this.status = $('#update-status', sc);
+ $.on(this.timer, 'click', ThreadUpdater.update);
+ $.on(this.status, 'click', ThreadUpdater.update);
+ this.checkPostCount = 0;
+ Header.addShortcut(sc);
+ subEntries = [];
+ _ref = Config.updater.checkbox;
+ for (name in _ref) {
+ conf = _ref[name];
+ checked = Conf[name] ? 'checked' : '';
+ el = $.el('label', {
+ title: "" + conf[1],
+ innerHTML: " " + name
+ });
+ input = el.firstElementChild;
+ $.on(input, 'change', $.cb.checked);
+ if (input.name === 'Scroll BG') {
+ $.on(input, 'change', ThreadUpdater.cb.scrollBG);
+ ThreadUpdater.cb.scrollBG();
+ }
+ subEntries.push({
+ el: el
+ });
+ }
+ settings = $.el('span', {
+ innerHTML: 'Interval'
+ });
+ $.on(settings, 'click', this.intervalShortcut);
+ subEntries.push({
+ el: settings
});
- input = $('input', this.controls);
- $.on(input, 'change', QuoteThreading.toggle);
$.event('AddMenuEntry', {
type: 'header',
- el: this.controls,
- order: 98
+ el: $.el('span', {
+ textContent: 'Updater'
+ }),
+ order: 110,
+ subEntries: subEntries
});
- $.on(d, '4chanXInitFinished', this.setup);
- return Post.prototype.callbacks.push({
- name: 'Quote Threading',
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Updater',
cb: this.node
});
},
- setup: function() {
- var ID, post, posts;
-
- $.off(d, '4chanXInitFinished', QuoteThreading.setup);
- posts = g.posts;
- for (ID in posts) {
- post = posts[ID];
- if (post.cb) {
- post.cb.call(post);
- }
- }
- return QuoteThreading.hasRun = true;
- },
node: function() {
- var ID, fullID, keys, len, post, posts, qid, quote, quotes, uniq, _i, _len;
+ ThreadUpdater.thread = this;
+ ThreadUpdater.root = this.OP.nodes.root.parentNode;
+ ThreadUpdater.lastPost = +ThreadUpdater.root.lastElementChild.id.match(/\d+/)[0];
+ ThreadUpdater.outdateCount = 0;
+ ThreadUpdater.lastModified = '0';
+ ThreadUpdater.cb.interval.call($.el('input', {
+ value: Conf['Interval']
+ }));
+ $.on(window, 'online offline', ThreadUpdater.cb.online);
+ $.on(d, 'QRPostSuccessful', ThreadUpdater.cb.post);
+ $.on(d, 'visibilitychange', ThreadUpdater.cb.visibility);
+ return ThreadUpdater.cb.online();
+ },
+ /*
+ http://freesound.org/people/pierrecartoons1979/sounds/90112/
+ cc-by-nc-3.0
+ */
- if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) {
+ beep: 'data:audio/wav;base64,UklGRjQDAABXQVZFZm10IBAAAAABAAEAgD4AAIA+AAABAAgAc21wbDwAAABBAAADAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkYXRhzAIAAGMms8em0tleMV4zIpLVo8nhfSlcPR102Ki+5JspVEkdVtKzs+K1NEhUIT7DwKrcy0g6WygsrM2k1NpiLl0zIY/WpMrjgCdbPhxw2Kq+5Z4qUkkdU9K1s+K5NkVTITzBwqnczko3WikrqM+l1NxlLF0zIIvXpsnjgydZPhxs2ay95aIrUEkdUdC3suK8N0NUIjq+xKrcz002WioppdGm091pK1w0IIjYp8jkhydXPxxq2K295aUrTkoeTs65suK+OUFUIzi7xqrb0VA0WSoootKm0t5tKlo1H4TYqMfkiydWQBxm16+85actTEseS8y7seHAPD9TIza5yKra01QyWSson9On0d5wKVk2H4DYqcfkjidUQB1j1rG75KsvSkseScu8seDCPz1TJDW2yara1FYxWSwnm9Sn0N9zKVg2H33ZqsXkkihSQR1g1bK65K0wSEsfR8i+seDEQTxUJTOzy6rY1VowWC0mmNWoz993KVc3H3rYq8TklSlRQh1d1LS647AyR0wgRMbAsN/GRDpTJTKwzKrX1l4vVy4lldWpzt97KVY4IXbUr8LZljVPRCxhw7W3z6ZISkw1VK+4sMWvXEhSPk6buay9sm5JVkZNiLWqtrJ+TldNTnquqbCwilZXU1BwpKirrpNgWFhTaZmnpquZbFlbVmWOpaOonHZcXlljhaGhpZ1+YWBdYn2cn6GdhmdhYGN3lp2enIttY2Jjco+bnJuOdGZlZXCImJqakHpoZ2Zug5WYmZJ/bGlobX6RlpeSg3BqaW16jZSVkoZ0bGtteImSk5KIeG5tbnaFkJKRinxxbm91gY2QkIt/c3BwdH6Kj4+LgnZxcXR8iI2OjIR5c3J0e4WLjYuFe3VzdHmCioyLhn52dHR5gIiKioeAeHV1eH+GiYqHgXp2dnh9hIiJh4J8eHd4fIKHiIeDfXl4eHyBhoeHhH96eHmA',
+ cb: {
+ online: function() {
+ if (ThreadUpdater.online = navigator.onLine) {
+ ThreadUpdater.outdateCount = 0;
+ ThreadUpdater.set('timer', ThreadUpdater.getInterval());
+ ThreadUpdater.update();
+ ThreadUpdater.set('status', null, null);
+ } else {
+ ThreadUpdater.set('timer', null);
+ ThreadUpdater.set('status', 'Offline', 'warning');
+ }
+ return ThreadUpdater.cb.autoUpdate();
+ },
+ post: function(e) {
+ if (e.detail.threadID !== ThreadUpdater.thread.ID) {
+ return;
+ }
+ ThreadUpdater.outdateCount = 0;
+ if (ThreadUpdater.seconds > 2) {
+ return setTimeout(ThreadUpdater.update, 1000);
+ }
+ },
+ checkpost: function() {
+ if (!(g.DEAD || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 10)) {
+ return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * 500);
+ }
+ ThreadUpdater.checkPostCount = 0;
+ delete ThreadUpdater.foundPost;
+ return delete ThreadUpdater.postID;
+ },
+ visibility: function() {
+ if (d.hidden) {
+ return;
+ }
+ ThreadUpdater.outdateCount = 0;
+ if (ThreadUpdater.seconds > ThreadUpdater.interval) {
+ return ThreadUpdater.set('timer', ThreadUpdater.getInterval());
+ }
+ },
+ scrollBG: function() {
+ return ThreadUpdater.scrollBG = Conf['Scroll BG'] ? function() {
+ return true;
+ } : function() {
+ return !d.hidden;
+ };
+ },
+ autoUpdate: function() {
+ if (ThreadUpdater.online) {
+ return ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
+ } else {
+ return clearTimeout(ThreadUpdater.timeoutID);
+ }
+ },
+ interval: function() {
+ var val;
+
+ val = +this.value;
+ if (val < 1) {
+ val = 1;
+ }
+ ThreadUpdater.interval = this.value = val;
+ return $.cb.value.call(this);
+ },
+ load: function() {
+ var klass, req, text, _ref;
+
+ req = ThreadUpdater.req;
+ switch (req.status) {
+ case 200:
+ g.DEAD = false;
+ ThreadUpdater.parse(JSON.parse(req.response).posts);
+ ThreadUpdater.lastModified = req.getResponseHeader('Last-Modified');
+ ThreadUpdater.set('timer', ThreadUpdater.getInterval());
+ break;
+ case 404:
+ g.DEAD = true;
+ ThreadUpdater.set('timer', null);
+ ThreadUpdater.set('status', '404', 'warning');
+ clearTimeout(ThreadUpdater.timeoutID);
+ ThreadUpdater.thread.kill();
+ $.event('ThreadUpdate', {
+ 404: true,
+ thread: ThreadUpdater.thread
+ });
+ break;
+ default:
+ ThreadUpdater.outdateCount++;
+ ThreadUpdater.set('timer', ThreadUpdater.getInterval());
+ /*
+ Status Code 304: Not modified
+ By sending the `If-Modified-Since` header we get a proper status code, and no response.
+ This saves bandwidth for both the user and the servers and avoid unnecessary computation.
+ */
+
+ _ref = [0, 304].contains(req.status) ? [null, null] : ["" + req.statusText + " (" + req.status + ")", 'warning'], text = _ref[0], klass = _ref[1];
+ ThreadUpdater.set('status', text, klass);
+ }
+ if (ThreadUpdater.postID) {
+ ThreadUpdater.cb.checkpost(this.status);
+ }
+ return delete ThreadUpdater.req;
+ }
+ },
+ getInterval: function() {
+ var i, j;
+
+ i = ThreadUpdater.interval;
+ j = Math.min(ThreadUpdater.outdateCount, 10);
+ if (!d.hidden) {
+ j = Math.min(j, 7);
+ }
+ return ThreadUpdater.seconds = Conf['Optional Increase'] ? Math.max(i, [0, 5, 10, 15, 20, 30, 60, 90, 120, 240, 300][j]) : i;
+ },
+ intervalShortcut: function() {
+ var settings;
+
+ Settings.open('Advanced');
+ settings = $.id('fourchanx-settings');
+ return $('input[name=Interval]', settings).focus();
+ },
+ set: function(name, text, klass) {
+ var el, node;
+
+ el = ThreadUpdater[name];
+ if (node = el.firstChild) {
+ node.data = text;
+ } else {
+ el.textContent = text;
+ }
+ if (klass !== void 0) {
+ return el.className = klass;
+ }
+ },
+ timeout: function() {
+ var n;
+
+ ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
+ if (!(n = --ThreadUpdater.seconds)) {
+ return ThreadUpdater.update();
+ } else if (n <= -60) {
+ ThreadUpdater.set('status', 'Retrying', null);
+ return ThreadUpdater.update();
+ } else if (n > 0) {
+ return ThreadUpdater.set('timer', n);
+ }
+ },
+ update: function() {
+ var url;
+
+ if (!ThreadUpdater.online) {
return;
}
- quotes = this.quotes, ID = this.ID, fullID = this.fullID;
- posts = g.posts;
- if (!(post = posts[fullID]) || post.isHidden) {
+ ThreadUpdater.seconds = 0;
+ ThreadUpdater.set('timer', '...');
+ if (ThreadUpdater.req) {
+ ThreadUpdater.req.onloadend = null;
+ ThreadUpdater.req.abort();
+ }
+ url = "//api.4chan.org/" + ThreadUpdater.thread.board + "/res/" + ThreadUpdater.thread + ".json";
+ return ThreadUpdater.req = $.ajax(url, {
+ onloadend: ThreadUpdater.cb.load
+ }, {
+ headers: {
+ 'If-Modified-Since': ThreadUpdater.lastModified
+ }
+ });
+ },
+ updateThreadStatus: function(title, OP) {
+ var icon, message, root, titleLC;
+
+ titleLC = title.toLowerCase();
+ if (ThreadUpdater.thread["is" + title] === !!OP[titleLC]) {
return;
}
- uniq = {};
- len = ("" + g.BOARD).length + 1;
- for (_i = 0, _len = quotes.length; _i < _len; _i++) {
- quote = quotes[_i];
- qid = quote;
- if (!(qid.slice(len) < ID)) {
+ if (!(ThreadUpdater.thread["is" + title] = !!OP[titleLC])) {
+ message = title === 'Sticky' ? 'The thread is not a sticky anymore.' : 'The thread is not closed anymore.';
+ new Notification('info', message, 30);
+ $.rm($("." + titleLC + "Icon", ThreadUpdater.thread.OP.nodes.info));
+ return;
+ }
+ message = title === 'Sticky' ? 'The thread is now a sticky.' : 'The thread is now closed.';
+ new Notification('info', message, 30);
+ icon = $.el('img', {
+ src: "//static.4chan.org/image/" + titleLC + ".gif",
+ alt: title,
+ title: title,
+ className: "" + titleLC + "Icon"
+ });
+ root = $('[title="Quote this post"]', ThreadUpdater.thread.OP.nodes.info);
+ if (title === 'Closed') {
+ root = $('.stickyIcon', ThreadUpdater.thread.OP.nodes.info) || root;
+ }
+ return $.after(root, [$.tn(' '), icon]);
+ },
+ parse: function(postObjects) {
+ var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, scroll, _i, _len, _ref;
+
+ OP = postObjects[0];
+ Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
+ ThreadUpdater.updateThreadStatus('Sticky', OP);
+ ThreadUpdater.updateThreadStatus('Closed', OP);
+ ThreadUpdater.thread.postLimit = !!OP.bumplimit;
+ ThreadUpdater.thread.fileLimit = !!OP.imagelimit;
+ posts = [];
+ index = [];
+ files = [];
+ count = 0;
+ for (_i = 0, _len = postObjects.length; _i < _len; _i++) {
+ postObject = postObjects[_i];
+ num = postObject.no;
+ index.push(num);
+ if (postObject.fsize) {
+ files.push(num);
+ }
+ if (num <= ThreadUpdater.lastPost) {
continue;
}
- if (qid in posts) {
- uniq[qid.slice(len)] = true;
+ count++;
+ node = Build.postFromObject(postObject, ThreadUpdater.thread.board);
+ posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
+ }
+ deletedPosts = [];
+ deletedFiles = [];
+ _ref = ThreadUpdater.thread.posts;
+ for (ID in _ref) {
+ post = _ref[ID];
+ ID = +ID;
+ if (post.isDead && index.contains(ID)) {
+ post.resurrect();
+ } else if (!index.contains(ID)) {
+ post.kill();
+ deletedPosts.push(post);
+ } else if (post.file && !post.file.isDead && !files.contains(ID)) {
+ post.kill(true);
+ deletedFiles.push(post);
+ }
+ if (ThreadUpdater.postID) {
+ if (ID === ThreadUpdater.postID) {
+ ThreadUpdater.foundPost = true;
+ }
}
}
- keys = Object.keys(uniq);
- if (keys.length !== 1) {
+ if (!count) {
+ ThreadUpdater.set('status', null, null);
+ ThreadUpdater.outdateCount++;
+ } else {
+ ThreadUpdater.set('status', "+" + count, 'new');
+ ThreadUpdater.outdateCount = 0;
+ if (Conf['Beep'] && d.hidden && Unread.posts && !Unread.posts.length) {
+ if (!ThreadUpdater.audio) {
+ ThreadUpdater.audio = $.el('audio', {
+ src: ThreadUpdater.beep
+ });
+ }
+ ThreadUpdater.audio.play();
+ }
+ ThreadUpdater.lastPost = posts[count - 1].ID;
+ Main.callbackNodes(Post, posts);
+ scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25;
+ for (key in posts) {
+ post = posts[key];
+ if (!posts.hasOwnProperty(key)) {
+ continue;
+ }
+ if (post.cb) {
+ if (!post.cb.call(post)) {
+ $.add(ThreadUpdater.root, post.nodes.root);
+ }
+ } else {
+ $.add(ThreadUpdater.root, post.nodes.root);
+ }
+ }
+ if (scroll) {
+ if (Conf['Bottom Scroll']) {
+ doc.scrollTop = d.body.clientHeight;
+ } else {
+ Header.scrollToPost(nodes[0]);
+ }
+ }
+ $.queueTask(function() {
+ var length, threadID;
+
+ threadID = ThreadUpdater.thread.ID;
+ length = $$('.thread > .postContainer', ThreadUpdater.root).length;
+ return Fourchan.parseThread(threadID, length - count, length);
+ });
+ }
+ return $.event('ThreadUpdate', {
+ 404: false,
+ thread: ThreadUpdater.thread,
+ newPosts: posts,
+ deletedPosts: deletedPosts,
+ deletedFiles: deletedFiles,
+ postCount: OP.replies + 1,
+ fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead)
+ });
+ }
+ };
+
+ ThreadWatcher = {
+ init: function() {
+ if (!Conf['Thread Watcher']) {
return;
}
- this.threaded = "" + g.BOARD + "." + keys[0];
- return this.cb = QuoteThreading.nodeinsert;
+ this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', 'Thread Watcher
');
+ $.on(d, 'QRPostSuccessful', this.cb.post);
+ $.on(d, '4chanXInitFinished', this.ready);
+ $.sync('WatchedThreads', this.refresh);
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Watcher',
+ cb: this.node
+ });
},
- nodeinsert: function() {
- var bottom, height, posts, qpost, qroot, threadContainer, top, _ref;
+ node: function() {
+ var favicon,
+ _this = this;
- posts = g.posts;
- qpost = posts[this.threaded];
- delete this.threaded;
- delete this.cb;
- if (this.thread.OP === qpost) {
- return false;
+ favicon = $.el('img', {
+ className: 'favicon'
+ });
+ $.on(favicon, 'click', ThreadWatcher.cb.toggle);
+ $.before($('input', this.OP.nodes.post), favicon);
+ if (g.VIEW !== 'thread') {
+ return;
}
- if (QuoteThreading.hasRun) {
- height = doc.clientHeight;
- _ref = qpost.nodes.root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top;
- if (!(Unread.posts.contains(qpost) || ((bottom < height) && (top > 0)))) {
+ return $.get('AutoWatch', 0, function(item) {
+ if (item['AutoWatch'] !== _this.ID) {
+ return;
+ }
+ ThreadWatcher.watch(_this);
+ return $["delete"]('AutoWatch');
+ });
+ },
+ ready: function() {
+ $.off(d, '4chanXInitFinished', ThreadWatcher.ready);
+ if (!Main.isThisPageLegit()) {
+ return;
+ }
+ ThreadWatcher.refresh();
+ return $.add(d.body, ThreadWatcher.dialog);
+ },
+ refresh: function(watched) {
+ var ID, board, div, favicon, id, link, nodes, props, thread, x, _ref, _ref1;
+
+ if (!watched) {
+ $.get('WatchedThreads', {}, function(item) {
+ return ThreadWatcher.refresh(item['WatchedThreads']);
+ });
+ return;
+ }
+ nodes = [$('.move', ThreadWatcher.dialog)];
+ for (board in watched) {
+ _ref = watched[board];
+ for (id in _ref) {
+ props = _ref[id];
+ x = $.el('a', {
+ textContent: '×',
+ href: 'javascript:;'
+ });
+ $.on(x, 'click', ThreadWatcher.cb.x);
+ link = $.el('a', props);
+ link.title = link.textContent;
+ div = $.el('div');
+ $.add(div, [x, $.tn(' '), link]);
+ nodes.push(div);
+ }
+ }
+ $.rmAll(ThreadWatcher.dialog);
+ $.add(ThreadWatcher.dialog, nodes);
+ watched = watched[g.BOARD] || {};
+ _ref1 = g.BOARD.threads;
+ for (ID in _ref1) {
+ thread = _ref1[ID];
+ favicon = $('.favicon', thread.OP.nodes.post);
+ favicon.src = ID in watched ? Favicon["default"] : Favicon.empty;
+ }
+ },
+ cb: {
+ toggle: function() {
+ return ThreadWatcher.toggle(Get.postFromNode(this).thread);
+ },
+ x: function() {
+ var thread;
+
+ thread = this.nextElementSibling.pathname.split('/');
+ return ThreadWatcher.unwatch(thread[1], thread[3]);
+ },
+ post: function(e) {
+ var board, postID, threadID, _ref;
+
+ _ref = e.detail, board = _ref.board, postID = _ref.postID, threadID = _ref.threadID;
+ if (postID === threadID) {
+ if (Conf['Auto Watch']) {
+ return $.set('AutoWatch', threadID);
+ }
+ } else if (Conf['Auto Watch Reply']) {
+ return ThreadWatcher.watch(board.threads[threadID]);
+ }
+ }
+ },
+ toggle: function(thread) {
+ if ($('.favicon', thread.OP.nodes.post).src === Favicon.empty) {
+ return ThreadWatcher.watch(thread);
+ } else {
+ return ThreadWatcher.unwatch(thread.board, thread.ID);
+ }
+ },
+ unwatch: function(board, threadID) {
+ return $.get('WatchedThreads', {}, function(item) {
+ var watched;
+
+ watched = item['WatchedThreads'];
+ delete watched[board][threadID];
+ if (!Object.keys(watched[board]).length) {
+ delete watched[board];
+ }
+ ThreadWatcher.refresh(watched);
+ return $.set('WatchedThreads', watched);
+ });
+ },
+ watch: function(thread) {
+ return $.get('WatchedThreads', {}, function(item) {
+ var watched, _name;
+
+ watched = item['WatchedThreads'];
+ watched[_name = thread.board] || (watched[_name] = {});
+ watched[thread.board][thread] = {
+ href: "/" + thread.board + "/res/" + thread,
+ textContent: Get.threadExcerpt(thread)
+ };
+ ThreadWatcher.refresh(watched);
+ return $.set('WatchedThreads', watched);
+ });
+ }
+ };
+
+ Unread = {
+ init: function() {
+ if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon']) {
+ return;
+ }
+ this.db = new DataBoard('lastReadPosts', this.sync);
+ this.hr = $.el('hr', {
+ id: 'unread-line'
+ });
+ this.posts = [];
+ this.postsQuotingYou = [];
+ return Thread.prototype.callbacks.push({
+ name: 'Unread',
+ cb: this.node
+ });
+ },
+ node: function() {
+ Unread.thread = this;
+ Unread.title = d.title;
+ Unread.lastReadPost = Unread.db.get({
+ boardID: this.board.ID,
+ threadID: this.ID,
+ defaultValue: 0
+ });
+ $.on(d, '4chanXInitFinished', Unread.ready);
+ $.on(d, 'ThreadUpdate', Unread.onUpdate);
+ $.on(d, 'scroll visibilitychange', Unread.read);
+ if (Conf['Unread Line']) {
+ $.on(d, 'visibilitychange', Unread.setLine);
+ }
+ if (Conf['Scroll to Last Read Post']) {
+ return $.on(window, 'load', Unread.scroll);
+ }
+ },
+ ready: function() {
+ var ID, post, posts, _ref;
+
+ $.off(d, '4chanXInitFinished', Unread.ready);
+ posts = [];
+ _ref = Unread.thread.posts;
+ for (ID in _ref) {
+ post = _ref[ID];
+ if (post.isReply) {
+ posts.push(post);
+ }
+ }
+ return Unread.addPosts(posts);
+ },
+ scroll: function() {
+ var hash, post, posts, prevID, root;
+
+ if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
+ return;
+ }
+ if (Unread.posts.length) {
+ prevID = 0;
+ while (root = $.x('preceding-sibling::div[contains(@class,"postContainer")][1]', Unread.posts[0].nodes.root)) {
+ post = Get.postFromRoot(root);
+ if (prevID === post.ID) {
+ break;
+ }
+ prevID = post.ID;
+ if (!post.isHidden) {
+ break;
+ }
+ }
+ root.scrollIntoView(false);
+ return;
+ }
+ posts = Object.keys(Unread.thread.posts);
+ return Header.scrollToPost(Unread.thread.posts[posts[posts.length - 1]].nodes.root);
+ },
+ sync: function() {
+ var lastReadPost;
+
+ lastReadPost = Unread.db.get({
+ boardID: Unread.thread.board.ID,
+ threadID: Unread.thread.ID,
+ defaultValue: 0
+ });
+ if (!(Unread.lastReadPost < lastReadPost)) {
+ return;
+ }
+ Unread.lastReadPost = lastReadPost;
+ Unread.readArray(Unread.posts);
+ Unread.readArray(Unread.postsQuotingYou);
+ Unread.setLine();
+ return Unread.update();
+ },
+ addPosts: function(newPosts) {
+ var ID, data, post, _i, _len;
+
+ for (_i = 0, _len = newPosts.length; _i < _len; _i++) {
+ post = newPosts[_i];
+ ID = post.ID;
+ if (ID <= Unread.lastReadPost || post.isHidden) {
+ continue;
+ }
+ if (QR.db) {
+ data = {
+ boardID: post.board.ID,
+ threadID: post.thread.ID,
+ postID: post.ID
+ };
+ if (QR.db.get(data)) {
+ continue;
+ }
+ }
+ Unread.posts.push(post);
+ Unread.addPostQuotingYou(post);
+ }
+ if (Conf['Unread Line']) {
+ Unread.setLine(newPosts.contains(Unread.posts[0]));
+ }
+ Unread.read();
+ return Unread.update();
+ },
+ addPostQuotingYou: function(post) {
+ var quotelink, _i, _len, _ref;
+
+ if (!QR.db) {
+ return;
+ }
+ _ref = post.nodes.quotelinks;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ quotelink = _ref[_i];
+ if (QR.db.get(Get.postDataFromLink(quotelink))) {
+ Unread.postsQuotingYou.push(post);
+ }
+ }
+ },
+ onUpdate: function(e) {
+ if (e.detail[404]) {
+ return Unread.update();
+ } else {
+ return Unread.addPosts(e.detail.newPosts);
+ }
+ },
+ readSinglePost: function(post) {
+ var i;
+
+ if ((i = Unread.posts.indexOf(post)) === -1) {
+ return;
+ }
+ Unread.posts.splice(i, 1);
+ if (i === 0) {
+ Unread.lastReadPost = post.ID;
+ Unread.saveLastReadPost();
+ }
+ if ((i = Unread.postsQuotingYou.indexOf(post)) !== -1) {
+ Unread.postsQuotingYou.splice(i, 1);
+ }
+ return Unread.update();
+ },
+ readArray: function(arr) {
+ var i, post, _i, _len;
+
+ for (i = _i = 0, _len = arr.length; _i < _len; i = ++_i) {
+ post = arr[i];
+ if (post.ID > Unread.lastReadPost) {
+ break;
+ }
+ }
+ return arr.splice(0, i);
+ },
+ read: $.debounce(50, function(e) {
+ var ID, bottom, height, i, post, posts, read;
+
+ if (d.hidden || !Unread.posts.length) {
+ return;
+ }
+ height = doc.clientHeight;
+ posts = Unread.posts;
+ read = [];
+ i = posts.length;
+ while (post = posts[--i]) {
+ bottom = post.nodes.root.getBoundingClientRect().bottom;
+ if (bottom < height) {
+ ID = post.ID;
+ posts.remove(post);
+ }
+ }
+ if (!ID) {
+ return;
+ }
+ Unread.lastReadPost = ID;
+ Unread.saveLastReadPost();
+ Unread.readArray(Unread.postsQuotingYou);
+ if (e) {
+ return Unread.update();
+ }
+ }),
+ saveLastReadPost: $.debounce(2 * $.SECOND, function() {
+ return Unread.db.set({
+ boardID: Unread.thread.board.ID,
+ threadID: Unread.thread.ID,
+ val: Unread.lastReadPost
+ });
+ }),
+ setLine: function(force) {
+ var post, root;
+
+ if (!(d.hidden || force === true)) {
+ return;
+ }
+ if (post = Unread.posts[0]) {
+ root = post.nodes.root;
+ if (root !== $('.thread > .replyContainer', root.parentNode)) {
+ return $.before(root, Unread.hr);
+ }
+ } else {
+ return $.rm(Unread.hr);
+ }
+ },
+ update: function() {
+ var count;
+
+ count = Unread.posts.length;
+ if (Conf['Unread Count']) {
+ d.title = "" + (count || !Conf['Hide Unread Count at (0)'] ? "(" + count + ") " : '') + (g.DEAD ? "/" + g.BOARD + "/ - 404" : "" + Unread.title);
+ }
+ if (!Conf['Unread Favicon']) {
+ return;
+ }
+ Favicon.el.href = g.DEAD ? Unread.postsQuotingYou.length ? Favicon.unreadDeadY : count ? Favicon.unreadDead : Favicon.dead : count ? Unread.postsQuotingYou.length ? Favicon.unreadY : Favicon.unread : Favicon["default"];
+ return $.add(d.head, Favicon.el);
+ }
+ };
+
+ Redirect = {
+ init: function() {
+ return $.sync('archs', this.updateArchives);
+ },
+ updateArchives: function() {
+ return $.get('archivers', {}, function(_arg) {
+ var archivers;
+
+ archivers = _arg.archivers;
+ return Conf['archivers'] = archivers;
+ });
+ },
+ image: function(boardID, filename) {
+ switch (boardID) {
+ case 'a':
+ case 'gd':
+ case 'jp':
+ case 'm':
+ case 'q':
+ case 'tg':
+ case 'vg':
+ case 'vp':
+ case 'vr':
+ case 'wsg':
+ return "//archive.foolz.us/" + boardID + "/full_image/" + filename;
+ case 'u':
+ return "//nsfw.foolz.us/" + boardID + "/full_image/" + filename;
+ case 'po':
+ return "//archive.thedarkcave.org/" + boardID + "/full_image/" + filename;
+ case 'hr':
+ case 'tv':
+ return "http://archive.4plebs.org/" + boardID + "/full_image/" + filename;
+ case 'ck':
+ case 'fa':
+ case 'lit':
+ case 's4s':
+ return "//fuuka.warosu.org/" + boardID + "/full_image/" + filename;
+ case 'cgl':
+ case 'g':
+ case 'mu':
+ case 'w':
+ return "//rbt.asia/" + boardID + "/full_image/" + filename;
+ case 'an':
+ case 'k':
+ case 'toy':
+ case 'x':
+ return "http://archive.heinessen.com/" + boardID + "/full_image/" + filename;
+ case 'c':
+ return "//archive.nyafuu.org/" + boardID + "/full_image/" + filename;
+ }
+ },
+ post: function(boardID, postID) {
+ var archive, name, _base, _ref;
+
+ if (Redirect.post[boardID] == null) {
+ _ref = this.archiver;
+ for (name in _ref) {
+ archive = _ref[name];
+ if (archive.type === 'foolfuuka' && archive.boards.contains(boardID)) {
+ Redirect.post[boardID] = archive.base;
+ break;
+ }
+ }
+ (_base = Redirect.post)[boardID] || (_base[boardID] = false);
+ }
+ if (Redirect.post[boardID]) {
+ return "" + Redirect.post[boardID] + "/_/api/chan/post/?board=" + boardID + "&num=" + postID;
+ } else {
+ return null;
+ }
+ },
+ select: function(board) {
+ var archive, name, _ref, _results;
+
+ _ref = this.archiver;
+ _results = [];
+ for (name in _ref) {
+ archive = _ref[name];
+ if (!archive.boards.contains(board)) {
+ continue;
+ }
+ _results.push(name);
+ }
+ return _results;
+ },
+ to: function(data) {
+ var arch, archive, boardID;
+
+ boardID = data.boardID;
+ if ((arch = Conf.archivers[boardID]) == null) {
+ Conf.archivers[boardID] = arch = this.select(boardID)[0];
+ $.set('archivers', Conf.archivers);
+ }
+ return (arch && (archive = this.archiver[arch]) ? Redirect.path(archive.base, archive.type, data) : data.threadID ? "//boards.4chan.org/" + boardID + "/" : null);
+ },
+ archiver: {
+ 'Foolz': {
+ base: 'https://archive.foolz.us',
+ boards: ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'v', 'vg', 'vp', 'vr', 'wsg'],
+ type: 'foolfuuka'
+ },
+ 'NSFWFoolz': {
+ base: 'https://nsfw.foolz.us',
+ boards: ['u'],
+ type: 'foolfuuka'
+ },
+ 'TheDarkCave': {
+ base: 'http://archive.thedarkcave.org',
+ boards: ['c', 'int', 'out', 'po'],
+ type: 'foolfuuka'
+ },
+ '4plebs': {
+ base: 'http://archive.4plebs.org',
+ boards: ['hr', 'tg', 'tv', 'x'],
+ base: 'foolfuuka'
+ },
+ 'Warosu': {
+ base: '//fuuka.warosu.org',
+ boards: ['cgl', 'ck', 'fa', 'jp', 'lit', 's4s', 'q', 'tg'],
+ type: 'fuuka'
+ },
+ 'InstallGentoo': {
+ base: '//archive.installgentoo.net',
+ boards: ['diy', 'g', 'sci'],
+ type: 'fuuka'
+ },
+ 'RebeccaBlackTech': {
+ base: '//rbt.asia',
+ boards: ['an', 'cgl', 'g', 'mu', 'w'],
+ type: 'fuuka_mail'
+ },
+ 'Heinessen': {
+ base: 'http://archive.heinessen.com',
+ boards: ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x'],
+ type: 'fuuka'
+ },
+ 'Cliche': {
+ base: '//www.cliché.net/4chan/cgi-board.pl',
+ boards: ['e'],
+ type: 'fuuka'
+ },
+ 'NyaFuu': {
+ base: '//archive.nyafuu.org',
+ boards: ['c', 'w'],
+ type: 'fuuka'
+ }
+ },
+ path: function(base, archiver, data) {
+ var boardID, path, postID, threadID, type, value;
+
+ if (data.isSearch) {
+ boardID = data.boardID, type = data.type, value = data.value;
+ type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type;
+ value = encodeURIComponent(value);
+ if (archiver === 'foolfuuka') {
+ return "" + base + "/" + boardID + "/search/" + type + "/" + value;
+ } else if (type === 'image') {
+ return "" + base + "/" + boardID + "/?task=search2&search_media_hash=" + value;
+ } else {
+ return "" + base + "/" + boardID + "/?task=search2&search_" + type + "=" + value;
+ }
+ }
+ boardID = data.boardID, threadID = data.threadID, postID = data.postID;
+ path = threadID ? "" + boardID + "/thread/" + threadID : "" + boardID + "/post/" + postID;
+ if (archiver === 'foolfuuka') {
+ path += '/';
+ }
+ if (threadID && postID) {
+ path += archiver === 'foolfuuka' ? "#" + postID : "#p" + postID;
+ }
+ return "" + base + "/" + path;
+ }
+ };
+
+ PSAHiding = {
+ init: function() {
+ var entry;
+
+ if (!Conf['Announcement Hiding']) {
+ return;
+ }
+ entry = {
+ type: 'header',
+ el: $.el('a', {
+ textContent: 'Show announcement',
+ className: 'show-announcement',
+ href: 'javascript:;'
+ }),
+ order: 50,
+ open: function() {
+ var _ref;
+
+ if ((_ref = $.id('globalMessage')) != null ? _ref.hidden : void 0) {
+ return true;
+ }
return false;
}
+ };
+ $.event('AddMenuEntry', entry);
+ $.on(entry.el, 'click', PSAHiding.toggle);
+ $.addClass(doc, 'hide-announcement');
+ return $.on(d, '4chanXInitFinished', this.setup);
+ },
+ setup: function() {
+ var btn, psa;
+
+ $.off(d, '4chanXInitFinished', PSAHiding.setup);
+ if (!(psa = $.id('globalMessage'))) {
+ $.rmClass(doc, 'hide-announcement');
+ return;
}
- qroot = qpost.nodes.root;
- if (!$.hasClass(qroot, 'threadOP')) {
- $.addClass(qroot, 'threadOP');
- threadContainer = $.el('div', {
- className: 'threadContainer'
- });
- $.after(qroot, threadContainer);
- } else {
- threadContainer = qroot.nextSibling;
+ PSAHiding.btn = btn = $.el('a', {
+ innerHTML: '[ - ]',
+ title: 'Hide announcement.',
+ className: 'hide-announcement',
+ href: 'javascript:;'
+ });
+ $.on(btn, 'click', PSAHiding.toggle);
+ $.get('hiddenPSAs', [], function(item) {
+ PSAHiding.sync(item['hiddenPSAs']);
+ $.before(psa, btn);
+ return $.rmClass(doc, 'hide-announcement');
+ });
+ return $.sync('hiddenPSAs', PSAHiding.sync);
+ },
+ toggle: function(e) {
+ var hide, text;
+
+ hide = $.hasClass(this, 'hide-announcement');
+ text = PSAHiding.trim($.id('globalMessage'));
+ return $.get('hiddenPSAs', [], function(_arg) {
+ var hiddenPSAs, i;
+
+ hiddenPSAs = _arg.hiddenPSAs;
+ if (hide) {
+ hiddenPSAs.push(text);
+ hiddenPSAs = hiddenPSAs.slice(-5);
+ } else {
+ $.event('CloseMenu');
+ i = hiddenPSAs.indexOf(text);
+ hiddenPSAs.splice(i, 1);
+ }
+ PSAHiding.sync(hiddenPSAs);
+ return $.set('hiddenPSAs', hiddenPSAs);
+ });
+ },
+ sync: function(hiddenPSAs) {
+ var hr, psa, _ref;
+
+ psa = $.id('globalMessage');
+ psa.hidden = PSAHiding.btn.hidden = (_ref = PSAHiding.trim(psa), __indexOf.call(hiddenPSAs, _ref) >= 0) ? true : false;
+ if ((hr = psa.nextElementSibling) && hr.nodeName === 'HR') {
+ return hr.hidden = psa.hidden;
}
- $.add(threadContainer, this.nodes.root);
- return true;
+ },
+ trim: function(psa) {
+ return psa.textContent.replace(/\W+/g, '').toLowerCase();
+ }
+ };
+
+ CatalogLinks = {
+ init: function() {
+ var el, input;
+
+ if (!Conf['Catalog Links']) {
+ return;
+ }
+ el = $.el('label', {
+ id: 'toggleCatalog',
+ href: 'javascript:;',
+ innerHTML: "Catalog Links",
+ title: "Turn catalog links " + (Conf['Header catalog links'] ? 'off' : 'on') + "."
+ });
+ input = $('input', el);
+ $.on(input, 'change', this.toggle);
+ $.sync('Header catalog links', CatalogLinks.set);
+ $.event('AddMenuEntry', {
+ type: 'header',
+ el: el,
+ order: 95
+ });
+ return $.on(d, '4chanXInitFinished', function() {
+ return CatalogLinks.set(Conf['Header catalog links']);
+ });
},
toggle: function() {
- var container, containers, node, nodes, replies, reply, thread, _i, _j, _len, _len1;
+ var useCatalog;
- thread = $('.thread');
- replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread);
- QuoteThreading.enabled = this.checked;
- if (this.checked) {
- nodes = (function() {
- var _i, _len, _results;
-
- _results = [];
- for (_i = 0, _len = replies.length; _i < _len; _i++) {
- reply = replies[_i];
- _results.push(Get.postFromNode(reply));
- }
- return _results;
- })();
- for (_i = 0, _len = nodes.length; _i < _len; _i++) {
- node = nodes[_i];
- QuoteThreading.node(node);
- }
- } else {
- replies.sort(function(a, b) {
- var aID, bID;
-
- aID = Number(a.id.slice(2));
- bID = Number(b.id.slice(2));
- return aID - bID;
- });
- $.add(thread, replies);
- containers = $$('.threadContainer', thread);
- for (_j = 0, _len1 = containers.length; _j < _len1; _j++) {
- container = containers[_j];
- $.rm(container);
- }
- Unread.update(true);
- }
+ $.event('CloseMenu');
+ $.set('Header catalog links', useCatalog = this.checked);
+ return CatalogLinks.set(useCatalog);
},
- kb: function() {
- var control;
+ set: function(useCatalog) {
+ var a, board, path, _i, _len, _ref;
- control = $.id('threadingControl');
- return control.click();
- }
- };
-
- QuoteYou = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Mark Quotes of You'] || !Conf['Quick Reply']) {
- return;
- }
- this.text = '\u00A0(You)';
- return Post.prototype.callbacks.push({
- name: 'Mark Quotes of You',
- cb: this.node
- });
- },
- node: function() {
- var quotelink, quotelinks, quotes, _i, _len;
-
- if (this.isClone) {
- return;
- }
- if (this.info.yours) {
- $.addClass(this.nodes.root, 'yourPost');
- }
- if (Conf['Highlight Own Posts']) {
- $.addClass(doc, 'highlight-own');
- }
- if (!(quotes = this.quotes).length) {
- return;
- }
- quotelinks = this.nodes.quotelinks;
- for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
- quotelink = quotelinks[_i];
- if (QR.db.get(Get.postDataFromLink(quotelink))) {
- $.add(quotelink, $.tn(QuoteYou.text));
- }
- }
- }
- };
-
- Quotify = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Resurrect Quotes']) {
- return;
- }
- if (Conf['Comment Expansion']) {
- ExpandComment.callbacks.push(this.node);
- }
- return Post.prototype.callbacks.push({
- name: 'Resurrect Quotes',
- cb: this.node
- });
- },
- node: function() {
- var deadlink, _i, _len, _ref;
-
- _ref = $$('.deadlink', this.nodes.comment);
+ path = useCatalog ? 'catalog' : '';
+ _ref = $$("#board-list a[href*=\"boards.4chan.org\"],\n#boardNavDesktop a[href*=\"boards.4chan.org\"],\n#boardNavDesktopFoot a[href*=\"boards.4chan.org\"]");
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- deadlink = _ref[_i];
- if (this.isClone) {
- if ($.hasClass(deadlink, 'quotelink')) {
- this.nodes.quotelinks.push(deadlink);
- }
- } else {
- Quotify.parseDeadlink.call(this, deadlink);
+ a = _ref[_i];
+ board = a.pathname.split('/')[1];
+ if (['f', 'status', '4chan'].contains(board) || !board) {
+ continue;
}
+ if (Conf['External Catalog']) {
+ a.href = useCatalog ? CatalogLinks.external(board) : "//boards.4chan.org/" + board + "/";
+ } else {
+ a.pathname = "/" + board + "/" + path;
+ }
+ a.title = useCatalog ? "" + a.title + " - Catalog" : a.title.replace(/\ -\ Catalog$/, '');
+ }
+ return this.title = "Turn catalog links " + (useCatalog ? 'off' : 'on') + ".";
+ },
+ external: function(board) {
+ return (['a', 'c', 'g', 'co', 'k', 'm', 'o', 'p', 'v', 'vg', 'w', 'cm', '3', 'adv', 'an', 'cgl', 'ck', 'diy', 'fa', 'fit', 'int', 'jp', 'mlp', 'lit', 'mu', 'n', 'po', 'sci', 'toy', 'trv', 'tv', 'vp', 'x', 'q'].contains(board) ? "http://catalog.neet.tv/" + board : ['d', 'e', 'gif', 'h', 'hr', 'hc', 'r9k', 's', 'pol', 'soc', 'u', 'i', 'ic', 'hm', 'r', 'w', 'wg', 'wsg', 't', 'y'].contains(board) ? "http://4index.gropes.us/" + board : "//boards.4chan.org/" + board + "/catalog");
+ }
+ };
+
+ IDColor = {
+ init: function() {
+ if (!Conf['Color User IDs']) {
+ return;
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Reveal Spoilers',
+ cb: this.node
+ });
+ },
+ node: function(post) {
+ var str, uid;
+
+ if (!(uid = $('.hand', this.nodes.uniqueID))) {
+ return;
+ }
+ str = this.info.uniqueID;
+ if (uid.nodeName === 'SPAN') {
+ return uid.style.cssText = IDColor.apply.call(str);
}
},
- parseDeadlink: function(deadlink) {
- var a, boardID, m, post, postID, quote, quoteID, redirect, _ref;
+ ids: {},
+ compute: function(str) {
+ var hash, rgb;
- if (deadlink.parentNode.className === 'prettyprint') {
- $.replace(deadlink, __slice.call(deadlink.childNodes));
- return;
- }
- quote = deadlink.textContent;
- if (!(postID = (_ref = quote.match(/\d+$/)) != null ? _ref[0] : void 0)) {
- return;
- }
- boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID;
- quoteID = "" + boardID + "." + postID;
- if (post = g.posts[quoteID]) {
- if (!post.isDead) {
- a = $.el('a', {
- href: "/" + boardID + "/" + post.thread + "/res/#p" + postID,
- className: 'quotelink',
- textContent: quote
- });
- } else {
- a = $.el('a', {
- href: "/" + boardID + "/" + post.thread + "/res/#p" + postID,
- className: 'quotelink deadlink',
- target: '_blank',
- textContent: "" + quote + "\u00A0(Dead)"
- });
- a.setAttribute('data-boardid', boardID);
- a.setAttribute('data-threadid', post.thread.ID);
- a.setAttribute('data-postid', postID);
- }
- } else if (redirect = Redirect.to({
- boardID: boardID,
- threadID: 0,
- postID: postID
- })) {
- a = $.el('a', {
- href: redirect,
- className: 'deadlink',
- target: '_blank',
- textContent: "" + quote + "\u00A0(Dead)"
- });
- if (Redirect.post(boardID, postID)) {
- $.addClass(a, 'quotelink');
- a.setAttribute('data-boardid', boardID);
- a.setAttribute('data-postid', postID);
- }
- }
- if (__indexOf.call(this.quotes, quoteID) < 0) {
- this.quotes.push(quoteID);
- }
- if (!a) {
- deadlink.textContent = "" + quote + "\u00A0(Dead)";
- return;
- }
- $.replace(deadlink, a);
- if ($.hasClass(a, 'quotelink')) {
- return this.nodes.quotelinks.push(a);
+ hash = this.hash(str);
+ rgb = [(hash >> 24) & 0xFF, (hash >> 16) & 0xFF, (hash >> 8) & 0xFF];
+ rgb[3] = ((rgb[0] * 0.299) + (rgb[1] * 0.587) + (rgb[2] * 0.114)) > 125;
+ this.ids[str] = rgb;
+ return rgb;
+ },
+ apply: function() {
+ var rgb;
+
+ rgb = IDColor.ids[this] || IDColor.compute(this);
+ return ("background-color: rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "); color: ") + (rgb[3] ? "black;" : "white; border-radius: 3px; padding: 0px 2px;");
+ },
+ hash: function(str) {
+ var i, j, msg;
+
+ msg = 0;
+ i = 0;
+ j = str.length;
+ while (i < j) {
+ msg = ((msg << 5) - msg) + str.charCodeAt(i);
+ ++i;
}
+ return msg;
}
};
@@ -8938,6 +7772,1172 @@
}
};
+ Emoji = {
+ init: function() {
+ var css, icon, name, pos, _ref;
+
+ if (!Conf['Emoji']) {
+ return;
+ }
+ pos = Conf['emojiPos'];
+ css = ["a.useremail[href]:last-of-type::" + pos + " {\n vertical-align: top;\n margin-" + (pos === "before" ? "right" : "left") + ": 5px;\n}\n"];
+ this.icons["PlanNine"] = Emoji.icons["Plan9"];
+ this.icons['Sage'] = Emoji.sage[Conf['sageEmoji']];
+ _ref = this.icons;
+ for (name in _ref) {
+ icon = _ref[name];
+ if (!this.icons.hasOwnProperty(name)) {
+ continue;
+ }
+ css.push("a.useremail[href*='" + name + "']:last-of-type::" + pos + ",\na.useremail[href*='" + (name.toLowerCase()) + "']:last-of-type::" + pos + ",\na.useremail[href*='" + (name.toUpperCase()) + "']:last-of-type::" + pos + " {\n content: url('data:image/png;base64," + icon + "');\n}\n");
+ }
+ return $.addStyle(css.join(""), 'emoji');
+ },
+ sage: {
+ '4chan SS': 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAYAAACZ3F9/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAa9JREFUKFOdkt0rg2EUwM95b2zlL0CRRLngksznXrJsNtYW1tjYhM3mY6+IXZAbikhTKJp8XZAp81UmWYhIRHHhUi60e7s6ntdCa2449es8PfU7z+k5B6AbyuE/wQlc4BcO2d06unAUBCgFE0hianOd3NHIcy8NPwrUf9NBPZcOEi7ayXZiea/1V7+ljaXeYAfOgg2So2TOwQWGnwQafOgi962TnMFmatozUeNu4yetASspVvgXiUvii5K5Nm6z56ol3Hdtpy+cwSYy+HRUt1nLsoEato0kXyh6wTac+24brThWv6MNOYNW9prlG/uxmbRrFaT0VrCspZoNPSUNJNyCBcoiLZuhLH0o9U6UrAfGKCz7RlLM81Q8XUwqr4oKPLIQmnA8IupBigacVy7yrya/2JouhryJHJJNykg+UxLGOtz6+SQNpEiMcduls4Wvoli9WklVKz+ol5SU4U6ngql8Qj2eRI+GyajBhSRH4r3cUxhSeRVhsYBmWUWiyM+UMDmDUI2nsfuSC1I27nLgYZJlP8jhjJ3PY8iE+L8tWx4kQC6MQA5b1D9HNiRCFhx8AF/e2qh92VnKAAAAAElFTkSuQmCC',
+ 'appchan': 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAABa1BMVEUAAACqrKiCgYIAAAAAAAAAAACHmX5pgl5NUEx/hnx4hXRSUVMiIyKwrbFzn19SbkZ1d3OvtqtpaWhcX1ooMyRsd2aWkZddkEV8vWGcpZl+kHd7jHNdYFuRmI4bHRthaV5WhUFsfGZReUBFZjdJazpGVUBnamYfHB9TeUMzSSpHgS1cY1k1NDUyOC8yWiFywVBoh1lDSEAZHBpucW0ICQgUHhBjfFhCRUA+QTtEQUUBAQFyo1praWspKigWFRZHU0F6j3E9Oz5VWFN0j2hncWONk4sAAABASDxJWkJKTUgAAAAvNC0fJR0DAwMAAAA9QzoWGhQAAAA8YytvrFOJsnlqyT9oqExqtkdrsExpsUsqQx9rpVJDbzBBbi5utk9jiFRuk11iqUR64k5Wf0JIZTpadk5om1BkyjmF1GRNY0FheFdXpjVXhz86XSp2yFJwslR3w1NbxitbtDWW5nNnilhFXTtYqDRwp1dSijiJ7H99AAAAUnRSTlMAJTgNGQml71ypu3cPEN/RDh8HBbOwQN7wVg4CAQZ28vs9EDluXjo58Ge8xwMy0P3+rV8cT73sawEdTv63NAa3rQwo4cUdAl3hWQSWvS8qqYsjEDiCzAAAAIVJREFUeNpFx7GKAQAYAOD/A7GbZVAWZTBZFGQw6LyCF/MIkiTdcOmWSzYbJVE2u1KX0J1v+8QDv/EkyS0yXF/NgeEILiHfyc74mICTQltqYXBeAWU9HGxU09YqqEvAElGjyZYjPyLqitjzHSEiGkrsfMWr0VLe+oy/djGP//YwfbeP8bN3Or0bkqEVblAAAAAASUVORK5CYII='
+ },
+ icons: {
+ 'Plan9': 'iVBORw0KGgoAAAANSUhEUgAAAAwAAAAPCAYAAAGn5h7fAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAzE15J1s7QAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAACAElEQVQoz3WSz4sSARTHvzMjygpqYg3+KIhkE83DKtKlf0C9SrTRuZNEx0VowU6CuSeJNlwwpEO2kJ6SQBiIUAzFjRDF4wrjKosnGx3HmdehFDfpe/2+z/s++D5gU7IsEwRByICIiAEAIiIAYAFAXsjYVr/fLxMRNVvN+prJ5/OA3+/XERFNf02JyeVyDx0OxyvLNQsnimLKfcf9KRQKXQAAnE6nlf5qMpnQycnbP/kAoKoqsSwLAJhOp+AAwOv1otvtpqxWq73dbt/r9XqvEQ6HUalUEvF4XLd5IpvNZqlerzd5nlf6/f6tTCZjBACk0+nb+XxeW4UrikLJZPImAGA0Gq0NIqJyuSyyANDr9Q5Wu1utFvR6/SULAI1G4+vK8Pv90DTtGwsAJpPpaGUYDAZ0Op3PHAAEg8H3tVqtbrtu21sqyxuRSOQJk0ql9IvF4r7b7f7pcrlejkaj57IsH58Pzp8dvjhc/lsBk0gkbLFYrFqtVvd27+4qOk733ePxPDCbzVBVFfP5fCiK4rvhxfDN/qP9wSasGwwGMv1HiqJQsVg8ZlfTHMepkiR1t05gGJBGmM/nMBqNj9nN9kql0lNN064ARISzH2cQBAGz2ewLu2na7XYLwzBbvxYIBBCNRrFj3BmsAZ/PZ+J5/kOhUIAkSVeA8XiMZqt5efrx9OA3GfcgvyVno9cAAAAASUVORK5CYII=',
+ 'Neko': 'iVBORw0KGgoAAAANSUhEUgAAABMAAAARCAMAAAAIRmf1AAACoFBMVEUAAABnUFZoUVddU1T6+PvFwLzn4eFXVlT/+vZpZGCgm5dKU1Cfnpz//flbWljr5uLp5OCalpNZWFb//f3r6+n28ff9+PRaVVH59Pr//vr38vj57/Dp7eyjn5zq8O5aVVJbYV9nVFhjUFRiWFlZVlFgZGOboJzm5uZhamfz9/bt8fDw6+drb26bl5j/8/lkX1z06uldWFS5r61UT0tfWlbDwr3Ew76moqNRTU7Mx8P75OpeY19pWl1XW1qzr6x5eHaLiojv7+1UT0xIU0uzqadVS0nV0MxkZGT5+PPk497///ra29Xq5eFtY2H28e2hnJignJlUUE1dXV2vrqxkY2FkYF/m3d5vZmfDuruhl5aZlJHx8O75+PZWVVP29vT/9fTj3trv6ubh5eRdXFqTkpBOTUtqZmX88/RMQ0T78vPEvr7HwcHDwsDq6ef///3Gx8H++fXEv7tZWVedmZZXXVudnJp0c3FZU1f79fnb1dlXUVVjXWFrZmy8t7359/qLj455e3q4s69vamZjX1zy4+avpaReWFz/+f1NR0vu6Ozp4+f48/lnYmi8ur3Iw7/69fHz7+xbV1SZmJZVUk1ZV1zq5ez++f/c196uqbDn4uj9+P7z7vRVVVXt6ORiXl/OycXHw8CPi4ihoJ5aWF3/+v/k3+axrLOsp67LzMZYU1m2sq9dWF5WUU1WUk/Au7eYlJGqpqObmphYVV749f7p5Or38fPu6OpiXFz38fH79vLz7urv6+hhYF5cWWKal6D//f/Z09Xg29exraqbl5RqaW6kpKTq5uPv7Of/+PDj29D//vP18Ozs5+OloJymoZ1ZVVJZWVlkYF2hnpmblIyspJmVjYKQi4enop5STUlRTUpcWUhqY1BgWT9ZUjhcV1NiXVkkhke3AAAABHRSTlMA5vjapJ+a9wAAAP9JREFUGBk9wA1EAwEAhuHv3dTQAkLiUlJFJWF0QDLFYDRXIMkomBgxNIYxhOk4wwCqQhQjxgxSGIsALFA5BiYbMZHajz1oJlx51sBJpf6Gd3zONcrqm/r1W8ByK0r+XV1LXyOLLnjW6hMGpu0u1IzPSdO17DgrGC6AadrVodGcDQYbhguP6wAvAaC0BRZQalkUQ8UQDz5tAof0XbejOFcV5xiUoCfjj3O/nf0ZbqAMPYmzU18KSDaRQ08qnfw+B2JNdAEQt2O5vctUGjhoIBU4ygPsj2Vh5zYopDK73hsirdkPTwGCbSHpiYFwYVVC/17pCFSBeUmoqwYQuZtWxx+BVEz0LeVKIQAAAABJRU5ErkJggg==',
+ 'Madotsuki': 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAMAAADTRh9nAAAALVBMVEUAAAC3iopWLTtWPkHnvqUcBxx5GCZyAAARERGbdXJrRUyGRUyYbY23coZFGDRFGEYfAAAAAXRSTlMAQObYZgAAAGhJREFUeF5Vy1kOQyEMQ1Fshzd12P9y61AixLX4yJFo1cvVUfT23GaflF0HPLln6bhnZVKCcrIWGqpCUcKYSP3JSIRySKTtULPNwMaD8/NC8tsyqsd1hR+6qeqIDHc3LD0B3KdtV1f2A+LJBBIHSgcEAAAAAElFTkSuQmCC',
+ 'Sega': 'iVBORw0KGgoAAAANSUhEUgAAACwAAAALBAMAAAD2A3K8AAAAMFBMVEUAAACMjpOChImytLmdnqMrKzDIyM55dnkODQ94foQ7PkXm5Olsb3VUUVVhZmw8Sl6klHLxAAAAAXRSTlMAQObYZgAAANFJREFUGJVjYIACRiUlJUUGDHBk4syTkxQwhO3/rQ/4ZYsuymi3YEFUqAhC4LCJZJGIi1uimKKjk3KysbOxsaMnAwNLyqoopaXhttf2it1anrJqke1pr1DlBAZhicLnM5YXZ4RWlIYoezx0zrjYqG6czCDsYRzxIko6Q/qFaKy0690Ij0MxN8K2MIhJXF+hsfxJxuwdpYGVaUU3Mm5bqgKFOZOFit3Vp23J3pgsqLxFUXpLtlD5bgcGBs45794dn6mkOVFQUOjNmXPPz8ysOcAAANw6SHLtrqolAAAAAElFTkSuQmCC',
+ 'Sakamoto': 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAYAAADwMZRfAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAxVJREFUOE+Nk19IU1EYwK+GQQTVQ39egh6ibKlzw91z7rn3bvfOmddNszl1bjKXc5rJJGmBUr7Yg9qTD0IalFgRBEYg6EDQQB+GovQyQgiaUZsoLcgHMcr069w7MgcGXfi453zn+37fv3MYZt/n99e76tzVj4JN/hP79fvXnV3hnNabwUBjoOHcgTYOu/JQspgTzsqKgn9BfD4vkWTzur287PqLVy+zM+yePB7KsRXLywTjnSpnZctBkPCdW8ccDuU55vBO8RXbkC/oP5ph19V5+7LIky0OY1BKbZEbLcFSt7u6pN7jLmltCVrr3DV5jY3+KovFEsccB1KJNVpefe10BqS2tqqO4/AuphBB4L/LkrRqNgtJs1lMypLls1kU38mytMLz/E8VIlutqVqX6/weZG52OttRXjbE0cP/FYLRlpVjDXuQ/r77x2XZPKkCHA4HBAIBkCQpAygIAvh8Pu2MZgO0Lz+QSa/sQfwN9RfpVN66XC6Ynp6GhYUFGBwczAC1t7fD0tISxONx6O7upgHILmsqvLcHodOggfiV/v5+SCaT4HQ6IRaLgdfr1bIRRREmJyfBZrNBNBqF+fl5sNsdgE2GiAbp6bmbdbXC7qWQbxMTE7C2tgY6nQ5SqRSEw2ENopaoZpCXlwdTU1NaoECgCbgiU6y8QH+ECYWaTymK7TWdys7MzIwGaWtrg42NDejo6AB1WjU1NZo+FArB2NgYrK6uQrAlCASxn2z6wkuMp87VIAhkE2MEAwMDkEgkYHx8HBYXF0HtkQpRy1BLiEQisLy8rPVNKSsFjEzrXH4+z1hlS4xDhKadNu7t7YPR0VHweDzAEVWfHru6HxkZgeHhYVAURYNjkylVWKArZjjMzqmdVi+QCsLUkQiEjvDvncEkvU7/qQ0Vgukeo48Go87IiCJnZNmipxiz7wXEbVDnbUxQOgM12h9n6qTq6NvapRdtkwaP0XK8RmPuYSbxYfaQ/sJJhjfknuFRURUi7AMOozcCwl94hLZp5F+EioDQVwqYI6jomZU1NFtM+rOSxZjVazcyvwHr/p/Kws1jegAAAABJRU5ErkJggg==',
+ 'Baka': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA0pJREFUOE91k3tI01EUx39JOpA0H4jNx0pbD3XTalISWf8YFlEgldqDsBLLyqjEKBCiLLWiggh6/KEV1WZ7OaelLZvDdDafNW1JFraWe/32+01FrUZ9uy4ylLpw4Z5z7/nc77n3HIqaMRIjZJyEcNX+uFCFeGmI/GZciEIsCFJUTvoAzDz+1y7K76MSwhX5hXl6z+WSbrzU2KB8YEGDwgrTaxZ3b7xHcaHhR3xw7Z5/UviB1ReP5XSg3+TAqYJOxMzWISFIC0GQDomhTVA9skCnsaAwp/vnMq66dBokNuBR9uFd7T9Z1zCunjci0qcRJUVdoJ3DYOhRnC/qBZ+jQbfeCc+37yjY2UEg0iwvJE0k9l8Z+8xqHmTgot0QLdQgTaQFQ2AsOzlHvOu1S5pwOLsHHo8HjHMCq2MazNvTlByKHyrJLDvdR25jMWRxYx5HjeMH2r1BDOOeguRua4OI14jx8a8YH5tA+al3EHKlW6mYOapb2oZBOOwMbEMseAE12L+jjUh3w+VipyAZ65oxn1NP/GMYGR6Ftn4Qsf7qa9S82Y/l/X122G0uL2TbxmZEz1WhXW8mUol8moXu+SCi/OoQ6VsDh3UUwyQ1k9GOaI5MTkX4yWTGHutvgI1F28sviAlRgxeoRm62HvsyW8En9pZ1TYgi6TntoyQtFm86rVgUoJZRvDnKMmXVAGxWmkAYOBwudBqGcHCvHulrGpGT2Uy+z4yT+QYsCXtCUpp8GxbKhx8gDK0ro+KjJGvzdjfDZnN6VdisLD5/JjArQ2zW66PJOj2lEZtStaBphkwah7K6kMJ/GEulp1bMWhAmMbTozOQRaWRtfoZVgjo4iRra4SYgGi26TwjxVeDKhR7Y7U606ixICq9tr7hd7+OthRWL7yUnJ1WPmXotqLhpRICPHCePtuFV6xdUPTAhcWEtRHEqfHpPyto4hPXLXnzflSEJnFaN3OCKDcsFsrEntR9RUmxARLAUgT5iBPuJsXWDBj0dZjRU9yNV+PTbpjTp9OA/pOSk24nRkXf1J462oPxcJ65f6ULlHSMulepRerYDgvj7A0cKpNz/tyTZqbzXO4t0ZZGQJ34RH11lFHIlA8LIqreCCMUZRY3cd2bwL/5/RmjNSXqtAAAAAElFTkSuQmCC',
+ 'Ponyo': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAuNJREFUOE+Nk3tI01EUx39BTytConQTt1am07m5abi5KT5S8z2dj1yOEMUC7aUgIoimlmUEWX9kBZGWaamEmE6U1BI1XNPNGTrnHs33IwuSXrL4NgcJ0mNdOHDh3PPhnPP9XoKwcroJYvMQiRSicHCQKCgUyZC9/T5rNet5KUFs0zCZbZMsFmZ9fTEjEEBDp4/KSSSb/4JoGIyWaTYbiykpWEhOxhSHAzWD0aqkUGhWAcVkW58xlvuPhfh4zItEmOHxYDR3MhcdDaNAsKJydAz5IySKRNjEUmy88vjOVaU8F0iPCqCNjEBHkC/UYaGYFwqxmJoKLYOhkxPElg0QsbNtTlmox9yjRD9UCbnoOR+J/lwRWtOCcdXfDc2BPpg0d7CQlIQZPh9KKlVkAQjJ2x2zmOSsQu7hpzUJfBhLjsNQmADjxcT10Bcl4rE4EHc5LjBEhEPn7f1WTqXSLQB/s1Tp7vslsoIkyPPiMJAbi86McBguiaHKjoEqR4jJy2K0nAxApzMN5iUGrclrKVaz2fUvuF4tRbxDKA90w5VjTFyLZKHpTBSq4/1QnxGB2qxoVIZx0JopRCPHFSNOThfWZzfrXDcZEowH4iA05ATg68hDtBaL0HAuCm3lJ9Bfcx2fFNUoi/DCjRgfNHHd1wCZA2TyXjNkE6F0cBDpPFiojeNi8EkJdFoN3vXch0nbBJOhDd907dANv8JITxNqziag3ZsJbUDAwLin50Q9QWwl1qSYoNOVvUcOoqOqAAa9Fu9H2/F9+B5WZLcwOyxFX18flLI+VASyMGVeoJHD+Tzq5BS1PoaKRrNT8127P74swsq4FCa9FKvqBqwaOiz3hdEuLKueYSyECT2LNW0eIfo3E/WmEbvnG1MUJnWdpWhDGDvxQXZHo+RR0uW2tnv+auPX+TvtJm7zKpaen/4y2yjBUlcxlvtvmvT16ZWDpQeoVv3/60F/NrHjTf4ugazIXtJ8ivjnz/sJ+yGQRjcqUdIAAAAASUVORK5CYII=',
+ 'Rabite': 'iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAD/0lEQVR4Xl2MXUxbdQDFz/9+9Lb3tkBLCxTKhzgoOOZAsokbJmZxDFHnd+LL4hKVzBgfNCY++ODbjDEaZowvErOM6HRu6hKZY2rIAOkCY4OSDTpFaAsrlJa2t5+39+NvjT7tnJzknIfzI98Nf/C6TuXdguWBd1q9rcb8/CwsZiu2Ywm4nDVo3VWLZCKDaDwJq9mCg31PgjAMKKUwmcyYvTbek9iJRDm6M/XswEDjwNz6plWW6wdZhjUAintFCEEhn0N04zYskljaDLaj8ar49oUrsYR6mrFJNj322w46H8y+mitM/ZJKZmyE4XAvjJSsazpyuSzslVZIkgWKOvvRgQ6Xrdlhqmds7o7bFZoLkctreKxf7GtuCE7IyUQjBQcQ8j/lvxCGQJZz0IoCVpamTtzfIh9nwiaIrCQyjNg8mq11oDLUhNXRJfT1Ozr3tS/PqpnQ80qRgjAmKIqBfK4ItbSLKoOZqR/6neLkENlSUAIhlktvEf+sD2rkm8nWTHtvZCGMVON1ePuaoBER31/MXGly1wSqq9Uug6FluYyWXJiPqFXmjd4Dh9oF9ZKKimYXRtYCx8lmMIDIxlIPGz591av0mtanF7FcCEN6iMXeox2wOJ0QJAmUAoRQaIqCnWAQY1/ewKNGNeQuYXkm0d2NC2e+wvmRr/Hx+6+8PHayrbDyyQBNDb9As3PHKDWG6MTM23RoeJAWsqeoWvyUUv0UHf7pBB0fe4OeeXe3/vmHbx3+8dwIGJ4IsFpMMFe0fbtAn+nwZePr1u4MBK8XIALG/Rt479wYrs2vgeNNAMNgMbiNzybuoKVvn+Gs9kbr6qpBfJfGYHFIkJUCoGwfqcoMX/b27EGhwgOjoCADDlP+CA51ugFFRzoB8FYNaQ1oqKD44+eNL+wNj7zJGQSIhe8+jgQ9thk+27v/KRY6L4FSCkVOwtlQj6P73Qgt/o1ERoKt4iUkE7+jrZMHyzIoK9cOBFfT4LbWAk+0a7ZLnvqHcTNdACgFScfAcjxEdy00VQclHGo7dqGeYxHbvIo6hwhSghCehb3G5p6eW7VxXC5/xGWToMgrKKoaCnIalI9CIARasQAqloMI/x4BWrLLYwE1AEPTwCGHaGjz7pw/leZUNV8wNm9BLy6CxsvxZ1kMbaY4TKIIXlNBsynoVjvAC4CuAoYOVi+CMfLYCUfg95tPHuzZB0YtKzsb58RMucWE/fZmhCbdOP9rNnLnxko6GVoB8lFwyVVw8b/AyeulHoJyN4Rb19dTFyeqBlu6njvfsWcvOJvLs7DMmw/7bvpeE4pU2OIcgcqmp4fGAgt2Txwvqr7lTp5V7LquZxXC6+BqEvGcY5pyjaM1tffJbk89NE3FP5VQ6y7a+paZAAAAAElFTkSuQmCC',
+ 'Arch': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABCFBMVEUAAAAA//8rqtVAqtUQj88tpdIYks46otwVldUbktEaldMjldM2qNcXk9IWktQZkdIYlc8mnNUXlNEZktEZlNIYktIWlNMXktE7o9klmdMXktFHqdkXk9EWk9EYk9IlmtQXlNEXktAWk9AWlNEYlNFDptkZldMYk9E4otg/p9kXktEXk9AXlNA4otclmdQXk9IYktEXlNEwn9YXk9IXk9FFp9o3otgXk9FPrdwXk9E2otdCptkXk9E/ptkcldIXk9Edl9IXk9EjmdUXk9EXk9EXk9EbldIcldIjmdMmmtQsndUvntYyn9YyoNYzoNc0odc1odc2odc6pNg7pNg9pdlDp9pJqttOrdzlYlFbAAAARXRSTlMAAQYMEBEVFhgcHR0mLS8zNTY3PT4/RU1kdXp6e3+Cg4WIiYqMjZGXl5mbnqSnrbS3zMzV3OPk7Ozv8fT29vf4+fz8/f7SyXIjAAAAmUlEQVR4XlXI1WLCUBQF0YM3SHB3a1B3l7Bx1///E6ANkDtva0jKbCW2XIH1z2hiZEZ4uUgxo7JedTQye/KN/Sb5tbJ+7V9OXd1n+O+38257TL+tah3mADAwSMM7wzQWF4Hff6ubQIZIAIb6vxEF4CZyATXhZa4HwEnEA+2QgoiyQDnIEWkjVSBBZBqXbCRlKYo8+Rwkyx54AOYfFe7HhFa7AAAAAElFTkSuQmCC',
+ 'CentOS': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAB5lBMVEUAAADy8tng4Ovs9tnk5O3c7bX44LLduNO1tdDh7r/eutj43q2kocX23az07N+qqsvUqcmXl7331ZXJj7r40o/Pn8T42qP63KjNw9n21p3Y387Ml7732JzR55z05MSxtMLGn8TC4Hx8eqt8e62Af6/B4HnG4oPC4HzH44fBf7LCgbOkoMTcsrmtn8PWqcfFtKrj4Jvs2ZOz2FnMqLXT3KfY5p60Z6NUU5XRuqHzwWSywqDn3JaiiLWahrWhkry5zJjRmqm1Z6P1wmb1y319fK632mK5cKi5nH+73Gu73Gy73W283W+9eK17e6y1yZS3aqRZWJdcW5ldXJplXZppaKBwb6VwcKV5eKswL306OYNPTpGkfK+m0kGpUJWq1EnEqIuXK3+Xh7ahP4qhkryMfK6BgK+CdpGMaKKMa6O9ea2+eq6+oYW/eq+NbqWVlL2Wlr7AjanA4HnA4HrBkqbBlafB33rCgbLCmKjCxIzC1mSs1UytV5mtxIWt1lCuz2evWpuvXJywxYzHjrvH4oXIjrrN2HXO5pTO5pXUlYnUlYvVl5Hb0G7e0XTg03rhr5fpzHPpzXTp0Hvtz3/wrDHytknyt0zyuE3yuVHzvVr0wGP1x3T1yHf1yXe0ZaL2zYP30o730pD31ZeRIcF5AAAAQ3RSTlMAFBkbHEhJS0xMTk5UWWBsd4SEiIiPkJCVlZaam6CjpK29wMPDxMTFxcnK193e3+Dg4uTn5+fo6e/v8/P4+fn7/P7+J4XBAAAAAOBJREFUeF5Vj1OvAwEYBb/yGlu717atLW0b17Zt2/6nze42TTpvMw8nOZCAmwUpiIY6c5IiLi9tPX64GairqszHQ4X2VB64v1Cs6PxMPJSdHM777s6/jyaMRGiRLyyrb88OpjZ3CzAXrm1sqzSNNeN7kVBPNgB7cG51abE5l9cXDces7emQ1uadHhutFUg6gpPKkSIqQGavwz7r7O/+/3t/rSdjI9XDM3qz4fr3B/3iA0aJTG9x71+9oR/PLDwUe2wm19bly+fTIxHyEETatbPewGEw6Mk/tKZCEqSQQUlIHB/QNBEjjVN1AAAAAElFTkSuQmCC',
+ 'Debian': 'iVBORw0KGgoAAAANSUhEUgAAAA0AAAAQCAYAAADNo/U5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAZ5JREFUOE+Nkk0oBHEYxv8fu5GQj3JwcaDkIAc5IpR87M7MKnIVJVKclaIQ5Sy5OLkgR7n5OigcSNpmd2c2Vyfl4KT8/muWiVU79TTv+7zv837NCBF6PG1X+NpZyEYSD9mIc+tHnBPe23B9xKrCuTmbQA/JKfABrhBswa1hH4A38IwfOxPdX1qcjiCQxO5NyrjKV70TnSbeRPwJvGN3i4yyqnEucPY8ZZX9GSEgGK+RvFfyjk2VKZxzBNG8wJWWgh/xtDOeUXZ7Slr6TrSLYL9N4SMgYTTcwdc2ArvJcElhSVcM6mCNSV8n9hA59yTU5UWMG6HIbLhIWlglgWiC2L4Z79qTdo40D6ISuOWwKCWHyk9Fv8ldpUHOuGTuynwSBUynddPdlbEosVpP9Eu4FnOsRzUYNTsdmZN/d5LDiqM0w+2CMdAFFsFGWgfXxZnheqe/z+0puwEM0HHYV3Z9Sgz8TEz7GkQvpuJ/36ggj2AaHLrSlkULWV5x+h2E8xkZL16YVjGNaAUscfZ/f6c/k9ywLKI2MMcRWl0RLy007idmRbQJ7RIfDAAAAABJRU5ErkJggg==',
+ 'Fedora': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABPlBMVEUAAAApQXIpQXIpQXIqQ3UpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIqQ3QpQXIpQXIqRHYpQXIpQXIqQ3QqRHYpQXI8brT///8uTYMpQnM5Zqg5ZqnS1+I4ZaY4ZactSn8uRnYrQ3MrRXgsRHUsR3s8bbM8brMtSX4wUosxVI01XZw2X50vUIguToQvR3c6X5o6aKs6aq08Un8qQnM9VIFDWINJXohKcKlXapEqQ3UvUIc2X55bhcBdcJVgcpdhfapmd5tuk8dxgqJ1hKR5jbB6iah/m8Shudq3v9C4wNG/x9bFy9nFzNnFzNrIz9zK0NzK0t/O2+3P1eA2YaDU2eTb3+jb4Oje4urj6fHm6e/s7/Tz9fj3+fz7/P38/f3+/v83YaEa/NNxAAAAHnRSTlMABAoVGyY1SVlpeIuQsLfDzdHW4+3y8/b39/n6+vr4+ns8AAAAyklEQVR4XiWN5XrDMAxF75KOknYdZJS0klNmHjMzMzO9/wvMcH7I37mSJShsJ+5NjMT6umDoHyXDcI/2qJadh++P3cle1de+9yPe3/bTY92wzfzr7wGtP3JrAI72BZGVtcAdQlwHy+JS1pDbBE9qamZF3BYrjQxPEXwKc6dC8bXFm0QIpmt8kn0Rn093q82UCtK8oXZckwFJzuulV8bHkajPyXdbnJnARfDHs0trz+JQ+5AFvzp/L0+cL2qPAINUPrq5OC6p/64F/AMnrST+Dq/r7QAAAABJRU5ErkJggg==',
+ 'FreeBSD': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAABIAAAASABGyWs+AAAABmJLR0QA/wD/AP+gvaeTAAADXklEQVQYGQXBS2wUZQDA8f83j33M9rF9d7u4loaWklaDpkSo9KDGaIKUaGxshD2YSPRiuDVeTDyhBxosJCoa40ktpAkPDcUqAYVIpUSUPrAulEdD2bbb7e7ObGcfM/P5+4kwKDvq6yJ1FYYcvb+YAkqAHo/HQ7FYrFIoCiurq9ZXJ06YSOkA+kBzfX06bys3zHxS9EL0tXDVyZfefacqV+X/ZSJx5+qLbx98LhaL9RiGEZWlEsWC/Thd9q6Pf3vs2u6Orc83rFsvTwwfLf5obgywT1Vjh2Hh+rbNsnTssJdNLedK5aIrpSuldKVXKsnH4+Pyn6FDXn5tMef9O+3NvdkvP1V4+EYw2AoQ+KSx8dRYS6NXXnwovaItXduSrrkinWxGOmZWJi9OyOK9m1LmsjIz9IH8QUMOd3WfAQwNKCy2tJwbHB5+XasPaxIHmc4g7WWEZ1MquBiRFlJTf1E7+Tl/H/8asavPzTY1nWd2ZkMDRPeBeHPz5ojwsilEQCBvTSKunCF3M8FSNkBGVTHDYYrLj8jVNhDZ2SMa2zo3MTamaIC/u6Ojr3DtrOrvP0BpdATnyBeIhTxpR5ABUlKSUlXS1dWstbVxdz6hPL0l1quGqkLaKwNvVcjEXNRd/4mit4Z19DjefBEPyCKxgQJQcF28dBrHNDGTSZSezsjeff0hraa2Vs2vrvit81O4vj9xLJcC4ADrQA7YAGqBGsAql/EtLdFQE/L7dF1XZmdnSrbPMJfXoLDmolQK8gJyQBowgQhQDRQBD+hsraVhd4e5MH+/oExfvWLJ9q3/3S7qMpNH2hsS40kFS4EUUAMA2IANRIBXv4uzuO67c2PykqkA5YmZ6bN18YPi0Yoknxc4AsJPCMLVAk2BLKDosCWqs/PZaulkuxk9fekcUBAAQGDks5FT0W++3NuYuC0DVUL4DIEdlIQDAj0IRkigaMjArkFx0tf523sffrQHyKsAgHPhwoXLL+yP9/kePNhk5ExUTyKFkJVAUAiCFZrQup4Rv9ftuLV/6ONBYBVABQAArMvJ5MXW7duD6P62sD8UrPAFRU1TpeCpCnGvPZr7WW///v0jpw+VC9ZdAAABAAAAAMLo7drWrmQyPWG/r8tnaGIjaM05ujr16x/ZBFh5AACA/wGZnIuw4Z4A3AAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxMi0wNy0wNFQxMDowOTo0OS0wNDowMOPVpFwAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTItMDctMDRUMTA6MDk6NDktMDQ6MDCSiBzgAAAAAElFTkSuQmCC',
+ 'Gentoo': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAB9VBMVEUAAAD///+AgICqqv+AgIC/v9+Ojqqii9GAgKptYZKQkOmPj/ddUYBgW4eVjeCTgfiWjO5wbJaZkvPBvepkXomYkNldV4Bzbpl6dJ+Uj7ynoO6Vi+1qZI63se2mnudjXYjOy+GCfaqZjvWlm/Pc2e+Oh7NeWIOWjfeXjeW1sd+gl+diXIfp5/KHgKnn5/F2cZx6c6ZgWoXc2e6dltrAvNu0scrX1eTOyujCvup4c5qpovVpY43///+6uPPJyPXq6fvm5vrz8/z8/P7+/v/d3PixqvmxrPSyrfe0sPO0sfS3tMve2/3r6vy6ufPz8/3d3fi3tM63tPO4tsu5tsu5tvO6tfe6t/Vva5KRjKy7tvW7t/W9vPO/vM+/vvPCwfPEw/TFwvTFxOfGxfTGxvTHxvTIx/TJx/aTiOrNzPXNzfXQzfnRzuHS0fbS0vbT0uHU0e/U0uTU0/bW0+zW1ffX1vfY1/jZ2Pjb2/jc2uSTiemVkLSlnvbe3PTe3vng3fzg3f3g4Pnh4Pnh4fri4enj4/nk5Prl5Prm4/ymn/bn5vro5/rp6O/p6funoPWsqs3t7Pvt7fXv7vzv7v3w7/nx7/3y8f3y8v3z8vytqPWuqPX09P319P319P719f339v739/34+P35+f37+/+uqev9/f6vqvSwrPQAR0dcAAAAPHRSTlMAAQIDBAgJCwwVFyAsNUFHSVBneH+Bh4mVmZmanKCxsrK2tr3ExtDW19rb4ODl5u3t7u/w8/T6+/z9/f4MkNJ1AAAA8ElEQVR4XjXNw5aDURSE0YrRtm3b54+dtm3btm3bz9k3Wek9+2pSYFwT8ibzE93hwAtdJqK3nZo4J9hFXbP+vFHOthV6gnGzstZq94wdCs4UCCDymQ2v7X0LdYoSQ0MIENRYzJbRlPTTHu73ZNAL8vivmVui98PpzuqffX0mIPHJGtOQenukteJ+aS3b9htNpDnT9TeZH1bHAwBRMhGpd6e6uNrLoRgxBKmsX47nBlp678ojpEA40fejcmW4e/No0V8IIPfj6eKgbEJ3ZUnzgE1OqWp9Q3VeWRAsg51f1dZ8c31RmAsc+N5JGbG+zvj3BzDCPrzMDC9SAAAAAElFTkSuQmCC',
+ 'Mint': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAACVVBMVEUAAADh4eEAAAAAAAAAAAAAAAAAAAAsLCyXl5dgYGCnp6eTk5N3d3fBwcGqqqq8vLzNzc3Ozs7Ozs7Pz8/Pz9DQ0NHR0dLS0tLS0tPT09Pf3t/Pz8/i4eLb29vZ2drZ2tna2dra2trf3t/u7O/u7e/u7O/r6+vt7O/w7/Lw8PDy8fTz8fXz8fbx8fHz8/P19fb49/j49/n6+vuPxlmWyGOx437h9NDr9eD6/fj////+/v75/vTA5Jv6/fb7/fnL5bDL5q+AxjeDxUCEzTyGxUaGzjyHxkiHzz6J0D+Kxk6K0kCLyE2M00WNy06P00mSz1OUyF+W2FGX1FiY0F6Z02CZ21ac0Wiez2yfz2+f2mOh4GCi4GOi4WKi4mOk12+k3Wul32um1Hin0nun4G6n5Gin5Wmo23Op2Huq1n+q43Cr526s4Hit23+v6XSw34Cw34Gw6nWx4IKy4IOy44Cy63ez146z34az4IWz4YW03Y217nu38H2625e645G74pK83pu98Iq984W+4ZjA4px0tzDA5ZrB8ZDC5p7D55/E947F6KHF+JHH4qvH6qTI46/K5LLL5LN1tzLL5bN1uTDL57DM5bPM6qzM66/N5rTP6LbP6bTR6rfS573T67vT7LrV7r3X68XX7MHX773Y77/Y9rvZ8cHa7cjd88bi88/j8tTk8djk9tHm8trn89vo89zo9N3p9N3p9d7p9tvq9d/s+93s/dzy+erz+O73+vT4/PX5/fT5/fX5/vN1uzB3vTD6/ff6/fh5uTj8/fv9/vr9/vx8wjV/xDmrMRH0AAAAOXRSTlMAAAECAwQJDzk/RUlNU3F0kpSVlpeYmpucnaKjpKWqqqqtu8LExMTEzdTU1NXY4evy8vP+/v7+/v6LaR1mAAABD0lEQVR4XiXI03bEABAA0KltW9kaW3eSZW3btm3btm3b/q4mp/fxgqKOtpamhrqaqoqykrQYABh+PVMU9fjE5Xp8o54kgPHN0EBHU2N5YXZykiua0HHd2759VF2Sk5IYE5GGsmCEWLV1kVWwt5O+3x/qpgsy8k4ja+cJl2/v5C22tlgCAHtw9TQSa4s+AzfPSm0BRNl9SydhWJzLC567KrNhgrNwHIJ5qTz/2f9w7Jw/DNqIjVr04exW0AEOXcN3Ab7enr9eDW2VTJgehONyc2Z8XP5YdD0Tcuhcc4/r45OjGX51TEjYPbh8THRPvbz+CHusgSZlT7rP8PkCwfQKaQUi9Igr6JsRBMFiWZgb/AHKElRzKopZJQAAAABJRU5ErkJggg==',
+ 'Osx': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABrVBMVEUAAAD///////+qqqr///+ZmZn///+qqqqAgID///////+tra339/eAgICoqKjx8fGMjIzm5ubh4eGPj4/g4ODIyMiAgICSkpKLi4vS1tbPz8+Xl5eMjIypqanIyMjW1tZ2dnbR0dGamprFxcV3d3d+fn60tbV3d3dcXFx3d3epqal7fHxxcXF+foCnp6hYWFhyc3Ojo6SMjI5fX196enp+fn6Li4xERERqamqgoKFpaWmFhoeen6A/Pz9QUFCWlpeSk5SUlZWUlZaOjo+Tk5RHR0cuLi5YWFgwMDAeHh40NDQ3Nzc6OjpcXF1rbG0XFxdSU1NVVVVXV1dZWVlbW1tnZ2lwcHABAQEEBAQXFxchISI+P0BISUpaW1xHR0kNDg4qKyszNDU1NTY9Pj8NDQ1cXF4XFxhSU1QSEhIDAwMrKywtLS4uLi4wMDFHSElISEggISE0NDVJSktNTU1FRUVWVlhGRkYEBAVBQUE0NTZQUVJQUVMFBQUqKitWV1lXV1daWlpaWlw+Pj8bGxtcXV9dXV1fX19fYGFgYGBkZGRlZmhpaWlsbGxwcHB2dna844Y9AAAAV3RSTlMAAQIDAwUFBggMDhkeICMkKCgqMDIzPj9ERFBib4CCg4iMjZCcnp+jqamrw83W1tvb3ePl6Ojp6+vs7u7v8PHy9PT09PT3+vr7/f39/f39/v7+/v7+/v50ou7NAAAA30lEQVR4XkXIY3vDYABG4SepMdq2bRSz/capzdm2fvOuDO397Rw0Ly4tz2QAQPbcxuZ2E/STJwfxPhWgG355fRrVAIVb1zeP9UDLfiSwkAcADe8fn7tFxWuEXFRDoer/OgoMTRBCumj8yJwPBo8Zhpk14U856/HI8n0ZUtpZ1udrSzfVneA4roNKjdrwpcMRilb8d8G60+lKnrpWcn9bO+B23w2O8Tzfq4aiNSZJqzn5O4Kw16h06fPZ+VUlUHfo97+VAEb7rSh2UgDd4/U+TBlQY7FMj5gBIGvcarVVfQPVPTG94D0j9QAAAABJRU5ErkJggg==',
+ 'Rhel': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABj1BMVEUAAAD///////8AAAD///////8AAAD///8AAAD///////8AAAD///8AAAD+/v4AAAAAAAAAAAArKysAAAD///////8AAAAAAAAAAAAAAAD///8AAAAAAAAAAAD///8AAAD///8AAAAAAAAAAAAAAAB5eXn+/v5JSUnKysrS0tJ5eXmqqqqxsrL+/v4ZCgknJyeHh4eIiIjo6OgZCAdOTk7t7e3///8GCwwPAAArKyv19fX29vb9/f0EAAD////+/v4AAAAGBgYHAAAJAAAMAAANAQAPAQAVAQFyCQV9fX2pIRzmEQjn5+cBAAAFAAAAAADnEQjvEgn////uEQjyEgnsEQjzEgnxEgljBwPaEAj9EwnwEglHBQJHBQNNBQIBAAB3CQR5CQSHCgWLCgWRCgWTCwadDAWmDAapDAa/DgfKDwjWEAgGAADh4eHiEQjmEQjmEQkKAADoEQgLAQDtEQgMAQDuEQnvEQjvEQkPAQAfAgEuAwEvAwE8BAL1Egn3Egn4Egn6Egk+BAL+/v5CBQJrB0muAAAAT3RSTlMAAAMEBAkYGhsbMTRLUmpvcHeIjLe6vcHCxM3P0NbW3Ojp6u/w9ff5+fn6+vr6+/v7+/v8/Pz9/f39/f39/f7+/v7+/v7+/v7+/v7+/v7+Q8UoNAAAAO5JREFUeF4tiwVPA0EYRL9SXIsWl+LuxfcOd2Z3764quLu788NZNrxkksmbDP2R7vH6GioLs+iffEzNXd4+TqPErUUpVqMOvwgdzMPn1rv5vPsVeufBTaBK/bH2FPvkEUuIG5jIIc+sHYn/HJ3dC/Hxuo4y8s44dzwBbFkisHN8bVIdXs6jb+H97aCwbHEIqgcml64CD7YllNkAVQC940MLYe5YzvIeQAXNrd19Roc5MdzfdQLUUKaUYyuG9I8y1g4gj6hIak4X5cBIT2MquZJrJdOqpY11ZpAiqVwbY/C7KY1cRCrZxX4pWXVuiuq/hs49kg4OyP4AAAAASUVORK5CYII=',
+ 'Sabayon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABvFBMVEUAAAAcUaYdVKwAAAAAAAUABAwWRY4YSZYhZtIhaNYHDx0KCgoFDBcKCgoRMmYSNm0fXL0fXb8AAAAYS5gaTp8fXLwgXsEGBgYFBQUZSpgZTZ4JFSgODg4IEiIOJkwOKVIkW7EnXbQLGzUTExMKGC8LHjwMIkITExMiIiIPEBEPJ00QEhMXOXAaPncOJEgoXbApXbEcHBwwMDAEAgAfHRgQDgo3NC8AAAAHBwcKCgoLCwsJCQkaGhofHx8lJSUwMDA0NDQ4ODiRkZEICQocHBweHh4GBgYHCg8mJiYnJycpKSkrKystLS0uLi4ICAgODg43NzcRERF1dXUUFBSjo6O1tbUbGxsEBAMLGS8MDA0iIiIjIyMkJCQNDQ0NHTYKCQkoKCgPDw8QEBArMDkKCgkRERIREhMxMTEyMjISIz00Njk1NTU2NjYCAgIVFRU5OTo5P0c8PD0+Pj4/QURAQEBHR0dKSkpMTExSUlJiYmJlZWVnZ2cWFhZ2dnZ4eHh8fHx9fX2FhYUXFxeVlZWXl5eYmJiZmZmcnJwZGRmlpaWrq6usrKyvr68KFiq/v7/FxcXY2Nji4uLn5+ft7e0yif9uAAAAN3RSTlMAAAApKSkqKioqg4OEhISEhoa1tra3t7y9vr7S09PT09TU+Pj5+fn5+/v7+/v7+/v7/v7+/v7+70RY/wAAAPpJREFUeF4dyWNjw2AUBeC7dfYyorM6rx1exKltzLZt2/rDa/J8OgBVVlFDX39jcTZoUqCse251a2dvu6ccUtWlanLQ4Vpel+ThlWq1l3wEz58tx4dOt1dMlAJk9A5gMjG75LHwo46hzkwosGOMbejumoRvubC9EOrMviT0E0Us9fvN9dA6zxJCNv6+ECGsb6oNWsgmpZT9/UTUZo3Em6AW34guTL4jiAudiCM1kLcw8/SmHERfT1/eueBiDqR1GK1n9w+K8nglxYxd6QAML4ztXoQuj8YFgWcgqdJp8qzty26vaboCNIxBCshyQDKov0aXr29v1ufq1PwPx5Q7bCoh6eoAAAAASUVORK5CYII=',
+ 'Slackware': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AcEDi0qZWWDgAAAAx1JREFUOMt9kktoXHUchb/ffc1M7rySSdJMOknFPMRitLgoNKKI8ZHGKkgrjU8SitidimSh2UkXoQmoO1dGQSxJjdvOtqSaqlR0USEGSjVJGxuSmWR6M3fu4/93YX0g4rc9HA6cc4Q7DI+fpzz7PA8++2mxvZAeBZ4xhHtFcJRmXWsWvb36/OLcyxf5B/KHeYHy7DmGx1+YSDjmWTdlobTGMAStQGkNoLXS4tXDq7u7tUcWz49tA8jR8QUuzB5n5NTCV13F9JEo1JJwTLKuzU61QiOMcd0UDb+BncwQK3Rl15eNja3ui/Njq8aF2eMcO/XlBz0H8oO2ZUkum6A13WB99TtyzXlaCi24SaFa+ZFCzsG2DNnfkdbFjsI1APPhk+d6ujqznycdCxFozadYWvyMpx47wa+bPkGksKwUNnsk3TaCGASRXDZh5LpHXPPg4Rcni+3uYBxrtBbQghlscOVKmYHeEm0ZIZ9xyLffw41ND6VAa43SmjiMByzHYtjzwr9arfshxf5jOKlvKZfn8es77N2uks24PPfSFD/9Uvt7AtPKWmEU9d645eHYJo5tcKi/FX/zG+zmQxQH+rANk862DOW5N/hhaY64cJSa5xNFCgDDILZACMKYWAmh73HmzFsMlBQJ06LeiMinE1S3KzRCm5rXIIoUIoKIYCVM36urZFbEoiBLNMIhAE6/NsSB7h6SKZdL8xsUOnpx9j1KbTdARACIowArYe1ergfNT2i0mIbJys0GI6PT3N1/hJvrPxOFdRJNBQIy/FapI4Bpgohgcjuw+jq8jy8tV55MNBWI4ohS802CpizKv8q+FgALZAfYgSyAZtNro1oLaU1VvxCA029Oraxs7u/tKnXiNjn8HyKwur6lI++6vPK4V7IA7u+1Dyu1tr183ddNbkHuXP8/zEIYeFqiLRl6YO/p0bHJdflT/PD9qZa1W+ry99fcvlAlcZwUpuUAglIRYVgnDEIOlna4q0M/NPnuO1/PzMwg/045O/XeibUt5/Xangx6viSVFpK2jtMpvdyWCz+5ryf10clX3/amp6eZmJjgd441URWWJY8BAAAAAElFTkSuQmCC',
+ 'Trisquel': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABjFBMVEX///8AAAAAAAAAAAAAADMAAGYAAAAAHFUAGWYAF10AImYAIGAAHloAHGMAKGsAGmYAJmYAJGEAKnUAJ1gAMXYAJnEAJGQAI2EAK28AK3cAGTEAMHgALXEALXgALG0AFUAAI2oAK3EAMngANoYALXMANIAAM4IANIIAL3gANIcANokANoQANYQAOY0ANIYANooAN4kAN40AOY0APZMANIUAOY0AO5AAPZUAPJAAP5MAPpQAQJUAOYsAPpYANoUAPpoAPpUAM4AAQJkAPZIAPJEAQpgAN4cAPpQAPZUAPJEAO4oAOosAOo8AQJoAOYsAO44AQpsAO48AQp0AP5UAQpoARJwAQ58ARaAAQZgAQ54AQ50AQpgARaIARqMARaMARaIAR6QARaIARaEASakARKEAR6MASqsARKEASKcAR6MARqYAR6UATbEATa8ARqUARKAAR6oARqMASKgATK8AR6QATbIATbAASq0AR6cASKgASqwAR6UASKcATa8ASqoASqwAS6wASKoAS60ATbHn4CTpAAAAhHRSTlMAAQIFBQUGCQoLDxAREhMUFBUYGhobHB0eHh8gIiIjJCQkJCYoLC0xMTE0NDo6Oz1BQUNHSUxOVFVVVldaWl5iY2RkZWZoamtsb3FycnR1ent9f4KDhIiJioyNkJGYm5+foqOkpqamqKmqrKytsLKzs7e4uLy8v8TFxcXGx8rO0NXY2eZc4XYcAAAA00lEQVR4XkWN1VoCUQAG/3NWtwh7CTsQJOyk7BaDxuxA6bbrxf32gt25m7kZqDRYxziooDV7+1AalMUavQh2AsEZoWvzigLun+T17/c8QiJZ7qu2QKiNmyZthdcR1/as353jIeU1GxMHo5XHdqPFeX8IaDMdHPYN6dRN7LR4qQewdTa35HWkyh+fbxERAMjwlAWJv3CPSKDQ+H7XvHdkV4Pua3Gtm4sPKIF/WV8dop4VKBw/NU33B3x1JbTt+XwhkJQoqRfWvHOy28uqH8JIdomR/R+s9yR3Cso77AAAAABJRU5ErkJggg==',
+ 'Ubuntu': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABKVBMVEX////ojFzplGf1zbnqnHLvs5P10b3yuZv1xKrytZXvtJXys5LysI32waT0n3HxiVHwg0jxhk31kFn0h0zxf0P0hUrveTv2iU3yfkD1hEfyejv5eDLybSX0aR7zZxvyayH6ZxnxZBj4YhH7XAb5WALlUQLeTwHgUAHeTgHfTwD65NzdTQDdTQHdTgD31MfcTgLcTADcTQD////xt5/31Mf54dfmfE/dUAbeVQ/jcUDcTgHeWBnnflHohFvpjGbqkGztnX342Mz53dLgXiP65d399PHdUgrtoYLyu6Xzvaf76eLfXB/rkm/fWhvupojwrpTeVhTgYSfgYynzwa30xbL1ybnngFT31snngljhZS3539XhZzDiajbibDn77OX88Ovrl3X99vTjbz1fisGCAAAAMHRSTlMABgYGBwcHJiorMDA1NXGHjY2Nl5mZmZyfn6O5u8XHzc3X193j9fj4+vr6/f39/f08OUojAAAAx0lEQVR4Xi3HZVbDYBhGwQctWqzFPXiQ+36pu+LubvtfBKcN82/UEhld2vWXxyL6F92gbTPabse8hU/uHMx1SZoyyJWPTwq1Rs7GpYE9+Cg+OJcs1MHvU9y4fnrN31yUm18vMCIPjtw3QMndw4rs8ieVzAAcBlewpe1KM3uaBuD3Dda1BhWXAsi6AFY1a2SqifxZ+rnxWYcJDRkUS3fO1R5vwe+XZgw4D4L3RAJiknoXCVX3WeiUpJ5pIxTvVmg45pl5k4Ot/AGV2iqZBWgJJAAAAABJRU5ErkJggg==',
+ 'Windows': 'iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA+pJREFUOE+F0n84FHYcB3CWSsL9ojo/6ik64c6PnTjmSS0limmrpBm2G002y++xzXRz6zE0R4nbw+RnTj/WD4sbanLkkAe55ccYlyNme4SrO9u9d13PI3/saZ+/vs/3831ez+f9eb5aWsuqy2mjRYeNUa7YmtjfTico7jNJ8z0eG24NB9vvnDrvufzpq89Npnr8VjMddNmuRh9rDfp36mFg91oM7qPIc5JdbDJq3An/JfCu7Hl53W2lpS220pP2OuniN299jAYbYizSENIoAgbCTdrTKtxOJVdvGo8psUwKy7Vxe4ez1YEVudGP8YEZzyveInFJ6mZRHHqYazDspw/pJwTIuERM5JIwmUdGdyo9K7/BszGzzg6fXzZHGJ8KvzQqXKOpoIeZLjofWR++BPWyCEnPY4xFGEKWQcLjMjKmr1MwfcMYwmz/Y4KOgNki0V5k1dkjUWCK93Kp2PMFFawos8cm1gZ2GqjLXktL4mbQPHLQ4B9ZDFE5+S356fQlyuJMqzH++HnTo6ui2OO1ko9Ul+4fxfd3d4F7k4YTReqpuFS88bGZUE2QNNDobuIq8Q5CduHb7lFJaTnvnym9ergjMWD/FG8zf+aKS3G9JO5C01Asah6wUXrvALKEDoitMMHhDKrKJdg8RU2s0EB2EWWur8dd7PDPFv6dUC0Gv3kAN36VPRGP/5k5NS6lljWxG0TDiSr1VKhoPwhevRMSqkwRxDObc/DavGtpP6zoi8XOyZfhnyNEvKANBU0P8VPfI/wyNCGXSn7wlEmyA9KrgmOKGth3eDVvPfyywq2dnUEv2R9qG2rLsH7xJXziKnWcI8tlTvEC7Mu8hROlImTU9aKqcwQ1vWOihWFu+sJknmph5CvxQh87c7bNh/NXo03hrMCosyvLmMNgMF7TQL6J1dsZIUVwjKqEO+cajp5vxPN439U/gKBt8PTcYHzL/BgHCyOf4unAISj6mFC2bYC82kB5Ls460NHRUVsDeYSXpGw7UgC7sAtwShDgzdM38W7BbURXtqpqhfmB8sEQuXwoCM/6faGQuGCxyxyKWhIm+PrSD495WL3cT0hhi8Whc3NbAs9KaOyCTvrJ8qkdX19XBeTUDU00+55USFzVU2yHstcaix0mUAjJkJeuRU868Ucmk0lcguiBnMAVxjbbdHV1yeq8+u4Hgo22huSG+iQXp83ftaxW3lsPZcs6KG5T8OwaAfJiPcxlrVRVRhvF02i0F/t5VbHZ7JWDfErKTLnhE3mFPuRFepg/uxqz6TqLv6euGj3ut87t/4ylvre3t3ZehOWWO1zjSFEqMVP4GfGb/DBykJcjmaZOoLsc+hcVY/LaAgcTQAAAAABJRU5ErkJggg==',
+ 'OpenBSD': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAykIPu64pQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADTklEQVQ4y32RXUxTdxjGn3N6eujoKT3SUkuk3VoBGfVjgFXAsZ7WkipyYXQbuu3CzUXZmGRbssnFEseFkWzgcGzGXky9MWL8TsC4IeFgtK4oAqOnG5vMVl1pCMVWQD7b/y5M6jLdflfvxfPked/nBQA0NDSChqnGVrLuGkES742NhJAdhAKAuk9yyUs5Gry7RQMZAARCWgivpQiPe71P5DUfH0xaqTL7m/iiLkJmphawa+e4SM2PvUyC4yUIBu8CnAQKAK53rCA5OUtQtStVpJ4Gw/FOBddZVKhCfq4MP4n6+at+DUsJm/e0G9JZzYEvI2tHwlEYjDxomkZ+3nG8WroRtHihZVOhVlorDQzh0okhcByDP4ZGcf+X9XAsvY5/RsBa7Kq5H/CqLctKyl/g08S2i6fq8W/MS3P34T9wNDVYSeDX1eTD9xhiLXbtB/Akwmmv6Kr+ICFkLpGhtNSM3qsSstS3oX8lSsmsxS6ZVn3j6PvVVqhUcvC8AtPxVPxwygVKvngN89WOjgVprggGA4eenjB4nsXsTASpC63I0wVTZYPR11FoKRB8Ax54PCFk6BhMTk5CPR3GSbHouGzknr/bYFq9EAvfc9Tu1sLjHcXNKxLuTOTgzOlOe7IHBc/beAXWpWmXlz8a84nhcLQ+ecVzsAEQrMWuMX+f9HZF2YPZ28FVSNfoPWqOzMUmqYMAJm7+/OOzXQFwHGpyEV+vi+yvtxBC9pDmpgJC4tvI3mo9GTitIxvW24nT7ug67HY/3eDs2bbyrVsrY2day70rV6kRfDAHk5lDLJqAmmeRiD9GJDKHvwb74R8G0mkTPjrQTTG122xkTTbwaV2b1H4u16JQKXGr7yG2b8/H1MQ09IsTSEmRwzf4CCwzD+dmE1re8CI7wwi5XNlFf9vaTXX4dWJg4LLl7h05fpNGwNAMWpp9CIVYNO/tRCzGwpDFQaVMQTS2CKY0BWr3GVGWNSXKACDDaA4Mh976pq9f5Sy09GgKlmeAMIBKzUKpU+BFoxJecRhUfAbMxDi4eADfHVmE79v7q575gvvYeVvjZ58LD5mwsKUyX0hnf0feslnQCWD4zxnc6reKisxsfH2oscqcmTmK/+Ow252cna7K52r+Bky6PqmoT5HBAAAAAElFTkSuQmCC',
+ 'Gnu': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAywUV5gQrwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADcElEQVQ4y43Tb0jjBRzH8c9v+7nNMebcUW21Cc78g/wcuhByIScoMRwoTBmFlZCmIJ14axqkgoYIkXIqKIVBEuJNUBEUPRlpqDC3Q2Ex0nTezun2YOaPLXNIv7Vvj7zgiOj1+PPk/eADjuNEuHN6ekqMw+H4IzMz8xChUCjV1NT0JbO7uxtfXFy8NZvNr21tbd0AAEQikY6I0m1tbQbx2NjYZiqV+vn29jY+PDw8xhYWFj45PDzcb25uhlQqfSTief6X0dFRpqKigvF4PPPipaWlY7lcXhCLxXJnZmY+ZTY2NnzX19ePGxsbHw0MDLivrq5mc3Jy2pPJZLVWq/2cdbvdDSzLholoNJ1OMy6Xq0Ymk5HNZktOTU29qMgA8HYqlaKDgwNKp9M0PT09BgAM/iGuqqoimUx2yPP8U5/P9wEAMB0dHRUKheJHiUTyeGhoqAUAnE7nR0qlsjcQCLwjlsvlz+bm5mQWi0VSWlr6bXV1tU6hUMj6+/vfN5lMN0xxcfG1zWZ7SETTSqWSGhoamPHxcajV6s+8Xu9Xou7u7t9VKtW00+mkSCTC6PV6aDQa8Dw/Wl9fP8UAQCgUosvLSyovL2eWl5dRUFBw7Ha7v9vc3By5K3g1EAg8FQSBiIguLi4IgBwA2LtEjuPuJxKJ62AwKFpdXf0eQBIvYVmW/cLlchEAWK1WAADT09NzX6PR/OTz+eKVlZUzKpVqTyqVvsnzfLCkpGSrtrb2t97eXnFeXl5ZKpWyZ2RkPPP7/UUnJyefGI3GU+zt7aU4jotOTk7mAUBfX1+b1Wq9kcvlBIAcDgctLCyQxWKhoqIi6uzs/BoAVlZW3qqpqbllZmdnf1hfX//Q4/HEzWbzX+3t7fcMBgMFg0EYjUYmEolAEAREo1Hk5+fT+fk5Mzg4GD86OpJ0dXXJGQBoaWl5Ra/XP6yrq3tQVlam2N7ehslkAsuySCaTUKvVSCQS2NnZSXAcJxYEQTEyMvKeIAhLDADY7fZ7BoPhm6ysLFpbWzuan5//WKvVvsHzPEWjUSYSiSA3N5d0Oh0TjUaf+/1+S2Nj46/4FwYAr7e2tnbF4/E/iYjC4TCFw+F0LBaj/f19mpiYeID/IAagAyABYLXb7cLZ2Rml02nyer3POY6rwv8hEr34u0IkEk1mZ2cTgGMA7768/RtL5JKsGzrLIgAAAABJRU5ErkJggg==',
+ 'CrunchBang': 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAQCAQAAAC45EetAAAA8ElEQVR4XnWOsUpCYQBGz1TIHYu2Qix6g0DEtSeQu/UIISJtUS8gJq61F1wcdMohcBDxKUR8hsz1xA/y44/cs3znbB+RJ0Skl3pSkeFQbUs79VAPzrwPFRmN1Ja0Ug/16I93+1oi4lKte+zMXv32WuoAm43lXMrqzbFncgWw21lORf4+/PREKpAhYqZuPXZ+T/3yXbZEajV1JavUQ104sRcq0myqc5mnHurWqc/7yhExVwuPncl+C4Bu13L60ueAwcByOtLhgAIRCzU38fRGTmSxUBvSSD3Ui1NvQkXWa7Uq1dRD9R17HiqyRUSy1NP6B7e1Yu2GtlUKAAAAAElFTkSuQmCC',
+ 'Yuno': 'iVBORw0KGgoAAAANSUhEUgAAABgAAAAPCAYAAAD+pA/bAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAABDtJREFUOE+FlHtMm1UYxrtsi8aEgCb+oTFmZur+WNS5RaPERU10C2qGaBgb6hgwLwMmHTIKlIKlQIHSQrmU24BSSmnpBVooUmihtEC5yKWDjVu5uOkcEca4lG5E93j6EQmELX7Jky/fOed9fu973vMdGu0xT3Cgz57yXMZLDdXcy821PFWLKmuA6HqLMqtLX5POl4iYb2ukWW8IOOFe/qfe3/M4n0eOjwyZD8//bldODOk37N1yDJgl+LVdjEGLFKO9KkzZm8hbje7mIrTXZ7sMtTydrJh15H8hHW11XvN/jGS7VudcD5w34ZZzeQYb67fwYO03LN4exo1+LWzNxbA05O5QuzbHqRYn+++CHDx4YK9WLfaedfQzV5em54g5Zbi8OIml+VFMDLWQ7GXoaSmFWZsDZVGCO2u0EbkhHTrhFqi9PmelSsQ8tAtSVch60dpUeGe4kxgZxegzVkBzlQ2NKBG2+iJIMqMok9r8OLRIMqApToSqmAWTmk9B2+o2YW79oshU7ABcuvAFrVGWXkVKpBYoSaBSxIS2mINpiwbjZiUMZRloVfJQyaXDKObBpimBScpHFe8KmmXpaKhK3arGrBVuVBclHN2CiPNin1OVs1tVJYlQlyZBxA6DviQVo6ZaOKd7sTplw53BVugruBBzfsRslw7rZPxaczWutSpQV/gzJPxo1JexyfaxKBBpuiEx+tw+CpKdEvGWTprGlhcwqbIzL5/DYKMYndpK3L1hxf3ZfkrzwybUZjPhnOqmvlcmutFF1jis9QSShOrcWNSXJ1MA0ou/NZWc8Ddfe4VGO3bk0JON1dyMMlK+gmxNrZCFhZF2Kng7YNO0awt4b7wLNp2EqtAsF6ImP56SG0B6siovTYpIjg15gapCVhAfJRUyIBFEo6k8AyuTtkcC/qvG/XbDexulWJvqgYH0o0nKhVHFJ40XwFQnWM5OCX+XMg86c3KvVMSMapCmPpSTIygTxGKZZOcOXhrr3Mp4uzkFuG6B3ajE3TELDDU8qEmsmvRATxquKkxAnSTFjwKEfv3JU9JC5unG6rQ1bTkbQ4Yq/DVgxOqwBWt2K9Yne3ZCZvrgHO2k5paHzOhSiVCZSkdNTgzy40JRlPgDhDHBCxUZdCs91G8fLeK87zOl6XSOICZYXMGNhDqX9fDP/mbK2DXVi/szm03eLpejl5pzOfqwOt4JBT8OeYwQt/4R/BR0OzXiLCM5LOCji/4nXt46rpywgG+zor5RxgSdupBzJdglSY+5ZZbl3XNY6mbn7W0Lcx06zBg1WBjtcC6OmG+OmRTrFrnIUZESZeVeCpwh8TpiPsQ47/tloM97T+/6m8mg55mT3tStyL54mhlwwtszNvjzD8/6HH8i7PvvPPRioZdRWuDBZUR6pEWG7I8P9Xs1Jsj36MfvvO5J/+rTw58dP7afJPfBgeef3XGz/gskFVpJc4HwGwAAAABJRU5ErkJggg=='
+ }
+ };
+
+ ExpandComment = {
+ init: function() {
+ if (g.VIEW !== 'index' || !Conf['Comment Expansion']) {
+ return;
+ }
+ if (g.BOARD.ID === 'g') {
+ this.callbacks.push(Fourchan.code);
+ }
+ if (g.BOARD.ID === 'sci') {
+ this.callbacks.push(Fourchan.math);
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Comment Expansion',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var a;
+
+ if (a = $('.abbr > a', this.nodes.comment)) {
+ return $.on(a, 'click', ExpandComment.cb);
+ }
+ },
+ callbacks: [],
+ cb: function(e) {
+ var post;
+
+ e.preventDefault();
+ post = Get.postFromNode(this);
+ return ExpandComment.expand(post);
+ },
+ expand: function(post) {
+ var a;
+
+ if (post.nodes.longComment && !post.nodes.longComment.parentNode) {
+ $.replace(post.nodes.shortComment, post.nodes.longComment);
+ post.nodes.comment = post.nodes.longComment;
+ return;
+ }
+ if (!(a = $('.abbr > a', post.nodes.comment))) {
+ return;
+ }
+ a.textContent = "Post No." + post + " Loading...";
+ return $.cache("//api.4chan.org" + a.pathname + ".json", function() {
+ return ExpandComment.parse(this, a, post);
+ });
+ },
+ contract: function(post) {
+ var a;
+
+ if (!post.nodes.shortComment) {
+ return;
+ }
+ a = $('.abbr > a', post.nodes.shortComment);
+ a.textContent = 'here';
+ $.replace(post.nodes.longComment, post.nodes.shortComment);
+ return post.nodes.comment = post.nodes.shortComment;
+ },
+ parse: function(req, a, post) {
+ var callback, clone, comment, href, postObj, posts, quote, spoilerRange, status, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
+
+ status = req.status;
+ if (![200, 304].contains(status)) {
+ a.textContent = "Error " + req.statusText + " (" + status + ")";
+ return;
+ }
+ posts = JSON.parse(req.response).posts;
+ if (spoilerRange = posts[0].custom_spoiler) {
+ Build.spoilerRange[g.BOARD] = spoilerRange;
+ }
+ for (_i = 0, _len = posts.length; _i < _len; _i++) {
+ postObj = posts[_i];
+ if (postObj.no === post.ID) {
+ break;
+ }
+ }
+ if (postObj.no !== post.ID) {
+ a.textContent = "Post No." + post + " not found.";
+ return;
+ }
+ comment = post.nodes.comment;
+ clone = comment.cloneNode(false);
+ clone.innerHTML = postObj.com;
+ _ref = $$('.quotelink', clone);
+ for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
+ quote = _ref[_j];
+ href = quote.getAttribute('href');
+ if (href[0] === '/') {
+ continue;
+ }
+ quote.href = "/" + post.board + "/res/" + href;
+ }
+ post.nodes.shortComment = comment;
+ $.replace(comment, clone);
+ post.nodes.comment = post.nodes.longComment = clone;
+ post.parseComment();
+ post.parseQuotes();
+ _ref1 = ExpandComment.callbacks;
+ for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
+ callback = _ref1[_k];
+ callback.call(post);
+ }
+ }
+ };
+
+ ExpandThread = {
+ init: function() {
+ if (g.VIEW !== 'index' || !Conf['Thread Expansion']) {
+ return;
+ }
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Expansion',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var a, span;
+
+ if (!(span = $('.summary', this.OP.nodes.root.parentNode))) {
+ return;
+ }
+ a = $.el('a', {
+ textContent: "+ " + span.textContent,
+ className: 'summary',
+ href: 'javascript:;'
+ });
+ $.on(a, 'click', ExpandThread.cbToggle);
+ return $.replace(span, a);
+ },
+ cbToggle: function() {
+ var op;
+
+ op = Get.postFromRoot(this.previousElementSibling);
+ return ExpandThread.toggle(op.thread);
+ },
+ toggle: function(thread) {
+ var a, inlined, num, post, replies, reply, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
+
+ threadRoot = thread.OP.nodes.root.parentNode;
+ a = $('.summary', threadRoot);
+ switch (thread.isExpanded) {
+ case false:
+ case void 0:
+ thread.isExpanded = 'loading';
+ _ref = $$('.thread > .postContainer', threadRoot);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ post = _ref[_i];
+ ExpandComment.expand(Get.postFromRoot(post));
+ }
+ if (!a) {
+ thread.isExpanded = true;
+ return;
+ }
+ thread.isExpanded = 'loading';
+ a.textContent = a.textContent.replace('+', '× Loading...');
+ $.cache("//api.4chan.org/" + thread.board + "/res/" + thread + ".json", function() {
+ return ExpandThread.parse(this, thread, a);
+ });
+ break;
+ case 'loading':
+ thread.isExpanded = false;
+ if (!a) {
+ return;
+ }
+ a.textContent = a.textContent.replace('× Loading...', '+');
+ break;
+ case true:
+ thread.isExpanded = false;
+ if (a) {
+ a.textContent = a.textContent.replace('-', '+');
+ num = (function() {
+ if (thread.isSticky) {
+ return 1;
+ } else {
+ switch (g.BOARD.ID) {
+ case 'b':
+ case 'vg':
+ case 'q':
+ return 3;
+ case 't':
+ return 1;
+ default:
+ return 5;
+ }
+ }
+ })();
+ replies = $$('.thread > .replyContainer', threadRoot).slice(0, -num);
+ for (_j = 0, _len1 = replies.length; _j < _len1; _j++) {
+ reply = replies[_j];
+ if (Conf['Quote Inlining']) {
+ while (inlined = $('.inlined', reply)) {
+ inlined.click();
+ }
+ }
+ $.rm(reply);
+ }
+ }
+ _ref1 = $$('.thread > .postContainer', threadRoot);
+ for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
+ post = _ref1[_k];
+ ExpandComment.contract(Get.postFromRoot(post));
+ }
+ }
+ },
+ parse: function(req, thread, a) {
+ var link, node, nodes, post, posts, replies, reply, spoilerRange, status, _i, _len;
+
+ if (a.textContent[0] === '+') {
+ return;
+ }
+ status = req.status;
+ if (![200, 304].contains(status)) {
+ a.textContent = "Error " + req.statusText + " (" + status + ")";
+ $.off(a, 'click', ExpandThread.cb.toggle);
+ return;
+ }
+ thread.isExpanded = true;
+ a.textContent = a.textContent.replace('× Loading...', '-');
+ posts = JSON.parse(req.response).posts;
+ if (spoilerRange = posts[0].custom_spoiler) {
+ Build.spoilerRange[g.BOARD] = spoilerRange;
+ }
+ replies = posts.slice(1);
+ posts = [];
+ nodes = [];
+ for (_i = 0, _len = replies.length; _i < _len; _i++) {
+ reply = replies[_i];
+ if (post = thread.posts[reply.no]) {
+ nodes.push(post.nodes.root);
+ continue;
+ }
+ node = Build.postFromObject(reply, thread.board);
+ post = new Post(node, thread, thread.board);
+ link = $('a[title="Highlight this post"]', node);
+ link.href = "res/" + thread + "#p" + post;
+ link.nextSibling.href = "res/" + thread + "#q" + post;
+ posts.push(post);
+ nodes.push(node);
+ }
+ Main.callbackNodes(Post, posts);
+ $.after(a, nodes);
+ return Fourchan.parseThread(thread.ID, 1, nodes.length);
+ }
+ };
+
+ FileInfo = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['File Info Formatting']) {
+ return;
+ }
+ this.funk = this.createFunc(Conf['fileInfo']);
+ return Post.prototype.callbacks.push({
+ name: 'File Info Formatting',
+ cb: this.node
+ });
+ },
+ node: function() {
+ if (!this.file || this.isClone) {
+ return;
+ }
+ return this.file.text.innerHTML = FileInfo.funk(FileInfo, this);
+ },
+ createFunc: function(format) {
+ var code;
+
+ code = format.replace(/%(.)/g, function(s, c) {
+ if (c in FileInfo.formatters) {
+ return "' + FileInfo.formatters." + c + ".call(post) + '";
+ } else {
+ return s;
+ }
+ });
+ return Function('FileInfo', 'post', "return '" + code + "'");
+ },
+ convertUnit: function(size, unit) {
+ var i;
+
+ if (unit === 'B') {
+ return "" + (size.toFixed()) + " Bytes";
+ }
+ i = 1 + ['KB', 'MB'].indexOf(unit);
+ while (i--) {
+ size /= 1024;
+ }
+ size = unit === 'MB' ? Math.round(size * 100) / 100 : size.toFixed();
+ return "" + size + " " + unit;
+ },
+ escape: function(name) {
+ return name.replace(/<|>/g, function(c) {
+ return c === '<' && '<' || '>';
+ });
+ },
+ formatters: {
+ t: function() {
+ return this.file.URL.match(/\d+\..+$/)[0];
+ },
+ T: function() {
+ return "" + (FileInfo.formatters.t.call(this)) + "";
+ },
+ l: function() {
+ return "" + (FileInfo.formatters.n.call(this)) + "";
+ },
+ L: function() {
+ return "" + (FileInfo.formatters.N.call(this)) + "";
+ },
+ n: function() {
+ var fullname, shortname;
+
+ fullname = this.file.name;
+ shortname = Build.shortFilename(this.file.name, this.isReply);
+ if (fullname === shortname) {
+ return FileInfo.escape(fullname);
+ } else {
+ return "" + (FileInfo.escape(shortname)) + "" + (FileInfo.escape(fullname)) + "";
+ }
+ },
+ N: function() {
+ return FileInfo.escape(this.file.name);
+ },
+ p: function() {
+ if (this.file.isSpoiler) {
+ return 'Spoiler, ';
+ } else {
+ return '';
+ }
+ },
+ s: function() {
+ return this.file.size;
+ },
+ B: function() {
+ return FileInfo.convertUnit(this.file.sizeInBytes, 'B');
+ },
+ K: function() {
+ return FileInfo.convertUnit(this.file.sizeInBytes, 'KB');
+ },
+ M: function() {
+ return FileInfo.convertUnit(this.file.sizeInBytes, 'MB');
+ },
+ r: function() {
+ if (this.file.isImage) {
+ return this.file.dimensions;
+ } else {
+ return 'PDF';
+ }
+ }
+ }
+ };
+
+ Fourchan = {
+ init: function() {
+ var board;
+
+ if (g.VIEW === 'catalog') {
+ return;
+ }
+ board = g.BOARD.ID;
+ if (board === 'g') {
+ $.globalEval("window.addEventListener('prettyprint', function(e) {\n var pre = e.detail;\n pre.innerHTML = prettyPrintOne(pre.innerHTML);\n}, false);");
+ Post.prototype.callbacks.push({
+ name: 'Parse /g/ code',
+ cb: this.code
+ });
+ }
+ if (board === 'sci') {
+ $.globalEval("window.addEventListener('jsmath', function(e) {\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(e.detail);\n } else {\n // load jsMath and process whole document\n jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);\n jsMath.Autoload.LoadJsMath();\n }\n}, false);");
+ return Post.prototype.callbacks.push({
+ name: 'Parse /sci/ math',
+ cb: this.math
+ });
+ }
+ },
+ code: function() {
+ var pre, _i, _len, _ref;
+
+ if (this.isClone) {
+ return;
+ }
+ _ref = $$('.prettyprint', this.nodes.comment);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ pre = _ref[_i];
+ $.event('prettyprint', pre, window);
+ }
+ },
+ math: function() {
+ if (this.isClone || !$('.math', this.nodes.comment)) {
+ return;
+ }
+ return $.event('jsmath', this.nodes.post, window);
+ },
+ parseThread: function(threadID, offset, limit) {
+ return $.event('4chanParsingDone', {
+ threadId: threadID,
+ offset: offset,
+ limit: limit
+ });
+ }
+ };
+
+ Keybinds = {
+ init: function() {
+ var init;
+
+ if (g.VIEW === 'catalog' || !Conf['Keybinds']) {
+ return;
+ }
+ init = function() {
+ var node, _i, _len, _ref;
+
+ $.off(d, '4chanXInitFinished', init);
+ $.on(d, 'keydown', Keybinds.keydown);
+ _ref = $$('[accesskey]');
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ node = _ref[_i];
+ node.removeAttribute('accesskey');
+ }
+ };
+ return $.on(d, '4chanXInitFinished', init);
+ },
+ keydown: function(e) {
+ var form, key, notification, notifications, op, target, thread, threadRoot, _i, _len;
+
+ if (!(key = Keybinds.keyCode(e))) {
+ return;
+ }
+ target = e.target;
+ if (['INPUT', 'TEXTAREA'].contains(target.nodeName)) {
+ if (!/(Esc|Alt|Ctrl|Meta)/.test(key)) {
+ return;
+ }
+ }
+ threadRoot = Nav.getThread();
+ if (op = $('.op', threadRoot)) {
+ thread = Get.postFromNode(op).thread;
+ }
+ switch (key) {
+ case Conf['Toggle board list']:
+ if (Conf['Custom Board Navigation']) {
+ Header.toggleBoardList();
+ }
+ break;
+ case Conf['Open empty QR']:
+ Keybinds.qr(threadRoot);
+ break;
+ case Conf['Open QR']:
+ Keybinds.qr(threadRoot, true);
+ break;
+ case Conf['Open settings']:
+ Settings.open();
+ break;
+ case Conf['Close']:
+ if (Settings.dialog) {
+ Settings.close();
+ } else if ((notifications = $$('.notification')).length) {
+ for (_i = 0, _len = notifications.length; _i < _len; _i++) {
+ notification = notifications[_i];
+ $('.close', notification).click();
+ }
+ } else if (QR.nodes) {
+ QR.close();
+ }
+ break;
+ case Conf['Spoiler tags']:
+ if (target.nodeName !== 'TEXTAREA') {
+ return;
+ }
+ Keybinds.tags('spoiler', target);
+ break;
+ case Conf['Code tags']:
+ if (target.nodeName !== 'TEXTAREA') {
+ return;
+ }
+ Keybinds.tags('code', target);
+ break;
+ case Conf['Eqn tags']:
+ if (target.nodeName !== 'TEXTAREA') {
+ return;
+ }
+ Keybinds.tags('eqn', target);
+ break;
+ case Conf['Math tags']:
+ if (target.nodeName !== 'TEXTAREA') {
+ return;
+ }
+ Keybinds.tags('math', target);
+ break;
+ case Conf['Toggle sage']:
+ if (QR.nodes) {
+ Keybinds.sage();
+ }
+ break;
+ case Conf['Submit QR']:
+ if (QR.nodes && !QR.status()) {
+ QR.submit();
+ }
+ break;
+ case Conf['Watch']:
+ ThreadWatcher.toggle(thread);
+ break;
+ case Conf['Update']:
+ ThreadUpdater.update();
+ break;
+ case Conf['Expand image']:
+ Keybinds.img(threadRoot);
+ break;
+ case Conf['Expand images']:
+ Keybinds.img(threadRoot, true);
+ break;
+ case Conf['fappeTyme']:
+ if (!$('#menu.left')) {
+ Header.menuButton.click();
+ }
+ FappeTyme.input.click();
+ break;
+ case Conf['Front page']:
+ window.location = "/" + g.BOARD + "/0#delform";
+ break;
+ case Conf['Open front page']:
+ $.open("/" + g.BOARD + "/#delform");
+ break;
+ case Conf['Next page']:
+ if (form = $('.next form')) {
+ window.location = form.action;
+ }
+ break;
+ case Conf['Previous page']:
+ if (form = $('.prev form')) {
+ window.location = form.action;
+ }
+ break;
+ case Conf['Open catalog']:
+ if (Conf['External Catalog']) {
+ window.location = CatalogLinks.external(g.BOARD.ID);
+ } else {
+ window.location = "/" + g.BOARD + "/catalog";
+ }
+ break;
+ case Conf['Next thread']:
+ if (g.VIEW === 'thread') {
+ return;
+ }
+ Nav.scroll(+1);
+ break;
+ case Conf['Previous thread']:
+ if (g.VIEW === 'thread') {
+ return;
+ }
+ Nav.scroll(-1);
+ break;
+ case Conf['Expand thread']:
+ ExpandThread.toggle(thread);
+ break;
+ case Conf['Open thread']:
+ Keybinds.open(thread);
+ break;
+ case Conf['Open thread tab']:
+ Keybinds.open(thread, true);
+ break;
+ case Conf['Next reply']:
+ Keybinds.hl(+1, threadRoot);
+ break;
+ case Conf['Previous reply']:
+ Keybinds.hl(-1, threadRoot);
+ break;
+ case Conf['Hide']:
+ if (g.VIEW === 'index') {
+ ThreadHiding.toggle(thread);
+ }
+ break;
+ default:
+ return;
+ }
+ e.preventDefault();
+ return e.stopPropagation();
+ },
+ keyCode: function(e) {
+ var kc, key;
+
+ key = (function() {
+ switch (kc = e.keyCode) {
+ case 8:
+ return '';
+ case 13:
+ return 'Enter';
+ case 27:
+ return 'Esc';
+ case 37:
+ return 'Left';
+ case 38:
+ return 'Up';
+ case 39:
+ return 'Right';
+ case 40:
+ return 'Down';
+ default:
+ if ((48 <= kc && kc <= 57) || (65 <= kc && kc <= 90)) {
+ return String.fromCharCode(kc).toLowerCase();
+ } else {
+ return null;
+ }
+ }
+ })();
+ if (key) {
+ if (e.altKey) {
+ key = 'Alt+' + key;
+ }
+ if (e.ctrlKey) {
+ key = 'Ctrl+' + key;
+ }
+ if (e.metaKey) {
+ key = 'Meta+' + key;
+ }
+ if (e.shiftKey) {
+ key = 'Shift+' + key;
+ }
+ }
+ return key;
+ },
+ qr: function(thread, quote) {
+ if (!(Conf['Quick Reply'] && QR.postingIsEnabled)) {
+ return;
+ }
+ QR.open();
+ if (quote) {
+ QR.quote.call($('input', $('.post.highlight', thread) || thread));
+ }
+ QR.nodes.com.focus();
+ if (Conf['QR Shortcut']) {
+ return $.rmClass($('.qr-shortcut'), 'disabled');
+ }
+ },
+ tags: function(tag, ta) {
+ var range, selEnd, selStart, value;
+
+ value = ta.value;
+ selStart = ta.selectionStart;
+ selEnd = ta.selectionEnd;
+ ta.value = value.slice(0, selStart) + ("[" + tag + "]") + value.slice(selStart, selEnd) + ("[/" + tag + "]") + value.slice(selEnd);
+ range = ("[" + tag + "]").length + selEnd;
+ ta.setSelectionRange(range, range);
+ return $.event('input', null, ta);
+ },
+ sage: function() {
+ var isSage;
+
+ isSage = /sage/i.test(QR.nodes.email.value);
+ return QR.nodes.email.value = isSage ? "" : "sage";
+ },
+ img: function(thread, all) {
+ var post;
+
+ if (all) {
+ return ImageExpand.cb.toggleAll();
+ } else {
+ post = Get.postFromNode($('.post.highlight', thread) || $('.op', thread));
+ return ImageExpand.toggle(post);
+ }
+ },
+ open: function(thread, tab) {
+ var url;
+
+ if (g.VIEW !== 'index') {
+ return;
+ }
+ url = "/" + thread.board + "/res/" + thread;
+ if (tab) {
+ return $.open(url);
+ } else {
+ return location.href = url;
+ }
+ },
+ hl: function(delta, thread) {
+ var headRect, next, postEl, rect, replies, reply, root, topMargin, _i, _len;
+
+ if (Conf['Fixed Header'] && Conf['Bottom header']) {
+ topMargin = 0;
+ } else {
+ headRect = Header.bar.getBoundingClientRect();
+ topMargin = headRect.top + headRect.height;
+ }
+ if (postEl = $('.reply.highlight', thread)) {
+ $.rmClass(postEl, 'highlight');
+ rect = postEl.getBoundingClientRect();
+ if (rect.bottom >= topMargin && rect.top <= doc.clientHeight) {
+ root = postEl.parentNode;
+ next = $.x('child::div[contains(@class,"post reply")]', delta === +1 ? root.nextElementSibling : root.previousElementSibling);
+ if (!next) {
+ this.focus(postEl);
+ return;
+ }
+ if (!(g.VIEW === 'thread' || $.x('ancestor::div[parent::div[@class="board"]]', next) === thread)) {
+ return;
+ }
+ rect = next.getBoundingClientRect();
+ if (rect.top < 0 || rect.bottom > doc.clientHeight) {
+ if (delta === -1) {
+ window.scrollBy(0, rect.top - topMargin);
+ } else {
+ next.scrollIntoView(false);
+ }
+ }
+ this.focus(next);
+ return;
+ }
+ }
+ replies = $$('.reply', thread);
+ if (delta === -1) {
+ replies.reverse();
+ }
+ for (_i = 0, _len = replies.length; _i < _len; _i++) {
+ reply = replies[_i];
+ rect = reply.getBoundingClientRect();
+ if (delta === +1 && rect.top >= topMargin || delta === -1 && rect.bottom <= doc.clientHeight) {
+ this.focus(reply);
+ return;
+ }
+ }
+ },
+ focus: function(post) {
+ return $.addClass(post, 'highlight');
+ }
+ };
+
+ Nav = {
+ init: function() {
+ var append, next, prev, span;
+
+ switch (g.VIEW) {
+ case 'index':
+ if (!Conf['Index Navigation']) {
+ return;
+ }
+ break;
+ case 'thread':
+ if (!Conf['Reply Navigation']) {
+ return;
+ }
+ break;
+ default:
+ return;
+ }
+ span = $.el('span', {
+ id: 'navlinks'
+ });
+ prev = $.el('a', {
+ textContent: '▲',
+ href: 'javascript:;'
+ });
+ next = $.el('a', {
+ textContent: '▼',
+ href: 'javascript:;'
+ });
+ $.on(prev, 'click', this.prev);
+ $.on(next, 'click', this.next);
+ $.add(span, [prev, $.tn(' '), next]);
+ append = function() {
+ $.off(d, '4chanXInitFinished', append);
+ return $.add(d.body, span);
+ };
+ return $.on(d, '4chanXInitFinished', append);
+ },
+ prev: function() {
+ if (g.VIEW === 'thread') {
+ return window.scrollTo(0, 0);
+ } else {
+ return Nav.scroll(-1);
+ }
+ },
+ next: function() {
+ if (g.VIEW === 'thread') {
+ return window.scrollTo(0, d.body.scrollHeight);
+ } else {
+ return Nav.scroll(+1);
+ }
+ },
+ getThread: function(full) {
+ var headRect, i, rect, thread, threads, topMargin, _i, _len;
+
+ if (Conf['Bottom header']) {
+ topMargin = 0;
+ } else {
+ headRect = Header.bar.getBoundingClientRect();
+ topMargin = headRect.top + headRect.height;
+ }
+ threads = $$('.thread:not([hidden])');
+ for (i = _i = 0, _len = threads.length; _i < _len; i = ++_i) {
+ thread = threads[i];
+ rect = thread.getBoundingClientRect();
+ if (rect.bottom > topMargin) {
+ if (full) {
+ return [threads, thread, i, rect, topMargin];
+ } else {
+ return thread;
+ }
+ }
+ }
+ return $('.board');
+ },
+ scroll: function(delta) {
+ var i, rect, thread, threads, top, topMargin, _ref, _ref1;
+
+ _ref = Nav.getThread(true), threads = _ref[0], thread = _ref[1], i = _ref[2], rect = _ref[3], topMargin = _ref[4];
+ top = rect.top - topMargin;
+ if (!((delta === -1 && Math.ceil(top) < 0) || (delta === +1 && top > 1))) {
+ i += delta;
+ }
+ top = ((_ref1 = threads[i]) != null ? _ref1.getBoundingClientRect().top : void 0) - topMargin;
+ return window.scrollBy(0, top);
+ }
+ };
+
+ RelativeDates = {
+ INTERVAL: $.MINUTE / 2,
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Relative Post Dates']) {
+ return;
+ }
+ $.on(d, 'visibilitychange ThreadUpdate', this.flush);
+ this.flush();
+ return Post.prototype.callbacks.push({
+ name: 'Relative Post Dates',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var dateEl;
+
+ if (this.isClone) {
+ return;
+ }
+ dateEl = this.nodes.date;
+ dateEl.title = dateEl.textContent;
+ return RelativeDates.setUpdate(this);
+ },
+ relative: function(diff, now, date) {
+ var days, months, number, rounded, unit, years;
+
+ unit = (number = diff / $.DAY) >= 1 ? (years = now.getYear() - date.getYear(), months = now.getMonth() - date.getMonth(), days = now.getDate() - date.getDate(), years > 1 ? (number = years - (months < 0 || months === 0 && days < 0), 'year') : years === 1 && (months > 0 || months === 0 && days >= 0) ? (number = years, 'year') : (months = (months + 12) % 12) > 1 ? (number = months - (days < 0), 'month') : months === 1 && days >= 0 ? (number = months, 'month') : 'day') : (number = diff / $.HOUR) >= 1 ? 'hour' : (number = diff / $.MINUTE) >= 1 ? 'minute' : (number = Math.max(0, diff) / $.SECOND, 'second');
+ rounded = Math.round(number);
+ if (rounded !== 1) {
+ unit += 's';
+ }
+ return "" + rounded + " " + unit + " ago";
+ },
+ stale: [],
+ flush: function() {
+ var now, update, _i, _len, _ref;
+
+ if (d.hidden) {
+ return;
+ }
+ now = new Date();
+ _ref = RelativeDates.stale;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ update = _ref[_i];
+ update(now);
+ }
+ RelativeDates.stale = [];
+ clearTimeout(RelativeDates.timeout);
+ return RelativeDates.timeout = setTimeout(RelativeDates.flush, RelativeDates.INTERVAL);
+ },
+ setUpdate: function(post) {
+ var markStale, setOwnTimeout, update;
+
+ setOwnTimeout = function(diff) {
+ var delay;
+
+ delay = diff < $.MINUTE ? $.SECOND - (diff + $.SECOND / 2) % $.SECOND : diff < $.HOUR ? $.MINUTE - (diff + $.MINUTE / 2) % $.MINUTE : diff < $.DAY ? $.HOUR - (diff + $.HOUR / 2) % $.HOUR : $.DAY - (diff + $.DAY / 2) % $.DAY;
+ return setTimeout(markStale, delay);
+ };
+ update = function(now) {
+ var date, diff, relative, singlePost, _i, _len, _ref;
+
+ date = post.info.date;
+ diff = now - date;
+ relative = RelativeDates.relative(diff, now, date);
+ _ref = [post].concat(post.clones);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ singlePost = _ref[_i];
+ singlePost.nodes.date.firstChild.textContent = relative;
+ }
+ return setOwnTimeout(diff);
+ };
+ markStale = function() {
+ return RelativeDates.stale.push(update);
+ };
+ return update(new Date());
+ }
+ };
+
+ RemoveSpoilers = {
+ init: function() {
+ if (!Conf['Remove Spoilers']) {
+ return;
+ }
+ if (Conf['Indicate Spoilers']) {
+ this.wrapper = function(text) {
+ return "[spoiler]" + text + "[/spoiler]";
+ };
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Reveal Spoilers',
+ cb: this.node
+ });
+ },
+ wrapper: function(text) {
+ return text;
+ },
+ node: function(post) {
+ var spoiler, spoilers, _i, _len;
+
+ spoilers = $$('s', this.nodes.comment);
+ for (_i = 0, _len = spoilers.length; _i < _len; _i++) {
+ spoiler = spoilers[_i];
+ $.replace(spoiler, $.tn(RemoveSpoilers.wrapper(spoiler.textContent)));
+ }
+ }
+ };
+
+ Report = {
+ init: function() {
+ if (!/report/.test(location.search)) {
+ return;
+ }
+ return $.ready(this.ready);
+ },
+ ready: function() {
+ var field, form;
+
+ form = $('form');
+ field = $.id('recaptcha_response_field');
+ $.on(field, 'keydown', function(e) {
+ if (e.keyCode === 8 && !field.value) {
+ return $.globalEval('Recaptcha.reload("t")');
+ }
+ });
+ return $.on(form, 'submit', function(e) {
+ var response;
+
+ e.preventDefault();
+ response = field.value.trim();
+ if (!/\s/.test(response)) {
+ field.value = "" + response + " " + response;
+ }
+ return form.submit();
+ });
+ }
+ };
+
+ Sauce = {
+ init: function() {
+ var link, links, _i, _len, _ref;
+
+ if (g.VIEW === 'catalog' || !Conf['Sauce']) {
+ return;
+ }
+ links = [];
+ _ref = Conf['sauces'].split('\n');
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ link = _ref[_i];
+ if (link[0] === '#') {
+ continue;
+ }
+ links.push(this.createSauceLink(link.trim()));
+ }
+ if (!links.length) {
+ return;
+ }
+ this.links = links;
+ this.link = $.el('a', {
+ target: '_blank'
+ });
+ return Post.prototype.callbacks.push({
+ name: 'Sauce',
+ cb: this.node
+ });
+ },
+ createSauceLink: function(link) {
+ var m, text;
+
+ link = link.replace(/%(T?URL|MD5|board)/ig, function(parameter) {
+ switch (parameter) {
+ case '%TURL':
+ return "' + encodeURIComponent(post.file.thumbURL) + '";
+ case '%URL':
+ return "' + encodeURIComponent(post.file.URL) + '";
+ case '%MD5':
+ return "' + encodeURIComponent(post.file.MD5) + '";
+ case '%board':
+ return "' + encodeURIComponent(post.board) + '";
+ default:
+ return parameter;
+ }
+ });
+ text = (m = link.match(/;text:(.+)$/)) ? m[1] : link.match(/(\w+)\.\w+\//)[1];
+ link = link.replace(/;text:.+$/, '');
+ return Function('post', 'a', "a.href = '" + link + "';\na.textContent = '" + text + "';\nreturn a;");
+ },
+ node: function() {
+ var link, nodes, _i, _len, _ref;
+
+ if (this.isClone || !this.file) {
+ return;
+ }
+ nodes = [];
+ _ref = Sauce.links;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ link = _ref[_i];
+ nodes.push($.tn('\u00A0'), link(this, Sauce.link.cloneNode(true)));
+ }
+ return $.add(this.file.info, nodes);
+ }
+ };
+
+ Time = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Time Formatting']) {
+ return;
+ }
+ this.funk = this.createFunc(Conf['time']);
+ return Post.prototype.callbacks.push({
+ name: 'Time Formatting',
+ cb: this.node
+ });
+ },
+ node: function() {
+ if (this.isClone) {
+ return;
+ }
+ return this.nodes.date.textContent = Time.funk(Time, this.info.date);
+ },
+ createFunc: function(format) {
+ var code;
+
+ code = format.replace(/%([A-Za-z])/g, function(s, c) {
+ if (c in Time.formatters) {
+ return "' + Time.formatters." + c + ".call(date) + '";
+ } else {
+ return s;
+ }
+ });
+ return Function('Time', 'date', "return '" + code + "'");
+ },
+ day: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
+ month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
+ zeroPad: function(n) {
+ if (n < 10) {
+ return "0" + n;
+ } else {
+ return n;
+ }
+ },
+ formatters: {
+ a: function() {
+ return Time.day[this.getDay()].slice(0, 3);
+ },
+ A: function() {
+ return Time.day[this.getDay()];
+ },
+ b: function() {
+ return Time.month[this.getMonth()].slice(0, 3);
+ },
+ B: function() {
+ return Time.month[this.getMonth()];
+ },
+ d: function() {
+ return Time.zeroPad(this.getDate());
+ },
+ e: function() {
+ return this.getDate();
+ },
+ H: function() {
+ return Time.zeroPad(this.getHours());
+ },
+ I: function() {
+ return Time.zeroPad(this.getHours() % 12 || 12);
+ },
+ k: function() {
+ return this.getHours();
+ },
+ l: function() {
+ return this.getHours() % 12 || 12;
+ },
+ m: function() {
+ return Time.zeroPad(this.getMonth() + 1);
+ },
+ M: function() {
+ return Time.zeroPad(this.getMinutes());
+ },
+ p: function() {
+ if (this.getHours() < 12) {
+ return 'AM';
+ } else {
+ return 'PM';
+ }
+ },
+ P: function() {
+ if (this.getHours() < 12) {
+ return 'am';
+ } else {
+ return 'pm';
+ }
+ },
+ S: function() {
+ return Time.zeroPad(this.getSeconds());
+ },
+ y: function() {
+ return this.getFullYear() - 2000;
+ }
+ }
+ };
+
Settings = {
init: function() {
var link, settings;
diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js
index 39bdef7a7..0a6ba93ad 100644
--- a/builds/4chan-X.user.js
+++ b/builds/4chan-X.user.js
@@ -810,159 +810,6 @@
return __slice.call(root.querySelectorAll(selector));
};
- Build = {
- spoilerRange: {},
- shortFilename: function(filename, isReply) {
- var threshold;
-
- threshold = isReply ? 30 : 40;
- if (filename.length - 4 > threshold) {
- return "" + filename.slice(0, threshold - 5) + "(...)." + filename.slice(-3);
- } else {
- return filename;
- }
- },
- postFromObject: function(data, boardID) {
- var o;
-
- o = {
- postID: data.no,
- threadID: data.resto || data.no,
- boardID: boardID,
- name: data.name,
- capcode: data.capcode,
- tripcode: data.trip,
- uniqueID: data.id,
- email: data.email ? encodeURI(data.email.replace(/"/g, '"')) : '',
- subject: data.sub,
- flagCode: data.country,
- flagName: data.country_name,
- date: data.now,
- dateUTC: data.time,
- comment: data.com,
- isSticky: !!data.sticky,
- isClosed: !!data.closed
- };
- if (data.ext || data.filedeleted) {
- o.file = {
- name: data.filename + data.ext,
- timestamp: "" + data.tim + data.ext,
- url: "//images.4chan.org/" + boardID + "/src/" + data.tim + data.ext,
- height: data.h,
- width: data.w,
- MD5: data.md5,
- size: data.fsize,
- turl: "//thumbs.4chan.org/" + boardID + "/thumb/" + data.tim + "s.jpg",
- theight: data.tn_h,
- twidth: data.tn_w,
- isSpoiler: !!data.spoiler,
- isDeleted: !!data.filedeleted
- };
- }
- return Build.post(o);
- },
- post: function(o, isArchived) {
- /*
- This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS).
- @license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
- */
-
- var a, boardID, capcode, capcodeClass, capcodeStart, closed, comment, container, date, dateUTC, email, emailEnd, emailStart, ext, file, fileDims, fileHTML, fileInfo, fileSize, fileThumb, filename, flag, flagCode, flagName, href, imgSrc, isClosed, isOP, isSticky, name, postID, quote, shortFilename, spoilerRange, staticPath, sticky, subject, threadID, tripcode, uniqueID, userID, _i, _len, _ref;
-
- postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, comment = o.comment, file = o.file;
- isOP = postID === threadID;
- staticPath = '//static.4chan.org';
- if (email) {
- emailStart = '';
- emailEnd = '';
- } else {
- emailStart = '';
- emailEnd = '';
- }
- subject = "" + (subject || '') + "";
- userID = !capcode && uniqueID ? (" (ID: ") + ("" + uniqueID + ") ") : '';
- switch (capcode) {
- case 'admin':
- case 'admin_highlight':
- capcodeClass = " capcodeAdmin";
- capcodeStart = " ## Admin";
- capcode = ("
";
- break;
- case 'mod':
- capcodeClass = " capcodeMod";
- capcodeStart = " ## Mod";
- capcode = ("
";
- break;
- case 'developer':
- capcodeClass = " capcodeDeveloper";
- capcodeStart = " ## Developer";
- capcode = ("
";
- break;
- default:
- capcodeClass = '';
- capcodeStart = '';
- capcode = '';
- }
- flag = flagCode ? ("
") : '';
- if (file != null ? file.isDeleted : void 0) {
- fileHTML = isOP ? ("") + ("
") + " " : ("") + ("
") + " ";
- } else if (file) {
- ext = file.name.slice(-3);
- if (!file.twidth && !file.theight && ext === 'gif') {
- file.twidth = file.width;
- file.theight = file.height;
- }
- fileSize = $.bytesToString(file.size);
- fileThumb = file.turl;
- if (file.isSpoiler) {
- fileSize = "Spoiler Image, " + fileSize;
- if (!isArchived) {
- fileThumb = '//static.4chan.org/image/spoiler';
- if (spoilerRange = Build.spoilerRange[boardID]) {
- fileThumb += ("-" + boardID) + Math.floor(1 + spoilerRange * Math.random());
- }
- fileThumb += '.png';
- file.twidth = file.theight = 100;
- }
- }
- if (boardID.ID !== 'f') {
- imgSrc = ("") + ("
");
- }
- a = $.el('a', {
- innerHTML: file.name
- });
- filename = a.textContent.replace(/%22/g, '"');
- a.textContent = Build.shortFilename(filename);
- shortFilename = a.innerHTML;
- a.textContent = filename;
- filename = a.innerHTML.replace(/'/g, ''');
- fileDims = ext === 'pdf' ? 'PDF' : "" + file.width + "x" + file.height;
- fileInfo = ("File: " + file.timestamp + "") + ("-(" + fileSize + ", " + fileDims + (file.isSpoiler ? '' : ", " + shortFilename + "")) + ")";
- fileHTML = "" + fileInfo + "
" + imgSrc + "
";
- } else {
- fileHTML = '';
- }
- tripcode = tripcode ? " " + tripcode + "" : '';
- sticky = isSticky ? '
' : '';
- closed = isClosed ? '
' : '';
- container = $.el('div', {
- id: "pc" + postID,
- className: "postContainer " + (isOP ? 'op' : 'reply') + "Container",
- innerHTML: (isOP ? '' : ">>
") + ("") + ("
") + ("
") + ("" + (name || '') + "") + tripcode + capcodeStart + capcode + userID + flag + sticky + closed + ("
" + subject) + ("" + date) + ("No.") + ("" + postID + "") + '' + '
' + (isOP ? fileHTML : '') + ("
") + ("
") + ("" + subject + " ") + ("
") + emailStart + ("" + (name || '') + "") + tripcode + capcodeStart + emailEnd + capcode + userID + flag + sticky + closed + ' ' + ("
" + date + " ") + "
" + ("No.") + ("" + postID + "") + '' + '
' + (isOP ? '' : fileHTML) + ("
" + (comment || '') + "
") + '
'
- });
- _ref = $$('.quotelink', container);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quote = _ref[_i];
- href = quote.getAttribute('href');
- if (href[0] === '/') {
- continue;
- }
- quote.href = "/" + boardID + "/res/" + href;
- }
- return container;
- }
- };
-
Board = (function() {
Board.prototype.toString = function() {
return this.ID;
@@ -1544,6 +1391,517 @@
})();
+ Polyfill = {
+ init: function() {
+ return Polyfill.visibility();
+ },
+ visibility: function() {
+ var event, prefix, property;
+
+ if ('visibilityState' in document || !(prefix = ('webkitVisibilityState' in document ? 'webkit' : 'mozVisibilityState' in document ? 'moz' : void 0))) {
+ return;
+ }
+ property = prefix + 'VisibilityState';
+ event = prefix + 'visibilitychange';
+ d.visibilityState = d[property];
+ d.hidden = d.visibilityState === 'hidden';
+ return $.on(d, event, function() {
+ d.visibilityState = d[property];
+ d.hidden = d.visibilityState === 'hidden';
+ return $.event('visibilitychange');
+ });
+ }
+ };
+
+ Header = {
+ init: function() {
+ var barFixedToggler, barPositionToggler, customNavToggler, editCustomNav, footerToggler, headerToggler,
+ _this = this;
+
+ this.menu = new UI.Menu('header');
+ this.menuButton = $.el('span', {
+ className: 'menu-button',
+ innerHTML: ''
+ });
+ barFixedToggler = $.el('label', {
+ innerHTML: ' Fixed Header'
+ });
+ headerToggler = $.el('label', {
+ innerHTML: ' Auto-hide header'
+ });
+ barPositionToggler = $.el('label', {
+ innerHTML: ' Bottom header'
+ });
+ customNavToggler = $.el('label', {
+ innerHTML: ' Custom board navigation'
+ });
+ footerToggler = $.el('label', {
+ innerHTML: " Hide bottom board list"
+ });
+ editCustomNav = $.el('a', {
+ textContent: 'Edit custom board navigation',
+ href: 'javascript:;'
+ });
+ this.barFixedToggler = barFixedToggler.firstElementChild;
+ this.barPositionToggler = barPositionToggler.firstElementChild;
+ this.headerToggler = headerToggler.firstElementChild;
+ this.footerToggler = footerToggler.firstElementChild;
+ this.customNavToggler = customNavToggler.firstElementChild;
+ $.on(this.menuButton, 'click', this.menuToggle);
+ $.on(this.barFixedToggler, 'change', this.toggleBarFixed);
+ $.on(this.barPositionToggler, 'change', this.toggleBarPosition);
+ $.on(this.headerToggler, 'change', this.toggleBarVisibility);
+ $.on(this.footerToggler, 'change', this.toggleFooterVisibility);
+ $.on(this.customNavToggler, 'change', this.toggleCustomNav);
+ $.on(editCustomNav, 'click', this.editCustomNav);
+ this.setBarFixed(Conf['Fixed Header']);
+ this.setBarVisibility(Conf['Header auto-hide']);
+ $.sync('Fixed Header', Header.setBarFixed);
+ $.sync('Bottom Header', Header.setBarPosition);
+ $.sync('Header auto-hide', Header.setBarVisibility);
+ this.addShortcut(Header.menuButton);
+ $.event('AddMenuEntry', {
+ type: 'header',
+ el: $.el('span', {
+ textContent: 'Header'
+ }),
+ order: 107,
+ subEntries: [
+ {
+ el: barFixedToggler
+ }, {
+ el: headerToggler
+ }, {
+ el: barPositionToggler
+ }, {
+ el: footerToggler
+ }, {
+ el: customNavToggler
+ }, {
+ el: editCustomNav
+ }
+ ]
+ });
+ $.on(window, 'load hashchange', Header.hashScroll);
+ $.on(d, 'CreateNotification', this.createNotification);
+ $.asap((function() {
+ return d.body;
+ }), function() {
+ if (!Main.isThisPageLegit()) {
+ return;
+ }
+ $.asap((function() {
+ return $.id('boardNavMobile') || d.readyState === 'complete';
+ }), Header.setBoardList);
+ $.prepend(d.body, _this.bar);
+ $.add(d.body, Header.hover);
+ return _this.setBarPosition(Conf['Bottom Header']);
+ });
+ return $.ready(function() {
+ var a, cs;
+
+ _this.footer = $.id('boardNavDesktopFoot');
+ if (a = $("a[href*='/" + g.BOARD + "/']", $.id('boardNavDesktopFoot'))) {
+ a.className = 'current';
+ }
+ cs = $.id('settingsWindowLink');
+ cs.textContent = 'Catalog Settings';
+ if (g.VIEW === 'catalog') {
+ _this.addShortcut(cs);
+ }
+ Header.setFooterVisibility(Conf['Bottom Board List']);
+ return $.sync('Bottom Board List', Header.setFooterVisibility);
+ });
+ },
+ bar: $.el('div', {
+ id: 'header-bar'
+ }),
+ notify: $.el('div', {
+ id: 'notifications'
+ }),
+ shortcuts: $.el('span', {
+ id: 'shortcuts'
+ }),
+ hover: $.el('div', {
+ id: 'hoverUI'
+ }),
+ toggle: $.el('div', {
+ id: 'scroll-marker'
+ }),
+ setBoardList: function() {
+ var a, boardList, btn, fourchannav, fullBoardList;
+
+ fourchannav = $.id('boardNavDesktop');
+ if (a = $("a[href*='/" + g.BOARD + "/']", fourchannav)) {
+ a.className = 'current';
+ }
+ boardList = $.el('span', {
+ id: 'board-list',
+ innerHTML: "[ - ] " + fourchannav.innerHTML + ""
+ });
+ fullBoardList = $('#full-board-list', boardList);
+ btn = $('.hide-board-list-button', fullBoardList);
+ $.on(btn, 'click', Header.toggleBoardList);
+ $.rm($('#navtopright', fullBoardList));
+ $.add(boardList, fullBoardList);
+ $.add(Header.bar, [boardList, Header.shortcuts, Header.notify, Header.toggle]);
+ Header.setCustomNav(Conf['Custom Board Navigation']);
+ Header.generateBoardList(Conf['boardnav']);
+ $.sync('Custom Board Navigation', Header.setCustomNav);
+ return $.sync('boardnav', Header.generateBoardList);
+ },
+ generateBoardList: function(text) {
+ var as, list, nodes;
+
+ list = $('#custom-board-list', Header.bar);
+ $.rmAll(list);
+ if (!text) {
+ return;
+ }
+ as = $$('#full-board-list a', Header.bar);
+ nodes = text.match(/[\w@]+(-(all|title|replace|full|index|catalog|text:"[^"]+"))*|[^\w@]+/g).map(function(t) {
+ var a, board, m, _i, _len;
+
+ if (/^[^\w@]/.test(t)) {
+ return $.tn(t);
+ }
+ if (/^toggle-all/.test(t)) {
+ a = $.el('a', {
+ className: 'show-board-list-button',
+ textContent: (t.match(/-text:"(.+)"/) || [null, '+'])[1],
+ href: 'javascript:;'
+ });
+ $.on(a, 'click', Header.toggleBoardList);
+ return a;
+ }
+ board = /^current/.test(t) ? g.BOARD.ID : t.match(/^[^-]+/)[0];
+ for (_i = 0, _len = as.length; _i < _len; _i++) {
+ a = as[_i];
+ if (a.textContent === board) {
+ a = a.cloneNode(true);
+ if (/-title/.test(t)) {
+ a.textContent = a.title;
+ } else if (/-replace/.test(t)) {
+ if ($.hasClass(a, 'current')) {
+ a.textContent = a.title;
+ }
+ } else if (/-full/.test(t)) {
+ a.textContent = "/" + board + "/ - " + a.title;
+ } else if (/-(index|catalog|text)/.test(t)) {
+ if (m = t.match(/-(index|catalog)/)) {
+ a.setAttribute('data-only', m[1]);
+ a.href = "//boards.4chan.org/" + board + "/";
+ if (m[1] === 'catalog') {
+ a.href += 'catalog';
+ }
+ }
+ if (m = t.match(/-text:"(.+)"/)) {
+ a.textContent = m[1];
+ }
+ } else if (board === '@') {
+ $.addClass(a, 'navSmall');
+ }
+ return a;
+ }
+ }
+ return $.tn(t);
+ });
+ return $.add(list, nodes);
+ },
+ toggleBoardList: function() {
+ var bar, custom, full, showBoardList;
+
+ bar = Header.bar;
+ custom = $('#custom-board-list', bar);
+ full = $('#full-board-list', bar);
+ showBoardList = !full.hidden;
+ custom.hidden = !showBoardList;
+ return full.hidden = showBoardList;
+ },
+ setBarPosition: function(bottom) {
+ Header.barPositionToggler.checked = bottom;
+ if (bottom) {
+ $.rmClass(doc, 'top');
+ $.addClass(doc, 'bottom');
+ return $.after(Header.bar, Header.notify);
+ } else {
+ $.rmClass(doc, 'bottom');
+ $.addClass(doc, 'top');
+ return $.add(Header.bar, Header.notify);
+ }
+ },
+ toggleBarPosition: function() {
+ $.event('CloseMenu');
+ Header.setBarPosition(this.checked);
+ Conf['Bottom Header'] = this.checked;
+ return $.set('Bottom Header', this.checked);
+ },
+ setBarFixed: function(fixed) {
+ Header.barFixedToggler.checked = fixed;
+ if (fixed) {
+ $.addClass(doc, 'fixed');
+ return $.addClass(Header.bar, 'dialog');
+ } else {
+ $.rmClass(doc, 'fixed');
+ return $.rmClass(Header.bar, 'dialog');
+ }
+ },
+ toggleBarFixed: function() {
+ $.event('CloseMenu');
+ Header.setBarFixed(this.checked);
+ Conf['Fixed Header'] = this.checked;
+ return $.set('Fixed Header', this.checked);
+ },
+ setBarVisibility: function(hide) {
+ Header.headerToggler.checked = hide;
+ $.event('CloseMenu');
+ (hide ? $.addClass : $.rmClass)(Header.bar, 'autohide');
+ return (hide ? $.addClass : $.rmClass)(doc, 'autohide');
+ },
+ toggleBarVisibility: function(e) {
+ var hide, message;
+
+ if (e.type === 'mousedown' && e.button !== 0) {
+ return;
+ }
+ hide = this.nodeName === 'INPUT' ? this.checked : !$.hasClass(Header.bar, 'autohide');
+ Conf['Header auto-hide'] = hide;
+ $.set('Header auto-hide', hide);
+ Header.setBarVisibility(hide);
+ message = hide ? 'The header bar will automatically hide itself.' : 'The header bar will remain visible.';
+ return new Notification('info', message, 2);
+ },
+ setFooterVisibility: function(hide) {
+ Header.footerToggler.checked = hide;
+ return Header.footer.hidden = hide;
+ },
+ toggleFooterVisibility: function() {
+ var hide, message;
+
+ $.event('CloseMenu');
+ hide = this.nodeName === 'INPUT' ? this.checked : !!Header.footer.hidden;
+ Header.setFooterVisibility(hide);
+ $.set('Bottom Board List', hide);
+ message = hide ? 'The bottom navigation will now be hidden.' : 'The bottom navigation will remain visible.';
+ return new Notification('info', message, 2);
+ },
+ setCustomNav: function(show) {
+ var btn, cust, full, _ref;
+
+ Header.customNavToggler.checked = show;
+ cust = $('#custom-board-list', Header.bar);
+ full = $('#full-board-list', Header.bar);
+ btn = $('.hide-board-list-button', full);
+ return _ref = show ? [false, true] : [true, false], cust.hidden = _ref[0], full.hidden = _ref[1], _ref;
+ },
+ toggleCustomNav: function() {
+ $.cb.checked.call(this);
+ return Header.setCustomNav(this.checked);
+ },
+ editCustomNav: function() {
+ var settings;
+
+ Settings.open('Advanced');
+ settings = $.id('fourchanx-settings');
+ return $('input[name=boardnav]', settings).focus();
+ },
+ hashScroll: function() {
+ var hash, post;
+
+ if (!((hash = this.location.hash) && (post = $.id(hash.slice(1))))) {
+ return;
+ }
+ if ((Get.postFromRoot(post)).isHidden) {
+ return;
+ }
+ return Header.scrollToPost(post);
+ },
+ scrollToPost: function(post) {
+ var headRect, top;
+
+ top = post.getBoundingClientRect().top;
+ if (Conf['Fixed Header'] && !Conf['Bottom Header']) {
+ headRect = Header.bar.getBoundingClientRect();
+ top += -headRect.top - headRect.height;
+ }
+ return ($.engine === 'webkit' ? d.body : doc).scrollTop += top;
+ },
+ addShortcut: function(el) {
+ var shortcut;
+
+ shortcut = $.el('span', {
+ className: 'shortcut'
+ });
+ $.add(shortcut, [$.tn(' ['), el, $.tn(']')]);
+ return $.prepend(Header.shortcuts, shortcut);
+ },
+ menuToggle: function(e) {
+ return Header.menu.toggle(e, this, g);
+ },
+ createNotification: function(e) {
+ var cb, content, lifetime, notif, type, _ref;
+
+ _ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb;
+ notif = new Notification(type, content, lifetime);
+ if (cb) {
+ return cb(notif);
+ }
+ }
+ };
+
+ Build = {
+ spoilerRange: {},
+ shortFilename: function(filename, isReply) {
+ var threshold;
+
+ threshold = isReply ? 30 : 40;
+ if (filename.length - 4 > threshold) {
+ return "" + filename.slice(0, threshold - 5) + "(...)." + filename.slice(-3);
+ } else {
+ return filename;
+ }
+ },
+ postFromObject: function(data, boardID) {
+ var o;
+
+ o = {
+ postID: data.no,
+ threadID: data.resto || data.no,
+ boardID: boardID,
+ name: data.name,
+ capcode: data.capcode,
+ tripcode: data.trip,
+ uniqueID: data.id,
+ email: data.email ? encodeURI(data.email.replace(/"/g, '"')) : '',
+ subject: data.sub,
+ flagCode: data.country,
+ flagName: data.country_name,
+ date: data.now,
+ dateUTC: data.time,
+ comment: data.com,
+ isSticky: !!data.sticky,
+ isClosed: !!data.closed
+ };
+ if (data.ext || data.filedeleted) {
+ o.file = {
+ name: data.filename + data.ext,
+ timestamp: "" + data.tim + data.ext,
+ url: "//images.4chan.org/" + boardID + "/src/" + data.tim + data.ext,
+ height: data.h,
+ width: data.w,
+ MD5: data.md5,
+ size: data.fsize,
+ turl: "//thumbs.4chan.org/" + boardID + "/thumb/" + data.tim + "s.jpg",
+ theight: data.tn_h,
+ twidth: data.tn_w,
+ isSpoiler: !!data.spoiler,
+ isDeleted: !!data.filedeleted
+ };
+ }
+ return Build.post(o);
+ },
+ post: function(o, isArchived) {
+ /*
+ This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS).
+ @license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
+ */
+
+ var a, boardID, capcode, capcodeClass, capcodeStart, closed, comment, container, date, dateUTC, email, emailEnd, emailStart, ext, file, fileDims, fileHTML, fileInfo, fileSize, fileThumb, filename, flag, flagCode, flagName, href, imgSrc, isClosed, isOP, isSticky, name, postID, quote, shortFilename, spoilerRange, staticPath, sticky, subject, threadID, tripcode, uniqueID, userID, _i, _len, _ref;
+
+ postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, comment = o.comment, file = o.file;
+ isOP = postID === threadID;
+ staticPath = '//static.4chan.org';
+ if (email) {
+ emailStart = '';
+ emailEnd = '';
+ } else {
+ emailStart = '';
+ emailEnd = '';
+ }
+ subject = "" + (subject || '') + "";
+ userID = !capcode && uniqueID ? (" (ID: ") + ("" + uniqueID + ") ") : '';
+ switch (capcode) {
+ case 'admin':
+ case 'admin_highlight':
+ capcodeClass = " capcodeAdmin";
+ capcodeStart = " ## Admin";
+ capcode = ("
";
+ break;
+ case 'mod':
+ capcodeClass = " capcodeMod";
+ capcodeStart = " ## Mod";
+ capcode = ("
";
+ break;
+ case 'developer':
+ capcodeClass = " capcodeDeveloper";
+ capcodeStart = " ## Developer";
+ capcode = ("
";
+ break;
+ default:
+ capcodeClass = '';
+ capcodeStart = '';
+ capcode = '';
+ }
+ flag = flagCode ? ("
") : '';
+ if (file != null ? file.isDeleted : void 0) {
+ fileHTML = isOP ? ("") + ("
") + " " : ("") + ("
") + " ";
+ } else if (file) {
+ ext = file.name.slice(-3);
+ if (!file.twidth && !file.theight && ext === 'gif') {
+ file.twidth = file.width;
+ file.theight = file.height;
+ }
+ fileSize = $.bytesToString(file.size);
+ fileThumb = file.turl;
+ if (file.isSpoiler) {
+ fileSize = "Spoiler Image, " + fileSize;
+ if (!isArchived) {
+ fileThumb = '//static.4chan.org/image/spoiler';
+ if (spoilerRange = Build.spoilerRange[boardID]) {
+ fileThumb += ("-" + boardID) + Math.floor(1 + spoilerRange * Math.random());
+ }
+ fileThumb += '.png';
+ file.twidth = file.theight = 100;
+ }
+ }
+ if (boardID.ID !== 'f') {
+ imgSrc = ("") + ("
");
+ }
+ a = $.el('a', {
+ innerHTML: file.name
+ });
+ filename = a.textContent.replace(/%22/g, '"');
+ a.textContent = Build.shortFilename(filename);
+ shortFilename = a.innerHTML;
+ a.textContent = filename;
+ filename = a.innerHTML.replace(/'/g, ''');
+ fileDims = ext === 'pdf' ? 'PDF' : "" + file.width + "x" + file.height;
+ fileInfo = ("File: " + file.timestamp + "") + ("-(" + fileSize + ", " + fileDims + (file.isSpoiler ? '' : ", " + shortFilename + "")) + ")";
+ fileHTML = "" + fileInfo + "
" + imgSrc + "
";
+ } else {
+ fileHTML = '';
+ }
+ tripcode = tripcode ? " " + tripcode + "" : '';
+ sticky = isSticky ? '
' : '';
+ closed = isClosed ? '
' : '';
+ container = $.el('div', {
+ id: "pc" + postID,
+ className: "postContainer " + (isOP ? 'op' : 'reply') + "Container",
+ innerHTML: (isOP ? '' : ">>
") + ("") + ("
") + ("
") + ("" + (name || '') + "") + tripcode + capcodeStart + capcode + userID + flag + sticky + closed + ("
" + subject) + ("" + date) + ("No.") + ("" + postID + "") + '' + '
' + (isOP ? fileHTML : '') + ("
") + ("
") + ("" + subject + " ") + ("
") + emailStart + ("" + (name || '') + "") + tripcode + capcodeStart + emailEnd + capcode + userID + flag + sticky + closed + ' ' + ("
" + date + " ") + "
" + ("No.") + ("" + postID + "") + '' + '
' + (isOP ? '' : fileHTML) + ("
" + (comment || '') + "
") + '
'
+ });
+ _ref = $$('.quotelink', container);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ quote = _ref[_i];
+ href = quote.getAttribute('href');
+ if (href[0] === '/') {
+ continue;
+ }
+ quote.href = "/" + boardID + "/res/" + href;
+ }
+ return container;
+ }
+ };
+
Get = {
threadExcerpt: function(thread) {
var OP, excerpt, _ref;
@@ -1800,28 +2158,6 @@
}
};
- Polyfill = {
- init: function() {
- return Polyfill.visibility();
- },
- visibility: function() {
- var event, prefix, property;
-
- if ('visibilityState' in document || !(prefix = ('webkitVisibilityState' in document ? 'webkit' : 'mozVisibilityState' in document ? 'moz' : void 0))) {
- return;
- }
- property = prefix + 'VisibilityState';
- event = prefix + 'visibilitychange';
- d.visibilityState = d[property];
- d.hidden = d.visibilityState === 'hidden';
- return $.on(d, event, function() {
- d.visibilityState = d[property];
- d.hidden = d.visibilityState === 'hidden';
- return $.event('visibilitychange');
- });
- }
- };
-
UI = (function() {
var Menu, dialog, drag, dragend, dragstart, hover, hoverend, hoverstart, touchend, touchmove;
@@ -2551,76 +2887,6 @@
}
};
- Recursive = {
- recursives: {},
- init: function() {
- if (g.VIEW === 'catalog') {
- return;
- }
- return Post.prototype.callbacks.push({
- name: 'Recursive',
- cb: this.node
- });
- },
- node: function() {
- var i, obj, quote, recursive, _i, _j, _len, _len1, _ref, _ref1;
-
- if (this.isClone) {
- return;
- }
- _ref = this.quotes;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quote = _ref[_i];
- if (obj = Recursive.recursives[quote]) {
- _ref1 = obj.recursives;
- for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
- recursive = _ref1[i];
- recursive.apply(null, [this].concat(__slice.call(obj.args[i])));
- }
- }
- }
- },
- add: function() {
- var args, obj, post, recursive, _base, _name;
-
- recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
- obj = (_base = Recursive.recursives)[_name = post.fullID] || (_base[_name] = {
- recursives: [],
- args: []
- });
- obj.recursives.push(recursive);
- return obj.args.push(args);
- },
- rm: function(recursive, post) {
- var i, obj, rec, _i, _len, _ref;
-
- if (!(obj = Recursive.recursives[post.fullID])) {
- return;
- }
- _ref = obj.recursives;
- for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
- rec = _ref[i];
- if (rec === recursive) {
- obj.recursives.splice(i, 1);
- obj.args.splice(i, 1);
- }
- }
- },
- apply: function() {
- var ID, args, fullID, post, recursive, _ref;
-
- recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
- fullID = post.fullID;
- _ref = g.posts;
- for (ID in _ref) {
- post = _ref[ID];
- if (post.quotes.contains(fullID)) {
- recursive.apply(null, [post].concat(__slice.call(args)));
- }
- }
- }
- };
-
PostHiding = {
init: function() {
if (g.VIEW === 'catalog' || !Conf['Reply Hiding Buttons'] && !Conf['Reply Hiding Link']) {
@@ -2899,28 +3165,71 @@
}
};
- QuoteStrikeThrough = {
+ Recursive = {
+ recursives: {},
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Reply Hiding Buttons'] && !Conf['Reply Hiding Link'] && !Conf['Filter']) {
+ if (g.VIEW === 'catalog') {
return;
}
return Post.prototype.callbacks.push({
- name: 'Strike-through Quotes',
+ name: 'Recursive',
cb: this.node
});
},
node: function() {
- var boardID, postID, quotelink, _i, _len, _ref, _ref1, _ref2;
+ var i, obj, quote, recursive, _i, _j, _len, _len1, _ref, _ref1;
if (this.isClone) {
return;
}
- _ref = this.nodes.quotelinks;
+ _ref = this.quotes;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quotelink = _ref[_i];
- _ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, postID = _ref1.postID;
- if ((_ref2 = g.posts["" + boardID + "." + postID]) != null ? _ref2.isHidden : void 0) {
- $.addClass(quotelink, 'filtered');
+ quote = _ref[_i];
+ if (obj = Recursive.recursives[quote]) {
+ _ref1 = obj.recursives;
+ for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
+ recursive = _ref1[i];
+ recursive.apply(null, [this].concat(__slice.call(obj.args[i])));
+ }
+ }
+ }
+ },
+ add: function() {
+ var args, obj, post, recursive, _base, _name;
+
+ recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
+ obj = (_base = Recursive.recursives)[_name = post.fullID] || (_base[_name] = {
+ recursives: [],
+ args: []
+ });
+ obj.recursives.push(recursive);
+ return obj.args.push(args);
+ },
+ rm: function(recursive, post) {
+ var i, obj, rec, _i, _len, _ref;
+
+ if (!(obj = Recursive.recursives[post.fullID])) {
+ return;
+ }
+ _ref = obj.recursives;
+ for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
+ rec = _ref[i];
+ if (rec === recursive) {
+ obj.recursives.splice(i, 1);
+ obj.args.splice(i, 1);
+ }
+ }
+ },
+ apply: function() {
+ var ID, args, fullID, post, recursive, _ref;
+
+ recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
+ fullID = post.fullID;
+ _ref = g.posts;
+ for (ID in _ref) {
+ post = _ref[ID];
+ if (post.quotes.contains(fullID)) {
+ recursive.apply(null, [post].concat(__slice.call(args)));
}
}
}
@@ -3153,455 +3462,646 @@
}
};
- FappeTyme = {
+ QuoteBacklink = {
init: function() {
- var el, input;
+ var format;
- if (!Conf['Fappe Tyme'] || g.VIEW === 'catalog' || g.BOARD === 'f') {
+ if (g.VIEW === 'catalog' || !Conf['Quote Backlinks']) {
return;
}
- el = $.el('label', {
- innerHTML: " Fappe Tyme",
- title: 'Fappe Tyme'
- });
- FappeTyme.input = input = el.firstElementChild;
- $.on(input, 'change', FappeTyme.toggle);
- $.event('AddMenuEntry', {
- type: 'header',
- el: el,
- order: 97
+ format = Conf['backlink'].replace(/%id/g, "' + id + '");
+ this.funk = Function('id', "return '" + format + "'");
+ this.containers = {};
+ Post.prototype.callbacks.push({
+ name: 'Quote Backlinking Part 1',
+ cb: this.firstNode
});
return Post.prototype.callbacks.push({
- name: 'Fappe Tyme',
- cb: this.node
+ name: 'Quote Backlinking Part 2',
+ cb: this.secondNode
});
},
- node: function() {
- if (this.file) {
+ firstNode: function() {
+ var a, clone, container, containers, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
+
+ if (this.isClone || !this.quotes.length) {
return;
}
- return $.addClass(this.nodes.root, "noFile");
+ a = $.el('a', {
+ href: "/" + this.board + "/res/" + this.thread + "#p" + this,
+ className: this.isHidden ? 'filtered backlink' : 'backlink',
+ textContent: (QuoteBacklink.funk(this.ID)) + (Conf['Mark Quotes of You'] && this.info.yours ? QuoteYou.text : '')
+ });
+ _ref = this.quotes;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ quote = _ref[_i];
+ containers = [QuoteBacklink.getContainer(quote)];
+ if ((post = g.posts[quote]) && post.nodes.backlinkContainer) {
+ _ref1 = post.clones;
+ for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
+ clone = _ref1[_j];
+ containers.push(clone.nodes.backlinkContainer);
+ }
+ }
+ for (_k = 0, _len2 = containers.length; _k < _len2; _k++) {
+ container = containers[_k];
+ link = a.cloneNode(true);
+ if (Conf['Quote Previewing']) {
+ $.on(link, 'mouseover', QuotePreview.mouseover);
+ }
+ if (Conf['Quote Inlining']) {
+ $.on(link, 'click', QuoteInline.toggle);
+ }
+ $.add(container, [$.tn(' '), link]);
+ }
+ }
},
- toggle: function() {
- $.event('CloseMenu');
- return (this.checked ? $.addClass : $.rmClass)(doc, 'fappeTyme');
+ secondNode: function() {
+ var container;
+
+ if (this.isClone && (this.origin.isReply || Conf['OP Backlinks'])) {
+ this.nodes.backlinkContainer = $('.container', this.nodes.info);
+ return;
+ }
+ if (!(this.isReply || Conf['OP Backlinks'])) {
+ return;
+ }
+ container = QuoteBacklink.getContainer(this.fullID);
+ this.nodes.backlinkContainer = container;
+ return $.add(this.nodes.info, container);
+ },
+ getContainer: function(id) {
+ var _base;
+
+ return (_base = this.containers)[id] || (_base[id] = $.el('span', {
+ className: 'container'
+ }));
}
};
- ImageExpand = {
+ QuoteCT = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
+ if (g.VIEW === 'catalog' || !Conf['Mark Cross-thread Quotes']) {
return;
}
- this.EAI = $.el('a', {
- className: 'expand-all-shortcut',
- textContent: 'EAI',
- title: 'Expand All Images',
- href: 'javascript:;'
- });
- $.on(this.EAI, 'click', ImageExpand.cb.toggleAll);
- Header.addShortcut(this.EAI);
+ if (Conf['Comment Expansion']) {
+ ExpandComment.callbacks.push(this.node);
+ }
+ this.text = '\u00A0(Cross-thread)';
return Post.prototype.callbacks.push({
- name: 'Image Expansion',
+ name: 'Mark Cross-thread Quotes',
cb: this.node
});
},
node: function() {
- var thumb, _ref;
+ var board, boardID, quotelink, quotelinks, quotes, thread, threadID, _i, _len, _ref, _ref1;
- if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ if (this.isClone && this.thread === this.context.thread) {
return;
}
- thumb = this.file.thumb;
- $.on(thumb.parentNode, 'click', ImageExpand.cb.toggle);
- if (this.isClone && $.hasClass(thumb, 'expanding')) {
- ImageExpand.contract(this);
- ImageExpand.expand(this);
+ if (!(quotes = this.quotes).length) {
return;
}
- if (ImageExpand.on && !this.isHidden) {
- return ImageExpand.expand(this);
- }
- },
- cb: {
- toggle: function(e) {
- if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
- return;
+ quotelinks = this.nodes.quotelinks;
+ _ref = this.isClone ? this.context : this, board = _ref.board, thread = _ref.thread;
+ for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
+ quotelink = quotelinks[_i];
+ _ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, threadID = _ref1.threadID;
+ if (!threadID) {
+ continue;
}
- e.preventDefault();
- return ImageExpand.toggle(Get.postFromNode(this));
- },
- toggleAll: function() {
- var ID, file, func, post, _i, _len, _ref, _ref1;
-
- $.event('CloseMenu');
- if (ImageExpand.on = $.hasClass(ImageExpand.EAI, 'expand-all-shortcut')) {
- ImageExpand.EAI.className = 'contract-all-shortcut';
- ImageExpand.EAI.title = 'Contract All Images';
- func = ImageExpand.expand;
- } else {
- ImageExpand.EAI.className = 'expand-all-shortcut';
- ImageExpand.EAI.title = 'Expand All Images';
- func = ImageExpand.contract;
+ if (this.isClone) {
+ quotelink.textContent = quotelink.textContent.replace(QuoteCT.text, '');
}
- _ref = g.posts;
- for (ID in _ref) {
- post = _ref[ID];
- _ref1 = [post].concat(post.clones);
- for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
- post = _ref1[_i];
- file = post.file;
- if (!(file && file.isImage && doc.contains(post.nodes.root))) {
- continue;
- }
- if (ImageExpand.on && (!Conf['Expand spoilers'] && file.isSpoiler || Conf['Expand from here'] && file.thumb.getBoundingClientRect().top < 0)) {
- continue;
- }
- $.queueTask(func, post);
- }
- }
- },
- setFitness: function() {
- var checked;
-
- checked = this.checked;
- (checked ? $.addClass : $.rmClass)(doc, this.name.toLowerCase().replace(/\s+/g, '-'));
- if (this.name !== 'Fit height') {
- return;
- }
- if (checked) {
- $.on(window, 'resize', ImageExpand.resize);
- if (!ImageExpand.style) {
- ImageExpand.style = $.addStyle(null);
- }
- return ImageExpand.resize();
- } else {
- return $.off(window, 'resize', ImageExpand.resize);
+ if (boardID === this.board.ID && threadID !== thread.ID) {
+ $.add(quotelink, $.tn(QuoteCT.text));
}
}
- },
- toggle: function(post) {
- var headRect, rect, root, thumb, top;
-
- thumb = post.file.thumb;
- if (!(post.file.isExpanded || $.hasClass(thumb, 'expanding'))) {
- ImageExpand.expand(post);
- return;
- }
- ImageExpand.contract(post);
- rect = post.nodes.root.getBoundingClientRect();
- if (!(rect.top <= 0 || rect.left <= 0)) {
- return;
- }
- top = rect.top;
- if (Conf['Fixed Header'] && !Conf['Bottom Header']) {
- headRect = Header.bar.getBoundingClientRect();
- top += -headRect.top - headRect.height;
- }
- root = doc;
- if (rect.top < 0) {
- root.scrollTop += top;
- }
- if (rect.left < 0) {
- return root.scrollLeft = 0;
- }
- },
- contract: function(post) {
- $.rmClass(post.nodes.root, 'expanded-image');
- $.rmClass(post.file.thumb, 'expanding');
- return post.file.isExpanded = false;
- },
- expand: function(post, src) {
- var img, thumb;
-
- thumb = post.file.thumb;
- if (post.isHidden || post.file.isExpanded || $.hasClass(thumb, 'expanding')) {
- return;
- }
- $.addClass(thumb, 'expanding');
- if (post.file.fullImage) {
- $.asap((function() {
- return post.file.fullImage.naturalHeight;
- }), function() {
- return ImageExpand.completeExpand(post);
- });
- return;
- }
- post.file.fullImage = img = $.el('img', {
- className: 'full-image',
- src: src || post.file.URL
- });
- $.on(img, 'error', ImageExpand.error);
- $.asap((function() {
- return post.file.fullImage.naturalHeight;
- }), function() {
- return ImageExpand.completeExpand(post);
- });
- return $.after(thumb, img);
- },
- completeExpand: function(post) {
- var prev, thumb;
-
- thumb = post.file.thumb;
- if (!$.hasClass(thumb, 'expanding')) {
- return;
- }
- post.file.isExpanded = true;
- if (!post.nodes.root.parentNode) {
- $.addClass(post.nodes.root, 'expanded-image');
- $.rmClass(post.file.thumb, 'expanding');
- return;
- }
- prev = post.nodes.root.getBoundingClientRect();
- return $.queueTask(function() {
- var curr, root;
-
- $.addClass(post.nodes.root, 'expanded-image');
- $.rmClass(post.file.thumb, 'expanding');
- if (!(prev.top + prev.height <= 0)) {
- return;
- }
- root = doc;
- curr = post.nodes.root.getBoundingClientRect();
- return root.scrollTop += curr.height - prev.height + curr.top - prev.top;
- });
- },
- error: function() {
- var URL, post, src, timeoutID;
-
- post = Get.postFromNode(this);
- $.rm(this);
- delete post.file.fullImage;
- if (!($.hasClass(post.file.thumb, 'expanding') || $.hasClass(post.nodes.root, 'expanded-image'))) {
- return;
- }
- ImageExpand.contract(post);
- src = this.src.split('/');
- if (src[2] === 'images.4chan.org') {
- if (URL = Redirect.image(src[3], src[5])) {
- setTimeout(ImageExpand.expand, 10000, post, URL);
- return;
- }
- if (g.DEAD || post.isDead || post.file.isDead) {
- return;
- }
- }
- timeoutID = setTimeout(ImageExpand.expand, 10000, post);
- return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", {
- onload: function() {
- var postObj, _i, _len, _ref;
-
- if (this.status !== 200) {
- return;
- }
- _ref = JSON.parse(this.response).posts;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- postObj = _ref[_i];
- if (postObj.no === post.ID) {
- break;
- }
- }
- if (postObj.no !== post.ID) {
- clearTimeout(timeoutID);
- return post.kill();
- } else if (postObj.filedeleted) {
- clearTimeout(timeoutID);
- return post.kill(true);
- }
- }
- });
- },
- menu: {
- init: function() {
- var conf, createSubEntry, el, key, subEntries, _ref;
-
- if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
- return;
- }
- el = $.el('span', {
- textContent: 'Image Expansion',
- className: 'image-expansion-link'
- });
- createSubEntry = ImageExpand.menu.createSubEntry;
- subEntries = [];
- _ref = Config.imageExpansion;
- for (key in _ref) {
- conf = _ref[key];
- subEntries.push(createSubEntry(key, conf));
- }
- return $.event('AddMenuEntry', {
- type: 'header',
- el: el,
- order: 105,
- subEntries: subEntries
- });
- },
- createSubEntry: function(type, config) {
- var input, label;
-
- label = $.el('label', {
- innerHTML: " " + type
- });
- input = label.firstElementChild;
- if (type === 'Fit width' || type === 'Fit height') {
- $.on(input, 'change', ImageExpand.cb.setFitness);
- }
- if (config) {
- label.title = config[1];
- input.checked = Conf[type];
- $.event('change', null, input);
- $.on(input, 'change', $.cb.checked);
- }
- return {
- el: label
- };
- }
- },
- resize: function() {
- return ImageExpand.style.textContent = ":root.fit-height .full-image {max-height:" + doc.clientHeight + "px}";
- },
- menuToggle: function(e) {
- return ImageExpand.opmenu.toggle(e, this, g);
}
};
- ImageHover = {
+ QuoteInline = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Image Hover']) {
+ if (g.VIEW === 'catalog' || !Conf['Quote Inlining']) {
return;
}
+ if (Conf['Comment Expansion']) {
+ ExpandComment.callbacks.push(this.node);
+ }
return Post.prototype.callbacks.push({
- name: 'Image Hover',
+ name: 'Quote Inlining',
cb: this.node
});
},
node: function() {
- var _ref;
+ var link, _i, _len, _ref;
- if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ link = _ref[_i];
+ $.on(link, 'click', QuoteInline.toggle);
+ }
+ },
+ toggle: function(e) {
+ var boardID, context, postID, threadID, _ref;
+
+ if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
return;
}
- return $.on(this.file.thumb, 'mouseover', ImageHover.mouseover);
+ e.preventDefault();
+ _ref = Get.postDataFromLink(this), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
+ context = Get.contextFromLink(this);
+ if ($.hasClass(this, 'inlined')) {
+ QuoteInline.rm(this, boardID, threadID, postID, context);
+ } else {
+ if ($.x("ancestor::div[@id='p" + postID + "']", this)) {
+ return;
+ }
+ QuoteInline.add(this, boardID, threadID, postID, context);
+ }
+ return this.classList.toggle('inlined');
+ },
+ findRoot: function(quotelink, isBacklink) {
+ if (isBacklink) {
+ return quotelink.parentNode.parentNode;
+ } else {
+ return $.x('ancestor-or-self::*[parent::blockquote][1]', quotelink);
+ }
+ },
+ add: function(quotelink, boardID, threadID, postID, context) {
+ var inline, isBacklink, post;
+
+ isBacklink = $.hasClass(quotelink, 'backlink');
+ inline = $.el('div', {
+ id: "i" + postID,
+ className: 'inline'
+ });
+ $.after(QuoteInline.findRoot(quotelink, isBacklink), inline);
+ Get.postClone(boardID, threadID, postID, inline, context);
+ if (!((post = g.posts["" + boardID + "." + postID]) && context.thread === post.thread)) {
+ return;
+ }
+ if (isBacklink && Conf['Forward Hiding']) {
+ $.addClass(post.nodes.root, 'forwarded');
+ post.forwarded++ || (post.forwarded = 1);
+ }
+ if (!Unread.posts) {
+ return;
+ }
+ return Unread.readSinglePost(post);
+ },
+ rm: function(quotelink, boardID, threadID, postID, context) {
+ var el, inlined, isBacklink, post, root, _ref;
+
+ isBacklink = $.hasClass(quotelink, 'backlink');
+ root = QuoteInline.findRoot(quotelink, isBacklink);
+ root = $.x("following-sibling::div[@id='i" + postID + "'][1]", root);
+ $.rm(root);
+ if (!(el = root.firstElementChild)) {
+ return;
+ }
+ post = g.posts["" + boardID + "." + postID];
+ post.rmClone(el.dataset.clone);
+ if (Conf['Forward Hiding'] && isBacklink && context.thread === g.threads["" + boardID + "." + threadID] && !--post.forwarded) {
+ delete post.forwarded;
+ $.rmClass(post.nodes.root, 'forwarded');
+ }
+ while (inlined = $('.inlined', el)) {
+ _ref = Get.postDataFromLink(inlined), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
+ QuoteInline.rm(inlined, boardID, threadID, postID, context);
+ $.rmClass(inlined, 'inlined');
+ }
+ }
+ };
+
+ QuoteOP = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Mark OP Quotes']) {
+ return;
+ }
+ if (Conf['Comment Expansion']) {
+ ExpandComment.callbacks.push(this.node);
+ }
+ this.text = '\u00A0(OP)';
+ return Post.prototype.callbacks.push({
+ name: 'Mark OP Quotes',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var boardID, op, postID, quotelink, quotelinks, quotes, _i, _j, _len, _len1, _ref;
+
+ if (this.isClone && this.thread === this.context.thread) {
+ return;
+ }
+ if (!(quotes = this.quotes).length) {
+ return;
+ }
+ quotelinks = this.nodes.quotelinks;
+ if (this.isClone && quotes.contains(this.thread.fullID)) {
+ for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
+ quotelink = quotelinks[_i];
+ quotelink.textContent = quotelink.textContent.replace(QuoteOP.text, '');
+ }
+ }
+ op = (this.isClone ? this.context : this).thread.fullID;
+ if (!quotes.contains(op)) {
+ return;
+ }
+ for (_j = 0, _len1 = quotelinks.length; _j < _len1; _j++) {
+ quotelink = quotelinks[_j];
+ _ref = Get.postDataFromLink(quotelink), boardID = _ref.boardID, postID = _ref.postID;
+ if (("" + boardID + "." + postID) === op) {
+ $.add(quotelink, $.tn(QuoteOP.text));
+ }
+ }
+ }
+ };
+
+ QuotePreview = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Quote Previewing']) {
+ return;
+ }
+ if (Conf['Comment Expansion']) {
+ ExpandComment.callbacks.push(this.node);
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Quote Previewing',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var link, _i, _len, _ref;
+
+ _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ link = _ref[_i];
+ $.on(link, 'mouseover', QuotePreview.mouseover);
+ }
},
mouseover: function(e) {
- var el, post;
+ var boardID, clone, origin, post, postID, posts, qp, quote, quoterID, threadID, _i, _j, _len, _len1, _ref, _ref1;
- post = Get.postFromNode(this);
- el = $.el('img', {
- id: 'ihover',
- src: post.file.URL
+ if ($.hasClass(this, 'inlined')) {
+ return;
+ }
+ _ref = Get.postDataFromLink(this), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
+ qp = $.el('div', {
+ id: 'qp',
+ className: 'dialog'
});
- el.setAttribute('data-fullid', post.fullID);
- $.add(Header.hover, el);
+ $.add(Header.hover, qp);
+ Get.postClone(boardID, threadID, postID, qp, Get.contextFromLink(this));
UI.hover({
root: this,
- el: el,
+ el: qp,
latestEvent: e,
endEvents: 'mouseout click',
+ cb: QuotePreview.mouseout,
asapTest: function() {
- return el.naturalHeight;
+ return qp.firstElementChild;
}
});
- return $.on(el, 'error', ImageHover.error);
- },
- error: function() {
- var URL, post, src, timeoutID,
- _this = this;
-
- if (!doc.contains(this)) {
+ if (!(origin = g.posts["" + boardID + "." + postID])) {
return;
}
- post = g.posts[this.dataset.fullid];
- src = this.src.split('/');
- if (src[2] === 'images.4chan.org') {
- if (URL = Redirect.image(src[3], src[5].replace(/\?.+$/, ''))) {
- this.src = URL;
- return;
- }
- if (g.DEAD || post.isDead || post.file.isDead) {
- return;
+ if (Conf['Quote Highlighting']) {
+ posts = [origin].concat(origin.clones);
+ posts.pop();
+ for (_i = 0, _len = posts.length; _i < _len; _i++) {
+ post = posts[_i];
+ $.addClass(post.nodes.post, 'qphl');
}
}
- timeoutID = setTimeout((function() {
- return _this.src = post.file.URL + '?' + Date.now();
- }), 3000);
- return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", {
- onload: function() {
- var postObj, _i, _len, _ref;
-
- if (this.status !== 200) {
- return;
- }
- _ref = JSON.parse(this.response).posts;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- postObj = _ref[_i];
- if (postObj.no === post.ID) {
- break;
- }
- }
- if (postObj.no !== post.ID) {
- clearTimeout(timeoutID);
- return post.kill();
- } else if (postObj.filedeleted) {
- clearTimeout(timeoutID);
- return post.kill(true);
- }
+ quoterID = $.x('ancestor::*[@id][1]', this).id.match(/\d+$/)[0];
+ clone = Get.postFromRoot(qp.firstChild);
+ _ref1 = clone.nodes.quotelinks.concat(__slice.call(clone.nodes.backlinks));
+ for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
+ quote = _ref1[_j];
+ if (quote.hash.slice(2) === quoterID) {
+ $.addClass(quote, 'forwardlink');
}
- });
+ }
+ },
+ mouseout: function() {
+ var clone, post, root, _i, _len, _ref;
+
+ if (!(root = this.el.firstElementChild)) {
+ return;
+ }
+ clone = Get.postFromRoot(root);
+ post = clone.origin;
+ post.rmClone(root.dataset.clone);
+ if (!Conf['Quote Highlighting']) {
+ return;
+ }
+ _ref = [post].concat(post.clones);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ post = _ref[_i];
+ $.rmClass(post.nodes.post, 'qphl');
+ }
}
};
- ImageReplace = {
+ QuoteStrikeThrough = {
init: function() {
- if (g.VIEW === 'catalog') {
+ if (g.VIEW === 'catalog' || !Conf['Reply Hiding Buttons'] && !Conf['Reply Hiding Link'] && !Conf['Filter']) {
return;
}
return Post.prototype.callbacks.push({
- name: 'Image Replace',
+ name: 'Strike-through Quotes',
cb: this.node
});
},
node: function() {
- var URL, img, style, thumb, type, _ref, _ref1;
+ var boardID, postID, quotelink, _i, _len, _ref, _ref1, _ref2;
- if (this.isClone || this.isHidden || this.thread.isHidden || !((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ if (this.isClone) {
return;
}
- _ref1 = this.file, thumb = _ref1.thumb, URL = _ref1.URL;
- if (!(Conf["Replace " + ((type = (URL.match(/\w{3}$/))[0].toUpperCase()) === 'PEG' ? 'JPG' : type)] && !/spoiler/.test(thumb.src))) {
- return;
+ _ref = this.nodes.quotelinks;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ quotelink = _ref[_i];
+ _ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, postID = _ref1.postID;
+ if ((_ref2 = g.posts["" + boardID + "." + postID]) != null ? _ref2.isHidden : void 0) {
+ $.addClass(quotelink, 'filtered');
+ }
}
- if (this.file.isSpoiler) {
- style = thumb.style;
- style.maxHeight = style.maxWidth = this.isReply ? '125px' : '250px';
- }
- img = $.el('img');
- $.on(img, 'load', function() {
- return thumb.src = URL;
- });
- return img.src = URL;
}
};
- RevealSpoilers = {
+ /*
+ <3 aeosynth
+ */
+
+
+ QuoteThreading = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Reveal Spoilers']) {
+ var input;
+
+ if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
return;
}
+ this.enabled = true;
+ this.controls = $.el('span', {
+ innerHTML: ''
+ });
+ input = $('input', this.controls);
+ $.on(input, 'change', QuoteThreading.toggle);
+ $.event('AddMenuEntry', {
+ type: 'header',
+ el: this.controls,
+ order: 98
+ });
+ $.on(d, '4chanXInitFinished', this.setup);
return Post.prototype.callbacks.push({
- name: 'Reveal Spoilers',
+ name: 'Quote Threading',
+ cb: this.node
+ });
+ },
+ setup: function() {
+ var ID, post, posts;
+
+ $.off(d, '4chanXInitFinished', QuoteThreading.setup);
+ posts = g.posts;
+ for (ID in posts) {
+ post = posts[ID];
+ if (post.cb) {
+ post.cb.call(post);
+ }
+ }
+ return QuoteThreading.hasRun = true;
+ },
+ node: function() {
+ var ID, fullID, keys, len, post, posts, qid, quote, quotes, uniq, _i, _len;
+
+ if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) {
+ return;
+ }
+ quotes = this.quotes, ID = this.ID, fullID = this.fullID;
+ posts = g.posts;
+ if (!(post = posts[fullID]) || post.isHidden) {
+ return;
+ }
+ uniq = {};
+ len = ("" + g.BOARD).length + 1;
+ for (_i = 0, _len = quotes.length; _i < _len; _i++) {
+ quote = quotes[_i];
+ qid = quote;
+ if (!(qid.slice(len) < ID)) {
+ continue;
+ }
+ if (qid in posts) {
+ uniq[qid.slice(len)] = true;
+ }
+ }
+ keys = Object.keys(uniq);
+ if (keys.length !== 1) {
+ return;
+ }
+ this.threaded = "" + g.BOARD + "." + keys[0];
+ return this.cb = QuoteThreading.nodeinsert;
+ },
+ nodeinsert: function() {
+ var bottom, height, posts, qpost, qroot, threadContainer, top, _ref;
+
+ posts = g.posts;
+ qpost = posts[this.threaded];
+ delete this.threaded;
+ delete this.cb;
+ if (this.thread.OP === qpost) {
+ return false;
+ }
+ if (QuoteThreading.hasRun) {
+ height = doc.clientHeight;
+ _ref = qpost.nodes.root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top;
+ if (!(Unread.posts.contains(qpost) || ((bottom < height) && (top > 0)))) {
+ return false;
+ }
+ }
+ qroot = qpost.nodes.root;
+ if (!$.hasClass(qroot, 'threadOP')) {
+ $.addClass(qroot, 'threadOP');
+ threadContainer = $.el('div', {
+ className: 'threadContainer'
+ });
+ $.after(qroot, threadContainer);
+ } else {
+ threadContainer = qroot.nextSibling;
+ }
+ $.add(threadContainer, this.nodes.root);
+ return true;
+ },
+ toggle: function() {
+ var container, containers, node, nodes, replies, reply, thread, _i, _j, _len, _len1;
+
+ thread = $('.thread');
+ replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread);
+ QuoteThreading.enabled = this.checked;
+ if (this.checked) {
+ nodes = (function() {
+ var _i, _len, _results;
+
+ _results = [];
+ for (_i = 0, _len = replies.length; _i < _len; _i++) {
+ reply = replies[_i];
+ _results.push(Get.postFromNode(reply));
+ }
+ return _results;
+ })();
+ for (_i = 0, _len = nodes.length; _i < _len; _i++) {
+ node = nodes[_i];
+ QuoteThreading.node(node);
+ }
+ } else {
+ replies.sort(function(a, b) {
+ var aID, bID;
+
+ aID = Number(a.id.slice(2));
+ bID = Number(b.id.slice(2));
+ return aID - bID;
+ });
+ $.add(thread, replies);
+ containers = $$('.threadContainer', thread);
+ for (_j = 0, _len1 = containers.length; _j < _len1; _j++) {
+ container = containers[_j];
+ $.rm(container);
+ }
+ Unread.update(true);
+ }
+ },
+ kb: function() {
+ var control;
+
+ control = $.id('threadingControl');
+ return control.click();
+ }
+ };
+
+ QuoteYou = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Mark Quotes of You'] || !Conf['Quick Reply']) {
+ return;
+ }
+ this.text = '\u00A0(You)';
+ return Post.prototype.callbacks.push({
+ name: 'Mark Quotes of You',
cb: this.node
});
},
node: function() {
- var thumb, _ref;
+ var quotelink, quotelinks, quotes, _i, _len;
- if (this.isClone || !((_ref = this.file) != null ? _ref.isSpoiler : void 0)) {
+ if (this.isClone) {
return;
}
- thumb = this.file.thumb;
- thumb.removeAttribute('style');
- return thumb.src = this.file.thumbURL;
+ if (this.info.yours) {
+ $.addClass(this.nodes.root, 'yourPost');
+ }
+ if (Conf['Highlight Own Posts']) {
+ $.addClass(doc, 'highlight-own');
+ }
+ if (!(quotes = this.quotes).length) {
+ return;
+ }
+ quotelinks = this.nodes.quotelinks;
+ for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
+ quotelink = quotelinks[_i];
+ if (QR.db.get(Get.postDataFromLink(quotelink))) {
+ $.add(quotelink, $.tn(QuoteYou.text));
+ }
+ }
+ }
+ };
+
+ Quotify = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Resurrect Quotes']) {
+ return;
+ }
+ if (Conf['Comment Expansion']) {
+ ExpandComment.callbacks.push(this.node);
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Resurrect Quotes',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var deadlink, _i, _len, _ref;
+
+ _ref = $$('.deadlink', this.nodes.comment);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ deadlink = _ref[_i];
+ if (this.isClone) {
+ if ($.hasClass(deadlink, 'quotelink')) {
+ this.nodes.quotelinks.push(deadlink);
+ }
+ } else {
+ Quotify.parseDeadlink.call(this, deadlink);
+ }
+ }
+ },
+ parseDeadlink: function(deadlink) {
+ var a, boardID, m, post, postID, quote, quoteID, redirect, _ref;
+
+ if (deadlink.parentNode.className === 'prettyprint') {
+ $.replace(deadlink, __slice.call(deadlink.childNodes));
+ return;
+ }
+ quote = deadlink.textContent;
+ if (!(postID = (_ref = quote.match(/\d+$/)) != null ? _ref[0] : void 0)) {
+ return;
+ }
+ boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID;
+ quoteID = "" + boardID + "." + postID;
+ if (post = g.posts[quoteID]) {
+ if (!post.isDead) {
+ a = $.el('a', {
+ href: "/" + boardID + "/" + post.thread + "/res/#p" + postID,
+ className: 'quotelink',
+ textContent: quote
+ });
+ } else {
+ a = $.el('a', {
+ href: "/" + boardID + "/" + post.thread + "/res/#p" + postID,
+ className: 'quotelink deadlink',
+ target: '_blank',
+ textContent: "" + quote + "\u00A0(Dead)"
+ });
+ a.setAttribute('data-boardid', boardID);
+ a.setAttribute('data-threadid', post.thread.ID);
+ a.setAttribute('data-postid', postID);
+ }
+ } else if (redirect = Redirect.to({
+ boardID: boardID,
+ threadID: 0,
+ postID: postID
+ })) {
+ a = $.el('a', {
+ href: redirect,
+ className: 'deadlink',
+ target: '_blank',
+ textContent: "" + quote + "\u00A0(Dead)"
+ });
+ if (Redirect.post(boardID, postID)) {
+ $.addClass(a, 'quotelink');
+ a.setAttribute('data-boardid', boardID);
+ a.setAttribute('data-postid', postID);
+ }
+ }
+ if (__indexOf.call(this.quotes, quoteID) < 0) {
+ this.quotes.push(quoteID);
+ }
+ if (!a) {
+ deadlink.textContent = "" + quote + "\u00A0(Dead)";
+ return;
+ }
+ $.replace(deadlink, a);
+ if ($.hasClass(a, 'quotelink')) {
+ return this.nodes.quotelinks.push(a);
+ }
}
};
@@ -3891,3081 +4391,6 @@
}
};
- ArchiveLink = {
- init: function() {
- var div, entry, type, _i, _len, _ref;
-
- if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Archive Link']) {
- return;
- }
- div = $.el('div', {
- textContent: 'Archive'
- });
- entry = {
- type: 'post',
- el: div,
- order: 90,
- open: function(_arg) {
- var ID, board, redirect, thread;
-
- ID = _arg.ID, thread = _arg.thread, board = _arg.board;
- redirect = Redirect.to({
- postID: ID,
- threadID: thread.ID,
- boardID: board.ID
- });
- return redirect !== ("//boards.4chan.org/" + board + "/");
- },
- subEntries: []
- };
- _ref = [['Post', 'post'], ['Name', 'name'], ['Tripcode', 'tripcode'], ['E-mail', 'email'], ['Subject', 'subject'], ['Filename', 'filename'], ['Image MD5', 'MD5']];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- type = _ref[_i];
- entry.subEntries.push(this.createSubEntry(type[0], type[1]));
- }
- return $.event('AddMenuEntry', entry);
- },
- createSubEntry: function(text, type) {
- var el, open;
-
- el = $.el('a', {
- textContent: text,
- target: '_blank'
- });
- open = type === 'post' ? function(_arg) {
- var ID, board, thread;
-
- ID = _arg.ID, thread = _arg.thread, board = _arg.board;
- el.href = Redirect.to({
- postID: ID,
- threadID: thread.ID,
- boardID: board.ID
- });
- return true;
- } : function(post) {
- var value;
-
- value = Filter[type](post);
- if (!value) {
- return false;
- }
- el.href = Redirect.to({
- boardID: post.board.ID,
- type: type,
- value: value,
- isSearch: true
- });
- return true;
- };
- return {
- el: el,
- open: open
- };
- }
- };
-
- DeleteLink = {
- init: function() {
- var div, fileEl, fileEntry, postEl, postEntry;
-
- if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Delete Link']) {
- return;
- }
- div = $.el('div', {
- className: 'delete-link',
- textContent: 'Delete'
- });
- postEl = $.el('a', {
- className: 'delete-post',
- href: 'javascript:;'
- });
- fileEl = $.el('a', {
- className: 'delete-file',
- href: 'javascript:;'
- });
- postEntry = {
- el: postEl,
- open: function() {
- postEl.textContent = 'Post';
- $.on(postEl, 'click', DeleteLink["delete"]);
- return true;
- }
- };
- fileEntry = {
- el: fileEl,
- open: function(_arg) {
- var file;
-
- file = _arg.file;
- if (!file || file.isDead) {
- return false;
- }
- fileEl.textContent = 'File';
- $.on(fileEl, 'click', DeleteLink["delete"]);
- return true;
- }
- };
- return $.event('AddMenuEntry', {
- type: 'post',
- el: div,
- order: 40,
- open: function(post) {
- var node;
-
- if (post.isDead) {
- return false;
- }
- DeleteLink.post = post;
- node = div.firstChild;
- node.textContent = 'Delete';
- DeleteLink.cooldown.start(post, node);
- return true;
- },
- subEntries: [postEntry, fileEntry]
- });
- },
- "delete": function() {
- var fileOnly, form, link, m, post, pwd;
-
- post = DeleteLink.post;
- if (DeleteLink.cooldown.counting === post) {
- return;
- }
- $.off(this, 'click', DeleteLink["delete"]);
- this.textContent = "Deleting " + this.textContent + "...";
- pwd = (m = d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : $.id('delPassword').value;
- fileOnly = $.hasClass(this, 'delete-file');
- form = {
- mode: 'usrdel',
- onlyimgdel: fileOnly,
- pwd: pwd
- };
- form[post.ID] = 'delete';
- link = this;
- return $.ajax($.id('delform').action.replace("/" + g.BOARD + "/", "/" + post.board + "/"), {
- onload: function() {
- return DeleteLink.load(link, post, fileOnly, this.response);
- },
- onerror: function() {
- return DeleteLink.error(link);
- }
- }, {
- cred: true,
- form: $.formData(form)
- });
- },
- load: function(link, post, fileOnly, html) {
- var msg, s, tmpDoc;
-
- tmpDoc = d.implementation.createHTMLDocument('');
- tmpDoc.documentElement.innerHTML = html;
- if (tmpDoc.title === '4chan - Banned') {
- s = 'Banned!';
- } else if (msg = tmpDoc.getElementById('errmsg')) {
- s = msg.textContent;
- $.on(link, 'click', DeleteLink["delete"]);
- } else {
- if (tmpDoc.title === 'Updating index...') {
- (post.origin || post).kill(fileOnly);
- }
- s = 'Deleted';
- }
- return link.textContent = s;
- },
- error: function(link) {
- link.textContent = 'Connection error, please retry.';
- return $.on(link, 'click', DeleteLink["delete"]);
- },
- cooldown: {
- start: function(post, node) {
- var length, seconds, _ref;
-
- if (!((_ref = QR.db) != null ? _ref.get({
- boardID: post.board.ID,
- threadID: post.thread.ID,
- postID: post.ID
- }) : void 0)) {
- delete DeleteLink.cooldown.counting;
- return;
- }
- DeleteLink.cooldown.counting = post;
- length = post.board.ID === 'q' ? 600 : 30;
- seconds = Math.ceil((length * $.SECOND - (Date.now() - post.info.date)) / $.SECOND);
- return DeleteLink.cooldown.count(post, seconds, length, node);
- },
- count: function(post, seconds, length, node) {
- if (DeleteLink.cooldown.counting !== post) {
- return;
- }
- if (!((0 <= seconds && seconds <= length))) {
- if (DeleteLink.cooldown.counting === post) {
- node.textContent = 'Delete';
- delete DeleteLink.cooldown.counting;
- }
- return;
- }
- setTimeout(DeleteLink.cooldown.count, 1000, post, seconds - 1, length, node);
- return node.textContent = "Delete (" + seconds + ")";
- }
- }
- };
-
- DownloadLink = {
- init: function() {
- var a;
-
- if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Download Link']) {
- return;
- }
- a = $.el('a', {
- className: 'download-link',
- textContent: 'Download file'
- });
- return $.event('AddMenuEntry', {
- type: 'post',
- el: a,
- order: 70,
- open: function(_arg) {
- var file;
-
- file = _arg.file;
- if (!file) {
- return false;
- }
- a.href = file.URL;
- a.download = file.name;
- return true;
- }
- });
- }
- };
-
- Menu = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Menu']) {
- return;
- }
- this.menu = new UI.Menu('post');
- return Post.prototype.callbacks.push({
- name: 'Menu',
- cb: this.node
- });
- },
- node: function() {
- var button;
-
- button = Menu.makeButton(this);
- if (this.isClone) {
- $.replace($('.menu-button', this.nodes.info), button);
- return;
- }
- return $.add(this.nodes.info, [$.tn('\u00A0'), button]);
- },
- makeButton: (function() {
- var a;
-
- a = null;
- return function(post) {
- var clone;
-
- a || (a = $.el('a', {
- className: 'menu-button',
- innerHTML: '[]',
- href: 'javascript:;'
- }));
- clone = a.cloneNode(true);
- clone.setAttribute('data-postid', post.fullID);
- if (post.isClone) {
- clone.setAttribute('data-clone', true);
- }
- $.on(clone, 'click', Menu.toggle);
- return clone;
- };
- })(),
- toggle: function(e) {
- var post;
-
- post = this.dataset.clone ? Get.postFromNode(this) : g.posts[this.dataset.postid];
- return Menu.menu.toggle(e, this, post);
- }
- };
-
- ReportLink = {
- init: function() {
- var a;
-
- if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Report Link']) {
- return;
- }
- a = $.el('a', {
- className: 'report-link',
- href: 'javascript:;',
- textContent: 'Report this post'
- });
- $.on(a, 'click', ReportLink.report);
- return $.event('AddMenuEntry', {
- type: 'post',
- el: a,
- order: 10,
- open: function(post) {
- ReportLink.post = post;
- return !post.isDead;
- }
- });
- },
- report: function() {
- var id, post, set, url;
-
- post = ReportLink.post;
- url = "//sys.4chan.org/" + post.board + "/imgboard.php?mode=report&no=" + post;
- id = Date.now();
- set = "toolbar=0,scrollbars=0,location=0,status=1,menubar=0,resizable=1,width=685,height=200";
- return window.open(url, id, set);
- }
- };
-
- PSAHiding = {
- init: function() {
- var entry;
-
- if (!Conf['Announcement Hiding']) {
- return;
- }
- entry = {
- type: 'header',
- el: $.el('a', {
- textContent: 'Show announcement',
- className: 'show-announcement',
- href: 'javascript:;'
- }),
- order: 50,
- open: function() {
- var _ref;
-
- if ((_ref = $.id('globalMessage')) != null ? _ref.hidden : void 0) {
- return true;
- }
- return false;
- }
- };
- $.event('AddMenuEntry', entry);
- $.on(entry.el, 'click', PSAHiding.toggle);
- $.addClass(doc, 'hide-announcement');
- return $.on(d, '4chanXInitFinished', this.setup);
- },
- setup: function() {
- var btn, psa;
-
- $.off(d, '4chanXInitFinished', PSAHiding.setup);
- if (!(psa = $.id('globalMessage'))) {
- $.rmClass(doc, 'hide-announcement');
- return;
- }
- PSAHiding.btn = btn = $.el('a', {
- innerHTML: '[ - ]',
- title: 'Hide announcement.',
- className: 'hide-announcement',
- href: 'javascript:;'
- });
- $.on(btn, 'click', PSAHiding.toggle);
- $.get('hiddenPSAs', [], function(item) {
- PSAHiding.sync(item['hiddenPSAs']);
- $.before(psa, btn);
- return $.rmClass(doc, 'hide-announcement');
- });
- return $.sync('hiddenPSAs', PSAHiding.sync);
- },
- toggle: function(e) {
- var hide, text;
-
- hide = $.hasClass(this, 'hide-announcement');
- text = PSAHiding.trim($.id('globalMessage'));
- return $.get('hiddenPSAs', [], function(_arg) {
- var hiddenPSAs, i;
-
- hiddenPSAs = _arg.hiddenPSAs;
- if (hide) {
- hiddenPSAs.push(text);
- hiddenPSAs = hiddenPSAs.slice(-5);
- } else {
- $.event('CloseMenu');
- i = hiddenPSAs.indexOf(text);
- hiddenPSAs.splice(i, 1);
- }
- PSAHiding.sync(hiddenPSAs);
- return $.set('hiddenPSAs', hiddenPSAs);
- });
- },
- sync: function(hiddenPSAs) {
- var hr, psa, _ref;
-
- psa = $.id('globalMessage');
- psa.hidden = PSAHiding.btn.hidden = (_ref = PSAHiding.trim(psa), __indexOf.call(hiddenPSAs, _ref) >= 0) ? true : false;
- if ((hr = psa.nextElementSibling) && hr.nodeName === 'HR') {
- return hr.hidden = psa.hidden;
- }
- },
- trim: function(psa) {
- return psa.textContent.replace(/\W+/g, '').toLowerCase();
- }
- };
-
- CatalogLinks = {
- init: function() {
- var el, input;
-
- if (!Conf['Catalog Links']) {
- return;
- }
- el = $.el('label', {
- id: 'toggleCatalog',
- href: 'javascript:;',
- innerHTML: "Catalog Links",
- title: "Turn catalog links " + (Conf['Header catalog links'] ? 'off' : 'on') + "."
- });
- input = $('input', el);
- $.on(input, 'change', this.toggle);
- $.sync('Header catalog links', CatalogLinks.set);
- $.event('AddMenuEntry', {
- type: 'header',
- el: el,
- order: 95
- });
- return $.on(d, '4chanXInitFinished', function() {
- return CatalogLinks.set(Conf['Header catalog links']);
- });
- },
- toggle: function() {
- var useCatalog;
-
- $.event('CloseMenu');
- $.set('Header catalog links', useCatalog = this.checked);
- return CatalogLinks.set(useCatalog);
- },
- set: function(useCatalog) {
- var a, board, path, _i, _len, _ref;
-
- path = useCatalog ? 'catalog' : '';
- _ref = $$("#board-list a[href*=\"boards.4chan.org\"],\n#boardNavDesktop a[href*=\"boards.4chan.org\"],\n#boardNavDesktopFoot a[href*=\"boards.4chan.org\"]");
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- a = _ref[_i];
- board = a.pathname.split('/')[1];
- if (['f', 'status', '4chan'].contains(board) || !board) {
- continue;
- }
- if (Conf['External Catalog']) {
- a.href = useCatalog ? CatalogLinks.external(board) : "//boards.4chan.org/" + board + "/";
- } else {
- a.pathname = "/" + board + "/" + path;
- }
- a.title = useCatalog ? "" + a.title + " - Catalog" : a.title.replace(/\ -\ Catalog$/, '');
- }
- return this.title = "Turn catalog links " + (useCatalog ? 'off' : 'on') + ".";
- },
- external: function(board) {
- return (['a', 'c', 'g', 'co', 'k', 'm', 'o', 'p', 'v', 'vg', 'w', 'cm', '3', 'adv', 'an', 'cgl', 'ck', 'diy', 'fa', 'fit', 'int', 'jp', 'mlp', 'lit', 'mu', 'n', 'po', 'sci', 'toy', 'trv', 'tv', 'vp', 'x', 'q'].contains(board) ? "http://catalog.neet.tv/" + board : ['d', 'e', 'gif', 'h', 'hr', 'hc', 'r9k', 's', 'pol', 'soc', 'u', 'i', 'ic', 'hm', 'r', 'w', 'wg', 'wsg', 't', 'y'].contains(board) ? "http://4index.gropes.us/" + board : "//boards.4chan.org/" + board + "/catalog");
- }
- };
-
- IDColor = {
- init: function() {
- if (!Conf['Color User IDs']) {
- return;
- }
- return Post.prototype.callbacks.push({
- name: 'Reveal Spoilers',
- cb: this.node
- });
- },
- node: function(post) {
- var str, uid;
-
- if (!(uid = $('.hand', this.nodes.uniqueID))) {
- return;
- }
- str = this.info.uniqueID;
- if (uid.nodeName === 'SPAN') {
- return uid.style.cssText = IDColor.apply.call(str);
- }
- },
- ids: {},
- compute: function(str) {
- var hash, rgb;
-
- hash = this.hash(str);
- rgb = [(hash >> 24) & 0xFF, (hash >> 16) & 0xFF, (hash >> 8) & 0xFF];
- rgb[3] = ((rgb[0] * 0.299) + (rgb[1] * 0.587) + (rgb[2] * 0.114)) > 125;
- this.ids[str] = rgb;
- return rgb;
- },
- apply: function() {
- var rgb;
-
- rgb = IDColor.ids[this] || IDColor.compute(this);
- return ("background-color: rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "); color: ") + (rgb[3] ? "black;" : "white; border-radius: 3px; padding: 0px 2px;");
- },
- hash: function(str) {
- var i, j, msg;
-
- msg = 0;
- i = 0;
- j = str.length;
- while (i < j) {
- msg = ((msg << 5) - msg) + str.charCodeAt(i);
- ++i;
- }
- return msg;
- }
- };
-
- Emoji = {
- init: function() {
- var css, icon, name, pos, _ref;
-
- if (!Conf['Emoji']) {
- return;
- }
- pos = Conf['emojiPos'];
- css = ["a.useremail[href]:last-of-type::" + pos + " {\n vertical-align: top;\n margin-" + (pos === "before" ? "right" : "left") + ": 5px;\n}\n"];
- this.icons["PlanNine"] = Emoji.icons["Plan9"];
- this.icons['Sage'] = Emoji.sage[Conf['sageEmoji']];
- _ref = this.icons;
- for (name in _ref) {
- icon = _ref[name];
- if (!this.icons.hasOwnProperty(name)) {
- continue;
- }
- css.push("a.useremail[href*='" + name + "']:last-of-type::" + pos + ",\na.useremail[href*='" + (name.toLowerCase()) + "']:last-of-type::" + pos + ",\na.useremail[href*='" + (name.toUpperCase()) + "']:last-of-type::" + pos + " {\n content: url('data:image/png;base64," + icon + "');\n}\n");
- }
- return $.addStyle(css.join(""), 'emoji');
- },
- sage: {
- '4chan SS': 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAYAAACZ3F9/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAa9JREFUKFOdkt0rg2EUwM95b2zlL0CRRLngksznXrJsNtYW1tjYhM3mY6+IXZAbikhTKJp8XZAp81UmWYhIRHHhUi60e7s6ntdCa2449es8PfU7z+k5B6AbyuE/wQlc4BcO2d06unAUBCgFE0hianOd3NHIcy8NPwrUf9NBPZcOEi7ayXZiea/1V7+ljaXeYAfOgg2So2TOwQWGnwQafOgi962TnMFmatozUeNu4yetASspVvgXiUvii5K5Nm6z56ol3Hdtpy+cwSYy+HRUt1nLsoEato0kXyh6wTac+24brThWv6MNOYNW9prlG/uxmbRrFaT0VrCspZoNPSUNJNyCBcoiLZuhLH0o9U6UrAfGKCz7RlLM81Q8XUwqr4oKPLIQmnA8IupBigacVy7yrya/2JouhryJHJJNykg+UxLGOtz6+SQNpEiMcduls4Wvoli9WklVKz+ol5SU4U6ngql8Qj2eRI+GyajBhSRH4r3cUxhSeRVhsYBmWUWiyM+UMDmDUI2nsfuSC1I27nLgYZJlP8jhjJ3PY8iE+L8tWx4kQC6MQA5b1D9HNiRCFhx8AF/e2qh92VnKAAAAAElFTkSuQmCC',
- 'appchan': 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAABa1BMVEUAAACqrKiCgYIAAAAAAAAAAACHmX5pgl5NUEx/hnx4hXRSUVMiIyKwrbFzn19SbkZ1d3OvtqtpaWhcX1ooMyRsd2aWkZddkEV8vWGcpZl+kHd7jHNdYFuRmI4bHRthaV5WhUFsfGZReUBFZjdJazpGVUBnamYfHB9TeUMzSSpHgS1cY1k1NDUyOC8yWiFywVBoh1lDSEAZHBpucW0ICQgUHhBjfFhCRUA+QTtEQUUBAQFyo1praWspKigWFRZHU0F6j3E9Oz5VWFN0j2hncWONk4sAAABASDxJWkJKTUgAAAAvNC0fJR0DAwMAAAA9QzoWGhQAAAA8YytvrFOJsnlqyT9oqExqtkdrsExpsUsqQx9rpVJDbzBBbi5utk9jiFRuk11iqUR64k5Wf0JIZTpadk5om1BkyjmF1GRNY0FheFdXpjVXhz86XSp2yFJwslR3w1NbxitbtDWW5nNnilhFXTtYqDRwp1dSijiJ7H99AAAAUnRSTlMAJTgNGQml71ypu3cPEN/RDh8HBbOwQN7wVg4CAQZ28vs9EDluXjo58Ge8xwMy0P3+rV8cT73sawEdTv63NAa3rQwo4cUdAl3hWQSWvS8qqYsjEDiCzAAAAIVJREFUeNpFx7GKAQAYAOD/A7GbZVAWZTBZFGQw6LyCF/MIkiTdcOmWSzYbJVE2u1KX0J1v+8QDv/EkyS0yXF/NgeEILiHfyc74mICTQltqYXBeAWU9HGxU09YqqEvAElGjyZYjPyLqitjzHSEiGkrsfMWr0VLe+oy/djGP//YwfbeP8bN3Or0bkqEVblAAAAAASUVORK5CYII='
- },
- icons: {
- 'Plan9': 'iVBORw0KGgoAAAANSUhEUgAAAAwAAAAPCAYAAAGn5h7fAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAzE15J1s7QAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAACAElEQVQoz3WSz4sSARTHvzMjygpqYg3+KIhkE83DKtKlf0C9SrTRuZNEx0VowU6CuSeJNlwwpEO2kJ6SQBiIUAzFjRDF4wrjKosnGx3HmdehFDfpe/2+z/s++D5gU7IsEwRByICIiAEAIiIAYAFAXsjYVr/fLxMRNVvN+prJ5/OA3+/XERFNf02JyeVyDx0OxyvLNQsnimLKfcf9KRQKXQAAnE6nlf5qMpnQycnbP/kAoKoqsSwLAJhOp+AAwOv1otvtpqxWq73dbt/r9XqvEQ6HUalUEvF4XLd5IpvNZqlerzd5nlf6/f6tTCZjBACk0+nb+XxeW4UrikLJZPImAGA0Gq0NIqJyuSyyANDr9Q5Wu1utFvR6/SULAI1G4+vK8Pv90DTtGwsAJpPpaGUYDAZ0Op3PHAAEg8H3tVqtbrtu21sqyxuRSOQJk0ql9IvF4r7b7f7pcrlejkaj57IsH58Pzp8dvjhc/lsBk0gkbLFYrFqtVvd27+4qOk733ePxPDCbzVBVFfP5fCiK4rvhxfDN/qP9wSasGwwGMv1HiqJQsVg8ZlfTHMepkiR1t05gGJBGmM/nMBqNj9nN9kql0lNN064ARISzH2cQBAGz2ewLu2na7XYLwzBbvxYIBBCNRrFj3BmsAZ/PZ+J5/kOhUIAkSVeA8XiMZqt5efrx9OA3GfcgvyVno9cAAAAASUVORK5CYII=',
- 'Neko': 'iVBORw0KGgoAAAANSUhEUgAAABMAAAARCAMAAAAIRmf1AAACoFBMVEUAAABnUFZoUVddU1T6+PvFwLzn4eFXVlT/+vZpZGCgm5dKU1Cfnpz//flbWljr5uLp5OCalpNZWFb//f3r6+n28ff9+PRaVVH59Pr//vr38vj57/Dp7eyjn5zq8O5aVVJbYV9nVFhjUFRiWFlZVlFgZGOboJzm5uZhamfz9/bt8fDw6+drb26bl5j/8/lkX1z06uldWFS5r61UT0tfWlbDwr3Ew76moqNRTU7Mx8P75OpeY19pWl1XW1qzr6x5eHaLiojv7+1UT0xIU0uzqadVS0nV0MxkZGT5+PPk497///ra29Xq5eFtY2H28e2hnJignJlUUE1dXV2vrqxkY2FkYF/m3d5vZmfDuruhl5aZlJHx8O75+PZWVVP29vT/9fTj3trv6ubh5eRdXFqTkpBOTUtqZmX88/RMQ0T78vPEvr7HwcHDwsDq6ef///3Gx8H++fXEv7tZWVedmZZXXVudnJp0c3FZU1f79fnb1dlXUVVjXWFrZmy8t7359/qLj455e3q4s69vamZjX1zy4+avpaReWFz/+f1NR0vu6Ozp4+f48/lnYmi8ur3Iw7/69fHz7+xbV1SZmJZVUk1ZV1zq5ez++f/c196uqbDn4uj9+P7z7vRVVVXt6ORiXl/OycXHw8CPi4ihoJ5aWF3/+v/k3+axrLOsp67LzMZYU1m2sq9dWF5WUU1WUk/Au7eYlJGqpqObmphYVV749f7p5Or38fPu6OpiXFz38fH79vLz7urv6+hhYF5cWWKal6D//f/Z09Xg29exraqbl5RqaW6kpKTq5uPv7Of/+PDj29D//vP18Ozs5+OloJymoZ1ZVVJZWVlkYF2hnpmblIyspJmVjYKQi4enop5STUlRTUpcWUhqY1BgWT9ZUjhcV1NiXVkkhke3AAAABHRSTlMA5vjapJ+a9wAAAP9JREFUGBk9wA1EAwEAhuHv3dTQAkLiUlJFJWF0QDLFYDRXIMkomBgxNIYxhOk4wwCqQhQjxgxSGIsALFA5BiYbMZHajz1oJlx51sBJpf6Gd3zONcrqm/r1W8ByK0r+XV1LXyOLLnjW6hMGpu0u1IzPSdO17DgrGC6AadrVodGcDQYbhguP6wAvAaC0BRZQalkUQ8UQDz5tAof0XbejOFcV5xiUoCfjj3O/nf0ZbqAMPYmzU18KSDaRQ08qnfw+B2JNdAEQt2O5vctUGjhoIBU4ygPsj2Vh5zYopDK73hsirdkPTwGCbSHpiYFwYVVC/17pCFSBeUmoqwYQuZtWxx+BVEz0LeVKIQAAAABJRU5ErkJggg==',
- 'Madotsuki': 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAMAAADTRh9nAAAALVBMVEUAAAC3iopWLTtWPkHnvqUcBxx5GCZyAAARERGbdXJrRUyGRUyYbY23coZFGDRFGEYfAAAAAXRSTlMAQObYZgAAAGhJREFUeF5Vy1kOQyEMQ1Fshzd12P9y61AixLX4yJFo1cvVUfT23GaflF0HPLln6bhnZVKCcrIWGqpCUcKYSP3JSIRySKTtULPNwMaD8/NC8tsyqsd1hR+6qeqIDHc3LD0B3KdtV1f2A+LJBBIHSgcEAAAAAElFTkSuQmCC',
- 'Sega': 'iVBORw0KGgoAAAANSUhEUgAAACwAAAALBAMAAAD2A3K8AAAAMFBMVEUAAACMjpOChImytLmdnqMrKzDIyM55dnkODQ94foQ7PkXm5Olsb3VUUVVhZmw8Sl6klHLxAAAAAXRSTlMAQObYZgAAANFJREFUGJVjYIACRiUlJUUGDHBk4syTkxQwhO3/rQ/4ZYsuymi3YEFUqAhC4LCJZJGIi1uimKKjk3KysbOxsaMnAwNLyqoopaXhttf2it1anrJqke1pr1DlBAZhicLnM5YXZ4RWlIYoezx0zrjYqG6czCDsYRzxIko6Q/qFaKy0690Ij0MxN8K2MIhJXF+hsfxJxuwdpYGVaUU3Mm5bqgKFOZOFit3Vp23J3pgsqLxFUXpLtlD5bgcGBs45794dn6mkOVFQUOjNmXPPz8ysOcAAANw6SHLtrqolAAAAAElFTkSuQmCC',
- 'Sakamoto': 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAYAAADwMZRfAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAxVJREFUOE+Nk19IU1EYwK+GQQTVQ39egh6ibKlzw91z7rn3bvfOmddNszl1bjKXc5rJJGmBUr7Yg9qTD0IalFgRBEYg6EDQQB+GovQyQgiaUZsoLcgHMcr069w7MgcGXfi453zn+37fv3MYZt/n99e76tzVj4JN/hP79fvXnV3hnNabwUBjoOHcgTYOu/JQspgTzsqKgn9BfD4vkWTzur287PqLVy+zM+yePB7KsRXLywTjnSpnZctBkPCdW8ccDuU55vBO8RXbkC/oP5ph19V5+7LIky0OY1BKbZEbLcFSt7u6pN7jLmltCVrr3DV5jY3+KovFEsccB1KJNVpefe10BqS2tqqO4/AuphBB4L/LkrRqNgtJs1lMypLls1kU38mytMLz/E8VIlutqVqX6/weZG52OttRXjbE0cP/FYLRlpVjDXuQ/r77x2XZPKkCHA4HBAIBkCQpAygIAvh8Pu2MZgO0Lz+QSa/sQfwN9RfpVN66XC6Ynp6GhYUFGBwczAC1t7fD0tISxONx6O7upgHILmsqvLcHodOggfiV/v5+SCaT4HQ6IRaLgdfr1bIRRREmJyfBZrNBNBqF+fl5sNsdgE2GiAbp6bmbdbXC7qWQbxMTE7C2tgY6nQ5SqRSEw2ENopaoZpCXlwdTU1NaoECgCbgiU6y8QH+ECYWaTymK7TWdys7MzIwGaWtrg42NDejo6AB1WjU1NZo+FArB2NgYrK6uQrAlCASxn2z6wkuMp87VIAhkE2MEAwMDkEgkYHx8HBYXF0HtkQpRy1BLiEQisLy8rPVNKSsFjEzrXH4+z1hlS4xDhKadNu7t7YPR0VHweDzAEVWfHru6HxkZgeHhYVAURYNjkylVWKArZjjMzqmdVi+QCsLUkQiEjvDvncEkvU7/qQ0Vgukeo48Go87IiCJnZNmipxiz7wXEbVDnbUxQOgM12h9n6qTq6NvapRdtkwaP0XK8RmPuYSbxYfaQ/sJJhjfknuFRURUi7AMOozcCwl94hLZp5F+EioDQVwqYI6jomZU1NFtM+rOSxZjVazcyvwHr/p/Kws1jegAAAABJRU5ErkJggg==',
- 'Baka': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA0pJREFUOE91k3tI01EUx39JOpA0H4jNx0pbD3XTalISWf8YFlEgldqDsBLLyqjEKBCiLLWiggh6/KEV1WZ7OaelLZvDdDafNW1JFraWe/32+01FrUZ9uy4ylLpw4Z5z7/nc77n3HIqaMRIjZJyEcNX+uFCFeGmI/GZciEIsCFJUTvoAzDz+1y7K76MSwhX5hXl6z+WSbrzU2KB8YEGDwgrTaxZ3b7xHcaHhR3xw7Z5/UviB1ReP5XSg3+TAqYJOxMzWISFIC0GQDomhTVA9skCnsaAwp/vnMq66dBokNuBR9uFd7T9Z1zCunjci0qcRJUVdoJ3DYOhRnC/qBZ+jQbfeCc+37yjY2UEg0iwvJE0k9l8Z+8xqHmTgot0QLdQgTaQFQ2AsOzlHvOu1S5pwOLsHHo8HjHMCq2MazNvTlByKHyrJLDvdR25jMWRxYx5HjeMH2r1BDOOeguRua4OI14jx8a8YH5tA+al3EHKlW6mYOapb2oZBOOwMbEMseAE12L+jjUh3w+VipyAZ65oxn1NP/GMYGR6Ftn4Qsf7qa9S82Y/l/X122G0uL2TbxmZEz1WhXW8mUol8moXu+SCi/OoQ6VsDh3UUwyQ1k9GOaI5MTkX4yWTGHutvgI1F28sviAlRgxeoRm62HvsyW8En9pZ1TYgi6TntoyQtFm86rVgUoJZRvDnKMmXVAGxWmkAYOBwudBqGcHCvHulrGpGT2Uy+z4yT+QYsCXtCUpp8GxbKhx8gDK0ro+KjJGvzdjfDZnN6VdisLD5/JjArQ2zW66PJOj2lEZtStaBphkwah7K6kMJ/GEulp1bMWhAmMbTozOQRaWRtfoZVgjo4iRra4SYgGi26TwjxVeDKhR7Y7U606ixICq9tr7hd7+OthRWL7yUnJ1WPmXotqLhpRICPHCePtuFV6xdUPTAhcWEtRHEqfHpPyto4hPXLXnzflSEJnFaN3OCKDcsFsrEntR9RUmxARLAUgT5iBPuJsXWDBj0dZjRU9yNV+PTbpjTp9OA/pOSk24nRkXf1J462oPxcJ65f6ULlHSMulepRerYDgvj7A0cKpNz/tyTZqbzXO4t0ZZGQJ34RH11lFHIlA8LIqreCCMUZRY3cd2bwL/5/RmjNSXqtAAAAAElFTkSuQmCC',
- 'Ponyo': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAuNJREFUOE+Nk3tI01EUx39BTytConQTt1am07m5abi5KT5S8z2dj1yOEMUC7aUgIoimlmUEWX9kBZGWaamEmE6U1BI1XNPNGTrnHs33IwuSXrL4NgcJ0mNdOHDh3PPhnPP9XoKwcroJYvMQiRSicHCQKCgUyZC9/T5rNet5KUFs0zCZbZMsFmZ9fTEjEEBDp4/KSSSb/4JoGIyWaTYbiykpWEhOxhSHAzWD0aqkUGhWAcVkW58xlvuPhfh4zItEmOHxYDR3MhcdDaNAsKJydAz5IySKRNjEUmy88vjOVaU8F0iPCqCNjEBHkC/UYaGYFwqxmJoKLYOhkxPElg0QsbNtTlmox9yjRD9UCbnoOR+J/lwRWtOCcdXfDc2BPpg0d7CQlIQZPh9KKlVkAQjJ2x2zmOSsQu7hpzUJfBhLjsNQmADjxcT10Bcl4rE4EHc5LjBEhEPn7f1WTqXSLQB/s1Tp7vslsoIkyPPiMJAbi86McBguiaHKjoEqR4jJy2K0nAxApzMN5iUGrclrKVaz2fUvuF4tRbxDKA90w5VjTFyLZKHpTBSq4/1QnxGB2qxoVIZx0JopRCPHFSNOThfWZzfrXDcZEowH4iA05ATg68hDtBaL0HAuCm3lJ9Bfcx2fFNUoi/DCjRgfNHHd1wCZA2TyXjNkE6F0cBDpPFiojeNi8EkJdFoN3vXch0nbBJOhDd907dANv8JITxNqziag3ZsJbUDAwLin50Q9QWwl1qSYoNOVvUcOoqOqAAa9Fu9H2/F9+B5WZLcwOyxFX18flLI+VASyMGVeoJHD+Tzq5BS1PoaKRrNT8127P74swsq4FCa9FKvqBqwaOiz3hdEuLKueYSyECT2LNW0eIfo3E/WmEbvnG1MUJnWdpWhDGDvxQXZHo+RR0uW2tnv+auPX+TvtJm7zKpaen/4y2yjBUlcxlvtvmvT16ZWDpQeoVv3/60F/NrHjTf4ugazIXtJ8ivjnz/sJ+yGQRjcqUdIAAAAASUVORK5CYII=',
- 'Rabite': 'iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAD/0lEQVR4Xl2MXUxbdQDFz/9+9Lb3tkBLCxTKhzgoOOZAsokbJmZxDFHnd+LL4hKVzBgfNCY++ODbjDEaZowvErOM6HRu6hKZY2rIAOkCY4OSDTpFaAsrlJa2t5+39+NvjT7tnJzknIfzI98Nf/C6TuXdguWBd1q9rcb8/CwsZiu2Ywm4nDVo3VWLZCKDaDwJq9mCg31PgjAMKKUwmcyYvTbek9iJRDm6M/XswEDjwNz6plWW6wdZhjUAintFCEEhn0N04zYskljaDLaj8ar49oUrsYR6mrFJNj322w46H8y+mitM/ZJKZmyE4XAvjJSsazpyuSzslVZIkgWKOvvRgQ6Xrdlhqmds7o7bFZoLkctreKxf7GtuCE7IyUQjBQcQ8j/lvxCGQJZz0IoCVpamTtzfIh9nwiaIrCQyjNg8mq11oDLUhNXRJfT1Ozr3tS/PqpnQ80qRgjAmKIqBfK4ItbSLKoOZqR/6neLkENlSUAIhlktvEf+sD2rkm8nWTHtvZCGMVON1ePuaoBER31/MXGly1wSqq9Uug6FluYyWXJiPqFXmjd4Dh9oF9ZKKimYXRtYCx8lmMIDIxlIPGz591av0mtanF7FcCEN6iMXeox2wOJ0QJAmUAoRQaIqCnWAQY1/ewKNGNeQuYXkm0d2NC2e+wvmRr/Hx+6+8PHayrbDyyQBNDb9As3PHKDWG6MTM23RoeJAWsqeoWvyUUv0UHf7pBB0fe4OeeXe3/vmHbx3+8dwIGJ4IsFpMMFe0fbtAn+nwZePr1u4MBK8XIALG/Rt479wYrs2vgeNNAMNgMbiNzybuoKVvn+Gs9kbr6qpBfJfGYHFIkJUCoGwfqcoMX/b27EGhwgOjoCADDlP+CA51ugFFRzoB8FYNaQ1oqKD44+eNL+wNj7zJGQSIhe8+jgQ9thk+27v/KRY6L4FSCkVOwtlQj6P73Qgt/o1ERoKt4iUkE7+jrZMHyzIoK9cOBFfT4LbWAk+0a7ZLnvqHcTNdACgFScfAcjxEdy00VQclHGo7dqGeYxHbvIo6hwhSghCehb3G5p6eW7VxXC5/xGWToMgrKKoaCnIalI9CIARasQAqloMI/x4BWrLLYwE1AEPTwCGHaGjz7pw/leZUNV8wNm9BLy6CxsvxZ1kMbaY4TKIIXlNBsynoVjvAC4CuAoYOVi+CMfLYCUfg95tPHuzZB0YtKzsb58RMucWE/fZmhCbdOP9rNnLnxko6GVoB8lFwyVVw8b/AyeulHoJyN4Rb19dTFyeqBlu6njvfsWcvOJvLs7DMmw/7bvpeE4pU2OIcgcqmp4fGAgt2Txwvqr7lTp5V7LquZxXC6+BqEvGcY5pyjaM1tffJbk89NE3FP5VQ6y7a+paZAAAAAElFTkSuQmCC',
- 'Arch': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABCFBMVEUAAAAA//8rqtVAqtUQj88tpdIYks46otwVldUbktEaldMjldM2qNcXk9IWktQZkdIYlc8mnNUXlNEZktEZlNIYktIWlNMXktE7o9klmdMXktFHqdkXk9EWk9EYk9IlmtQXlNEXktAWk9AWlNEYlNFDptkZldMYk9E4otg/p9kXktEXk9AXlNA4otclmdQXk9IYktEXlNEwn9YXk9IXk9FFp9o3otgXk9FPrdwXk9E2otdCptkXk9E/ptkcldIXk9Edl9IXk9EjmdUXk9EXk9EXk9EbldIcldIjmdMmmtQsndUvntYyn9YyoNYzoNc0odc1odc2odc6pNg7pNg9pdlDp9pJqttOrdzlYlFbAAAARXRSTlMAAQYMEBEVFhgcHR0mLS8zNTY3PT4/RU1kdXp6e3+Cg4WIiYqMjZGXl5mbnqSnrbS3zMzV3OPk7Ozv8fT29vf4+fz8/f7SyXIjAAAAmUlEQVR4XlXI1WLCUBQF0YM3SHB3a1B3l7Bx1///E6ANkDtva0jKbCW2XIH1z2hiZEZ4uUgxo7JedTQye/KN/Sb5tbJ+7V9OXd1n+O+38257TL+tah3mADAwSMM7wzQWF4Hff6ubQIZIAIb6vxEF4CZyATXhZa4HwEnEA+2QgoiyQDnIEWkjVSBBZBqXbCRlKYo8+Rwkyx54AOYfFe7HhFa7AAAAAElFTkSuQmCC',
- 'CentOS': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAB5lBMVEUAAADy8tng4Ovs9tnk5O3c7bX44LLduNO1tdDh7r/eutj43q2kocX23az07N+qqsvUqcmXl7331ZXJj7r40o/Pn8T42qP63KjNw9n21p3Y387Ml7732JzR55z05MSxtMLGn8TC4Hx8eqt8e62Af6/B4HnG4oPC4HzH44fBf7LCgbOkoMTcsrmtn8PWqcfFtKrj4Jvs2ZOz2FnMqLXT3KfY5p60Z6NUU5XRuqHzwWSywqDn3JaiiLWahrWhkry5zJjRmqm1Z6P1wmb1y319fK632mK5cKi5nH+73Gu73Gy73W283W+9eK17e6y1yZS3aqRZWJdcW5ldXJplXZppaKBwb6VwcKV5eKswL306OYNPTpGkfK+m0kGpUJWq1EnEqIuXK3+Xh7ahP4qhkryMfK6BgK+CdpGMaKKMa6O9ea2+eq6+oYW/eq+NbqWVlL2Wlr7AjanA4HnA4HrBkqbBlafB33rCgbLCmKjCxIzC1mSs1UytV5mtxIWt1lCuz2evWpuvXJywxYzHjrvH4oXIjrrN2HXO5pTO5pXUlYnUlYvVl5Hb0G7e0XTg03rhr5fpzHPpzXTp0Hvtz3/wrDHytknyt0zyuE3yuVHzvVr0wGP1x3T1yHf1yXe0ZaL2zYP30o730pD31ZeRIcF5AAAAQ3RSTlMAFBkbHEhJS0xMTk5UWWBsd4SEiIiPkJCVlZaam6CjpK29wMPDxMTFxcnK193e3+Dg4uTn5+fo6e/v8/P4+fn7/P7+J4XBAAAAAOBJREFUeF5Vj1OvAwEYBb/yGlu717atLW0b17Zt2/6nze42TTpvMw8nOZCAmwUpiIY6c5IiLi9tPX64GairqszHQ4X2VB64v1Cs6PxMPJSdHM777s6/jyaMRGiRLyyrb88OpjZ3CzAXrm1sqzSNNeN7kVBPNgB7cG51abE5l9cXDces7emQ1uadHhutFUg6gpPKkSIqQGavwz7r7O/+/3t/rSdjI9XDM3qz4fr3B/3iA0aJTG9x71+9oR/PLDwUe2wm19bly+fTIxHyEETatbPewGEw6Mk/tKZCEqSQQUlIHB/QNBEjjVN1AAAAAElFTkSuQmCC',
- 'Debian': 'iVBORw0KGgoAAAANSUhEUgAAAA0AAAAQCAYAAADNo/U5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAZ5JREFUOE+Nkk0oBHEYxv8fu5GQj3JwcaDkIAc5IpR87M7MKnIVJVKclaIQ5Sy5OLkgR7n5OigcSNpmd2c2Vyfl4KT8/muWiVU79TTv+7zv837NCBF6PG1X+NpZyEYSD9mIc+tHnBPe23B9xKrCuTmbQA/JKfABrhBswa1hH4A38IwfOxPdX1qcjiCQxO5NyrjKV70TnSbeRPwJvGN3i4yyqnEucPY8ZZX9GSEgGK+RvFfyjk2VKZxzBNG8wJWWgh/xtDOeUXZ7Slr6TrSLYL9N4SMgYTTcwdc2ArvJcElhSVcM6mCNSV8n9hA59yTU5UWMG6HIbLhIWlglgWiC2L4Z79qTdo40D6ISuOWwKCWHyk9Fv8ldpUHOuGTuynwSBUynddPdlbEosVpP9Eu4FnOsRzUYNTsdmZN/d5LDiqM0w+2CMdAFFsFGWgfXxZnheqe/z+0puwEM0HHYV3Z9Sgz8TEz7GkQvpuJ/36ggj2AaHLrSlkULWV5x+h2E8xkZL16YVjGNaAUscfZ/f6c/k9ywLKI2MMcRWl0RLy007idmRbQJ7RIfDAAAAABJRU5ErkJggg==',
- 'Fedora': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABPlBMVEUAAAApQXIpQXIpQXIqQ3UpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIqQ3QpQXIpQXIqRHYpQXIpQXIqQ3QqRHYpQXI8brT///8uTYMpQnM5Zqg5ZqnS1+I4ZaY4ZactSn8uRnYrQ3MrRXgsRHUsR3s8bbM8brMtSX4wUosxVI01XZw2X50vUIguToQvR3c6X5o6aKs6aq08Un8qQnM9VIFDWINJXohKcKlXapEqQ3UvUIc2X55bhcBdcJVgcpdhfapmd5tuk8dxgqJ1hKR5jbB6iah/m8Shudq3v9C4wNG/x9bFy9nFzNnFzNrIz9zK0NzK0t/O2+3P1eA2YaDU2eTb3+jb4Oje4urj6fHm6e/s7/Tz9fj3+fz7/P38/f3+/v83YaEa/NNxAAAAHnRSTlMABAoVGyY1SVlpeIuQsLfDzdHW4+3y8/b39/n6+vr4+ns8AAAAyklEQVR4XiWN5XrDMAxF75KOknYdZJS0klNmHjMzMzO9/wvMcH7I37mSJShsJ+5NjMT6umDoHyXDcI/2qJadh++P3cle1de+9yPe3/bTY92wzfzr7wGtP3JrAI72BZGVtcAdQlwHy+JS1pDbBE9qamZF3BYrjQxPEXwKc6dC8bXFm0QIpmt8kn0Rn093q82UCtK8oXZckwFJzuulV8bHkajPyXdbnJnARfDHs0trz+JQ+5AFvzp/L0+cL2qPAINUPrq5OC6p/64F/AMnrST+Dq/r7QAAAABJRU5ErkJggg==',
- 'FreeBSD': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAABIAAAASABGyWs+AAAABmJLR0QA/wD/AP+gvaeTAAADXklEQVQYGQXBS2wUZQDA8f83j33M9rF9d7u4loaWklaDpkSo9KDGaIKUaGxshD2YSPRiuDVeTDyhBxosJCoa40ktpAkPDcUqAYVIpUSUPrAulEdD2bbb7e7ObGcfM/P5+4kwKDvq6yJ1FYYcvb+YAkqAHo/HQ7FYrFIoCiurq9ZXJ06YSOkA+kBzfX06bys3zHxS9EL0tXDVyZfefacqV+X/ZSJx5+qLbx98LhaL9RiGEZWlEsWC/Thd9q6Pf3vs2u6Orc83rFsvTwwfLf5obgywT1Vjh2Hh+rbNsnTssJdNLedK5aIrpSuldKVXKsnH4+Pyn6FDXn5tMef9O+3NvdkvP1V4+EYw2AoQ+KSx8dRYS6NXXnwovaItXduSrrkinWxGOmZWJi9OyOK9m1LmsjIz9IH8QUMOd3WfAQwNKCy2tJwbHB5+XasPaxIHmc4g7WWEZ1MquBiRFlJTf1E7+Tl/H/8asavPzTY1nWd2ZkMDRPeBeHPz5ojwsilEQCBvTSKunCF3M8FSNkBGVTHDYYrLj8jVNhDZ2SMa2zo3MTamaIC/u6Ojr3DtrOrvP0BpdATnyBeIhTxpR5ABUlKSUlXS1dWstbVxdz6hPL0l1quGqkLaKwNvVcjEXNRd/4mit4Z19DjefBEPyCKxgQJQcF28dBrHNDGTSZSezsjeff0hraa2Vs2vrvit81O4vj9xLJcC4ADrQA7YAGqBGsAql/EtLdFQE/L7dF1XZmdnSrbPMJfXoLDmolQK8gJyQBowgQhQDRQBD+hsraVhd4e5MH+/oExfvWLJ9q3/3S7qMpNH2hsS40kFS4EUUAMA2IANRIBXv4uzuO67c2PykqkA5YmZ6bN18YPi0Yoknxc4AsJPCMLVAk2BLKDosCWqs/PZaulkuxk9fekcUBAAQGDks5FT0W++3NuYuC0DVUL4DIEdlIQDAj0IRkigaMjArkFx0tf523sffrQHyKsAgHPhwoXLL+yP9/kePNhk5ExUTyKFkJVAUAiCFZrQup4Rv9ftuLV/6ONBYBVABQAArMvJ5MXW7duD6P62sD8UrPAFRU1TpeCpCnGvPZr7WW///v0jpw+VC9ZdAAABAAAAAMLo7drWrmQyPWG/r8tnaGIjaM05ujr16x/ZBFh5AACA/wGZnIuw4Z4A3AAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxMi0wNy0wNFQxMDowOTo0OS0wNDowMOPVpFwAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTItMDctMDRUMTA6MDk6NDktMDQ6MDCSiBzgAAAAAElFTkSuQmCC',
- 'Gentoo': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAB9VBMVEUAAAD///+AgICqqv+AgIC/v9+Ojqqii9GAgKptYZKQkOmPj/ddUYBgW4eVjeCTgfiWjO5wbJaZkvPBvepkXomYkNldV4Bzbpl6dJ+Uj7ynoO6Vi+1qZI63se2mnudjXYjOy+GCfaqZjvWlm/Pc2e+Oh7NeWIOWjfeXjeW1sd+gl+diXIfp5/KHgKnn5/F2cZx6c6ZgWoXc2e6dltrAvNu0scrX1eTOyujCvup4c5qpovVpY43///+6uPPJyPXq6fvm5vrz8/z8/P7+/v/d3PixqvmxrPSyrfe0sPO0sfS3tMve2/3r6vy6ufPz8/3d3fi3tM63tPO4tsu5tsu5tvO6tfe6t/Vva5KRjKy7tvW7t/W9vPO/vM+/vvPCwfPEw/TFwvTFxOfGxfTGxvTHxvTIx/TJx/aTiOrNzPXNzfXQzfnRzuHS0fbS0vbT0uHU0e/U0uTU0/bW0+zW1ffX1vfY1/jZ2Pjb2/jc2uSTiemVkLSlnvbe3PTe3vng3fzg3f3g4Pnh4Pnh4fri4enj4/nk5Prl5Prm4/ymn/bn5vro5/rp6O/p6funoPWsqs3t7Pvt7fXv7vzv7v3w7/nx7/3y8f3y8v3z8vytqPWuqPX09P319P319P719f339v739/34+P35+f37+/+uqev9/f6vqvSwrPQAR0dcAAAAPHRSTlMAAQIDBAgJCwwVFyAsNUFHSVBneH+Bh4mVmZmanKCxsrK2tr3ExtDW19rb4ODl5u3t7u/w8/T6+/z9/f4MkNJ1AAAA8ElEQVR4XjXNw5aDURSE0YrRtm3b54+dtm3btm3bz9k3Wek9+2pSYFwT8ibzE93hwAtdJqK3nZo4J9hFXbP+vFHOthV6gnGzstZq94wdCs4UCCDymQ2v7X0LdYoSQ0MIENRYzJbRlPTTHu73ZNAL8vivmVui98PpzuqffX0mIPHJGtOQenukteJ+aS3b9htNpDnT9TeZH1bHAwBRMhGpd6e6uNrLoRgxBKmsX47nBlp678ojpEA40fejcmW4e/No0V8IIPfj6eKgbEJ3ZUnzgE1OqWp9Q3VeWRAsg51f1dZ8c31RmAsc+N5JGbG+zvj3BzDCPrzMDC9SAAAAAElFTkSuQmCC',
- 'Mint': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAACVVBMVEUAAADh4eEAAAAAAAAAAAAAAAAAAAAsLCyXl5dgYGCnp6eTk5N3d3fBwcGqqqq8vLzNzc3Ozs7Ozs7Pz8/Pz9DQ0NHR0dLS0tLS0tPT09Pf3t/Pz8/i4eLb29vZ2drZ2tna2dra2trf3t/u7O/u7e/u7O/r6+vt7O/w7/Lw8PDy8fTz8fXz8fbx8fHz8/P19fb49/j49/n6+vuPxlmWyGOx437h9NDr9eD6/fj////+/v75/vTA5Jv6/fb7/fnL5bDL5q+AxjeDxUCEzTyGxUaGzjyHxkiHzz6J0D+Kxk6K0kCLyE2M00WNy06P00mSz1OUyF+W2FGX1FiY0F6Z02CZ21ac0Wiez2yfz2+f2mOh4GCi4GOi4WKi4mOk12+k3Wul32um1Hin0nun4G6n5Gin5Wmo23Op2Huq1n+q43Cr526s4Hit23+v6XSw34Cw34Gw6nWx4IKy4IOy44Cy63ez146z34az4IWz4YW03Y217nu38H2625e645G74pK83pu98Iq984W+4ZjA4px0tzDA5ZrB8ZDC5p7D55/E947F6KHF+JHH4qvH6qTI46/K5LLL5LN1tzLL5bN1uTDL57DM5bPM6qzM66/N5rTP6LbP6bTR6rfS573T67vT7LrV7r3X68XX7MHX773Y77/Y9rvZ8cHa7cjd88bi88/j8tTk8djk9tHm8trn89vo89zo9N3p9N3p9d7p9tvq9d/s+93s/dzy+erz+O73+vT4/PX5/fT5/fX5/vN1uzB3vTD6/ff6/fh5uTj8/fv9/vr9/vx8wjV/xDmrMRH0AAAAOXRSTlMAAAECAwQJDzk/RUlNU3F0kpSVlpeYmpucnaKjpKWqqqqtu8LExMTEzdTU1NXY4evy8vP+/v7+/v6LaR1mAAABD0lEQVR4XiXI03bEABAA0KltW9kaW3eSZW3btm3btm3b/q4mp/fxgqKOtpamhrqaqoqykrQYABh+PVMU9fjE5Xp8o54kgPHN0EBHU2N5YXZykiua0HHd2759VF2Sk5IYE5GGsmCEWLV1kVWwt5O+3x/qpgsy8k4ja+cJl2/v5C22tlgCAHtw9TQSa4s+AzfPSm0BRNl9SydhWJzLC567KrNhgrNwHIJ5qTz/2f9w7Jw/DNqIjVr04exW0AEOXcN3Ab7enr9eDW2VTJgehONyc2Z8XP5YdD0Tcuhcc4/r45OjGX51TEjYPbh8THRPvbz+CHusgSZlT7rP8PkCwfQKaQUi9Igr6JsRBMFiWZgb/AHKElRzKopZJQAAAABJRU5ErkJggg==',
- 'Osx': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABrVBMVEUAAAD///////+qqqr///+ZmZn///+qqqqAgID///////+tra339/eAgICoqKjx8fGMjIzm5ubh4eGPj4/g4ODIyMiAgICSkpKLi4vS1tbPz8+Xl5eMjIypqanIyMjW1tZ2dnbR0dGamprFxcV3d3d+fn60tbV3d3dcXFx3d3epqal7fHxxcXF+foCnp6hYWFhyc3Ojo6SMjI5fX196enp+fn6Li4xERERqamqgoKFpaWmFhoeen6A/Pz9QUFCWlpeSk5SUlZWUlZaOjo+Tk5RHR0cuLi5YWFgwMDAeHh40NDQ3Nzc6OjpcXF1rbG0XFxdSU1NVVVVXV1dZWVlbW1tnZ2lwcHABAQEEBAQXFxchISI+P0BISUpaW1xHR0kNDg4qKyszNDU1NTY9Pj8NDQ1cXF4XFxhSU1QSEhIDAwMrKywtLS4uLi4wMDFHSElISEggISE0NDVJSktNTU1FRUVWVlhGRkYEBAVBQUE0NTZQUVJQUVMFBQUqKitWV1lXV1daWlpaWlw+Pj8bGxtcXV9dXV1fX19fYGFgYGBkZGRlZmhpaWlsbGxwcHB2dna844Y9AAAAV3RSTlMAAQIDAwUFBggMDhkeICMkKCgqMDIzPj9ERFBib4CCg4iMjZCcnp+jqamrw83W1tvb3ePl6Ojp6+vs7u7v8PHy9PT09PT3+vr7/f39/f39/v7+/v7+/v50ou7NAAAA30lEQVR4XkXIY3vDYABG4SepMdq2bRSz/capzdm2fvOuDO397Rw0Ly4tz2QAQPbcxuZ2E/STJwfxPhWgG355fRrVAIVb1zeP9UDLfiSwkAcADe8fn7tFxWuEXFRDoer/OgoMTRBCumj8yJwPBo8Zhpk14U856/HI8n0ZUtpZ1udrSzfVneA4roNKjdrwpcMRilb8d8G60+lKnrpWcn9bO+B23w2O8Tzfq4aiNSZJqzn5O4Kw16h06fPZ+VUlUHfo97+VAEb7rSh2UgDd4/U+TBlQY7FMj5gBIGvcarVVfQPVPTG94D0j9QAAAABJRU5ErkJggg==',
- 'Rhel': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABj1BMVEUAAAD///////8AAAD///////8AAAD///8AAAD///////8AAAD///8AAAD+/v4AAAAAAAAAAAArKysAAAD///////8AAAAAAAAAAAAAAAD///8AAAAAAAAAAAD///8AAAD///8AAAAAAAAAAAAAAAB5eXn+/v5JSUnKysrS0tJ5eXmqqqqxsrL+/v4ZCgknJyeHh4eIiIjo6OgZCAdOTk7t7e3///8GCwwPAAArKyv19fX29vb9/f0EAAD////+/v4AAAAGBgYHAAAJAAAMAAANAQAPAQAVAQFyCQV9fX2pIRzmEQjn5+cBAAAFAAAAAADnEQjvEgn////uEQjyEgnsEQjzEgnxEgljBwPaEAj9EwnwEglHBQJHBQNNBQIBAAB3CQR5CQSHCgWLCgWRCgWTCwadDAWmDAapDAa/DgfKDwjWEAgGAADh4eHiEQjmEQjmEQkKAADoEQgLAQDtEQgMAQDuEQnvEQjvEQkPAQAfAgEuAwEvAwE8BAL1Egn3Egn4Egn6Egk+BAL+/v5CBQJrB0muAAAAT3RSTlMAAAMEBAkYGhsbMTRLUmpvcHeIjLe6vcHCxM3P0NbW3Ojp6u/w9ff5+fn6+vr6+/v7+/v8/Pz9/f39/f39/f7+/v7+/v7+/v7+/v7+/v7+Q8UoNAAAAO5JREFUeF4tiwVPA0EYRL9SXIsWl+LuxfcOd2Z3764quLu788NZNrxkksmbDP2R7vH6GioLs+iffEzNXd4+TqPErUUpVqMOvwgdzMPn1rv5vPsVeufBTaBK/bH2FPvkEUuIG5jIIc+sHYn/HJ3dC/Hxuo4y8s44dzwBbFkisHN8bVIdXs6jb+H97aCwbHEIqgcml64CD7YllNkAVQC940MLYe5YzvIeQAXNrd19Roc5MdzfdQLUUKaUYyuG9I8y1g4gj6hIak4X5cBIT2MquZJrJdOqpY11ZpAiqVwbY/C7KY1cRCrZxX4pWXVuiuq/hs49kg4OyP4AAAAASUVORK5CYII=',
- 'Sabayon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABvFBMVEUAAAAcUaYdVKwAAAAAAAUABAwWRY4YSZYhZtIhaNYHDx0KCgoFDBcKCgoRMmYSNm0fXL0fXb8AAAAYS5gaTp8fXLwgXsEGBgYFBQUZSpgZTZ4JFSgODg4IEiIOJkwOKVIkW7EnXbQLGzUTExMKGC8LHjwMIkITExMiIiIPEBEPJ00QEhMXOXAaPncOJEgoXbApXbEcHBwwMDAEAgAfHRgQDgo3NC8AAAAHBwcKCgoLCwsJCQkaGhofHx8lJSUwMDA0NDQ4ODiRkZEICQocHBweHh4GBgYHCg8mJiYnJycpKSkrKystLS0uLi4ICAgODg43NzcRERF1dXUUFBSjo6O1tbUbGxsEBAMLGS8MDA0iIiIjIyMkJCQNDQ0NHTYKCQkoKCgPDw8QEBArMDkKCgkRERIREhMxMTEyMjISIz00Njk1NTU2NjYCAgIVFRU5OTo5P0c8PD0+Pj4/QURAQEBHR0dKSkpMTExSUlJiYmJlZWVnZ2cWFhZ2dnZ4eHh8fHx9fX2FhYUXFxeVlZWXl5eYmJiZmZmcnJwZGRmlpaWrq6usrKyvr68KFiq/v7/FxcXY2Nji4uLn5+ft7e0yif9uAAAAN3RSTlMAAAApKSkqKioqg4OEhISEhoa1tra3t7y9vr7S09PT09TU+Pj5+fn5+/v7+/v7+/v7/v7+/v7+70RY/wAAAPpJREFUeF4dyWNjw2AUBeC7dfYyorM6rx1exKltzLZt2/rDa/J8OgBVVlFDX39jcTZoUqCse251a2dvu6ccUtWlanLQ4Vpel+ThlWq1l3wEz58tx4dOt1dMlAJk9A5gMjG75LHwo46hzkwosGOMbejumoRvubC9EOrMviT0E0Us9fvN9dA6zxJCNv6+ECGsb6oNWsgmpZT9/UTUZo3Em6AW34guTL4jiAudiCM1kLcw8/SmHERfT1/eueBiDqR1GK1n9w+K8nglxYxd6QAML4ztXoQuj8YFgWcgqdJp8qzty26vaboCNIxBCshyQDKov0aXr29v1ufq1PwPx5Q7bCoh6eoAAAAASUVORK5CYII=',
- 'Slackware': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AcEDi0qZWWDgAAAAx1JREFUOMt9kktoXHUchb/ffc1M7rySSdJMOknFPMRitLgoNKKI8ZHGKkgrjU8SitidimSh2UkXoQmoO1dGQSxJjdvOtqSaqlR0USEGSjVJGxuSmWR6M3fu4/93YX0g4rc9HA6cc4Q7DI+fpzz7PA8++2mxvZAeBZ4xhHtFcJRmXWsWvb36/OLcyxf5B/KHeYHy7DmGx1+YSDjmWTdlobTGMAStQGkNoLXS4tXDq7u7tUcWz49tA8jR8QUuzB5n5NTCV13F9JEo1JJwTLKuzU61QiOMcd0UDb+BncwQK3Rl15eNja3ui/Njq8aF2eMcO/XlBz0H8oO2ZUkum6A13WB99TtyzXlaCi24SaFa+ZFCzsG2DNnfkdbFjsI1APPhk+d6ujqznycdCxFozadYWvyMpx47wa+bPkGksKwUNnsk3TaCGASRXDZh5LpHXPPg4Rcni+3uYBxrtBbQghlscOVKmYHeEm0ZIZ9xyLffw41ND6VAa43SmjiMByzHYtjzwr9arfshxf5jOKlvKZfn8es77N2uks24PPfSFD/9Uvt7AtPKWmEU9d645eHYJo5tcKi/FX/zG+zmQxQH+rANk862DOW5N/hhaY64cJSa5xNFCgDDILZACMKYWAmh73HmzFsMlBQJ06LeiMinE1S3KzRCm5rXIIoUIoKIYCVM36urZFbEoiBLNMIhAE6/NsSB7h6SKZdL8xsUOnpx9j1KbTdARACIowArYe1ergfNT2i0mIbJys0GI6PT3N1/hJvrPxOFdRJNBQIy/FapI4Bpgohgcjuw+jq8jy8tV55MNBWI4ohS802CpizKv8q+FgALZAfYgSyAZtNro1oLaU1VvxCA029Oraxs7u/tKnXiNjn8HyKwur6lI++6vPK4V7IA7u+1Dyu1tr183ddNbkHuXP8/zEIYeFqiLRl6YO/p0bHJdflT/PD9qZa1W+ry99fcvlAlcZwUpuUAglIRYVgnDEIOlna4q0M/NPnuO1/PzMwg/045O/XeibUt5/Xangx6viSVFpK2jtMpvdyWCz+5ryf10clX3/amp6eZmJjgd441URWWJY8BAAAAAElFTkSuQmCC',
- 'Trisquel': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABjFBMVEX///8AAAAAAAAAAAAAADMAAGYAAAAAHFUAGWYAF10AImYAIGAAHloAHGMAKGsAGmYAJmYAJGEAKnUAJ1gAMXYAJnEAJGQAI2EAK28AK3cAGTEAMHgALXEALXgALG0AFUAAI2oAK3EAMngANoYALXMANIAAM4IANIIAL3gANIcANokANoQANYQAOY0ANIYANooAN4kAN40AOY0APZMANIUAOY0AO5AAPZUAPJAAP5MAPpQAQJUAOYsAPpYANoUAPpoAPpUAM4AAQJkAPZIAPJEAQpgAN4cAPpQAPZUAPJEAO4oAOosAOo8AQJoAOYsAO44AQpsAO48AQp0AP5UAQpoARJwAQ58ARaAAQZgAQ54AQ50AQpgARaIARqMARaMARaIAR6QARaIARaEASakARKEAR6MASqsARKEASKcAR6MARqYAR6UATbEATa8ARqUARKAAR6oARqMASKgATK8AR6QATbIATbAASq0AR6cASKgASqwAR6UASKcATa8ASqoASqwAS6wASKoAS60ATbHn4CTpAAAAhHRSTlMAAQIFBQUGCQoLDxAREhMUFBUYGhobHB0eHh8gIiIjJCQkJCYoLC0xMTE0NDo6Oz1BQUNHSUxOVFVVVldaWl5iY2RkZWZoamtsb3FycnR1ent9f4KDhIiJioyNkJGYm5+foqOkpqamqKmqrKytsLKzs7e4uLy8v8TFxcXGx8rO0NXY2eZc4XYcAAAA00lEQVR4XkWN1VoCUQAG/3NWtwh7CTsQJOyk7BaDxuxA6bbrxf32gt25m7kZqDRYxziooDV7+1AalMUavQh2AsEZoWvzigLun+T17/c8QiJZ7qu2QKiNmyZthdcR1/as353jIeU1GxMHo5XHdqPFeX8IaDMdHPYN6dRN7LR4qQewdTa35HWkyh+fbxERAMjwlAWJv3CPSKDQ+H7XvHdkV4Pua3Gtm4sPKIF/WV8dop4VKBw/NU33B3x1JbTt+XwhkJQoqRfWvHOy28uqH8JIdomR/R+s9yR3Cso77AAAAABJRU5ErkJggg==',
- 'Ubuntu': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABKVBMVEX////ojFzplGf1zbnqnHLvs5P10b3yuZv1xKrytZXvtJXys5LysI32waT0n3HxiVHwg0jxhk31kFn0h0zxf0P0hUrveTv2iU3yfkD1hEfyejv5eDLybSX0aR7zZxvyayH6ZxnxZBj4YhH7XAb5WALlUQLeTwHgUAHeTgHfTwD65NzdTQDdTQHdTgD31MfcTgLcTADcTQD////xt5/31Mf54dfmfE/dUAbeVQ/jcUDcTgHeWBnnflHohFvpjGbqkGztnX342Mz53dLgXiP65d399PHdUgrtoYLyu6Xzvaf76eLfXB/rkm/fWhvupojwrpTeVhTgYSfgYynzwa30xbL1ybnngFT31snngljhZS3539XhZzDiajbibDn77OX88Ovrl3X99vTjbz1fisGCAAAAMHRSTlMABgYGBwcHJiorMDA1NXGHjY2Nl5mZmZyfn6O5u8XHzc3X193j9fj4+vr6/f39/f08OUojAAAAx0lEQVR4Xi3HZVbDYBhGwQctWqzFPXiQ+36pu+LubvtfBKcN82/UEhld2vWXxyL6F92gbTPabse8hU/uHMx1SZoyyJWPTwq1Rs7GpYE9+Cg+OJcs1MHvU9y4fnrN31yUm18vMCIPjtw3QMndw4rs8ieVzAAcBlewpe1KM3uaBuD3Dda1BhWXAsi6AFY1a2SqifxZ+rnxWYcJDRkUS3fO1R5vwe+XZgw4D4L3RAJiknoXCVX3WeiUpJ5pIxTvVmg45pl5k4Ot/AGV2iqZBWgJJAAAAABJRU5ErkJggg==',
- 'Windows': 'iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA+pJREFUOE+F0n84FHYcB3CWSsL9ojo/6ik64c6PnTjmSS0limmrpBm2G002y++xzXRz6zE0R4nbw+RnTj/WD4sbanLkkAe55ccYlyNme4SrO9u9d13PI3/saZ+/vs/3831ez+f9eb5aWsuqy2mjRYeNUa7YmtjfTico7jNJ8z0eG24NB9vvnDrvufzpq89Npnr8VjMddNmuRh9rDfp36mFg91oM7qPIc5JdbDJq3An/JfCu7Hl53W2lpS220pP2OuniN299jAYbYizSENIoAgbCTdrTKtxOJVdvGo8psUwKy7Vxe4ez1YEVudGP8YEZzyveInFJ6mZRHHqYazDspw/pJwTIuERM5JIwmUdGdyo9K7/BszGzzg6fXzZHGJ8KvzQqXKOpoIeZLjofWR++BPWyCEnPY4xFGEKWQcLjMjKmr1MwfcMYwmz/Y4KOgNki0V5k1dkjUWCK93Kp2PMFFawos8cm1gZ2GqjLXktL4mbQPHLQ4B9ZDFE5+S356fQlyuJMqzH++HnTo6ui2OO1ko9Ul+4fxfd3d4F7k4YTReqpuFS88bGZUE2QNNDobuIq8Q5CduHb7lFJaTnvnym9ergjMWD/FG8zf+aKS3G9JO5C01Asah6wUXrvALKEDoitMMHhDKrKJdg8RU2s0EB2EWWur8dd7PDPFv6dUC0Gv3kAN36VPRGP/5k5NS6lljWxG0TDiSr1VKhoPwhevRMSqkwRxDObc/DavGtpP6zoi8XOyZfhnyNEvKANBU0P8VPfI/wyNCGXSn7wlEmyA9KrgmOKGth3eDVvPfyywq2dnUEv2R9qG2rLsH7xJXziKnWcI8tlTvEC7Mu8hROlImTU9aKqcwQ1vWOihWFu+sJknmph5CvxQh87c7bNh/NXo03hrMCosyvLmMNgMF7TQL6J1dsZIUVwjKqEO+cajp5vxPN439U/gKBt8PTcYHzL/BgHCyOf4unAISj6mFC2bYC82kB5Ls460NHRUVsDeYSXpGw7UgC7sAtwShDgzdM38W7BbURXtqpqhfmB8sEQuXwoCM/6faGQuGCxyxyKWhIm+PrSD495WL3cT0hhi8Whc3NbAs9KaOyCTvrJ8qkdX19XBeTUDU00+55USFzVU2yHstcaix0mUAjJkJeuRU868Ucmk0lcguiBnMAVxjbbdHV1yeq8+u4Hgo22huSG+iQXp83ftaxW3lsPZcs6KG5T8OwaAfJiPcxlrVRVRhvF02i0F/t5VbHZ7JWDfErKTLnhE3mFPuRFepg/uxqz6TqLv6euGj3ut87t/4ylvre3t3ZehOWWO1zjSFEqMVP4GfGb/DBykJcjmaZOoLsc+hcVY/LaAgcTQAAAAABJRU5ErkJggg==',
- 'OpenBSD': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAykIPu64pQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADTklEQVQ4y32RXUxTdxjGn3N6eujoKT3SUkuk3VoBGfVjgFXAsZ7WkipyYXQbuu3CzUXZmGRbssnFEseFkWzgcGzGXky9MWL8TsC4IeFgtK4oAqOnG5vMVl1pCMVWQD7b/y5M6jLdflfvxfPked/nBQA0NDSChqnGVrLuGkES742NhJAdhAKAuk9yyUs5Gry7RQMZAARCWgivpQiPe71P5DUfH0xaqTL7m/iiLkJmphawa+e4SM2PvUyC4yUIBu8CnAQKAK53rCA5OUtQtStVpJ4Gw/FOBddZVKhCfq4MP4n6+at+DUsJm/e0G9JZzYEvI2tHwlEYjDxomkZ+3nG8WroRtHihZVOhVlorDQzh0okhcByDP4ZGcf+X9XAsvY5/RsBa7Kq5H/CqLctKyl/g08S2i6fq8W/MS3P34T9wNDVYSeDX1eTD9xhiLXbtB/Akwmmv6Kr+ICFkLpGhtNSM3qsSstS3oX8lSsmsxS6ZVn3j6PvVVqhUcvC8AtPxVPxwygVKvngN89WOjgVprggGA4eenjB4nsXsTASpC63I0wVTZYPR11FoKRB8Ax54PCFk6BhMTk5CPR3GSbHouGzknr/bYFq9EAvfc9Tu1sLjHcXNKxLuTOTgzOlOe7IHBc/beAXWpWmXlz8a84nhcLQ+ecVzsAEQrMWuMX+f9HZF2YPZ28FVSNfoPWqOzMUmqYMAJm7+/OOzXQFwHGpyEV+vi+yvtxBC9pDmpgJC4tvI3mo9GTitIxvW24nT7ug67HY/3eDs2bbyrVsrY2day70rV6kRfDAHk5lDLJqAmmeRiD9GJDKHvwb74R8G0mkTPjrQTTG122xkTTbwaV2b1H4u16JQKXGr7yG2b8/H1MQ09IsTSEmRwzf4CCwzD+dmE1re8CI7wwi5XNlFf9vaTXX4dWJg4LLl7h05fpNGwNAMWpp9CIVYNO/tRCzGwpDFQaVMQTS2CKY0BWr3GVGWNSXKACDDaA4Mh976pq9f5Sy09GgKlmeAMIBKzUKpU+BFoxJecRhUfAbMxDi4eADfHVmE79v7q575gvvYeVvjZ58LD5mwsKUyX0hnf0feslnQCWD4zxnc6reKisxsfH2oscqcmTmK/+Ow252cna7K52r+Bky6PqmoT5HBAAAAAElFTkSuQmCC',
- 'Gnu': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAywUV5gQrwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADcElEQVQ4y43Tb0jjBRzH8c9v+7nNMebcUW21Cc78g/wcuhByIScoMRwoTBmFlZCmIJ14axqkgoYIkXIqKIVBEuJNUBEUPRlpqDC3Q2Ex0nTezun2YOaPLXNIv7Vvj7zgiOj1+PPk/eADjuNEuHN6ekqMw+H4IzMz8xChUCjV1NT0JbO7uxtfXFy8NZvNr21tbd0AAEQikY6I0m1tbQbx2NjYZiqV+vn29jY+PDw8xhYWFj45PDzcb25uhlQqfSTief6X0dFRpqKigvF4PPPipaWlY7lcXhCLxXJnZmY+ZTY2NnzX19ePGxsbHw0MDLivrq5mc3Jy2pPJZLVWq/2cdbvdDSzLholoNJ1OMy6Xq0Ymk5HNZktOTU29qMgA8HYqlaKDgwNKp9M0PT09BgAM/iGuqqoimUx2yPP8U5/P9wEAMB0dHRUKheJHiUTyeGhoqAUAnE7nR0qlsjcQCLwjlsvlz+bm5mQWi0VSWlr6bXV1tU6hUMj6+/vfN5lMN0xxcfG1zWZ7SETTSqWSGhoamPHxcajV6s+8Xu9Xou7u7t9VKtW00+mkSCTC6PV6aDQa8Dw/Wl9fP8UAQCgUosvLSyovL2eWl5dRUFBw7Ha7v9vc3By5K3g1EAg8FQSBiIguLi4IgBwA2LtEjuPuJxKJ62AwKFpdXf0eQBIvYVmW/cLlchEAWK1WAADT09NzX6PR/OTz+eKVlZUzKpVqTyqVvsnzfLCkpGSrtrb2t97eXnFeXl5ZKpWyZ2RkPPP7/UUnJyefGI3GU+zt7aU4jotOTk7mAUBfX1+b1Wq9kcvlBIAcDgctLCyQxWKhoqIi6uzs/BoAVlZW3qqpqbllZmdnf1hfX//Q4/HEzWbzX+3t7fcMBgMFg0EYjUYmEolAEAREo1Hk5+fT+fk5Mzg4GD86OpJ0dXXJGQBoaWl5Ra/XP6yrq3tQVlam2N7ehslkAsuySCaTUKvVSCQS2NnZSXAcJxYEQTEyMvKeIAhLDADY7fZ7BoPhm6ysLFpbWzuan5//WKvVvsHzPEWjUSYSiSA3N5d0Oh0TjUaf+/1+S2Nj46/4FwYAr7e2tnbF4/E/iYjC4TCFw+F0LBaj/f19mpiYeID/IAagAyABYLXb7cLZ2Rml02nyer3POY6rwv8hEr34u0IkEk1mZ2cTgGMA7768/RtL5JKsGzrLIgAAAABJRU5ErkJggg==',
- 'CrunchBang': 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAQCAQAAAC45EetAAAA8ElEQVR4XnWOsUpCYQBGz1TIHYu2Qix6g0DEtSeQu/UIISJtUS8gJq61F1wcdMohcBDxKUR8hsz1xA/y44/cs3znbB+RJ0Skl3pSkeFQbUs79VAPzrwPFRmN1Ja0Ug/16I93+1oi4lKte+zMXv32WuoAm43lXMrqzbFncgWw21lORf4+/PREKpAhYqZuPXZ+T/3yXbZEajV1JavUQ104sRcq0myqc5mnHurWqc/7yhExVwuPncl+C4Bu13L60ueAwcByOtLhgAIRCzU38fRGTmSxUBvSSD3Ui1NvQkXWa7Uq1dRD9R17HiqyRUSy1NP6B7e1Yu2GtlUKAAAAAElFTkSuQmCC',
- 'Yuno': 'iVBORw0KGgoAAAANSUhEUgAAABgAAAAPCAYAAAD+pA/bAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAABDtJREFUOE+FlHtMm1UYxrtsi8aEgCb+oTFmZur+WNS5RaPERU10C2qGaBgb6hgwLwMmHTIKlIKlQIHSQrmU24BSSmnpBVooUmihtEC5yKWDjVu5uOkcEca4lG5E93j6EQmELX7Jky/fOed9fu973vMdGu0xT3Cgz57yXMZLDdXcy821PFWLKmuA6HqLMqtLX5POl4iYb2ukWW8IOOFe/qfe3/M4n0eOjwyZD8//bldODOk37N1yDJgl+LVdjEGLFKO9KkzZm8hbje7mIrTXZ7sMtTydrJh15H8hHW11XvN/jGS7VudcD5w34ZZzeQYb67fwYO03LN4exo1+LWzNxbA05O5QuzbHqRYn+++CHDx4YK9WLfaedfQzV5em54g5Zbi8OIml+VFMDLWQ7GXoaSmFWZsDZVGCO2u0EbkhHTrhFqi9PmelSsQ8tAtSVch60dpUeGe4kxgZxegzVkBzlQ2NKBG2+iJIMqMok9r8OLRIMqApToSqmAWTmk9B2+o2YW79oshU7ABcuvAFrVGWXkVKpBYoSaBSxIS2mINpiwbjZiUMZRloVfJQyaXDKObBpimBScpHFe8KmmXpaKhK3arGrBVuVBclHN2CiPNin1OVs1tVJYlQlyZBxA6DviQVo6ZaOKd7sTplw53BVugruBBzfsRslw7rZPxaczWutSpQV/gzJPxo1JexyfaxKBBpuiEx+tw+CpKdEvGWTprGlhcwqbIzL5/DYKMYndpK3L1hxf3ZfkrzwybUZjPhnOqmvlcmutFF1jis9QSShOrcWNSXJ1MA0ou/NZWc8Ddfe4VGO3bk0JON1dyMMlK+gmxNrZCFhZF2Kng7YNO0awt4b7wLNp2EqtAsF6ImP56SG0B6siovTYpIjg15gapCVhAfJRUyIBFEo6k8AyuTtkcC/qvG/XbDexulWJvqgYH0o0nKhVHFJ40XwFQnWM5OCX+XMg86c3KvVMSMapCmPpSTIygTxGKZZOcOXhrr3Mp4uzkFuG6B3ajE3TELDDU8qEmsmvRATxquKkxAnSTFjwKEfv3JU9JC5unG6rQ1bTkbQ4Yq/DVgxOqwBWt2K9Yne3ZCZvrgHO2k5paHzOhSiVCZSkdNTgzy40JRlPgDhDHBCxUZdCs91G8fLeK87zOl6XSOICZYXMGNhDqX9fDP/mbK2DXVi/szm03eLpejl5pzOfqwOt4JBT8OeYwQt/4R/BR0OzXiLCM5LOCji/4nXt46rpywgG+zor5RxgSdupBzJdglSY+5ZZbl3XNY6mbn7W0Lcx06zBg1WBjtcC6OmG+OmRTrFrnIUZESZeVeCpwh8TpiPsQ47/tloM97T+/6m8mg55mT3tStyL54mhlwwtszNvjzD8/6HH8i7PvvPPRioZdRWuDBZUR6pEWG7I8P9Xs1Jsj36MfvvO5J/+rTw58dP7afJPfBgeef3XGz/gskFVpJc4HwGwAAAABJRU5ErkJggg=='
- }
- };
-
- ExpandComment = {
- init: function() {
- if (g.VIEW !== 'index' || !Conf['Comment Expansion']) {
- return;
- }
- if (g.BOARD.ID === 'g') {
- this.callbacks.push(Fourchan.code);
- }
- if (g.BOARD.ID === 'sci') {
- this.callbacks.push(Fourchan.math);
- }
- return Post.prototype.callbacks.push({
- name: 'Comment Expansion',
- cb: this.node
- });
- },
- node: function() {
- var a;
-
- if (a = $('.abbr > a', this.nodes.comment)) {
- return $.on(a, 'click', ExpandComment.cb);
- }
- },
- callbacks: [],
- cb: function(e) {
- var post;
-
- e.preventDefault();
- post = Get.postFromNode(this);
- return ExpandComment.expand(post);
- },
- expand: function(post) {
- var a;
-
- if (post.nodes.longComment && !post.nodes.longComment.parentNode) {
- $.replace(post.nodes.shortComment, post.nodes.longComment);
- post.nodes.comment = post.nodes.longComment;
- return;
- }
- if (!(a = $('.abbr > a', post.nodes.comment))) {
- return;
- }
- a.textContent = "Post No." + post + " Loading...";
- return $.cache("//api.4chan.org" + a.pathname + ".json", function() {
- return ExpandComment.parse(this, a, post);
- });
- },
- contract: function(post) {
- var a;
-
- if (!post.nodes.shortComment) {
- return;
- }
- a = $('.abbr > a', post.nodes.shortComment);
- a.textContent = 'here';
- $.replace(post.nodes.longComment, post.nodes.shortComment);
- return post.nodes.comment = post.nodes.shortComment;
- },
- parse: function(req, a, post) {
- var callback, clone, comment, href, postObj, posts, quote, spoilerRange, status, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
-
- status = req.status;
- if (![200, 304].contains(status)) {
- a.textContent = "Error " + req.statusText + " (" + status + ")";
- return;
- }
- posts = JSON.parse(req.response).posts;
- if (spoilerRange = posts[0].custom_spoiler) {
- Build.spoilerRange[g.BOARD] = spoilerRange;
- }
- for (_i = 0, _len = posts.length; _i < _len; _i++) {
- postObj = posts[_i];
- if (postObj.no === post.ID) {
- break;
- }
- }
- if (postObj.no !== post.ID) {
- a.textContent = "Post No." + post + " not found.";
- return;
- }
- comment = post.nodes.comment;
- clone = comment.cloneNode(false);
- clone.innerHTML = postObj.com;
- _ref = $$('.quotelink', clone);
- for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
- quote = _ref[_j];
- href = quote.getAttribute('href');
- if (href[0] === '/') {
- continue;
- }
- quote.href = "/" + post.board + "/res/" + href;
- }
- post.nodes.shortComment = comment;
- $.replace(comment, clone);
- post.nodes.comment = post.nodes.longComment = clone;
- post.parseComment();
- post.parseQuotes();
- _ref1 = ExpandComment.callbacks;
- for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
- callback = _ref1[_k];
- callback.call(post);
- }
- }
- };
-
- ExpandThread = {
- init: function() {
- if (g.VIEW !== 'index' || !Conf['Thread Expansion']) {
- return;
- }
- return Thread.prototype.callbacks.push({
- name: 'Thread Expansion',
- cb: this.node
- });
- },
- node: function() {
- var a, span;
-
- if (!(span = $('.summary', this.OP.nodes.root.parentNode))) {
- return;
- }
- a = $.el('a', {
- textContent: "+ " + span.textContent,
- className: 'summary',
- href: 'javascript:;'
- });
- $.on(a, 'click', ExpandThread.cbToggle);
- return $.replace(span, a);
- },
- cbToggle: function() {
- var op;
-
- op = Get.postFromRoot(this.previousElementSibling);
- return ExpandThread.toggle(op.thread);
- },
- toggle: function(thread) {
- var a, inlined, num, post, replies, reply, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
-
- threadRoot = thread.OP.nodes.root.parentNode;
- a = $('.summary', threadRoot);
- switch (thread.isExpanded) {
- case false:
- case void 0:
- thread.isExpanded = 'loading';
- _ref = $$('.thread > .postContainer', threadRoot);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- post = _ref[_i];
- ExpandComment.expand(Get.postFromRoot(post));
- }
- if (!a) {
- thread.isExpanded = true;
- return;
- }
- thread.isExpanded = 'loading';
- a.textContent = a.textContent.replace('+', '× Loading...');
- $.cache("//api.4chan.org/" + thread.board + "/res/" + thread + ".json", function() {
- return ExpandThread.parse(this, thread, a);
- });
- break;
- case 'loading':
- thread.isExpanded = false;
- if (!a) {
- return;
- }
- a.textContent = a.textContent.replace('× Loading...', '+');
- break;
- case true:
- thread.isExpanded = false;
- if (a) {
- a.textContent = a.textContent.replace('-', '+');
- num = (function() {
- if (thread.isSticky) {
- return 1;
- } else {
- switch (g.BOARD.ID) {
- case 'b':
- case 'vg':
- case 'q':
- return 3;
- case 't':
- return 1;
- default:
- return 5;
- }
- }
- })();
- replies = $$('.thread > .replyContainer', threadRoot).slice(0, -num);
- for (_j = 0, _len1 = replies.length; _j < _len1; _j++) {
- reply = replies[_j];
- if (Conf['Quote Inlining']) {
- while (inlined = $('.inlined', reply)) {
- inlined.click();
- }
- }
- $.rm(reply);
- }
- }
- _ref1 = $$('.thread > .postContainer', threadRoot);
- for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
- post = _ref1[_k];
- ExpandComment.contract(Get.postFromRoot(post));
- }
- }
- },
- parse: function(req, thread, a) {
- var link, node, nodes, post, posts, replies, reply, spoilerRange, status, _i, _len;
-
- if (a.textContent[0] === '+') {
- return;
- }
- status = req.status;
- if (![200, 304].contains(status)) {
- a.textContent = "Error " + req.statusText + " (" + status + ")";
- $.off(a, 'click', ExpandThread.cb.toggle);
- return;
- }
- thread.isExpanded = true;
- a.textContent = a.textContent.replace('× Loading...', '-');
- posts = JSON.parse(req.response).posts;
- if (spoilerRange = posts[0].custom_spoiler) {
- Build.spoilerRange[g.BOARD] = spoilerRange;
- }
- replies = posts.slice(1);
- posts = [];
- nodes = [];
- for (_i = 0, _len = replies.length; _i < _len; _i++) {
- reply = replies[_i];
- if (post = thread.posts[reply.no]) {
- nodes.push(post.nodes.root);
- continue;
- }
- node = Build.postFromObject(reply, thread.board);
- post = new Post(node, thread, thread.board);
- link = $('a[title="Highlight this post"]', node);
- link.href = "res/" + thread + "#p" + post;
- link.nextSibling.href = "res/" + thread + "#q" + post;
- posts.push(post);
- nodes.push(node);
- }
- Main.callbackNodes(Post, posts);
- $.after(a, nodes);
- return Fourchan.parseThread(thread.ID, 1, nodes.length);
- }
- };
-
- FileInfo = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['File Info Formatting']) {
- return;
- }
- this.funk = this.createFunc(Conf['fileInfo']);
- return Post.prototype.callbacks.push({
- name: 'File Info Formatting',
- cb: this.node
- });
- },
- node: function() {
- if (!this.file || this.isClone) {
- return;
- }
- return this.file.text.innerHTML = FileInfo.funk(FileInfo, this);
- },
- createFunc: function(format) {
- var code;
-
- code = format.replace(/%(.)/g, function(s, c) {
- if (c in FileInfo.formatters) {
- return "' + FileInfo.formatters." + c + ".call(post) + '";
- } else {
- return s;
- }
- });
- return Function('FileInfo', 'post', "return '" + code + "'");
- },
- convertUnit: function(size, unit) {
- var i;
-
- if (unit === 'B') {
- return "" + (size.toFixed()) + " Bytes";
- }
- i = 1 + ['KB', 'MB'].indexOf(unit);
- while (i--) {
- size /= 1024;
- }
- size = unit === 'MB' ? Math.round(size * 100) / 100 : size.toFixed();
- return "" + size + " " + unit;
- },
- escape: function(name) {
- return name.replace(/<|>/g, function(c) {
- return c === '<' && '<' || '>';
- });
- },
- formatters: {
- t: function() {
- return this.file.URL.match(/\d+\..+$/)[0];
- },
- T: function() {
- return "" + (FileInfo.formatters.t.call(this)) + "";
- },
- l: function() {
- return "" + (FileInfo.formatters.n.call(this)) + "";
- },
- L: function() {
- return "" + (FileInfo.formatters.N.call(this)) + "";
- },
- n: function() {
- var fullname, shortname;
-
- fullname = this.file.name;
- shortname = Build.shortFilename(this.file.name, this.isReply);
- if (fullname === shortname) {
- return FileInfo.escape(fullname);
- } else {
- return "" + (FileInfo.escape(shortname)) + "" + (FileInfo.escape(fullname)) + "";
- }
- },
- N: function() {
- return FileInfo.escape(this.file.name);
- },
- p: function() {
- if (this.file.isSpoiler) {
- return 'Spoiler, ';
- } else {
- return '';
- }
- },
- s: function() {
- return this.file.size;
- },
- B: function() {
- return FileInfo.convertUnit(this.file.sizeInBytes, 'B');
- },
- K: function() {
- return FileInfo.convertUnit(this.file.sizeInBytes, 'KB');
- },
- M: function() {
- return FileInfo.convertUnit(this.file.sizeInBytes, 'MB');
- },
- r: function() {
- if (this.file.isImage) {
- return this.file.dimensions;
- } else {
- return 'PDF';
- }
- }
- }
- };
-
- Fourchan = {
- init: function() {
- var board;
-
- if (g.VIEW === 'catalog') {
- return;
- }
- board = g.BOARD.ID;
- if (board === 'g') {
- $.globalEval("window.addEventListener('prettyprint', function(e) {\n var pre = e.detail;\n pre.innerHTML = prettyPrintOne(pre.innerHTML);\n}, false);");
- Post.prototype.callbacks.push({
- name: 'Parse /g/ code',
- cb: this.code
- });
- }
- if (board === 'sci') {
- $.globalEval("window.addEventListener('jsmath', function(e) {\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(e.detail);\n } else {\n // load jsMath and process whole document\n jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);\n jsMath.Autoload.LoadJsMath();\n }\n}, false);");
- return Post.prototype.callbacks.push({
- name: 'Parse /sci/ math',
- cb: this.math
- });
- }
- },
- code: function() {
- var pre, _i, _len, _ref;
-
- if (this.isClone) {
- return;
- }
- _ref = $$('.prettyprint', this.nodes.comment);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- pre = _ref[_i];
- $.event('prettyprint', pre, window);
- }
- },
- math: function() {
- if (this.isClone || !$('.math', this.nodes.comment)) {
- return;
- }
- return $.event('jsmath', this.nodes.post, window);
- },
- parseThread: function(threadID, offset, limit) {
- return $.event('4chanParsingDone', {
- threadId: threadID,
- offset: offset,
- limit: limit
- });
- }
- };
-
- Header = {
- init: function() {
- var barFixedToggler, barPositionToggler, customNavToggler, editCustomNav, footerToggler, headerToggler,
- _this = this;
-
- this.menu = new UI.Menu('header');
- this.menuButton = $.el('span', {
- className: 'menu-button',
- innerHTML: ''
- });
- barFixedToggler = $.el('label', {
- innerHTML: ' Fixed Header'
- });
- headerToggler = $.el('label', {
- innerHTML: ' Auto-hide header'
- });
- barPositionToggler = $.el('label', {
- innerHTML: ' Bottom header'
- });
- customNavToggler = $.el('label', {
- innerHTML: ' Custom board navigation'
- });
- footerToggler = $.el('label', {
- innerHTML: " Hide bottom board list"
- });
- editCustomNav = $.el('a', {
- textContent: 'Edit custom board navigation',
- href: 'javascript:;'
- });
- this.barFixedToggler = barFixedToggler.firstElementChild;
- this.barPositionToggler = barPositionToggler.firstElementChild;
- this.headerToggler = headerToggler.firstElementChild;
- this.footerToggler = footerToggler.firstElementChild;
- this.customNavToggler = customNavToggler.firstElementChild;
- $.on(this.menuButton, 'click', this.menuToggle);
- $.on(this.barFixedToggler, 'change', this.toggleBarFixed);
- $.on(this.barPositionToggler, 'change', this.toggleBarPosition);
- $.on(this.headerToggler, 'change', this.toggleBarVisibility);
- $.on(this.footerToggler, 'change', this.toggleFooterVisibility);
- $.on(this.customNavToggler, 'change', this.toggleCustomNav);
- $.on(editCustomNav, 'click', this.editCustomNav);
- this.setBarFixed(Conf['Fixed Header']);
- this.setBarVisibility(Conf['Header auto-hide']);
- $.sync('Fixed Header', Header.setBarFixed);
- $.sync('Bottom Header', Header.setBarPosition);
- $.sync('Header auto-hide', Header.setBarVisibility);
- this.addShortcut(Header.menuButton);
- $.event('AddMenuEntry', {
- type: 'header',
- el: $.el('span', {
- textContent: 'Header'
- }),
- order: 107,
- subEntries: [
- {
- el: barFixedToggler
- }, {
- el: headerToggler
- }, {
- el: barPositionToggler
- }, {
- el: footerToggler
- }, {
- el: customNavToggler
- }, {
- el: editCustomNav
- }
- ]
- });
- $.on(window, 'load hashchange', Header.hashScroll);
- $.on(d, 'CreateNotification', this.createNotification);
- $.asap((function() {
- return d.body;
- }), function() {
- if (!Main.isThisPageLegit()) {
- return;
- }
- $.asap((function() {
- return $.id('boardNavMobile') || d.readyState === 'complete';
- }), Header.setBoardList);
- $.prepend(d.body, _this.bar);
- $.add(d.body, Header.hover);
- return _this.setBarPosition(Conf['Bottom Header']);
- });
- return $.ready(function() {
- var a, cs;
-
- _this.footer = $.id('boardNavDesktopFoot');
- if (a = $("a[href*='/" + g.BOARD + "/']", $.id('boardNavDesktopFoot'))) {
- a.className = 'current';
- }
- cs = $.id('settingsWindowLink');
- cs.textContent = 'Catalog Settings';
- if (g.VIEW === 'catalog') {
- _this.addShortcut(cs);
- }
- Header.setFooterVisibility(Conf['Bottom Board List']);
- return $.sync('Bottom Board List', Header.setFooterVisibility);
- });
- },
- bar: $.el('div', {
- id: 'header-bar'
- }),
- notify: $.el('div', {
- id: 'notifications'
- }),
- shortcuts: $.el('span', {
- id: 'shortcuts'
- }),
- hover: $.el('div', {
- id: 'hoverUI'
- }),
- toggle: $.el('div', {
- id: 'scroll-marker'
- }),
- setBoardList: function() {
- var a, boardList, btn, fourchannav, fullBoardList;
-
- fourchannav = $.id('boardNavDesktop');
- if (a = $("a[href*='/" + g.BOARD + "/']", fourchannav)) {
- a.className = 'current';
- }
- boardList = $.el('span', {
- id: 'board-list',
- innerHTML: "[ - ] " + fourchannav.innerHTML + ""
- });
- fullBoardList = $('#full-board-list', boardList);
- btn = $('.hide-board-list-button', fullBoardList);
- $.on(btn, 'click', Header.toggleBoardList);
- $.rm($('#navtopright', fullBoardList));
- $.add(boardList, fullBoardList);
- $.add(Header.bar, [boardList, Header.shortcuts, Header.notify, Header.toggle]);
- Header.setCustomNav(Conf['Custom Board Navigation']);
- Header.generateBoardList(Conf['boardnav']);
- $.sync('Custom Board Navigation', Header.setCustomNav);
- return $.sync('boardnav', Header.generateBoardList);
- },
- generateBoardList: function(text) {
- var as, list, nodes;
-
- list = $('#custom-board-list', Header.bar);
- $.rmAll(list);
- if (!text) {
- return;
- }
- as = $$('#full-board-list a', Header.bar);
- nodes = text.match(/[\w@]+(-(all|title|replace|full|index|catalog|text:"[^"]+"))*|[^\w@]+/g).map(function(t) {
- var a, board, m, _i, _len;
-
- if (/^[^\w@]/.test(t)) {
- return $.tn(t);
- }
- if (/^toggle-all/.test(t)) {
- a = $.el('a', {
- className: 'show-board-list-button',
- textContent: (t.match(/-text:"(.+)"/) || [null, '+'])[1],
- href: 'javascript:;'
- });
- $.on(a, 'click', Header.toggleBoardList);
- return a;
- }
- board = /^current/.test(t) ? g.BOARD.ID : t.match(/^[^-]+/)[0];
- for (_i = 0, _len = as.length; _i < _len; _i++) {
- a = as[_i];
- if (a.textContent === board) {
- a = a.cloneNode(true);
- if (/-title/.test(t)) {
- a.textContent = a.title;
- } else if (/-replace/.test(t)) {
- if ($.hasClass(a, 'current')) {
- a.textContent = a.title;
- }
- } else if (/-full/.test(t)) {
- a.textContent = "/" + board + "/ - " + a.title;
- } else if (/-(index|catalog|text)/.test(t)) {
- if (m = t.match(/-(index|catalog)/)) {
- a.setAttribute('data-only', m[1]);
- a.href = "//boards.4chan.org/" + board + "/";
- if (m[1] === 'catalog') {
- a.href += 'catalog';
- }
- }
- if (m = t.match(/-text:"(.+)"/)) {
- a.textContent = m[1];
- }
- } else if (board === '@') {
- $.addClass(a, 'navSmall');
- }
- return a;
- }
- }
- return $.tn(t);
- });
- return $.add(list, nodes);
- },
- toggleBoardList: function() {
- var bar, custom, full, showBoardList;
-
- bar = Header.bar;
- custom = $('#custom-board-list', bar);
- full = $('#full-board-list', bar);
- showBoardList = !full.hidden;
- custom.hidden = !showBoardList;
- return full.hidden = showBoardList;
- },
- setBarPosition: function(bottom) {
- Header.barPositionToggler.checked = bottom;
- if (bottom) {
- $.rmClass(doc, 'top');
- $.addClass(doc, 'bottom');
- return $.after(Header.bar, Header.notify);
- } else {
- $.rmClass(doc, 'bottom');
- $.addClass(doc, 'top');
- return $.add(Header.bar, Header.notify);
- }
- },
- toggleBarPosition: function() {
- $.event('CloseMenu');
- Header.setBarPosition(this.checked);
- Conf['Bottom Header'] = this.checked;
- return $.set('Bottom Header', this.checked);
- },
- setBarFixed: function(fixed) {
- Header.barFixedToggler.checked = fixed;
- if (fixed) {
- $.addClass(doc, 'fixed');
- return $.addClass(Header.bar, 'dialog');
- } else {
- $.rmClass(doc, 'fixed');
- return $.rmClass(Header.bar, 'dialog');
- }
- },
- toggleBarFixed: function() {
- $.event('CloseMenu');
- Header.setBarFixed(this.checked);
- Conf['Fixed Header'] = this.checked;
- return $.set('Fixed Header', this.checked);
- },
- setBarVisibility: function(hide) {
- Header.headerToggler.checked = hide;
- $.event('CloseMenu');
- (hide ? $.addClass : $.rmClass)(Header.bar, 'autohide');
- return (hide ? $.addClass : $.rmClass)(doc, 'autohide');
- },
- toggleBarVisibility: function(e) {
- var hide, message;
-
- if (e.type === 'mousedown' && e.button !== 0) {
- return;
- }
- hide = this.nodeName === 'INPUT' ? this.checked : !$.hasClass(Header.bar, 'autohide');
- Conf['Header auto-hide'] = hide;
- $.set('Header auto-hide', hide);
- Header.setBarVisibility(hide);
- message = hide ? 'The header bar will automatically hide itself.' : 'The header bar will remain visible.';
- return new Notification('info', message, 2);
- },
- setFooterVisibility: function(hide) {
- Header.footerToggler.checked = hide;
- return Header.footer.hidden = hide;
- },
- toggleFooterVisibility: function() {
- var hide, message;
-
- $.event('CloseMenu');
- hide = this.nodeName === 'INPUT' ? this.checked : !!Header.footer.hidden;
- Header.setFooterVisibility(hide);
- $.set('Bottom Board List', hide);
- message = hide ? 'The bottom navigation will now be hidden.' : 'The bottom navigation will remain visible.';
- return new Notification('info', message, 2);
- },
- setCustomNav: function(show) {
- var btn, cust, full, _ref;
-
- Header.customNavToggler.checked = show;
- cust = $('#custom-board-list', Header.bar);
- full = $('#full-board-list', Header.bar);
- btn = $('.hide-board-list-button', full);
- return _ref = show ? [false, true] : [true, false], cust.hidden = _ref[0], full.hidden = _ref[1], _ref;
- },
- toggleCustomNav: function() {
- $.cb.checked.call(this);
- return Header.setCustomNav(this.checked);
- },
- editCustomNav: function() {
- var settings;
-
- Settings.open('Advanced');
- settings = $.id('fourchanx-settings');
- return $('input[name=boardnav]', settings).focus();
- },
- hashScroll: function() {
- var hash, post;
-
- if (!((hash = this.location.hash) && (post = $.id(hash.slice(1))))) {
- return;
- }
- if ((Get.postFromRoot(post)).isHidden) {
- return;
- }
- return Header.scrollToPost(post);
- },
- scrollToPost: function(post) {
- var headRect, top;
-
- top = post.getBoundingClientRect().top;
- if (Conf['Fixed Header'] && !Conf['Bottom Header']) {
- headRect = Header.bar.getBoundingClientRect();
- top += -headRect.top - headRect.height;
- }
- return ($.engine === 'webkit' ? d.body : doc).scrollTop += top;
- },
- addShortcut: function(el) {
- var shortcut;
-
- shortcut = $.el('span', {
- className: 'shortcut'
- });
- $.add(shortcut, [$.tn(' ['), el, $.tn(']')]);
- return $.prepend(Header.shortcuts, shortcut);
- },
- menuToggle: function(e) {
- return Header.menu.toggle(e, this, g);
- },
- createNotification: function(e) {
- var cb, content, lifetime, notif, type, _ref;
-
- _ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb;
- notif = new Notification(type, content, lifetime);
- if (cb) {
- return cb(notif);
- }
- }
- };
-
- Keybinds = {
- init: function() {
- var init;
-
- if (g.VIEW === 'catalog' || !Conf['Keybinds']) {
- return;
- }
- init = function() {
- var node, _i, _len, _ref;
-
- $.off(d, '4chanXInitFinished', init);
- $.on(d, 'keydown', Keybinds.keydown);
- _ref = $$('[accesskey]');
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- node = _ref[_i];
- node.removeAttribute('accesskey');
- }
- };
- return $.on(d, '4chanXInitFinished', init);
- },
- keydown: function(e) {
- var form, key, notification, notifications, op, target, thread, threadRoot, _i, _len;
-
- if (!(key = Keybinds.keyCode(e))) {
- return;
- }
- target = e.target;
- if (['INPUT', 'TEXTAREA'].contains(target.nodeName)) {
- if (!/(Esc|Alt|Ctrl|Meta)/.test(key)) {
- return;
- }
- }
- threadRoot = Nav.getThread();
- if (op = $('.op', threadRoot)) {
- thread = Get.postFromNode(op).thread;
- }
- switch (key) {
- case Conf['Toggle board list']:
- if (Conf['Custom Board Navigation']) {
- Header.toggleBoardList();
- }
- break;
- case Conf['Open empty QR']:
- Keybinds.qr(threadRoot);
- break;
- case Conf['Open QR']:
- Keybinds.qr(threadRoot, true);
- break;
- case Conf['Open settings']:
- Settings.open();
- break;
- case Conf['Close']:
- if (Settings.dialog) {
- Settings.close();
- } else if ((notifications = $$('.notification')).length) {
- for (_i = 0, _len = notifications.length; _i < _len; _i++) {
- notification = notifications[_i];
- $('.close', notification).click();
- }
- } else if (QR.nodes) {
- QR.close();
- }
- break;
- case Conf['Spoiler tags']:
- if (target.nodeName !== 'TEXTAREA') {
- return;
- }
- Keybinds.tags('spoiler', target);
- break;
- case Conf['Code tags']:
- if (target.nodeName !== 'TEXTAREA') {
- return;
- }
- Keybinds.tags('code', target);
- break;
- case Conf['Eqn tags']:
- if (target.nodeName !== 'TEXTAREA') {
- return;
- }
- Keybinds.tags('eqn', target);
- break;
- case Conf['Math tags']:
- if (target.nodeName !== 'TEXTAREA') {
- return;
- }
- Keybinds.tags('math', target);
- break;
- case Conf['Toggle sage']:
- if (QR.nodes) {
- Keybinds.sage();
- }
- break;
- case Conf['Submit QR']:
- if (QR.nodes && !QR.status()) {
- QR.submit();
- }
- break;
- case Conf['Watch']:
- ThreadWatcher.toggle(thread);
- break;
- case Conf['Update']:
- ThreadUpdater.update();
- break;
- case Conf['Expand image']:
- Keybinds.img(threadRoot);
- break;
- case Conf['Expand images']:
- Keybinds.img(threadRoot, true);
- break;
- case Conf['fappeTyme']:
- if (!$('#menu.left')) {
- Header.menuButton.click();
- }
- FappeTyme.input.click();
- break;
- case Conf['Front page']:
- window.location = "/" + g.BOARD + "/0#delform";
- break;
- case Conf['Open front page']:
- $.open("/" + g.BOARD + "/#delform");
- break;
- case Conf['Next page']:
- if (form = $('.next form')) {
- window.location = form.action;
- }
- break;
- case Conf['Previous page']:
- if (form = $('.prev form')) {
- window.location = form.action;
- }
- break;
- case Conf['Open catalog']:
- if (Conf['External Catalog']) {
- window.location = CatalogLinks.external(g.BOARD.ID);
- } else {
- window.location = "/" + g.BOARD + "/catalog";
- }
- break;
- case Conf['Next thread']:
- if (g.VIEW === 'thread') {
- return;
- }
- Nav.scroll(+1);
- break;
- case Conf['Previous thread']:
- if (g.VIEW === 'thread') {
- return;
- }
- Nav.scroll(-1);
- break;
- case Conf['Expand thread']:
- ExpandThread.toggle(thread);
- break;
- case Conf['Open thread']:
- Keybinds.open(thread);
- break;
- case Conf['Open thread tab']:
- Keybinds.open(thread, true);
- break;
- case Conf['Next reply']:
- Keybinds.hl(+1, threadRoot);
- break;
- case Conf['Previous reply']:
- Keybinds.hl(-1, threadRoot);
- break;
- case Conf['Hide']:
- if (g.VIEW === 'index') {
- ThreadHiding.toggle(thread);
- }
- break;
- default:
- return;
- }
- e.preventDefault();
- return e.stopPropagation();
- },
- keyCode: function(e) {
- var kc, key;
-
- key = (function() {
- switch (kc = e.keyCode) {
- case 8:
- return '';
- case 13:
- return 'Enter';
- case 27:
- return 'Esc';
- case 37:
- return 'Left';
- case 38:
- return 'Up';
- case 39:
- return 'Right';
- case 40:
- return 'Down';
- default:
- if ((48 <= kc && kc <= 57) || (65 <= kc && kc <= 90)) {
- return String.fromCharCode(kc).toLowerCase();
- } else {
- return null;
- }
- }
- })();
- if (key) {
- if (e.altKey) {
- key = 'Alt+' + key;
- }
- if (e.ctrlKey) {
- key = 'Ctrl+' + key;
- }
- if (e.metaKey) {
- key = 'Meta+' + key;
- }
- if (e.shiftKey) {
- key = 'Shift+' + key;
- }
- }
- return key;
- },
- qr: function(thread, quote) {
- if (!(Conf['Quick Reply'] && QR.postingIsEnabled)) {
- return;
- }
- QR.open();
- if (quote) {
- QR.quote.call($('input', $('.post.highlight', thread) || thread));
- }
- QR.nodes.com.focus();
- if (Conf['QR Shortcut']) {
- return $.rmClass($('.qr-shortcut'), 'disabled');
- }
- },
- tags: function(tag, ta) {
- var range, selEnd, selStart, value;
-
- value = ta.value;
- selStart = ta.selectionStart;
- selEnd = ta.selectionEnd;
- ta.value = value.slice(0, selStart) + ("[" + tag + "]") + value.slice(selStart, selEnd) + ("[/" + tag + "]") + value.slice(selEnd);
- range = ("[" + tag + "]").length + selEnd;
- ta.setSelectionRange(range, range);
- return $.event('input', null, ta);
- },
- sage: function() {
- var isSage;
-
- isSage = /sage/i.test(QR.nodes.email.value);
- return QR.nodes.email.value = isSage ? "" : "sage";
- },
- img: function(thread, all) {
- var post;
-
- if (all) {
- return ImageExpand.cb.toggleAll();
- } else {
- post = Get.postFromNode($('.post.highlight', thread) || $('.op', thread));
- return ImageExpand.toggle(post);
- }
- },
- open: function(thread, tab) {
- var url;
-
- if (g.VIEW !== 'index') {
- return;
- }
- url = "/" + thread.board + "/res/" + thread;
- if (tab) {
- return $.open(url);
- } else {
- return location.href = url;
- }
- },
- hl: function(delta, thread) {
- var headRect, next, postEl, rect, replies, reply, root, topMargin, _i, _len;
-
- if (Conf['Fixed Header'] && Conf['Bottom header']) {
- topMargin = 0;
- } else {
- headRect = Header.bar.getBoundingClientRect();
- topMargin = headRect.top + headRect.height;
- }
- if (postEl = $('.reply.highlight', thread)) {
- $.rmClass(postEl, 'highlight');
- rect = postEl.getBoundingClientRect();
- if (rect.bottom >= topMargin && rect.top <= doc.clientHeight) {
- root = postEl.parentNode;
- next = $.x('child::div[contains(@class,"post reply")]', delta === +1 ? root.nextElementSibling : root.previousElementSibling);
- if (!next) {
- this.focus(postEl);
- return;
- }
- if (!(g.VIEW === 'thread' || $.x('ancestor::div[parent::div[@class="board"]]', next) === thread)) {
- return;
- }
- rect = next.getBoundingClientRect();
- if (rect.top < 0 || rect.bottom > doc.clientHeight) {
- if (delta === -1) {
- window.scrollBy(0, rect.top - topMargin);
- } else {
- next.scrollIntoView(false);
- }
- }
- this.focus(next);
- return;
- }
- }
- replies = $$('.reply', thread);
- if (delta === -1) {
- replies.reverse();
- }
- for (_i = 0, _len = replies.length; _i < _len; _i++) {
- reply = replies[_i];
- rect = reply.getBoundingClientRect();
- if (delta === +1 && rect.top >= topMargin || delta === -1 && rect.bottom <= doc.clientHeight) {
- this.focus(reply);
- return;
- }
- }
- },
- focus: function(post) {
- return $.addClass(post, 'highlight');
- }
- };
-
- Redirect = {
- init: function() {
- return $.sync('archs', this.updateArchives);
- },
- updateArchives: function() {
- return $.get('archivers', {}, function(_arg) {
- var archivers;
-
- archivers = _arg.archivers;
- return Conf['archivers'] = archivers;
- });
- },
- image: function(boardID, filename) {
- switch (boardID) {
- case 'a':
- case 'gd':
- case 'jp':
- case 'm':
- case 'q':
- case 'tg':
- case 'vg':
- case 'vp':
- case 'vr':
- case 'wsg':
- return "//archive.foolz.us/" + boardID + "/full_image/" + filename;
- case 'u':
- return "//nsfw.foolz.us/" + boardID + "/full_image/" + filename;
- case 'po':
- return "//archive.thedarkcave.org/" + boardID + "/full_image/" + filename;
- case 'hr':
- case 'tv':
- return "http://archive.4plebs.org/" + boardID + "/full_image/" + filename;
- case 'ck':
- case 'fa':
- case 'lit':
- case 's4s':
- return "//fuuka.warosu.org/" + boardID + "/full_image/" + filename;
- case 'cgl':
- case 'g':
- case 'mu':
- case 'w':
- return "//rbt.asia/" + boardID + "/full_image/" + filename;
- case 'an':
- case 'k':
- case 'toy':
- case 'x':
- return "http://archive.heinessen.com/" + boardID + "/full_image/" + filename;
- case 'c':
- return "//archive.nyafuu.org/" + boardID + "/full_image/" + filename;
- }
- },
- post: function(boardID, postID) {
- var archive, name, _base, _ref;
-
- if (Redirect.post[boardID] == null) {
- _ref = this.archiver;
- for (name in _ref) {
- archive = _ref[name];
- if (archive.type === 'foolfuuka' && archive.boards.contains(boardID)) {
- Redirect.post[boardID] = archive.base;
- break;
- }
- }
- (_base = Redirect.post)[boardID] || (_base[boardID] = false);
- }
- if (Redirect.post[boardID]) {
- return "" + Redirect.post[boardID] + "/_/api/chan/post/?board=" + boardID + "&num=" + postID;
- } else {
- return null;
- }
- },
- select: function(board) {
- var archive, name, _ref, _results;
-
- _ref = this.archiver;
- _results = [];
- for (name in _ref) {
- archive = _ref[name];
- if (!archive.boards.contains(board)) {
- continue;
- }
- _results.push(name);
- }
- return _results;
- },
- to: function(data) {
- var arch, archive, boardID;
-
- boardID = data.boardID;
- if ((arch = Conf.archivers[boardID]) == null) {
- Conf.archivers[boardID] = arch = this.select(boardID)[0];
- $.set('archivers', Conf.archivers);
- }
- return (arch && (archive = this.archiver[arch]) ? Redirect.path(archive.base, archive.type, data) : data.threadID ? "//boards.4chan.org/" + boardID + "/" : null);
- },
- archiver: {
- 'Foolz': {
- base: 'https://archive.foolz.us',
- boards: ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'v', 'vg', 'vp', 'vr', 'wsg'],
- type: 'foolfuuka'
- },
- 'NSFWFoolz': {
- base: 'https://nsfw.foolz.us',
- boards: ['u'],
- type: 'foolfuuka'
- },
- 'TheDarkCave': {
- base: 'http://archive.thedarkcave.org',
- boards: ['c', 'int', 'out', 'po'],
- type: 'foolfuuka'
- },
- '4plebs': {
- base: 'http://archive.4plebs.org',
- boards: ['hr', 'tg', 'tv', 'x'],
- base: 'foolfuuka'
- },
- 'Warosu': {
- base: '//fuuka.warosu.org',
- boards: ['cgl', 'ck', 'fa', 'jp', 'lit', 's4s', 'q', 'tg'],
- type: 'fuuka'
- },
- 'InstallGentoo': {
- base: '//archive.installgentoo.net',
- boards: ['diy', 'g', 'sci'],
- type: 'fuuka'
- },
- 'RebeccaBlackTech': {
- base: '//rbt.asia',
- boards: ['an', 'cgl', 'g', 'mu', 'w'],
- type: 'fuuka_mail'
- },
- 'Heinessen': {
- base: 'http://archive.heinessen.com',
- boards: ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x'],
- type: 'fuuka'
- },
- 'Cliche': {
- base: '//www.cliché.net/4chan/cgi-board.pl',
- boards: ['e'],
- type: 'fuuka'
- },
- 'NyaFuu': {
- base: '//archive.nyafuu.org',
- boards: ['c', 'w'],
- type: 'fuuka'
- }
- },
- path: function(base, archiver, data) {
- var boardID, path, postID, threadID, type, value;
-
- if (data.isSearch) {
- boardID = data.boardID, type = data.type, value = data.value;
- type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type;
- value = encodeURIComponent(value);
- if (archiver === 'foolfuuka') {
- return "" + base + "/" + boardID + "/search/" + type + "/" + value;
- } else if (type === 'image') {
- return "" + base + "/" + boardID + "/?task=search2&search_media_hash=" + value;
- } else {
- return "" + base + "/" + boardID + "/?task=search2&search_" + type + "=" + value;
- }
- }
- boardID = data.boardID, threadID = data.threadID, postID = data.postID;
- path = threadID ? "" + boardID + "/thread/" + threadID : "" + boardID + "/post/" + postID;
- if (archiver === 'foolfuuka') {
- path += '/';
- }
- if (threadID && postID) {
- path += archiver === 'foolfuuka' ? "#" + postID : "#p" + postID;
- }
- return "" + base + "/" + path;
- }
- };
-
- RelativeDates = {
- INTERVAL: $.MINUTE / 2,
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Relative Post Dates']) {
- return;
- }
- $.on(d, 'visibilitychange ThreadUpdate', this.flush);
- this.flush();
- return Post.prototype.callbacks.push({
- name: 'Relative Post Dates',
- cb: this.node
- });
- },
- node: function() {
- var dateEl;
-
- if (this.isClone) {
- return;
- }
- dateEl = this.nodes.date;
- dateEl.title = dateEl.textContent;
- return RelativeDates.setUpdate(this);
- },
- relative: function(diff, now, date) {
- var days, months, number, rounded, unit, years;
-
- unit = (number = diff / $.DAY) >= 1 ? (years = now.getYear() - date.getYear(), months = now.getMonth() - date.getMonth(), days = now.getDate() - date.getDate(), years > 1 ? (number = years - (months < 0 || months === 0 && days < 0), 'year') : years === 1 && (months > 0 || months === 0 && days >= 0) ? (number = years, 'year') : (months = (months + 12) % 12) > 1 ? (number = months - (days < 0), 'month') : months === 1 && days >= 0 ? (number = months, 'month') : 'day') : (number = diff / $.HOUR) >= 1 ? 'hour' : (number = diff / $.MINUTE) >= 1 ? 'minute' : (number = Math.max(0, diff) / $.SECOND, 'second');
- rounded = Math.round(number);
- if (rounded !== 1) {
- unit += 's';
- }
- return "" + rounded + " " + unit + " ago";
- },
- stale: [],
- flush: function() {
- var now, update, _i, _len, _ref;
-
- if (d.hidden) {
- return;
- }
- now = new Date();
- _ref = RelativeDates.stale;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- update = _ref[_i];
- update(now);
- }
- RelativeDates.stale = [];
- clearTimeout(RelativeDates.timeout);
- return RelativeDates.timeout = setTimeout(RelativeDates.flush, RelativeDates.INTERVAL);
- },
- setUpdate: function(post) {
- var markStale, setOwnTimeout, update;
-
- setOwnTimeout = function(diff) {
- var delay;
-
- delay = diff < $.MINUTE ? $.SECOND - (diff + $.SECOND / 2) % $.SECOND : diff < $.HOUR ? $.MINUTE - (diff + $.MINUTE / 2) % $.MINUTE : diff < $.DAY ? $.HOUR - (diff + $.HOUR / 2) % $.HOUR : $.DAY - (diff + $.DAY / 2) % $.DAY;
- return setTimeout(markStale, delay);
- };
- update = function(now) {
- var date, diff, relative, singlePost, _i, _len, _ref;
-
- date = post.info.date;
- diff = now - date;
- relative = RelativeDates.relative(diff, now, date);
- _ref = [post].concat(post.clones);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- singlePost = _ref[_i];
- singlePost.nodes.date.firstChild.textContent = relative;
- }
- return setOwnTimeout(diff);
- };
- markStale = function() {
- return RelativeDates.stale.push(update);
- };
- return update(new Date());
- }
- };
-
- RemoveSpoilers = {
- init: function() {
- if (!Conf['Remove Spoilers']) {
- return;
- }
- if (Conf['Indicate Spoilers']) {
- this.wrapper = function(text) {
- return "[spoiler]" + text + "[/spoiler]";
- };
- }
- return Post.prototype.callbacks.push({
- name: 'Reveal Spoilers',
- cb: this.node
- });
- },
- wrapper: function(text) {
- return text;
- },
- node: function(post) {
- var spoiler, spoilers, _i, _len;
-
- spoilers = $$('s', this.nodes.comment);
- for (_i = 0, _len = spoilers.length; _i < _len; _i++) {
- spoiler = spoilers[_i];
- $.replace(spoiler, $.tn(RemoveSpoilers.wrapper(spoiler.textContent)));
- }
- }
- };
-
- Report = {
- init: function() {
- if (!/report/.test(location.search)) {
- return;
- }
- return $.ready(this.ready);
- },
- ready: function() {
- var field, form;
-
- form = $('form');
- field = $.id('recaptcha_response_field');
- $.on(field, 'keydown', function(e) {
- if (e.keyCode === 8 && !field.value) {
- return $.globalEval('Recaptcha.reload("t")');
- }
- });
- return $.on(form, 'submit', function(e) {
- var response;
-
- e.preventDefault();
- response = field.value.trim();
- if (!/\s/.test(response)) {
- field.value = "" + response + " " + response;
- }
- return form.submit();
- });
- }
- };
-
- Nav = {
- init: function() {
- var append, next, prev, span;
-
- switch (g.VIEW) {
- case 'index':
- if (!Conf['Index Navigation']) {
- return;
- }
- break;
- case 'thread':
- if (!Conf['Reply Navigation']) {
- return;
- }
- break;
- default:
- return;
- }
- span = $.el('span', {
- id: 'navlinks'
- });
- prev = $.el('a', {
- textContent: '▲',
- href: 'javascript:;'
- });
- next = $.el('a', {
- textContent: '▼',
- href: 'javascript:;'
- });
- $.on(prev, 'click', this.prev);
- $.on(next, 'click', this.next);
- $.add(span, [prev, $.tn(' '), next]);
- append = function() {
- $.off(d, '4chanXInitFinished', append);
- return $.add(d.body, span);
- };
- return $.on(d, '4chanXInitFinished', append);
- },
- prev: function() {
- if (g.VIEW === 'thread') {
- return window.scrollTo(0, 0);
- } else {
- return Nav.scroll(-1);
- }
- },
- next: function() {
- if (g.VIEW === 'thread') {
- return window.scrollTo(0, d.body.scrollHeight);
- } else {
- return Nav.scroll(+1);
- }
- },
- getThread: function(full) {
- var headRect, i, rect, thread, threads, topMargin, _i, _len;
-
- if (Conf['Bottom header']) {
- topMargin = 0;
- } else {
- headRect = Header.bar.getBoundingClientRect();
- topMargin = headRect.top + headRect.height;
- }
- threads = $$('.thread:not([hidden])');
- for (i = _i = 0, _len = threads.length; _i < _len; i = ++_i) {
- thread = threads[i];
- rect = thread.getBoundingClientRect();
- if (rect.bottom > topMargin) {
- if (full) {
- return [threads, thread, i, rect, topMargin];
- } else {
- return thread;
- }
- }
- }
- return $('.board');
- },
- scroll: function(delta) {
- var i, rect, thread, threads, top, topMargin, _ref, _ref1;
-
- _ref = Nav.getThread(true), threads = _ref[0], thread = _ref[1], i = _ref[2], rect = _ref[3], topMargin = _ref[4];
- top = rect.top - topMargin;
- if (!((delta === -1 && Math.ceil(top) < 0) || (delta === +1 && top > 1))) {
- i += delta;
- }
- top = ((_ref1 = threads[i]) != null ? _ref1.getBoundingClientRect().top : void 0) - topMargin;
- return window.scrollBy(0, top);
- }
- };
-
- Sauce = {
- init: function() {
- var link, links, _i, _len, _ref;
-
- if (g.VIEW === 'catalog' || !Conf['Sauce']) {
- return;
- }
- links = [];
- _ref = Conf['sauces'].split('\n');
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- link = _ref[_i];
- if (link[0] === '#') {
- continue;
- }
- links.push(this.createSauceLink(link.trim()));
- }
- if (!links.length) {
- return;
- }
- this.links = links;
- this.link = $.el('a', {
- target: '_blank'
- });
- return Post.prototype.callbacks.push({
- name: 'Sauce',
- cb: this.node
- });
- },
- createSauceLink: function(link) {
- var m, text;
-
- link = link.replace(/%(T?URL|MD5|board)/ig, function(parameter) {
- switch (parameter) {
- case '%TURL':
- return "' + encodeURIComponent(post.file.thumbURL) + '";
- case '%URL':
- return "' + encodeURIComponent(post.file.URL) + '";
- case '%MD5':
- return "' + encodeURIComponent(post.file.MD5) + '";
- case '%board':
- return "' + encodeURIComponent(post.board) + '";
- default:
- return parameter;
- }
- });
- text = (m = link.match(/;text:(.+)$/)) ? m[1] : link.match(/(\w+)\.\w+\//)[1];
- link = link.replace(/;text:.+$/, '');
- return Function('post', 'a', "a.href = '" + link + "';\na.textContent = '" + text + "';\nreturn a;");
- },
- node: function() {
- var link, nodes, _i, _len, _ref;
-
- if (this.isClone || !this.file) {
- return;
- }
- nodes = [];
- _ref = Sauce.links;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- link = _ref[_i];
- nodes.push($.tn('\u00A0'), link(this, Sauce.link.cloneNode(true)));
- }
- return $.add(this.file.info, nodes);
- }
- };
-
- Time = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Time Formatting']) {
- return;
- }
- this.funk = this.createFunc(Conf['time']);
- return Post.prototype.callbacks.push({
- name: 'Time Formatting',
- cb: this.node
- });
- },
- node: function() {
- if (this.isClone) {
- return;
- }
- return this.nodes.date.textContent = Time.funk(Time, this.info.date);
- },
- createFunc: function(format) {
- var code;
-
- code = format.replace(/%([A-Za-z])/g, function(s, c) {
- if (c in Time.formatters) {
- return "' + Time.formatters." + c + ".call(date) + '";
- } else {
- return s;
- }
- });
- return Function('Time', 'date', "return '" + code + "'");
- },
- day: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
- month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
- zeroPad: function(n) {
- if (n < 10) {
- return "0" + n;
- } else {
- return n;
- }
- },
- formatters: {
- a: function() {
- return Time.day[this.getDay()].slice(0, 3);
- },
- A: function() {
- return Time.day[this.getDay()];
- },
- b: function() {
- return Time.month[this.getMonth()].slice(0, 3);
- },
- B: function() {
- return Time.month[this.getMonth()];
- },
- d: function() {
- return Time.zeroPad(this.getDate());
- },
- e: function() {
- return this.getDate();
- },
- H: function() {
- return Time.zeroPad(this.getHours());
- },
- I: function() {
- return Time.zeroPad(this.getHours() % 12 || 12);
- },
- k: function() {
- return this.getHours();
- },
- l: function() {
- return this.getHours() % 12 || 12;
- },
- m: function() {
- return Time.zeroPad(this.getMonth() + 1);
- },
- M: function() {
- return Time.zeroPad(this.getMinutes());
- },
- p: function() {
- if (this.getHours() < 12) {
- return 'AM';
- } else {
- return 'PM';
- }
- },
- P: function() {
- if (this.getHours() < 12) {
- return 'am';
- } else {
- return 'pm';
- }
- },
- S: function() {
- return Time.zeroPad(this.getSeconds());
- },
- y: function() {
- return this.getFullYear() - 2000;
- }
- }
- };
-
- Favicon = {
- init: function() {
- return $.ready(function() {
- var href;
-
- Favicon.el = $('link[rel="shortcut icon"]', d.head);
- Favicon.el.type = 'image/x-icon';
- href = Favicon.el.href;
- Favicon.SFW = /ws\.ico$/.test(href);
- Favicon["default"] = href;
- return Favicon["switch"]();
- });
- },
- "switch": function() {
- switch (Conf['favicon']) {
- case 'ferongr':
- Favicon.unreadDead = 'data:image/gif;base64,R0lGODlhEAAQAOMHAOgLAnMFAL8AAOgLAukMA/+AgP+rq////////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
- Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAS1BMVEUAAAAAAAAAAAAJAAASAAAZAQAaAQAiAQAkAQAoFBQyAgAzAgA1AgA4AABBAgBXAwBzBQCEBgGvCAG/AADoCwLpDAP/gID/q6v///9zILr8AAAAA3RSTlMAx9dmesIgAAAAc0lEQVQY02WPgQ6DIBBDmTqnbE70Cvb/v3TAnW5OSKB9ybXg3HUBOAmEEH4FQtrSn4gxi+xjVC9SVOEiSvbZI8zSV+/Xo7icnryZ15GObMxvtWUkB/VJW57kHU7fUcHStm8FkncGE/mwP6CGzq/eauHwvT7sWQt3gZLW+AAAAABJRU5ErkJggg==';
- Favicon.unreadSFW = 'data:image/gif;base64,R0lGODlhEAAQAOMHAADX8QBwfgC2zADX8QDY8nnl8qLp8v///////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
- Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAASFBMVEUAAAAAAAAAAAAACAkAERMAGBsAGR0AISUALzQALzUAMTcANjwAP0cAVF8AcH4AeokAorYAtswA1/EA2PISIyV55fKi6fL////l+pZqAAAAA3RSTlMAx9dmesIgAAAAcklEQVQY02VPARLCIAxjsjnUWdcg6/9/ukIr00nvIMldEhrC/wHwA0BE3wBUtnICOStQnrNx5oqqzmzKx9vDPH1Nae3F9U4ig3OzjCIX51treYvMxou13EQmBPtHE14xLiawjgoPtfgOaKHP+9VrEXA8O1v7CmSPE3u0AAAAAElFTkSuQmCC';
- Favicon.unreadNSFW = 'data:image/gif;base64,R0lGODlhEAAQAOMHAFT+ACh5AEncAFT+AFX/Acz/su7/5v///////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
- Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAS1BMVEUAAAAAAAAAAAADCgAGEgAIGgAJGwALJAANJwASNwASOAATOgAVQQAWRAAeWwAgKBsoeQAwkQA/wABJ3ABU/gBV/wHM/7Lu/+b////r+K2AAAAAA3RSTlMAx9dmesIgAAAAc0lEQVQY02WPgQ6DIBBDmTonbk70Cvb/v3TAnW5OSKB9ybXg3HUBOAmEEH4FQtrSn4gxi+xjVC9SVOEiSvbZI8zSV+/Xo7icnryZ15GObMxvtWUmB/VJW0byDqfvqGBp20mB5J3Bi3zYH1BD38/eauHwvT7sEAt1Fb320QAAAABJRU5ErkJggg==';
- break;
- case 'xat-':
- Favicon.unreadDead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA2ElEQVQ4y61TQQrCMBDMQ8WDIEV6LbT2A4og2Hq0veo7fIAH04dY9N4xmyYlpGmI2MCQTWYy3Wy2DAD7B2wWAzWgcTgVeZKlZRxHNYFi2jM18oBh0IcKtC6ixf22WT4IFLs0owxswXu9egm0Ls6bwfCFfNsJYJKfqoEkd3vgUgFVLWObtzNgVKyruC+ljSzr5OEnBzjvjcQecaQhbZgBb4CmGQw+PoMkTUtdbd8VSEPakcGxPOcsoIgUKy0LecY29BmdBrqRfjIwZ93KLs5loHvBnL3cLH/jF+C/+z5dgUysAAAAAElFTkSuQmCC';
- Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACKkJGNkpN0d3d0eHdra2dGRkORZ1wAAACmaV6naV4PDw8LCwsLCwvyZWLyZWIeExEyFBTAWlr/eHj/enkAAAAKAAAoAAA4AAA4GhpMAACRAAD/AAD/enn/h4j/m5z/nJ3/0dL/0tL/0tP/09P///9VK8WFAAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uZfI0YOdiiMiJw+2CKIPkZzGtcbgKYIJaI26LAfQOzOqoYNA4Z49Nguv/gEEhw2/C5BUZgAAAABJRU5ErkJggg==';
- Favicon.unreadSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA30lEQVQ4y2P4//8/AyWYgSoGQMF/GJ7Y11VVUVoyKTM9ey4Ig9ggMWQ1YA1IBvzXm34YjkH8mPyJB+Nqlp8FYRAbmxoMF6ArSNrw6T0Qf8Amh9cFMEWVR/7/A+L/uORxhgEIt5/+/3/2lf//5wAxiI0uj+4CBlBgxVUvOwtydgXQZpDmi2/+/7/0GmIQSAwkB1IDUkuUAZeABlx+g2zAZ9wGlAOjChba+LwAUgNSi2HA5Am9VciBhSsQQWyoWgZiovEDsdGI1QBYQiLJAGQalpSxyWEzAJYWkGm8clTJjQCZ1hkoVG0CygAAAABJRU5ErkJggg==';
- Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACRjoqTkI13dXR4dXRpZ2tFQ0Zcb5EAAABee6ZefKcPDw8LCwsLCwtisPJisPIRFh4UJDJalMB4xP95xP8AAAABBQcHFx4KISoNLToaKzgaVW4ul8N5xP+Hy/+b1P+c1P/R7P/S6//S7P/T7P////9P0rk0AAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uUrk6MFOxRGRkwdbBNGHSE7jWmPwFMEEtEZdlgPonRmvoYNA4Z49Nguv/gEE3A2/sQ7iRgAAAABJRU5ErkJggg==';
- Favicon.unreadNSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA4ElEQVQ4y2P4//8/AyWYgSoGQMF/GJ7YNbGqrKRiUnp21lwQBrFBYshqwBqQDPifdsYYjkH8mInxB+OWx58FYRAbmxoMF6ArKPmU9B6IP2CTw+sCmKKe/5X/gPg/LnmcYQDCs/63/1/9fzYQzwGz0eXRXcAACqy4ZfFnQc7u+V/xD6T55v+LQHwJbBBIDCQHUgNSS5QBt4Cab/2/jDDgMx4DykrKJ8FCG58XQGpAajEMmNw7uQo5sHAFIogNVctATDR+IDYasRoAS0gkGYBMw5IyNjlsBsDSAjKNV44quREAx58Mr9vt5wQAAAAASUVORK5CYII=';
- Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACRipGTjZN2dHd2dHhna2pDRkVckV8AAABepl9ep18PDw8LCwsLCwt08mJ08mIRHhEYMhRpwFqM/3iM/3kAAAAECAIQIAgWLAseOBoePA86dB1mzDOM/3ma/4er/5ur/5zZ/9HZ/9La/9La/9P///85Jx7jAAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uZfI0YOdiiMiJw+2CKIPkZzGtcbgKYIJaI26LAfQOzOqoYNA4Z49Nguv/gEEhw2/C5BUZgAAAABJRU5ErkJggg==';
- break;
- case 'Mayhem':
- Favicon.unreadDead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABIUlEQVQ4jZ2ScWuDMBDFgw4pIkU0WsoQkWAYIkXZH4N9/+/V3dmfXSrKYIFHwt17j8vdGWNMIkgFuaDgzgQnwRs4EQs5KdolUQtagRN0givEDBTEOjgtGs0Zq8F7cKqqusVxrMQLaDUWcjBSrXkn8gs51tpJSWLk9b3HUa0aNIL5gPBR1/V4kJvR7lTwl8GmAm1Gf9+c3S+89qBHa8502AsmSrtBaEBPbIbj0ah2madlNAPEccdgJDfAtWifBjqWKShRBT6KoiH8QlEUn/qt0CCjnNdmPUwmFWzj9Oe6LpKuZXcwqq88z78Pch3aZU3dPwwc2sWlfZKCW5tWluV8kGvXClLm6dYN4/aUqfCbnEOzNDGhGZbNargvxCzvMGfRJD8UaDVvgkzo6QAAAABJRU5ErkJggg==';
- Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABj0lEQVQ4y42TQUorQRCGv+oekpj43pOhOyIiKoHBxTMkuAnEtWcwx/AY3sUbBIRcwCw8gCfIMkaTOOUiNdgGRRuKoav+v2qq/i4BakBmXweUwDoxLF5ZhVkC64rYBHYMUAIvwKuBMEwdaFiCNbAAngEC0NHkxBi73vsOsG92HGPsphigY1wOzfNhqhpC6AEd730RQuh9hQEOAY6A/jeAs3a7/f+bWB84ckCpqg+I8Osjgqo+AKUDViJS8LkGMcY+sJrNZssYY387LiIFsBLgL9AC/pgaArzZlF+sZgO4BG7sfgvcA3MxUtOStBIpX7cS3Klqd9OBTIEr4DlLOsuAmqpODXQOiHMuy/O8FkLoJth/6Uh2gQPg87Q3k+7leX6hqnpmPvM/GWfXWeWGqj5+oUS9LMs6wF7iHAwGJ9ZW5uxpup+UGwEtEVoijEYjKl66PJujmvIW3vsFwBiYqzJXZTweY5wSU6Bd7UP1KoECODUrJpOJAtPhcKjAtXGaYptWs57qWyv9Zn/it1a5knj5Dm3v4q8APeACAAAAAElFTkSuQmCC';
- Favicon.unreadSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABCElEQVQ4jZ2S4crCMAxF+0OGDJEPKYrIGKOsiJSx/fJRfSAfTJNyKqXfiuDg0C25N2RJjTGmEVrhTzhw7oStsIEtsVzT4o2Jo9ALThiEM8IdHIgNaHo8mjNWg6/ske8bohPo+63QOLzmooHp8fyAICBSQkVz0QKdsFQEV6WSW/D+7+BbgbIDHcb4Kp61XyjyI16zZ8JemGltQtDBSGxB4/GoN+7TpkkjDCsFArm0IYv3U0BbnYtf8BCy+JytsE0X6VyuKhPPK/GAJ14kvZZDZVV3pZIb8MZr6n4o4PDGKn0S5SdDmyq5PnXQsk+Xbhinp03FFzmHJw6xYRiWm9VxnohZ3vOcxdO8ARmXRvbWdtzQAAAAAElFTkSuQmCC';
- Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAkFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OztMTEyRkZHBwcH///9dzWZ0AAAAI3RSTlMEBggKDA4QEhQWFxkbHR8hIyUmKCosLjAxN1hbYc7P0dLc3mzWzBUAAAC+SURBVBjTNY3pcsIwEIM3ePERx/bG5IIe0NIrhVbv/3Y4Ydj9Ic030ogqpY3mDdGGi1EVsYuSvGE2Pkl0TFYAdLGuY1eMWGowzzN6kX41DYVpNbvdKlO4Jx5gSbi2VO+Vcq2jrc/jNLQhtM+n05PfkrKxG/oFHIEXqwqQsVRy7n+AtwLYL3sYR3wA755Jp3Vvv8cn8Js0GXmA7/P5TwzpiLn8MOALuEZNygkm5JTy/+vl4BRVbJvQ1NbWRSxXN64PGOBlhG0qAAAAAElFTkSuQmCC';
- Favicon.unreadNSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABCklEQVQ4jZ2S0WrDMAxF/TBCCKWMYhZKCSGYmFJMSNjD/mhf239qJXNcjBdTWODgRLpXKJKNMaYROuFTOHEehFb4gJZYrunwxsSXMApOmIQzwgOciE1oRjyaM1aDj+yR7xuiHvT9VmgcXnPRwO/9+wWCgEgJFc1FCwzCVhFclUpuw/u3g3cFyg50GPOjePZ+ocjPeM2RCXthpbUFwQAzsQ2Nx6PeuE+bJo0w7BQI5NKGLN5XAW11LX7BQ8jia7bCLl2kc7mqTLzuxAOeeJH0Wk6VVf0oldyEN15T948CDm+sMiZRfjK0pZIbUwcd+3TphnF62lR8kXN44hAbhmG5WQNnT8zynucsnuYJhFpBfkMzqD4AAAAASUVORK5CYII=';
- Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAkFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztMTExmzDORkZHBwcH///92I3mvAAAAI3RSTlMEBggKDA4QEhQWFxkbHR8hIyUmKCosLjAxN1hbYc7P0dLc3mzWzBUAAAC+SURBVBjTNY3pcsIwEIM3ePERx/bG5IIe0NIT0ur93w4nDLs/pPlGGlGltNG8IdpwMaoidlGSN8zGJ4mOyQqALtZ17IoRSw3meUYv0q+moTCtZrdbZQr3xAMsCdeW6r1SrnW09XmchjaE9vl0evJbUjZ2Q7+AI/BiVQEylkrO/TfwVgD7ZQ/jiA/g3TPptO7t9/gEfpImIw/wez7/iSEdMZcfBnwB16hJOcGEnFL+f70cnKKKbROa2tq6iOXqBuMXGTe4CAUbAAAAAElFTkSuQmCC';
- break;
- case 'Original':
- Favicon.unreadDead = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
- Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAAKAAAoAAAoKCg4AAA4ODg7OztMAACRAADBwcH/AAD///+WCcPSAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQmAUAxEb4Isk0rwp3EPR3ECcRQrh7C3/nAasPwzmCgYuPBy5AH/NALSImqAK+H1oJRqyJVHNAnZqDITVhj7/PrAciJ9il0BHs/jjU+fnB9sQ0IxX6OBO6Xr0xKAxANLZzUanCWzZQAAAABJRU5ErkJggg==';
- Favicon.unreadSFW = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAC6Xw////////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
- Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OzvBwcH///8uS/CdAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQ2AUAhEbwKWoftRGvdwBEewchM7d9BFbE6pbP4Mgj+R5MjjwgP+qQSkRtQAV8K3lVI2Q648oknIRpWZsMI4988HjgvpU+wO8HgeHzR9cjZYhoRiPkcDd0rXpyUAiRd5YjKC7MvNRgAAAABJRU5ErkJggg==';
- Favicon.unreadNSFW = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAGbMM////////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
- Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztmzDPBwcH///+rsf3XAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQ2AUAhEbwKWofRL4x6O4AhuopWb2P4F7E5prP4MgiaSHHlceMA/jYC0iBrgSnjdKaUacuURTUI2qsyEFcaxvD6wnkifYleAx/N449Mn5wfbkFDM52jgTun6tAQg8QAEvjQg42KY2AAAAABJRU5ErkJggg==';
- }
- if (Favicon.SFW) {
- Favicon.unread = Favicon.unreadSFW;
- return Favicon.unreadY = Favicon.unreadSFWY;
- } else {
- Favicon.unread = Favicon.unreadNSFW;
- return Favicon.unreadY = Favicon.unreadNSFWY;
- }
- },
- empty: 'data:image/gif;base64,R0lGODlhEAAQAJEAAAAAAP///9vb2////yH5BAEAAAMALAAAAAAQABAAAAIvnI+pq+D9DBAUoFkPFnbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw==',
- dead: 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAIALAAAAAAQABAAAAIvlI+pq+D9DAgUoFkPDlbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw=='
- };
-
- ThreadExcerpt = {
- init: function() {
- if (g.VIEW !== 'thread' || !Conf['Thread Excerpt']) {
- return;
- }
- return Thread.prototype.callbacks.push({
- name: 'Thread Excerpt',
- cb: this.node
- });
- },
- node: function() {
- return d.title = Get.threadExcerpt(this);
- }
- };
-
- ThreadStats = {
- init: function() {
- var sc;
-
- if (g.VIEW !== 'thread' || !Conf['Thread Stats']) {
- return;
- }
- this.dialog = sc = $.el('span', {
- innerHTML: "0 / 0",
- id: 'thread-stats'
- });
- this.postCountEl = $('#post-count', sc);
- this.fileCountEl = $('#file-count', sc);
- Header.addShortcut(sc);
- return Thread.prototype.callbacks.push({
- name: 'Thread Stats',
- cb: this.node
- });
- },
- node: function() {
- var ID, fileCount, post, postCount, _ref;
-
- postCount = 0;
- fileCount = 0;
- _ref = this.posts;
- for (ID in _ref) {
- post = _ref[ID];
- postCount++;
- if (post.file) {
- fileCount++;
- }
- }
- ThreadStats.thread = this;
- ThreadStats.update(postCount, fileCount);
- return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate);
- },
- onUpdate: function(e) {
- var fileCount, postCount, _ref;
-
- if (e.detail[404]) {
- return;
- }
- _ref = e.detail, postCount = _ref.postCount, fileCount = _ref.fileCount;
- return ThreadStats.update(postCount, fileCount);
- },
- update: function(postCount, fileCount) {
- var fileCountEl, postCountEl, thread;
-
- thread = ThreadStats.thread, postCountEl = ThreadStats.postCountEl, fileCountEl = ThreadStats.fileCountEl;
- postCountEl.textContent = postCount;
- fileCountEl.textContent = fileCount;
- (thread.postLimit && !thread.isSticky ? $.addClass : $.rmClass)(postCountEl, 'warning');
- return (thread.fileLimit && !thread.isSticky ? $.addClass : $.rmClass)(fileCountEl, 'warning');
- }
- };
-
- ThreadUpdater = {
- init: function() {
- var checked, conf, el, input, name, sc, settings, subEntries, _ref;
-
- if (g.VIEW !== 'thread' || !Conf['Thread Updater']) {
- return;
- }
- checked = Conf['Auto Update'] ? 'checked' : '';
- this.dialog = sc = $.el('span', {
- innerHTML: "",
- id: 'updater'
- });
- this.timer = $('#update-timer', sc);
- this.status = $('#update-status', sc);
- $.on(this.timer, 'click', ThreadUpdater.update);
- $.on(this.status, 'click', ThreadUpdater.update);
- this.checkPostCount = 0;
- Header.addShortcut(sc);
- subEntries = [];
- _ref = Config.updater.checkbox;
- for (name in _ref) {
- conf = _ref[name];
- checked = Conf[name] ? 'checked' : '';
- el = $.el('label', {
- title: "" + conf[1],
- innerHTML: " " + name
- });
- input = el.firstElementChild;
- $.on(input, 'change', $.cb.checked);
- if (input.name === 'Scroll BG') {
- $.on(input, 'change', ThreadUpdater.cb.scrollBG);
- ThreadUpdater.cb.scrollBG();
- }
- subEntries.push({
- el: el
- });
- }
- settings = $.el('span', {
- innerHTML: 'Interval'
- });
- $.on(settings, 'click', this.intervalShortcut);
- subEntries.push({
- el: settings
- });
- $.event('AddMenuEntry', {
- type: 'header',
- el: $.el('span', {
- textContent: 'Updater'
- }),
- order: 110,
- subEntries: subEntries
- });
- return Thread.prototype.callbacks.push({
- name: 'Thread Updater',
- cb: this.node
- });
- },
- node: function() {
- ThreadUpdater.thread = this;
- ThreadUpdater.root = this.OP.nodes.root.parentNode;
- ThreadUpdater.lastPost = +ThreadUpdater.root.lastElementChild.id.match(/\d+/)[0];
- ThreadUpdater.outdateCount = 0;
- ThreadUpdater.lastModified = '0';
- ThreadUpdater.cb.interval.call($.el('input', {
- value: Conf['Interval']
- }));
- $.on(window, 'online offline', ThreadUpdater.cb.online);
- $.on(d, 'QRPostSuccessful', ThreadUpdater.cb.post);
- $.on(d, 'visibilitychange', ThreadUpdater.cb.visibility);
- return ThreadUpdater.cb.online();
- },
- /*
- http://freesound.org/people/pierrecartoons1979/sounds/90112/
- cc-by-nc-3.0
- */
-
- beep: 'data:audio/wav;base64,UklGRjQDAABXQVZFZm10IBAAAAABAAEAgD4AAIA+AAABAAgAc21wbDwAAABBAAADAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkYXRhzAIAAGMms8em0tleMV4zIpLVo8nhfSlcPR102Ki+5JspVEkdVtKzs+K1NEhUIT7DwKrcy0g6WygsrM2k1NpiLl0zIY/WpMrjgCdbPhxw2Kq+5Z4qUkkdU9K1s+K5NkVTITzBwqnczko3WikrqM+l1NxlLF0zIIvXpsnjgydZPhxs2ay95aIrUEkdUdC3suK8N0NUIjq+xKrcz002WioppdGm091pK1w0IIjYp8jkhydXPxxq2K295aUrTkoeTs65suK+OUFUIzi7xqrb0VA0WSoootKm0t5tKlo1H4TYqMfkiydWQBxm16+85actTEseS8y7seHAPD9TIza5yKra01QyWSson9On0d5wKVk2H4DYqcfkjidUQB1j1rG75KsvSkseScu8seDCPz1TJDW2yara1FYxWSwnm9Sn0N9zKVg2H33ZqsXkkihSQR1g1bK65K0wSEsfR8i+seDEQTxUJTOzy6rY1VowWC0mmNWoz993KVc3H3rYq8TklSlRQh1d1LS647AyR0wgRMbAsN/GRDpTJTKwzKrX1l4vVy4lldWpzt97KVY4IXbUr8LZljVPRCxhw7W3z6ZISkw1VK+4sMWvXEhSPk6buay9sm5JVkZNiLWqtrJ+TldNTnquqbCwilZXU1BwpKirrpNgWFhTaZmnpquZbFlbVmWOpaOonHZcXlljhaGhpZ1+YWBdYn2cn6GdhmdhYGN3lp2enIttY2Jjco+bnJuOdGZlZXCImJqakHpoZ2Zug5WYmZJ/bGlobX6RlpeSg3BqaW16jZSVkoZ0bGtteImSk5KIeG5tbnaFkJKRinxxbm91gY2QkIt/c3BwdH6Kj4+LgnZxcXR8iI2OjIR5c3J0e4WLjYuFe3VzdHmCioyLhn52dHR5gIiKioeAeHV1eH+GiYqHgXp2dnh9hIiJh4J8eHd4fIKHiIeDfXl4eHyBhoeHhH96eHmA',
- cb: {
- online: function() {
- if (ThreadUpdater.online = navigator.onLine) {
- ThreadUpdater.outdateCount = 0;
- ThreadUpdater.set('timer', ThreadUpdater.getInterval());
- ThreadUpdater.update();
- ThreadUpdater.set('status', null, null);
- } else {
- ThreadUpdater.set('timer', null);
- ThreadUpdater.set('status', 'Offline', 'warning');
- }
- return ThreadUpdater.cb.autoUpdate();
- },
- post: function(e) {
- if (e.detail.threadID !== ThreadUpdater.thread.ID) {
- return;
- }
- ThreadUpdater.outdateCount = 0;
- if (ThreadUpdater.seconds > 2) {
- return setTimeout(ThreadUpdater.update, 1000);
- }
- },
- checkpost: function() {
- if (!(g.DEAD || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 10)) {
- return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * 500);
- }
- ThreadUpdater.checkPostCount = 0;
- delete ThreadUpdater.foundPost;
- return delete ThreadUpdater.postID;
- },
- visibility: function() {
- if (d.hidden) {
- return;
- }
- ThreadUpdater.outdateCount = 0;
- if (ThreadUpdater.seconds > ThreadUpdater.interval) {
- return ThreadUpdater.set('timer', ThreadUpdater.getInterval());
- }
- },
- scrollBG: function() {
- return ThreadUpdater.scrollBG = Conf['Scroll BG'] ? function() {
- return true;
- } : function() {
- return !d.hidden;
- };
- },
- autoUpdate: function() {
- if (ThreadUpdater.online) {
- return ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
- } else {
- return clearTimeout(ThreadUpdater.timeoutID);
- }
- },
- interval: function() {
- var val;
-
- val = +this.value;
- if (val < 1) {
- val = 1;
- }
- ThreadUpdater.interval = this.value = val;
- return $.cb.value.call(this);
- },
- load: function() {
- var klass, req, text, _ref;
-
- req = ThreadUpdater.req;
- switch (req.status) {
- case 200:
- g.DEAD = false;
- ThreadUpdater.parse(JSON.parse(req.response).posts);
- ThreadUpdater.lastModified = req.getResponseHeader('Last-Modified');
- ThreadUpdater.set('timer', ThreadUpdater.getInterval());
- break;
- case 404:
- g.DEAD = true;
- ThreadUpdater.set('timer', null);
- ThreadUpdater.set('status', '404', 'warning');
- clearTimeout(ThreadUpdater.timeoutID);
- ThreadUpdater.thread.kill();
- $.event('ThreadUpdate', {
- 404: true,
- thread: ThreadUpdater.thread
- });
- break;
- default:
- ThreadUpdater.outdateCount++;
- ThreadUpdater.set('timer', ThreadUpdater.getInterval());
- /*
- Status Code 304: Not modified
- By sending the `If-Modified-Since` header we get a proper status code, and no response.
- This saves bandwidth for both the user and the servers and avoid unnecessary computation.
- */
-
- _ref = [0, 304].contains(req.status) ? [null, null] : ["" + req.statusText + " (" + req.status + ")", 'warning'], text = _ref[0], klass = _ref[1];
- ThreadUpdater.set('status', text, klass);
- }
- if (ThreadUpdater.postID) {
- ThreadUpdater.cb.checkpost(this.status);
- }
- return delete ThreadUpdater.req;
- }
- },
- getInterval: function() {
- var i, j;
-
- i = ThreadUpdater.interval;
- j = Math.min(ThreadUpdater.outdateCount, 10);
- if (!d.hidden) {
- j = Math.min(j, 7);
- }
- return ThreadUpdater.seconds = Conf['Optional Increase'] ? Math.max(i, [0, 5, 10, 15, 20, 30, 60, 90, 120, 240, 300][j]) : i;
- },
- intervalShortcut: function() {
- var settings;
-
- Settings.open('Advanced');
- settings = $.id('fourchanx-settings');
- return $('input[name=Interval]', settings).focus();
- },
- set: function(name, text, klass) {
- var el, node;
-
- el = ThreadUpdater[name];
- if (node = el.firstChild) {
- node.data = text;
- } else {
- el.textContent = text;
- }
- if (klass !== void 0) {
- return el.className = klass;
- }
- },
- timeout: function() {
- var n;
-
- ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
- if (!(n = --ThreadUpdater.seconds)) {
- return ThreadUpdater.update();
- } else if (n <= -60) {
- ThreadUpdater.set('status', 'Retrying', null);
- return ThreadUpdater.update();
- } else if (n > 0) {
- return ThreadUpdater.set('timer', n);
- }
- },
- update: function() {
- var url;
-
- if (!ThreadUpdater.online) {
- return;
- }
- ThreadUpdater.seconds = 0;
- ThreadUpdater.set('timer', '...');
- if (ThreadUpdater.req) {
- ThreadUpdater.req.onloadend = null;
- ThreadUpdater.req.abort();
- }
- url = "//api.4chan.org/" + ThreadUpdater.thread.board + "/res/" + ThreadUpdater.thread + ".json";
- return ThreadUpdater.req = $.ajax(url, {
- onloadend: ThreadUpdater.cb.load
- }, {
- headers: {
- 'If-Modified-Since': ThreadUpdater.lastModified
- }
- });
- },
- updateThreadStatus: function(title, OP) {
- var icon, message, root, titleLC;
-
- titleLC = title.toLowerCase();
- if (ThreadUpdater.thread["is" + title] === !!OP[titleLC]) {
- return;
- }
- if (!(ThreadUpdater.thread["is" + title] = !!OP[titleLC])) {
- message = title === 'Sticky' ? 'The thread is not a sticky anymore.' : 'The thread is not closed anymore.';
- new Notification('info', message, 30);
- $.rm($("." + titleLC + "Icon", ThreadUpdater.thread.OP.nodes.info));
- return;
- }
- message = title === 'Sticky' ? 'The thread is now a sticky.' : 'The thread is now closed.';
- new Notification('info', message, 30);
- icon = $.el('img', {
- src: "//static.4chan.org/image/" + titleLC + ".gif",
- alt: title,
- title: title,
- className: "" + titleLC + "Icon"
- });
- root = $('[title="Quote this post"]', ThreadUpdater.thread.OP.nodes.info);
- if (title === 'Closed') {
- root = $('.stickyIcon', ThreadUpdater.thread.OP.nodes.info) || root;
- }
- return $.after(root, [$.tn(' '), icon]);
- },
- parse: function(postObjects) {
- var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, scroll, _i, _len, _ref;
-
- OP = postObjects[0];
- Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
- ThreadUpdater.updateThreadStatus('Sticky', OP);
- ThreadUpdater.updateThreadStatus('Closed', OP);
- ThreadUpdater.thread.postLimit = !!OP.bumplimit;
- ThreadUpdater.thread.fileLimit = !!OP.imagelimit;
- posts = [];
- index = [];
- files = [];
- count = 0;
- for (_i = 0, _len = postObjects.length; _i < _len; _i++) {
- postObject = postObjects[_i];
- num = postObject.no;
- index.push(num);
- if (postObject.fsize) {
- files.push(num);
- }
- if (num <= ThreadUpdater.lastPost) {
- continue;
- }
- count++;
- node = Build.postFromObject(postObject, ThreadUpdater.thread.board);
- posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
- }
- deletedPosts = [];
- deletedFiles = [];
- _ref = ThreadUpdater.thread.posts;
- for (ID in _ref) {
- post = _ref[ID];
- ID = +ID;
- if (post.isDead && index.contains(ID)) {
- post.resurrect();
- } else if (!index.contains(ID)) {
- post.kill();
- deletedPosts.push(post);
- } else if (post.file && !post.file.isDead && !files.contains(ID)) {
- post.kill(true);
- deletedFiles.push(post);
- }
- if (ThreadUpdater.postID) {
- if (ID === ThreadUpdater.postID) {
- ThreadUpdater.foundPost = true;
- }
- }
- }
- if (!count) {
- ThreadUpdater.set('status', null, null);
- ThreadUpdater.outdateCount++;
- } else {
- ThreadUpdater.set('status', "+" + count, 'new');
- ThreadUpdater.outdateCount = 0;
- if (Conf['Beep'] && d.hidden && Unread.posts && !Unread.posts.length) {
- if (!ThreadUpdater.audio) {
- ThreadUpdater.audio = $.el('audio', {
- src: ThreadUpdater.beep
- });
- }
- ThreadUpdater.audio.play();
- }
- ThreadUpdater.lastPost = posts[count - 1].ID;
- Main.callbackNodes(Post, posts);
- scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25;
- for (key in posts) {
- post = posts[key];
- if (!posts.hasOwnProperty(key)) {
- continue;
- }
- if (post.cb) {
- if (!post.cb.call(post)) {
- $.add(ThreadUpdater.root, post.nodes.root);
- }
- } else {
- $.add(ThreadUpdater.root, post.nodes.root);
- }
- }
- if (scroll) {
- if (Conf['Bottom Scroll']) {
- doc.scrollTop = d.body.clientHeight;
- } else {
- Header.scrollToPost(nodes[0]);
- }
- }
- $.queueTask(function() {
- var length, threadID;
-
- threadID = ThreadUpdater.thread.ID;
- length = $$('.thread > .postContainer', ThreadUpdater.root).length;
- return Fourchan.parseThread(threadID, length - count, length);
- });
- }
- return $.event('ThreadUpdate', {
- 404: false,
- thread: ThreadUpdater.thread,
- newPosts: posts,
- deletedPosts: deletedPosts,
- deletedFiles: deletedFiles,
- postCount: OP.replies + 1,
- fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead)
- });
- }
- };
-
- ThreadWatcher = {
- init: function() {
- if (!Conf['Thread Watcher']) {
- return;
- }
- this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', 'Thread Watcher
');
- $.on(d, 'QRPostSuccessful', this.cb.post);
- $.on(d, '4chanXInitFinished', this.ready);
- $.sync('WatchedThreads', this.refresh);
- return Thread.prototype.callbacks.push({
- name: 'Thread Watcher',
- cb: this.node
- });
- },
- node: function() {
- var favicon,
- _this = this;
-
- favicon = $.el('img', {
- className: 'favicon'
- });
- $.on(favicon, 'click', ThreadWatcher.cb.toggle);
- $.before($('input', this.OP.nodes.post), favicon);
- if (g.VIEW !== 'thread') {
- return;
- }
- return $.get('AutoWatch', 0, function(item) {
- if (item['AutoWatch'] !== _this.ID) {
- return;
- }
- ThreadWatcher.watch(_this);
- return $["delete"]('AutoWatch');
- });
- },
- ready: function() {
- $.off(d, '4chanXInitFinished', ThreadWatcher.ready);
- if (!Main.isThisPageLegit()) {
- return;
- }
- ThreadWatcher.refresh();
- return $.add(d.body, ThreadWatcher.dialog);
- },
- refresh: function(watched) {
- var ID, board, div, favicon, id, link, nodes, props, thread, x, _ref, _ref1;
-
- if (!watched) {
- $.get('WatchedThreads', {}, function(item) {
- return ThreadWatcher.refresh(item['WatchedThreads']);
- });
- return;
- }
- nodes = [$('.move', ThreadWatcher.dialog)];
- for (board in watched) {
- _ref = watched[board];
- for (id in _ref) {
- props = _ref[id];
- x = $.el('a', {
- textContent: '×',
- href: 'javascript:;'
- });
- $.on(x, 'click', ThreadWatcher.cb.x);
- link = $.el('a', props);
- link.title = link.textContent;
- div = $.el('div');
- $.add(div, [x, $.tn(' '), link]);
- nodes.push(div);
- }
- }
- $.rmAll(ThreadWatcher.dialog);
- $.add(ThreadWatcher.dialog, nodes);
- watched = watched[g.BOARD] || {};
- _ref1 = g.BOARD.threads;
- for (ID in _ref1) {
- thread = _ref1[ID];
- favicon = $('.favicon', thread.OP.nodes.post);
- favicon.src = ID in watched ? Favicon["default"] : Favicon.empty;
- }
- },
- cb: {
- toggle: function() {
- return ThreadWatcher.toggle(Get.postFromNode(this).thread);
- },
- x: function() {
- var thread;
-
- thread = this.nextElementSibling.pathname.split('/');
- return ThreadWatcher.unwatch(thread[1], thread[3]);
- },
- post: function(e) {
- var board, postID, threadID, _ref;
-
- _ref = e.detail, board = _ref.board, postID = _ref.postID, threadID = _ref.threadID;
- if (postID === threadID) {
- if (Conf['Auto Watch']) {
- return $.set('AutoWatch', threadID);
- }
- } else if (Conf['Auto Watch Reply']) {
- return ThreadWatcher.watch(board.threads[threadID]);
- }
- }
- },
- toggle: function(thread) {
- if ($('.favicon', thread.OP.nodes.post).src === Favicon.empty) {
- return ThreadWatcher.watch(thread);
- } else {
- return ThreadWatcher.unwatch(thread.board, thread.ID);
- }
- },
- unwatch: function(board, threadID) {
- return $.get('WatchedThreads', {}, function(item) {
- var watched;
-
- watched = item['WatchedThreads'];
- delete watched[board][threadID];
- if (!Object.keys(watched[board]).length) {
- delete watched[board];
- }
- ThreadWatcher.refresh(watched);
- return $.set('WatchedThreads', watched);
- });
- },
- watch: function(thread) {
- return $.get('WatchedThreads', {}, function(item) {
- var watched, _name;
-
- watched = item['WatchedThreads'];
- watched[_name = thread.board] || (watched[_name] = {});
- watched[thread.board][thread] = {
- href: "/" + thread.board + "/res/" + thread,
- textContent: Get.threadExcerpt(thread)
- };
- ThreadWatcher.refresh(watched);
- return $.set('WatchedThreads', watched);
- });
- }
- };
-
- Unread = {
- init: function() {
- if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon']) {
- return;
- }
- this.db = new DataBoard('lastReadPosts', this.sync);
- this.hr = $.el('hr', {
- id: 'unread-line'
- });
- this.posts = [];
- this.postsQuotingYou = [];
- return Thread.prototype.callbacks.push({
- name: 'Unread',
- cb: this.node
- });
- },
- node: function() {
- Unread.thread = this;
- Unread.title = d.title;
- Unread.lastReadPost = Unread.db.get({
- boardID: this.board.ID,
- threadID: this.ID,
- defaultValue: 0
- });
- $.on(d, '4chanXInitFinished', Unread.ready);
- $.on(d, 'ThreadUpdate', Unread.onUpdate);
- $.on(d, 'scroll visibilitychange', Unread.read);
- if (Conf['Unread Line']) {
- $.on(d, 'visibilitychange', Unread.setLine);
- }
- if (Conf['Scroll to Last Read Post']) {
- return $.on(window, 'load', Unread.scroll);
- }
- },
- ready: function() {
- var ID, post, posts, _ref;
-
- $.off(d, '4chanXInitFinished', Unread.ready);
- posts = [];
- _ref = Unread.thread.posts;
- for (ID in _ref) {
- post = _ref[ID];
- if (post.isReply) {
- posts.push(post);
- }
- }
- return Unread.addPosts(posts);
- },
- scroll: function() {
- var hash, post, posts, prevID, root;
-
- if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
- return;
- }
- if (Unread.posts.length) {
- prevID = 0;
- while (root = $.x('preceding-sibling::div[contains(@class,"postContainer")][1]', Unread.posts[0].nodes.root)) {
- post = Get.postFromRoot(root);
- if (prevID === post.ID) {
- break;
- }
- prevID = post.ID;
- if (!post.isHidden) {
- break;
- }
- }
- root.scrollIntoView(false);
- return;
- }
- posts = Object.keys(Unread.thread.posts);
- return Header.scrollToPost(Unread.thread.posts[posts[posts.length - 1]].nodes.root);
- },
- sync: function() {
- var lastReadPost;
-
- lastReadPost = Unread.db.get({
- boardID: Unread.thread.board.ID,
- threadID: Unread.thread.ID,
- defaultValue: 0
- });
- if (!(Unread.lastReadPost < lastReadPost)) {
- return;
- }
- Unread.lastReadPost = lastReadPost;
- Unread.readArray(Unread.posts);
- Unread.readArray(Unread.postsQuotingYou);
- Unread.setLine();
- return Unread.update();
- },
- addPosts: function(newPosts) {
- var ID, data, post, _i, _len;
-
- for (_i = 0, _len = newPosts.length; _i < _len; _i++) {
- post = newPosts[_i];
- ID = post.ID;
- if (ID <= Unread.lastReadPost || post.isHidden) {
- continue;
- }
- if (QR.db) {
- data = {
- boardID: post.board.ID,
- threadID: post.thread.ID,
- postID: post.ID
- };
- if (QR.db.get(data)) {
- continue;
- }
- }
- Unread.posts.push(post);
- Unread.addPostQuotingYou(post);
- }
- if (Conf['Unread Line']) {
- Unread.setLine(newPosts.contains(Unread.posts[0]));
- }
- Unread.read();
- return Unread.update();
- },
- addPostQuotingYou: function(post) {
- var quotelink, _i, _len, _ref;
-
- if (!QR.db) {
- return;
- }
- _ref = post.nodes.quotelinks;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quotelink = _ref[_i];
- if (QR.db.get(Get.postDataFromLink(quotelink))) {
- Unread.postsQuotingYou.push(post);
- }
- }
- },
- onUpdate: function(e) {
- if (e.detail[404]) {
- return Unread.update();
- } else {
- return Unread.addPosts(e.detail.newPosts);
- }
- },
- readSinglePost: function(post) {
- var i;
-
- if ((i = Unread.posts.indexOf(post)) === -1) {
- return;
- }
- Unread.posts.splice(i, 1);
- if (i === 0) {
- Unread.lastReadPost = post.ID;
- Unread.saveLastReadPost();
- }
- if ((i = Unread.postsQuotingYou.indexOf(post)) !== -1) {
- Unread.postsQuotingYou.splice(i, 1);
- }
- return Unread.update();
- },
- readArray: function(arr) {
- var i, post, _i, _len;
-
- for (i = _i = 0, _len = arr.length; _i < _len; i = ++_i) {
- post = arr[i];
- if (post.ID > Unread.lastReadPost) {
- break;
- }
- }
- return arr.splice(0, i);
- },
- read: $.debounce(50, function(e) {
- var ID, bottom, height, i, post, posts, read;
-
- if (d.hidden || !Unread.posts.length) {
- return;
- }
- height = doc.clientHeight;
- posts = Unread.posts;
- read = [];
- i = posts.length;
- while (post = posts[--i]) {
- bottom = post.nodes.root.getBoundingClientRect().bottom;
- if (bottom < height) {
- ID = post.ID;
- posts.remove(post);
- }
- }
- if (!ID) {
- return;
- }
- Unread.lastReadPost = ID;
- Unread.saveLastReadPost();
- Unread.readArray(Unread.postsQuotingYou);
- if (e) {
- return Unread.update();
- }
- }),
- saveLastReadPost: $.debounce(2 * $.SECOND, function() {
- return Unread.db.set({
- boardID: Unread.thread.board.ID,
- threadID: Unread.thread.ID,
- val: Unread.lastReadPost
- });
- }),
- setLine: function(force) {
- var post, root;
-
- if (!(d.hidden || force === true)) {
- return;
- }
- if (post = Unread.posts[0]) {
- root = post.nodes.root;
- if (root !== $('.thread > .replyContainer', root.parentNode)) {
- return $.before(root, Unread.hr);
- }
- } else {
- return $.rm(Unread.hr);
- }
- },
- update: function() {
- var count;
-
- count = Unread.posts.length;
- if (Conf['Unread Count']) {
- d.title = "" + (count || !Conf['Hide Unread Count at (0)'] ? "(" + count + ") " : '') + (g.DEAD ? "/" + g.BOARD + "/ - 404" : "" + Unread.title);
- }
- if (!Conf['Unread Favicon']) {
- return;
- }
- Favicon.el.href = g.DEAD ? Unread.postsQuotingYou.length ? Favicon.unreadDeadY : count ? Favicon.unreadDead : Favicon.dead : count ? Unread.postsQuotingYou.length ? Favicon.unreadY : Favicon.unread : Favicon["default"];
- return $.add(d.head, Favicon.el);
- }
- };
-
QR = {
init: function() {
var sc;
@@ -8319,619 +5744,2028 @@
}
};
- QuoteBacklink = {
+ FappeTyme = {
init: function() {
- var format;
+ var el, input;
- if (g.VIEW === 'catalog' || !Conf['Quote Backlinks']) {
+ if (!Conf['Fappe Tyme'] || g.VIEW === 'catalog' || g.BOARD === 'f') {
return;
}
- format = Conf['backlink'].replace(/%id/g, "' + id + '");
- this.funk = Function('id', "return '" + format + "'");
- this.containers = {};
- Post.prototype.callbacks.push({
- name: 'Quote Backlinking Part 1',
- cb: this.firstNode
+ el = $.el('label', {
+ innerHTML: " Fappe Tyme",
+ title: 'Fappe Tyme'
+ });
+ FappeTyme.input = input = el.firstElementChild;
+ $.on(input, 'change', FappeTyme.toggle);
+ $.event('AddMenuEntry', {
+ type: 'header',
+ el: el,
+ order: 97
});
return Post.prototype.callbacks.push({
- name: 'Quote Backlinking Part 2',
- cb: this.secondNode
+ name: 'Fappe Tyme',
+ cb: this.node
});
},
- firstNode: function() {
- var a, clone, container, containers, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
+ node: function() {
+ if (this.file) {
+ return;
+ }
+ return $.addClass(this.nodes.root, "noFile");
+ },
+ toggle: function() {
+ $.event('CloseMenu');
+ return (this.checked ? $.addClass : $.rmClass)(doc, 'fappeTyme');
+ }
+ };
- if (this.isClone || !this.quotes.length) {
+ ImageExpand = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
+ return;
+ }
+ this.EAI = $.el('a', {
+ className: 'expand-all-shortcut',
+ textContent: 'EAI',
+ title: 'Expand All Images',
+ href: 'javascript:;'
+ });
+ $.on(this.EAI, 'click', ImageExpand.cb.toggleAll);
+ Header.addShortcut(this.EAI);
+ return Post.prototype.callbacks.push({
+ name: 'Image Expansion',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var thumb, _ref;
+
+ if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ return;
+ }
+ thumb = this.file.thumb;
+ $.on(thumb.parentNode, 'click', ImageExpand.cb.toggle);
+ if (this.isClone && $.hasClass(thumb, 'expanding')) {
+ ImageExpand.contract(this);
+ ImageExpand.expand(this);
+ return;
+ }
+ if (ImageExpand.on && !this.isHidden) {
+ return ImageExpand.expand(this);
+ }
+ },
+ cb: {
+ toggle: function(e) {
+ if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
+ return;
+ }
+ e.preventDefault();
+ return ImageExpand.toggle(Get.postFromNode(this));
+ },
+ toggleAll: function() {
+ var ID, file, func, post, _i, _len, _ref, _ref1;
+
+ $.event('CloseMenu');
+ if (ImageExpand.on = $.hasClass(ImageExpand.EAI, 'expand-all-shortcut')) {
+ ImageExpand.EAI.className = 'contract-all-shortcut';
+ ImageExpand.EAI.title = 'Contract All Images';
+ func = ImageExpand.expand;
+ } else {
+ ImageExpand.EAI.className = 'expand-all-shortcut';
+ ImageExpand.EAI.title = 'Expand All Images';
+ func = ImageExpand.contract;
+ }
+ _ref = g.posts;
+ for (ID in _ref) {
+ post = _ref[ID];
+ _ref1 = [post].concat(post.clones);
+ for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
+ post = _ref1[_i];
+ file = post.file;
+ if (!(file && file.isImage && doc.contains(post.nodes.root))) {
+ continue;
+ }
+ if (ImageExpand.on && (!Conf['Expand spoilers'] && file.isSpoiler || Conf['Expand from here'] && file.thumb.getBoundingClientRect().top < 0)) {
+ continue;
+ }
+ $.queueTask(func, post);
+ }
+ }
+ },
+ setFitness: function() {
+ var checked;
+
+ checked = this.checked;
+ (checked ? $.addClass : $.rmClass)(doc, this.name.toLowerCase().replace(/\s+/g, '-'));
+ if (this.name !== 'Fit height') {
+ return;
+ }
+ if (checked) {
+ $.on(window, 'resize', ImageExpand.resize);
+ if (!ImageExpand.style) {
+ ImageExpand.style = $.addStyle(null);
+ }
+ return ImageExpand.resize();
+ } else {
+ return $.off(window, 'resize', ImageExpand.resize);
+ }
+ }
+ },
+ toggle: function(post) {
+ var headRect, rect, root, thumb, top;
+
+ thumb = post.file.thumb;
+ if (!(post.file.isExpanded || $.hasClass(thumb, 'expanding'))) {
+ ImageExpand.expand(post);
+ return;
+ }
+ ImageExpand.contract(post);
+ rect = post.nodes.root.getBoundingClientRect();
+ if (!(rect.top <= 0 || rect.left <= 0)) {
+ return;
+ }
+ top = rect.top;
+ if (Conf['Fixed Header'] && !Conf['Bottom Header']) {
+ headRect = Header.bar.getBoundingClientRect();
+ top += -headRect.top - headRect.height;
+ }
+ root = doc;
+ if (rect.top < 0) {
+ root.scrollTop += top;
+ }
+ if (rect.left < 0) {
+ return root.scrollLeft = 0;
+ }
+ },
+ contract: function(post) {
+ $.rmClass(post.nodes.root, 'expanded-image');
+ $.rmClass(post.file.thumb, 'expanding');
+ return post.file.isExpanded = false;
+ },
+ expand: function(post, src) {
+ var img, thumb;
+
+ thumb = post.file.thumb;
+ if (post.isHidden || post.file.isExpanded || $.hasClass(thumb, 'expanding')) {
+ return;
+ }
+ $.addClass(thumb, 'expanding');
+ if (post.file.fullImage) {
+ $.asap((function() {
+ return post.file.fullImage.naturalHeight;
+ }), function() {
+ return ImageExpand.completeExpand(post);
+ });
+ return;
+ }
+ post.file.fullImage = img = $.el('img', {
+ className: 'full-image',
+ src: src || post.file.URL
+ });
+ $.on(img, 'error', ImageExpand.error);
+ $.asap((function() {
+ return post.file.fullImage.naturalHeight;
+ }), function() {
+ return ImageExpand.completeExpand(post);
+ });
+ return $.after(thumb, img);
+ },
+ completeExpand: function(post) {
+ var prev, thumb;
+
+ thumb = post.file.thumb;
+ if (!$.hasClass(thumb, 'expanding')) {
+ return;
+ }
+ post.file.isExpanded = true;
+ if (!post.nodes.root.parentNode) {
+ $.addClass(post.nodes.root, 'expanded-image');
+ $.rmClass(post.file.thumb, 'expanding');
+ return;
+ }
+ prev = post.nodes.root.getBoundingClientRect();
+ return $.queueTask(function() {
+ var curr, root;
+
+ $.addClass(post.nodes.root, 'expanded-image');
+ $.rmClass(post.file.thumb, 'expanding');
+ if (!(prev.top + prev.height <= 0)) {
+ return;
+ }
+ root = doc;
+ curr = post.nodes.root.getBoundingClientRect();
+ return root.scrollTop += curr.height - prev.height + curr.top - prev.top;
+ });
+ },
+ error: function() {
+ var URL, post, src, timeoutID;
+
+ post = Get.postFromNode(this);
+ $.rm(this);
+ delete post.file.fullImage;
+ if (!($.hasClass(post.file.thumb, 'expanding') || $.hasClass(post.nodes.root, 'expanded-image'))) {
+ return;
+ }
+ ImageExpand.contract(post);
+ src = this.src.split('/');
+ if (src[2] === 'images.4chan.org') {
+ if (URL = Redirect.image(src[3], src[5])) {
+ setTimeout(ImageExpand.expand, 10000, post, URL);
+ return;
+ }
+ if (g.DEAD || post.isDead || post.file.isDead) {
+ return;
+ }
+ }
+ timeoutID = setTimeout(ImageExpand.expand, 10000, post);
+ return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", {
+ onload: function() {
+ var postObj, _i, _len, _ref;
+
+ if (this.status !== 200) {
+ return;
+ }
+ _ref = JSON.parse(this.response).posts;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ postObj = _ref[_i];
+ if (postObj.no === post.ID) {
+ break;
+ }
+ }
+ if (postObj.no !== post.ID) {
+ clearTimeout(timeoutID);
+ return post.kill();
+ } else if (postObj.filedeleted) {
+ clearTimeout(timeoutID);
+ return post.kill(true);
+ }
+ }
+ });
+ },
+ menu: {
+ init: function() {
+ var conf, createSubEntry, el, key, subEntries, _ref;
+
+ if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
+ return;
+ }
+ el = $.el('span', {
+ textContent: 'Image Expansion',
+ className: 'image-expansion-link'
+ });
+ createSubEntry = ImageExpand.menu.createSubEntry;
+ subEntries = [];
+ _ref = Config.imageExpansion;
+ for (key in _ref) {
+ conf = _ref[key];
+ subEntries.push(createSubEntry(key, conf));
+ }
+ return $.event('AddMenuEntry', {
+ type: 'header',
+ el: el,
+ order: 105,
+ subEntries: subEntries
+ });
+ },
+ createSubEntry: function(type, config) {
+ var input, label;
+
+ label = $.el('label', {
+ innerHTML: " " + type
+ });
+ input = label.firstElementChild;
+ if (type === 'Fit width' || type === 'Fit height') {
+ $.on(input, 'change', ImageExpand.cb.setFitness);
+ }
+ if (config) {
+ label.title = config[1];
+ input.checked = Conf[type];
+ $.event('change', null, input);
+ $.on(input, 'change', $.cb.checked);
+ }
+ return {
+ el: label
+ };
+ }
+ },
+ resize: function() {
+ return ImageExpand.style.textContent = ":root.fit-height .full-image {max-height:" + doc.clientHeight + "px}";
+ },
+ menuToggle: function(e) {
+ return ImageExpand.opmenu.toggle(e, this, g);
+ }
+ };
+
+ ImageHover = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Image Hover']) {
+ return;
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Image Hover',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var _ref;
+
+ if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ return;
+ }
+ return $.on(this.file.thumb, 'mouseover', ImageHover.mouseover);
+ },
+ mouseover: function(e) {
+ var el, post;
+
+ post = Get.postFromNode(this);
+ el = $.el('img', {
+ id: 'ihover',
+ src: post.file.URL
+ });
+ el.setAttribute('data-fullid', post.fullID);
+ $.add(Header.hover, el);
+ UI.hover({
+ root: this,
+ el: el,
+ latestEvent: e,
+ endEvents: 'mouseout click',
+ asapTest: function() {
+ return el.naturalHeight;
+ }
+ });
+ return $.on(el, 'error', ImageHover.error);
+ },
+ error: function() {
+ var URL, post, src, timeoutID,
+ _this = this;
+
+ if (!doc.contains(this)) {
+ return;
+ }
+ post = g.posts[this.dataset.fullid];
+ src = this.src.split('/');
+ if (src[2] === 'images.4chan.org') {
+ if (URL = Redirect.image(src[3], src[5].replace(/\?.+$/, ''))) {
+ this.src = URL;
+ return;
+ }
+ if (g.DEAD || post.isDead || post.file.isDead) {
+ return;
+ }
+ }
+ timeoutID = setTimeout((function() {
+ return _this.src = post.file.URL + '?' + Date.now();
+ }), 3000);
+ return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", {
+ onload: function() {
+ var postObj, _i, _len, _ref;
+
+ if (this.status !== 200) {
+ return;
+ }
+ _ref = JSON.parse(this.response).posts;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ postObj = _ref[_i];
+ if (postObj.no === post.ID) {
+ break;
+ }
+ }
+ if (postObj.no !== post.ID) {
+ clearTimeout(timeoutID);
+ return post.kill();
+ } else if (postObj.filedeleted) {
+ clearTimeout(timeoutID);
+ return post.kill(true);
+ }
+ }
+ });
+ }
+ };
+
+ ImageReplace = {
+ init: function() {
+ if (g.VIEW === 'catalog') {
+ return;
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Image Replace',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var URL, img, style, thumb, type, _ref, _ref1;
+
+ if (this.isClone || this.isHidden || this.thread.isHidden || !((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ return;
+ }
+ _ref1 = this.file, thumb = _ref1.thumb, URL = _ref1.URL;
+ if (!(Conf["Replace " + ((type = (URL.match(/\w{3}$/))[0].toUpperCase()) === 'PEG' ? 'JPG' : type)] && !/spoiler/.test(thumb.src))) {
+ return;
+ }
+ if (this.file.isSpoiler) {
+ style = thumb.style;
+ style.maxHeight = style.maxWidth = this.isReply ? '125px' : '250px';
+ }
+ img = $.el('img');
+ $.on(img, 'load', function() {
+ return thumb.src = URL;
+ });
+ return img.src = URL;
+ }
+ };
+
+ RevealSpoilers = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Reveal Spoilers']) {
+ return;
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Reveal Spoilers',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var thumb, _ref;
+
+ if (this.isClone || !((_ref = this.file) != null ? _ref.isSpoiler : void 0)) {
+ return;
+ }
+ thumb = this.file.thumb;
+ thumb.removeAttribute('style');
+ return thumb.src = this.file.thumbURL;
+ }
+ };
+
+ ArchiveLink = {
+ init: function() {
+ var div, entry, type, _i, _len, _ref;
+
+ if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Archive Link']) {
+ return;
+ }
+ div = $.el('div', {
+ textContent: 'Archive'
+ });
+ entry = {
+ type: 'post',
+ el: div,
+ order: 90,
+ open: function(_arg) {
+ var ID, board, redirect, thread;
+
+ ID = _arg.ID, thread = _arg.thread, board = _arg.board;
+ redirect = Redirect.to({
+ postID: ID,
+ threadID: thread.ID,
+ boardID: board.ID
+ });
+ return redirect !== ("//boards.4chan.org/" + board + "/");
+ },
+ subEntries: []
+ };
+ _ref = [['Post', 'post'], ['Name', 'name'], ['Tripcode', 'tripcode'], ['E-mail', 'email'], ['Subject', 'subject'], ['Filename', 'filename'], ['Image MD5', 'MD5']];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ type = _ref[_i];
+ entry.subEntries.push(this.createSubEntry(type[0], type[1]));
+ }
+ return $.event('AddMenuEntry', entry);
+ },
+ createSubEntry: function(text, type) {
+ var el, open;
+
+ el = $.el('a', {
+ textContent: text,
+ target: '_blank'
+ });
+ open = type === 'post' ? function(_arg) {
+ var ID, board, thread;
+
+ ID = _arg.ID, thread = _arg.thread, board = _arg.board;
+ el.href = Redirect.to({
+ postID: ID,
+ threadID: thread.ID,
+ boardID: board.ID
+ });
+ return true;
+ } : function(post) {
+ var value;
+
+ value = Filter[type](post);
+ if (!value) {
+ return false;
+ }
+ el.href = Redirect.to({
+ boardID: post.board.ID,
+ type: type,
+ value: value,
+ isSearch: true
+ });
+ return true;
+ };
+ return {
+ el: el,
+ open: open
+ };
+ }
+ };
+
+ DeleteLink = {
+ init: function() {
+ var div, fileEl, fileEntry, postEl, postEntry;
+
+ if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Delete Link']) {
+ return;
+ }
+ div = $.el('div', {
+ className: 'delete-link',
+ textContent: 'Delete'
+ });
+ postEl = $.el('a', {
+ className: 'delete-post',
+ href: 'javascript:;'
+ });
+ fileEl = $.el('a', {
+ className: 'delete-file',
+ href: 'javascript:;'
+ });
+ postEntry = {
+ el: postEl,
+ open: function() {
+ postEl.textContent = 'Post';
+ $.on(postEl, 'click', DeleteLink["delete"]);
+ return true;
+ }
+ };
+ fileEntry = {
+ el: fileEl,
+ open: function(_arg) {
+ var file;
+
+ file = _arg.file;
+ if (!file || file.isDead) {
+ return false;
+ }
+ fileEl.textContent = 'File';
+ $.on(fileEl, 'click', DeleteLink["delete"]);
+ return true;
+ }
+ };
+ return $.event('AddMenuEntry', {
+ type: 'post',
+ el: div,
+ order: 40,
+ open: function(post) {
+ var node;
+
+ if (post.isDead) {
+ return false;
+ }
+ DeleteLink.post = post;
+ node = div.firstChild;
+ node.textContent = 'Delete';
+ DeleteLink.cooldown.start(post, node);
+ return true;
+ },
+ subEntries: [postEntry, fileEntry]
+ });
+ },
+ "delete": function() {
+ var fileOnly, form, link, m, post, pwd;
+
+ post = DeleteLink.post;
+ if (DeleteLink.cooldown.counting === post) {
+ return;
+ }
+ $.off(this, 'click', DeleteLink["delete"]);
+ this.textContent = "Deleting " + this.textContent + "...";
+ pwd = (m = d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : $.id('delPassword').value;
+ fileOnly = $.hasClass(this, 'delete-file');
+ form = {
+ mode: 'usrdel',
+ onlyimgdel: fileOnly,
+ pwd: pwd
+ };
+ form[post.ID] = 'delete';
+ link = this;
+ return $.ajax($.id('delform').action.replace("/" + g.BOARD + "/", "/" + post.board + "/"), {
+ onload: function() {
+ return DeleteLink.load(link, post, fileOnly, this.response);
+ },
+ onerror: function() {
+ return DeleteLink.error(link);
+ }
+ }, {
+ cred: true,
+ form: $.formData(form)
+ });
+ },
+ load: function(link, post, fileOnly, html) {
+ var msg, s, tmpDoc;
+
+ tmpDoc = d.implementation.createHTMLDocument('');
+ tmpDoc.documentElement.innerHTML = html;
+ if (tmpDoc.title === '4chan - Banned') {
+ s = 'Banned!';
+ } else if (msg = tmpDoc.getElementById('errmsg')) {
+ s = msg.textContent;
+ $.on(link, 'click', DeleteLink["delete"]);
+ } else {
+ if (tmpDoc.title === 'Updating index...') {
+ (post.origin || post).kill(fileOnly);
+ }
+ s = 'Deleted';
+ }
+ return link.textContent = s;
+ },
+ error: function(link) {
+ link.textContent = 'Connection error, please retry.';
+ return $.on(link, 'click', DeleteLink["delete"]);
+ },
+ cooldown: {
+ start: function(post, node) {
+ var length, seconds, _ref;
+
+ if (!((_ref = QR.db) != null ? _ref.get({
+ boardID: post.board.ID,
+ threadID: post.thread.ID,
+ postID: post.ID
+ }) : void 0)) {
+ delete DeleteLink.cooldown.counting;
+ return;
+ }
+ DeleteLink.cooldown.counting = post;
+ length = post.board.ID === 'q' ? 600 : 30;
+ seconds = Math.ceil((length * $.SECOND - (Date.now() - post.info.date)) / $.SECOND);
+ return DeleteLink.cooldown.count(post, seconds, length, node);
+ },
+ count: function(post, seconds, length, node) {
+ if (DeleteLink.cooldown.counting !== post) {
+ return;
+ }
+ if (!((0 <= seconds && seconds <= length))) {
+ if (DeleteLink.cooldown.counting === post) {
+ node.textContent = 'Delete';
+ delete DeleteLink.cooldown.counting;
+ }
+ return;
+ }
+ setTimeout(DeleteLink.cooldown.count, 1000, post, seconds - 1, length, node);
+ return node.textContent = "Delete (" + seconds + ")";
+ }
+ }
+ };
+
+ DownloadLink = {
+ init: function() {
+ var a;
+
+ if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Download Link']) {
return;
}
a = $.el('a', {
- href: "/" + this.board + "/res/" + this.thread + "#p" + this,
- className: this.isHidden ? 'filtered backlink' : 'backlink',
- textContent: (QuoteBacklink.funk(this.ID)) + (Conf['Mark Quotes of You'] && this.info.yours ? QuoteYou.text : '')
+ className: 'download-link',
+ textContent: 'Download file'
});
- _ref = this.quotes;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quote = _ref[_i];
- containers = [QuoteBacklink.getContainer(quote)];
- if ((post = g.posts[quote]) && post.nodes.backlinkContainer) {
- _ref1 = post.clones;
- for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
- clone = _ref1[_j];
- containers.push(clone.nodes.backlinkContainer);
- }
- }
- for (_k = 0, _len2 = containers.length; _k < _len2; _k++) {
- container = containers[_k];
- link = a.cloneNode(true);
- if (Conf['Quote Previewing']) {
- $.on(link, 'mouseover', QuotePreview.mouseover);
- }
- if (Conf['Quote Inlining']) {
- $.on(link, 'click', QuoteInline.toggle);
- }
- $.add(container, [$.tn(' '), link]);
- }
- }
- },
- secondNode: function() {
- var container;
+ return $.event('AddMenuEntry', {
+ type: 'post',
+ el: a,
+ order: 70,
+ open: function(_arg) {
+ var file;
- if (this.isClone && (this.origin.isReply || Conf['OP Backlinks'])) {
- this.nodes.backlinkContainer = $('.container', this.nodes.info);
- return;
- }
- if (!(this.isReply || Conf['OP Backlinks'])) {
- return;
- }
- container = QuoteBacklink.getContainer(this.fullID);
- this.nodes.backlinkContainer = container;
- return $.add(this.nodes.info, container);
- },
- getContainer: function(id) {
- var _base;
-
- return (_base = this.containers)[id] || (_base[id] = $.el('span', {
- className: 'container'
- }));
+ file = _arg.file;
+ if (!file) {
+ return false;
+ }
+ a.href = file.URL;
+ a.download = file.name;
+ return true;
+ }
+ });
}
};
- QuoteCT = {
+ Menu = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Mark Cross-thread Quotes']) {
+ if (g.VIEW === 'catalog' || !Conf['Menu']) {
return;
}
- if (Conf['Comment Expansion']) {
- ExpandComment.callbacks.push(this.node);
- }
- this.text = '\u00A0(Cross-thread)';
+ this.menu = new UI.Menu('post');
return Post.prototype.callbacks.push({
- name: 'Mark Cross-thread Quotes',
+ name: 'Menu',
cb: this.node
});
},
node: function() {
- var board, boardID, quotelink, quotelinks, quotes, thread, threadID, _i, _len, _ref, _ref1;
+ var button;
- if (this.isClone && this.thread === this.context.thread) {
+ button = Menu.makeButton(this);
+ if (this.isClone) {
+ $.replace($('.menu-button', this.nodes.info), button);
return;
}
- if (!(quotes = this.quotes).length) {
- return;
- }
- quotelinks = this.nodes.quotelinks;
- _ref = this.isClone ? this.context : this, board = _ref.board, thread = _ref.thread;
- for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
- quotelink = quotelinks[_i];
- _ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, threadID = _ref1.threadID;
- if (!threadID) {
- continue;
- }
- if (this.isClone) {
- quotelink.textContent = quotelink.textContent.replace(QuoteCT.text, '');
- }
- if (boardID === this.board.ID && threadID !== thread.ID) {
- $.add(quotelink, $.tn(QuoteCT.text));
- }
- }
- }
- };
-
- QuoteInline = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Quote Inlining']) {
- return;
- }
- if (Conf['Comment Expansion']) {
- ExpandComment.callbacks.push(this.node);
- }
- return Post.prototype.callbacks.push({
- name: 'Quote Inlining',
- cb: this.node
- });
+ return $.add(this.nodes.info, [$.tn('\u00A0'), button]);
},
- node: function() {
- var link, _i, _len, _ref;
+ makeButton: (function() {
+ var a;
- _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- link = _ref[_i];
- $.on(link, 'click', QuoteInline.toggle);
- }
- },
+ a = null;
+ return function(post) {
+ var clone;
+
+ a || (a = $.el('a', {
+ className: 'menu-button',
+ innerHTML: '[]',
+ href: 'javascript:;'
+ }));
+ clone = a.cloneNode(true);
+ clone.setAttribute('data-postid', post.fullID);
+ if (post.isClone) {
+ clone.setAttribute('data-clone', true);
+ }
+ $.on(clone, 'click', Menu.toggle);
+ return clone;
+ };
+ })(),
toggle: function(e) {
- var boardID, context, postID, threadID, _ref;
+ var post;
- if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
- return;
- }
- e.preventDefault();
- _ref = Get.postDataFromLink(this), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
- context = Get.contextFromLink(this);
- if ($.hasClass(this, 'inlined')) {
- QuoteInline.rm(this, boardID, threadID, postID, context);
- } else {
- if ($.x("ancestor::div[@id='p" + postID + "']", this)) {
- return;
- }
- QuoteInline.add(this, boardID, threadID, postID, context);
- }
- return this.classList.toggle('inlined');
- },
- findRoot: function(quotelink, isBacklink) {
- if (isBacklink) {
- return quotelink.parentNode.parentNode;
- } else {
- return $.x('ancestor-or-self::*[parent::blockquote][1]', quotelink);
- }
- },
- add: function(quotelink, boardID, threadID, postID, context) {
- var inline, isBacklink, post;
-
- isBacklink = $.hasClass(quotelink, 'backlink');
- inline = $.el('div', {
- id: "i" + postID,
- className: 'inline'
- });
- $.after(QuoteInline.findRoot(quotelink, isBacklink), inline);
- Get.postClone(boardID, threadID, postID, inline, context);
- if (!((post = g.posts["" + boardID + "." + postID]) && context.thread === post.thread)) {
- return;
- }
- if (isBacklink && Conf['Forward Hiding']) {
- $.addClass(post.nodes.root, 'forwarded');
- post.forwarded++ || (post.forwarded = 1);
- }
- if (!Unread.posts) {
- return;
- }
- return Unread.readSinglePost(post);
- },
- rm: function(quotelink, boardID, threadID, postID, context) {
- var el, inlined, isBacklink, post, root, _ref;
-
- isBacklink = $.hasClass(quotelink, 'backlink');
- root = QuoteInline.findRoot(quotelink, isBacklink);
- root = $.x("following-sibling::div[@id='i" + postID + "'][1]", root);
- $.rm(root);
- if (!(el = root.firstElementChild)) {
- return;
- }
- post = g.posts["" + boardID + "." + postID];
- post.rmClone(el.dataset.clone);
- if (Conf['Forward Hiding'] && isBacklink && context.thread === g.threads["" + boardID + "." + threadID] && !--post.forwarded) {
- delete post.forwarded;
- $.rmClass(post.nodes.root, 'forwarded');
- }
- while (inlined = $('.inlined', el)) {
- _ref = Get.postDataFromLink(inlined), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
- QuoteInline.rm(inlined, boardID, threadID, postID, context);
- $.rmClass(inlined, 'inlined');
- }
+ post = this.dataset.clone ? Get.postFromNode(this) : g.posts[this.dataset.postid];
+ return Menu.menu.toggle(e, this, post);
}
};
- QuoteOP = {
+ ReportLink = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Mark OP Quotes']) {
+ var a;
+
+ if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Report Link']) {
return;
}
- if (Conf['Comment Expansion']) {
- ExpandComment.callbacks.push(this.node);
+ a = $.el('a', {
+ className: 'report-link',
+ href: 'javascript:;',
+ textContent: 'Report this post'
+ });
+ $.on(a, 'click', ReportLink.report);
+ return $.event('AddMenuEntry', {
+ type: 'post',
+ el: a,
+ order: 10,
+ open: function(post) {
+ ReportLink.post = post;
+ return !post.isDead;
+ }
+ });
+ },
+ report: function() {
+ var id, post, set, url;
+
+ post = ReportLink.post;
+ url = "//sys.4chan.org/" + post.board + "/imgboard.php?mode=report&no=" + post;
+ id = Date.now();
+ set = "toolbar=0,scrollbars=0,location=0,status=1,menubar=0,resizable=1,width=685,height=200";
+ return window.open(url, id, set);
+ }
+ };
+
+ Favicon = {
+ init: function() {
+ return $.ready(function() {
+ var href;
+
+ Favicon.el = $('link[rel="shortcut icon"]', d.head);
+ Favicon.el.type = 'image/x-icon';
+ href = Favicon.el.href;
+ Favicon.SFW = /ws\.ico$/.test(href);
+ Favicon["default"] = href;
+ return Favicon["switch"]();
+ });
+ },
+ "switch": function() {
+ switch (Conf['favicon']) {
+ case 'ferongr':
+ Favicon.unreadDead = 'data:image/gif;base64,R0lGODlhEAAQAOMHAOgLAnMFAL8AAOgLAukMA/+AgP+rq////////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
+ Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAS1BMVEUAAAAAAAAAAAAJAAASAAAZAQAaAQAiAQAkAQAoFBQyAgAzAgA1AgA4AABBAgBXAwBzBQCEBgGvCAG/AADoCwLpDAP/gID/q6v///9zILr8AAAAA3RSTlMAx9dmesIgAAAAc0lEQVQY02WPgQ6DIBBDmTqnbE70Cvb/v3TAnW5OSKB9ybXg3HUBOAmEEH4FQtrSn4gxi+xjVC9SVOEiSvbZI8zSV+/Xo7icnryZ15GObMxvtWUkB/VJW57kHU7fUcHStm8FkncGE/mwP6CGzq/eauHwvT7sWQt3gZLW+AAAAABJRU5ErkJggg==';
+ Favicon.unreadSFW = 'data:image/gif;base64,R0lGODlhEAAQAOMHAADX8QBwfgC2zADX8QDY8nnl8qLp8v///////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
+ Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAASFBMVEUAAAAAAAAAAAAACAkAERMAGBsAGR0AISUALzQALzUAMTcANjwAP0cAVF8AcH4AeokAorYAtswA1/EA2PISIyV55fKi6fL////l+pZqAAAAA3RSTlMAx9dmesIgAAAAcklEQVQY02VPARLCIAxjsjnUWdcg6/9/ukIr00nvIMldEhrC/wHwA0BE3wBUtnICOStQnrNx5oqqzmzKx9vDPH1Nae3F9U4ig3OzjCIX51treYvMxou13EQmBPtHE14xLiawjgoPtfgOaKHP+9VrEXA8O1v7CmSPE3u0AAAAAElFTkSuQmCC';
+ Favicon.unreadNSFW = 'data:image/gif;base64,R0lGODlhEAAQAOMHAFT+ACh5AEncAFT+AFX/Acz/su7/5v///////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
+ Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAS1BMVEUAAAAAAAAAAAADCgAGEgAIGgAJGwALJAANJwASNwASOAATOgAVQQAWRAAeWwAgKBsoeQAwkQA/wABJ3ABU/gBV/wHM/7Lu/+b////r+K2AAAAAA3RSTlMAx9dmesIgAAAAc0lEQVQY02WPgQ6DIBBDmTonbk70Cvb/v3TAnW5OSKB9ybXg3HUBOAmEEH4FQtrSn4gxi+xjVC9SVOEiSvbZI8zSV+/Xo7icnryZ15GObMxvtWUmB/VJW0byDqfvqGBp20mB5J3Bi3zYH1BD38/eauHwvT7sEAt1Fb320QAAAABJRU5ErkJggg==';
+ break;
+ case 'xat-':
+ Favicon.unreadDead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA2ElEQVQ4y61TQQrCMBDMQ8WDIEV6LbT2A4og2Hq0veo7fIAH04dY9N4xmyYlpGmI2MCQTWYy3Wy2DAD7B2wWAzWgcTgVeZKlZRxHNYFi2jM18oBh0IcKtC6ixf22WT4IFLs0owxswXu9egm0Ls6bwfCFfNsJYJKfqoEkd3vgUgFVLWObtzNgVKyruC+ljSzr5OEnBzjvjcQecaQhbZgBb4CmGQw+PoMkTUtdbd8VSEPakcGxPOcsoIgUKy0LecY29BmdBrqRfjIwZ93KLs5loHvBnL3cLH/jF+C/+z5dgUysAAAAAElFTkSuQmCC';
+ Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACKkJGNkpN0d3d0eHdra2dGRkORZ1wAAACmaV6naV4PDw8LCwsLCwvyZWLyZWIeExEyFBTAWlr/eHj/enkAAAAKAAAoAAA4AAA4GhpMAACRAAD/AAD/enn/h4j/m5z/nJ3/0dL/0tL/0tP/09P///9VK8WFAAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uZfI0YOdiiMiJw+2CKIPkZzGtcbgKYIJaI26LAfQOzOqoYNA4Z49Nguv/gEEhw2/C5BUZgAAAABJRU5ErkJggg==';
+ Favicon.unreadSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA30lEQVQ4y2P4//8/AyWYgSoGQMF/GJ7Y11VVUVoyKTM9ey4Ig9ggMWQ1YA1IBvzXm34YjkH8mPyJB+Nqlp8FYRAbmxoMF6ArSNrw6T0Qf8Amh9cFMEWVR/7/A+L/uORxhgEIt5/+/3/2lf//5wAxiI0uj+4CBlBgxVUvOwtydgXQZpDmi2/+/7/0GmIQSAwkB1IDUkuUAZeABlx+g2zAZ9wGlAOjChba+LwAUgNSi2HA5Am9VciBhSsQQWyoWgZiovEDsdGI1QBYQiLJAGQalpSxyWEzAJYWkGm8clTJjQCZ1hkoVG0CygAAAABJRU5ErkJggg==';
+ Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACRjoqTkI13dXR4dXRpZ2tFQ0Zcb5EAAABee6ZefKcPDw8LCwsLCwtisPJisPIRFh4UJDJalMB4xP95xP8AAAABBQcHFx4KISoNLToaKzgaVW4ul8N5xP+Hy/+b1P+c1P/R7P/S6//S7P/T7P////9P0rk0AAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uUrk6MFOxRGRkwdbBNGHSE7jWmPwFMEEtEZdlgPonRmvoYNA4Z49Nguv/gEE3A2/sQ7iRgAAAABJRU5ErkJggg==';
+ Favicon.unreadNSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA4ElEQVQ4y2P4//8/AyWYgSoGQMF/GJ7YNbGqrKRiUnp21lwQBrFBYshqwBqQDPifdsYYjkH8mInxB+OWx58FYRAbmxoMF6ArKPmU9B6IP2CTw+sCmKKe/5X/gPg/LnmcYQDCs/63/1/9fzYQzwGz0eXRXcAACqy4ZfFnQc7u+V/xD6T55v+LQHwJbBBIDCQHUgNSS5QBt4Cab/2/jDDgMx4DykrKJ8FCG58XQGpAajEMmNw7uQo5sHAFIogNVctATDR+IDYasRoAS0gkGYBMw5IyNjlsBsDSAjKNV44quREAx58Mr9vt5wQAAAAASUVORK5CYII=';
+ Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACRipGTjZN2dHd2dHhna2pDRkVckV8AAABepl9ep18PDw8LCwsLCwt08mJ08mIRHhEYMhRpwFqM/3iM/3kAAAAECAIQIAgWLAseOBoePA86dB1mzDOM/3ma/4er/5ur/5zZ/9HZ/9La/9La/9P///85Jx7jAAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uZfI0YOdiiMiJw+2CKIPkZzGtcbgKYIJaI26LAfQOzOqoYNA4Z49Nguv/gEEhw2/C5BUZgAAAABJRU5ErkJggg==';
+ break;
+ case 'Mayhem':
+ Favicon.unreadDead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABIUlEQVQ4jZ2ScWuDMBDFgw4pIkU0WsoQkWAYIkXZH4N9/+/V3dmfXSrKYIFHwt17j8vdGWNMIkgFuaDgzgQnwRs4EQs5KdolUQtagRN0givEDBTEOjgtGs0Zq8F7cKqqusVxrMQLaDUWcjBSrXkn8gs51tpJSWLk9b3HUa0aNIL5gPBR1/V4kJvR7lTwl8GmAm1Gf9+c3S+89qBHa8502AsmSrtBaEBPbIbj0ah2madlNAPEccdgJDfAtWifBjqWKShRBT6KoiH8QlEUn/qt0CCjnNdmPUwmFWzj9Oe6LpKuZXcwqq88z78Pch3aZU3dPwwc2sWlfZKCW5tWluV8kGvXClLm6dYN4/aUqfCbnEOzNDGhGZbNargvxCzvMGfRJD8UaDVvgkzo6QAAAABJRU5ErkJggg==';
+ Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABj0lEQVQ4y42TQUorQRCGv+oekpj43pOhOyIiKoHBxTMkuAnEtWcwx/AY3sUbBIRcwCw8gCfIMkaTOOUiNdgGRRuKoav+v2qq/i4BakBmXweUwDoxLF5ZhVkC64rYBHYMUAIvwKuBMEwdaFiCNbAAngEC0NHkxBi73vsOsG92HGPsphigY1wOzfNhqhpC6AEd730RQuh9hQEOAY6A/jeAs3a7/f+bWB84ckCpqg+I8Osjgqo+AKUDViJS8LkGMcY+sJrNZssYY387LiIFsBLgL9AC/pgaArzZlF+sZgO4BG7sfgvcA3MxUtOStBIpX7cS3Klqd9OBTIEr4DlLOsuAmqpODXQOiHMuy/O8FkLoJth/6Uh2gQPg87Q3k+7leX6hqnpmPvM/GWfXWeWGqj5+oUS9LMs6wF7iHAwGJ9ZW5uxpup+UGwEtEVoijEYjKl66PJujmvIW3vsFwBiYqzJXZTweY5wSU6Bd7UP1KoECODUrJpOJAtPhcKjAtXGaYptWs57qWyv9Zn/it1a5knj5Dm3v4q8APeACAAAAAElFTkSuQmCC';
+ Favicon.unreadSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABCElEQVQ4jZ2S4crCMAxF+0OGDJEPKYrIGKOsiJSx/fJRfSAfTJNyKqXfiuDg0C25N2RJjTGmEVrhTzhw7oStsIEtsVzT4o2Jo9ALThiEM8IdHIgNaHo8mjNWg6/ske8bohPo+63QOLzmooHp8fyAICBSQkVz0QKdsFQEV6WSW/D+7+BbgbIDHcb4Kp61XyjyI16zZ8JemGltQtDBSGxB4/GoN+7TpkkjDCsFArm0IYv3U0BbnYtf8BCy+JytsE0X6VyuKhPPK/GAJ14kvZZDZVV3pZIb8MZr6n4o4PDGKn0S5SdDmyq5PnXQsk+Xbhinp03FFzmHJw6xYRiWm9VxnohZ3vOcxdO8ARmXRvbWdtzQAAAAAElFTkSuQmCC';
+ Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAkFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OztMTEyRkZHBwcH///9dzWZ0AAAAI3RSTlMEBggKDA4QEhQWFxkbHR8hIyUmKCosLjAxN1hbYc7P0dLc3mzWzBUAAAC+SURBVBjTNY3pcsIwEIM3ePERx/bG5IIe0NIrhVbv/3Y4Ydj9Ic030ogqpY3mDdGGi1EVsYuSvGE2Pkl0TFYAdLGuY1eMWGowzzN6kX41DYVpNbvdKlO4Jx5gSbi2VO+Vcq2jrc/jNLQhtM+n05PfkrKxG/oFHIEXqwqQsVRy7n+AtwLYL3sYR3wA755Jp3Vvv8cn8Js0GXmA7/P5TwzpiLn8MOALuEZNygkm5JTy/+vl4BRVbJvQ1NbWRSxXN64PGOBlhG0qAAAAAElFTkSuQmCC';
+ Favicon.unreadNSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABCklEQVQ4jZ2S0WrDMAxF/TBCCKWMYhZKCSGYmFJMSNjD/mhf239qJXNcjBdTWODgRLpXKJKNMaYROuFTOHEehFb4gJZYrunwxsSXMApOmIQzwgOciE1oRjyaM1aDj+yR7xuiHvT9VmgcXnPRwO/9+wWCgEgJFc1FCwzCVhFclUpuw/u3g3cFyg50GPOjePZ+ocjPeM2RCXthpbUFwQAzsQ2Nx6PeuE+bJo0w7BQI5NKGLN5XAW11LX7BQ8jia7bCLl2kc7mqTLzuxAOeeJH0Wk6VVf0oldyEN15T948CDm+sMiZRfjK0pZIbUwcd+3TphnF62lR8kXN44hAbhmG5WQNnT8zynucsnuYJhFpBfkMzqD4AAAAASUVORK5CYII=';
+ Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAkFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztMTExmzDORkZHBwcH///92I3mvAAAAI3RSTlMEBggKDA4QEhQWFxkbHR8hIyUmKCosLjAxN1hbYc7P0dLc3mzWzBUAAAC+SURBVBjTNY3pcsIwEIM3ePERx/bG5IIe0NIT0ur93w4nDLs/pPlGGlGltNG8IdpwMaoidlGSN8zGJ4mOyQqALtZ17IoRSw3meUYv0q+moTCtZrdbZQr3xAMsCdeW6r1SrnW09XmchjaE9vl0evJbUjZ2Q7+AI/BiVQEylkrO/TfwVgD7ZQ/jiA/g3TPptO7t9/gEfpImIw/wez7/iSEdMZcfBnwB16hJOcGEnFL+f70cnKKKbROa2tq6iOXqBuMXGTe4CAUbAAAAAElFTkSuQmCC';
+ break;
+ case 'Original':
+ Favicon.unreadDead = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
+ Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAAKAAAoAAAoKCg4AAA4ODg7OztMAACRAADBwcH/AAD///+WCcPSAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQmAUAxEb4Isk0rwp3EPR3ECcRQrh7C3/nAasPwzmCgYuPBy5AH/NALSImqAK+H1oJRqyJVHNAnZqDITVhj7/PrAciJ9il0BHs/jjU+fnB9sQ0IxX6OBO6Xr0xKAxANLZzUanCWzZQAAAABJRU5ErkJggg==';
+ Favicon.unreadSFW = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAC6Xw////////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
+ Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OzvBwcH///8uS/CdAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQ2AUAhEbwKWoftRGvdwBEewchM7d9BFbE6pbP4Mgj+R5MjjwgP+qQSkRtQAV8K3lVI2Q648oknIRpWZsMI4988HjgvpU+wO8HgeHzR9cjZYhoRiPkcDd0rXpyUAiRd5YjKC7MvNRgAAAABJRU5ErkJggg==';
+ Favicon.unreadNSFW = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAGbMM////////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
+ Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztmzDPBwcH///+rsf3XAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQ2AUAhEbwKWofRL4x6O4AhuopWb2P4F7E5prP4MgiaSHHlceMA/jYC0iBrgSnjdKaUacuURTUI2qsyEFcaxvD6wnkifYleAx/N449Mn5wfbkFDM52jgTun6tAQg8QAEvjQg42KY2AAAAABJRU5ErkJggg==';
}
- this.text = '\u00A0(OP)';
- return Post.prototype.callbacks.push({
- name: 'Mark OP Quotes',
+ if (Favicon.SFW) {
+ Favicon.unread = Favicon.unreadSFW;
+ return Favicon.unreadY = Favicon.unreadSFWY;
+ } else {
+ Favicon.unread = Favicon.unreadNSFW;
+ return Favicon.unreadY = Favicon.unreadNSFWY;
+ }
+ },
+ empty: 'data:image/gif;base64,R0lGODlhEAAQAJEAAAAAAP///9vb2////yH5BAEAAAMALAAAAAAQABAAAAIvnI+pq+D9DBAUoFkPFnbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw==',
+ dead: 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAIALAAAAAAQABAAAAIvlI+pq+D9DAgUoFkPDlbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw=='
+ };
+
+ ThreadExcerpt = {
+ init: function() {
+ if (g.VIEW !== 'thread' || !Conf['Thread Excerpt']) {
+ return;
+ }
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Excerpt',
cb: this.node
});
},
node: function() {
- var boardID, op, postID, quotelink, quotelinks, quotes, _i, _j, _len, _len1, _ref;
-
- if (this.isClone && this.thread === this.context.thread) {
- return;
- }
- if (!(quotes = this.quotes).length) {
- return;
- }
- quotelinks = this.nodes.quotelinks;
- if (this.isClone && quotes.contains(this.thread.fullID)) {
- for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
- quotelink = quotelinks[_i];
- quotelink.textContent = quotelink.textContent.replace(QuoteOP.text, '');
- }
- }
- op = (this.isClone ? this.context : this).thread.fullID;
- if (!quotes.contains(op)) {
- return;
- }
- for (_j = 0, _len1 = quotelinks.length; _j < _len1; _j++) {
- quotelink = quotelinks[_j];
- _ref = Get.postDataFromLink(quotelink), boardID = _ref.boardID, postID = _ref.postID;
- if (("" + boardID + "." + postID) === op) {
- $.add(quotelink, $.tn(QuoteOP.text));
- }
- }
+ return d.title = Get.threadExcerpt(this);
}
};
- QuotePreview = {
+ ThreadStats = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Quote Previewing']) {
+ var sc;
+
+ if (g.VIEW !== 'thread' || !Conf['Thread Stats']) {
return;
}
- if (Conf['Comment Expansion']) {
- ExpandComment.callbacks.push(this.node);
- }
- return Post.prototype.callbacks.push({
- name: 'Quote Previewing',
+ this.dialog = sc = $.el('span', {
+ innerHTML: "0 / 0",
+ id: 'thread-stats'
+ });
+ this.postCountEl = $('#post-count', sc);
+ this.fileCountEl = $('#file-count', sc);
+ Header.addShortcut(sc);
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Stats',
cb: this.node
});
},
node: function() {
- var link, _i, _len, _ref;
+ var ID, fileCount, post, postCount, _ref;
- _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- link = _ref[_i];
- $.on(link, 'mouseover', QuotePreview.mouseover);
+ postCount = 0;
+ fileCount = 0;
+ _ref = this.posts;
+ for (ID in _ref) {
+ post = _ref[ID];
+ postCount++;
+ if (post.file) {
+ fileCount++;
+ }
}
+ ThreadStats.thread = this;
+ ThreadStats.update(postCount, fileCount);
+ return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate);
},
- mouseover: function(e) {
- var boardID, clone, origin, post, postID, posts, qp, quote, quoterID, threadID, _i, _j, _len, _len1, _ref, _ref1;
+ onUpdate: function(e) {
+ var fileCount, postCount, _ref;
- if ($.hasClass(this, 'inlined')) {
+ if (e.detail[404]) {
return;
}
- _ref = Get.postDataFromLink(this), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
- qp = $.el('div', {
- id: 'qp',
- className: 'dialog'
- });
- $.add(Header.hover, qp);
- Get.postClone(boardID, threadID, postID, qp, Get.contextFromLink(this));
- UI.hover({
- root: this,
- el: qp,
- latestEvent: e,
- endEvents: 'mouseout click',
- cb: QuotePreview.mouseout,
- asapTest: function() {
- return qp.firstElementChild;
- }
- });
- if (!(origin = g.posts["" + boardID + "." + postID])) {
- return;
- }
- if (Conf['Quote Highlighting']) {
- posts = [origin].concat(origin.clones);
- posts.pop();
- for (_i = 0, _len = posts.length; _i < _len; _i++) {
- post = posts[_i];
- $.addClass(post.nodes.post, 'qphl');
- }
- }
- quoterID = $.x('ancestor::*[@id][1]', this).id.match(/\d+$/)[0];
- clone = Get.postFromRoot(qp.firstChild);
- _ref1 = clone.nodes.quotelinks.concat(__slice.call(clone.nodes.backlinks));
- for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
- quote = _ref1[_j];
- if (quote.hash.slice(2) === quoterID) {
- $.addClass(quote, 'forwardlink');
- }
- }
+ _ref = e.detail, postCount = _ref.postCount, fileCount = _ref.fileCount;
+ return ThreadStats.update(postCount, fileCount);
},
- mouseout: function() {
- var clone, post, root, _i, _len, _ref;
+ update: function(postCount, fileCount) {
+ var fileCountEl, postCountEl, thread;
- if (!(root = this.el.firstElementChild)) {
- return;
- }
- clone = Get.postFromRoot(root);
- post = clone.origin;
- post.rmClone(root.dataset.clone);
- if (!Conf['Quote Highlighting']) {
- return;
- }
- _ref = [post].concat(post.clones);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- post = _ref[_i];
- $.rmClass(post.nodes.post, 'qphl');
- }
+ thread = ThreadStats.thread, postCountEl = ThreadStats.postCountEl, fileCountEl = ThreadStats.fileCountEl;
+ postCountEl.textContent = postCount;
+ fileCountEl.textContent = fileCount;
+ (thread.postLimit && !thread.isSticky ? $.addClass : $.rmClass)(postCountEl, 'warning');
+ return (thread.fileLimit && !thread.isSticky ? $.addClass : $.rmClass)(fileCountEl, 'warning');
}
};
- /*
- <3 aeosynth
- */
-
-
- QuoteThreading = {
+ ThreadUpdater = {
init: function() {
- var input;
+ var checked, conf, el, input, name, sc, settings, subEntries, _ref;
- if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
+ if (g.VIEW !== 'thread' || !Conf['Thread Updater']) {
return;
}
- this.enabled = true;
- this.controls = $.el('span', {
- innerHTML: ''
+ checked = Conf['Auto Update'] ? 'checked' : '';
+ this.dialog = sc = $.el('span', {
+ innerHTML: "",
+ id: 'updater'
+ });
+ this.timer = $('#update-timer', sc);
+ this.status = $('#update-status', sc);
+ $.on(this.timer, 'click', ThreadUpdater.update);
+ $.on(this.status, 'click', ThreadUpdater.update);
+ this.checkPostCount = 0;
+ Header.addShortcut(sc);
+ subEntries = [];
+ _ref = Config.updater.checkbox;
+ for (name in _ref) {
+ conf = _ref[name];
+ checked = Conf[name] ? 'checked' : '';
+ el = $.el('label', {
+ title: "" + conf[1],
+ innerHTML: " " + name
+ });
+ input = el.firstElementChild;
+ $.on(input, 'change', $.cb.checked);
+ if (input.name === 'Scroll BG') {
+ $.on(input, 'change', ThreadUpdater.cb.scrollBG);
+ ThreadUpdater.cb.scrollBG();
+ }
+ subEntries.push({
+ el: el
+ });
+ }
+ settings = $.el('span', {
+ innerHTML: 'Interval'
+ });
+ $.on(settings, 'click', this.intervalShortcut);
+ subEntries.push({
+ el: settings
});
- input = $('input', this.controls);
- $.on(input, 'change', QuoteThreading.toggle);
$.event('AddMenuEntry', {
type: 'header',
- el: this.controls,
- order: 98
+ el: $.el('span', {
+ textContent: 'Updater'
+ }),
+ order: 110,
+ subEntries: subEntries
});
- $.on(d, '4chanXInitFinished', this.setup);
- return Post.prototype.callbacks.push({
- name: 'Quote Threading',
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Updater',
cb: this.node
});
},
- setup: function() {
- var ID, post, posts;
-
- $.off(d, '4chanXInitFinished', QuoteThreading.setup);
- posts = g.posts;
- for (ID in posts) {
- post = posts[ID];
- if (post.cb) {
- post.cb.call(post);
- }
- }
- return QuoteThreading.hasRun = true;
- },
node: function() {
- var ID, fullID, keys, len, post, posts, qid, quote, quotes, uniq, _i, _len;
+ ThreadUpdater.thread = this;
+ ThreadUpdater.root = this.OP.nodes.root.parentNode;
+ ThreadUpdater.lastPost = +ThreadUpdater.root.lastElementChild.id.match(/\d+/)[0];
+ ThreadUpdater.outdateCount = 0;
+ ThreadUpdater.lastModified = '0';
+ ThreadUpdater.cb.interval.call($.el('input', {
+ value: Conf['Interval']
+ }));
+ $.on(window, 'online offline', ThreadUpdater.cb.online);
+ $.on(d, 'QRPostSuccessful', ThreadUpdater.cb.post);
+ $.on(d, 'visibilitychange', ThreadUpdater.cb.visibility);
+ return ThreadUpdater.cb.online();
+ },
+ /*
+ http://freesound.org/people/pierrecartoons1979/sounds/90112/
+ cc-by-nc-3.0
+ */
- if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) {
+ beep: 'data:audio/wav;base64,UklGRjQDAABXQVZFZm10IBAAAAABAAEAgD4AAIA+AAABAAgAc21wbDwAAABBAAADAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkYXRhzAIAAGMms8em0tleMV4zIpLVo8nhfSlcPR102Ki+5JspVEkdVtKzs+K1NEhUIT7DwKrcy0g6WygsrM2k1NpiLl0zIY/WpMrjgCdbPhxw2Kq+5Z4qUkkdU9K1s+K5NkVTITzBwqnczko3WikrqM+l1NxlLF0zIIvXpsnjgydZPhxs2ay95aIrUEkdUdC3suK8N0NUIjq+xKrcz002WioppdGm091pK1w0IIjYp8jkhydXPxxq2K295aUrTkoeTs65suK+OUFUIzi7xqrb0VA0WSoootKm0t5tKlo1H4TYqMfkiydWQBxm16+85actTEseS8y7seHAPD9TIza5yKra01QyWSson9On0d5wKVk2H4DYqcfkjidUQB1j1rG75KsvSkseScu8seDCPz1TJDW2yara1FYxWSwnm9Sn0N9zKVg2H33ZqsXkkihSQR1g1bK65K0wSEsfR8i+seDEQTxUJTOzy6rY1VowWC0mmNWoz993KVc3H3rYq8TklSlRQh1d1LS647AyR0wgRMbAsN/GRDpTJTKwzKrX1l4vVy4lldWpzt97KVY4IXbUr8LZljVPRCxhw7W3z6ZISkw1VK+4sMWvXEhSPk6buay9sm5JVkZNiLWqtrJ+TldNTnquqbCwilZXU1BwpKirrpNgWFhTaZmnpquZbFlbVmWOpaOonHZcXlljhaGhpZ1+YWBdYn2cn6GdhmdhYGN3lp2enIttY2Jjco+bnJuOdGZlZXCImJqakHpoZ2Zug5WYmZJ/bGlobX6RlpeSg3BqaW16jZSVkoZ0bGtteImSk5KIeG5tbnaFkJKRinxxbm91gY2QkIt/c3BwdH6Kj4+LgnZxcXR8iI2OjIR5c3J0e4WLjYuFe3VzdHmCioyLhn52dHR5gIiKioeAeHV1eH+GiYqHgXp2dnh9hIiJh4J8eHd4fIKHiIeDfXl4eHyBhoeHhH96eHmA',
+ cb: {
+ online: function() {
+ if (ThreadUpdater.online = navigator.onLine) {
+ ThreadUpdater.outdateCount = 0;
+ ThreadUpdater.set('timer', ThreadUpdater.getInterval());
+ ThreadUpdater.update();
+ ThreadUpdater.set('status', null, null);
+ } else {
+ ThreadUpdater.set('timer', null);
+ ThreadUpdater.set('status', 'Offline', 'warning');
+ }
+ return ThreadUpdater.cb.autoUpdate();
+ },
+ post: function(e) {
+ if (e.detail.threadID !== ThreadUpdater.thread.ID) {
+ return;
+ }
+ ThreadUpdater.outdateCount = 0;
+ if (ThreadUpdater.seconds > 2) {
+ return setTimeout(ThreadUpdater.update, 1000);
+ }
+ },
+ checkpost: function() {
+ if (!(g.DEAD || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 10)) {
+ return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * 500);
+ }
+ ThreadUpdater.checkPostCount = 0;
+ delete ThreadUpdater.foundPost;
+ return delete ThreadUpdater.postID;
+ },
+ visibility: function() {
+ if (d.hidden) {
+ return;
+ }
+ ThreadUpdater.outdateCount = 0;
+ if (ThreadUpdater.seconds > ThreadUpdater.interval) {
+ return ThreadUpdater.set('timer', ThreadUpdater.getInterval());
+ }
+ },
+ scrollBG: function() {
+ return ThreadUpdater.scrollBG = Conf['Scroll BG'] ? function() {
+ return true;
+ } : function() {
+ return !d.hidden;
+ };
+ },
+ autoUpdate: function() {
+ if (ThreadUpdater.online) {
+ return ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
+ } else {
+ return clearTimeout(ThreadUpdater.timeoutID);
+ }
+ },
+ interval: function() {
+ var val;
+
+ val = +this.value;
+ if (val < 1) {
+ val = 1;
+ }
+ ThreadUpdater.interval = this.value = val;
+ return $.cb.value.call(this);
+ },
+ load: function() {
+ var klass, req, text, _ref;
+
+ req = ThreadUpdater.req;
+ switch (req.status) {
+ case 200:
+ g.DEAD = false;
+ ThreadUpdater.parse(JSON.parse(req.response).posts);
+ ThreadUpdater.lastModified = req.getResponseHeader('Last-Modified');
+ ThreadUpdater.set('timer', ThreadUpdater.getInterval());
+ break;
+ case 404:
+ g.DEAD = true;
+ ThreadUpdater.set('timer', null);
+ ThreadUpdater.set('status', '404', 'warning');
+ clearTimeout(ThreadUpdater.timeoutID);
+ ThreadUpdater.thread.kill();
+ $.event('ThreadUpdate', {
+ 404: true,
+ thread: ThreadUpdater.thread
+ });
+ break;
+ default:
+ ThreadUpdater.outdateCount++;
+ ThreadUpdater.set('timer', ThreadUpdater.getInterval());
+ /*
+ Status Code 304: Not modified
+ By sending the `If-Modified-Since` header we get a proper status code, and no response.
+ This saves bandwidth for both the user and the servers and avoid unnecessary computation.
+ */
+
+ _ref = [0, 304].contains(req.status) ? [null, null] : ["" + req.statusText + " (" + req.status + ")", 'warning'], text = _ref[0], klass = _ref[1];
+ ThreadUpdater.set('status', text, klass);
+ }
+ if (ThreadUpdater.postID) {
+ ThreadUpdater.cb.checkpost(this.status);
+ }
+ return delete ThreadUpdater.req;
+ }
+ },
+ getInterval: function() {
+ var i, j;
+
+ i = ThreadUpdater.interval;
+ j = Math.min(ThreadUpdater.outdateCount, 10);
+ if (!d.hidden) {
+ j = Math.min(j, 7);
+ }
+ return ThreadUpdater.seconds = Conf['Optional Increase'] ? Math.max(i, [0, 5, 10, 15, 20, 30, 60, 90, 120, 240, 300][j]) : i;
+ },
+ intervalShortcut: function() {
+ var settings;
+
+ Settings.open('Advanced');
+ settings = $.id('fourchanx-settings');
+ return $('input[name=Interval]', settings).focus();
+ },
+ set: function(name, text, klass) {
+ var el, node;
+
+ el = ThreadUpdater[name];
+ if (node = el.firstChild) {
+ node.data = text;
+ } else {
+ el.textContent = text;
+ }
+ if (klass !== void 0) {
+ return el.className = klass;
+ }
+ },
+ timeout: function() {
+ var n;
+
+ ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
+ if (!(n = --ThreadUpdater.seconds)) {
+ return ThreadUpdater.update();
+ } else if (n <= -60) {
+ ThreadUpdater.set('status', 'Retrying', null);
+ return ThreadUpdater.update();
+ } else if (n > 0) {
+ return ThreadUpdater.set('timer', n);
+ }
+ },
+ update: function() {
+ var url;
+
+ if (!ThreadUpdater.online) {
return;
}
- quotes = this.quotes, ID = this.ID, fullID = this.fullID;
- posts = g.posts;
- if (!(post = posts[fullID]) || post.isHidden) {
+ ThreadUpdater.seconds = 0;
+ ThreadUpdater.set('timer', '...');
+ if (ThreadUpdater.req) {
+ ThreadUpdater.req.onloadend = null;
+ ThreadUpdater.req.abort();
+ }
+ url = "//api.4chan.org/" + ThreadUpdater.thread.board + "/res/" + ThreadUpdater.thread + ".json";
+ return ThreadUpdater.req = $.ajax(url, {
+ onloadend: ThreadUpdater.cb.load
+ }, {
+ headers: {
+ 'If-Modified-Since': ThreadUpdater.lastModified
+ }
+ });
+ },
+ updateThreadStatus: function(title, OP) {
+ var icon, message, root, titleLC;
+
+ titleLC = title.toLowerCase();
+ if (ThreadUpdater.thread["is" + title] === !!OP[titleLC]) {
return;
}
- uniq = {};
- len = ("" + g.BOARD).length + 1;
- for (_i = 0, _len = quotes.length; _i < _len; _i++) {
- quote = quotes[_i];
- qid = quote;
- if (!(qid.slice(len) < ID)) {
+ if (!(ThreadUpdater.thread["is" + title] = !!OP[titleLC])) {
+ message = title === 'Sticky' ? 'The thread is not a sticky anymore.' : 'The thread is not closed anymore.';
+ new Notification('info', message, 30);
+ $.rm($("." + titleLC + "Icon", ThreadUpdater.thread.OP.nodes.info));
+ return;
+ }
+ message = title === 'Sticky' ? 'The thread is now a sticky.' : 'The thread is now closed.';
+ new Notification('info', message, 30);
+ icon = $.el('img', {
+ src: "//static.4chan.org/image/" + titleLC + ".gif",
+ alt: title,
+ title: title,
+ className: "" + titleLC + "Icon"
+ });
+ root = $('[title="Quote this post"]', ThreadUpdater.thread.OP.nodes.info);
+ if (title === 'Closed') {
+ root = $('.stickyIcon', ThreadUpdater.thread.OP.nodes.info) || root;
+ }
+ return $.after(root, [$.tn(' '), icon]);
+ },
+ parse: function(postObjects) {
+ var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, scroll, _i, _len, _ref;
+
+ OP = postObjects[0];
+ Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
+ ThreadUpdater.updateThreadStatus('Sticky', OP);
+ ThreadUpdater.updateThreadStatus('Closed', OP);
+ ThreadUpdater.thread.postLimit = !!OP.bumplimit;
+ ThreadUpdater.thread.fileLimit = !!OP.imagelimit;
+ posts = [];
+ index = [];
+ files = [];
+ count = 0;
+ for (_i = 0, _len = postObjects.length; _i < _len; _i++) {
+ postObject = postObjects[_i];
+ num = postObject.no;
+ index.push(num);
+ if (postObject.fsize) {
+ files.push(num);
+ }
+ if (num <= ThreadUpdater.lastPost) {
continue;
}
- if (qid in posts) {
- uniq[qid.slice(len)] = true;
+ count++;
+ node = Build.postFromObject(postObject, ThreadUpdater.thread.board);
+ posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
+ }
+ deletedPosts = [];
+ deletedFiles = [];
+ _ref = ThreadUpdater.thread.posts;
+ for (ID in _ref) {
+ post = _ref[ID];
+ ID = +ID;
+ if (post.isDead && index.contains(ID)) {
+ post.resurrect();
+ } else if (!index.contains(ID)) {
+ post.kill();
+ deletedPosts.push(post);
+ } else if (post.file && !post.file.isDead && !files.contains(ID)) {
+ post.kill(true);
+ deletedFiles.push(post);
+ }
+ if (ThreadUpdater.postID) {
+ if (ID === ThreadUpdater.postID) {
+ ThreadUpdater.foundPost = true;
+ }
}
}
- keys = Object.keys(uniq);
- if (keys.length !== 1) {
+ if (!count) {
+ ThreadUpdater.set('status', null, null);
+ ThreadUpdater.outdateCount++;
+ } else {
+ ThreadUpdater.set('status', "+" + count, 'new');
+ ThreadUpdater.outdateCount = 0;
+ if (Conf['Beep'] && d.hidden && Unread.posts && !Unread.posts.length) {
+ if (!ThreadUpdater.audio) {
+ ThreadUpdater.audio = $.el('audio', {
+ src: ThreadUpdater.beep
+ });
+ }
+ ThreadUpdater.audio.play();
+ }
+ ThreadUpdater.lastPost = posts[count - 1].ID;
+ Main.callbackNodes(Post, posts);
+ scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25;
+ for (key in posts) {
+ post = posts[key];
+ if (!posts.hasOwnProperty(key)) {
+ continue;
+ }
+ if (post.cb) {
+ if (!post.cb.call(post)) {
+ $.add(ThreadUpdater.root, post.nodes.root);
+ }
+ } else {
+ $.add(ThreadUpdater.root, post.nodes.root);
+ }
+ }
+ if (scroll) {
+ if (Conf['Bottom Scroll']) {
+ doc.scrollTop = d.body.clientHeight;
+ } else {
+ Header.scrollToPost(nodes[0]);
+ }
+ }
+ $.queueTask(function() {
+ var length, threadID;
+
+ threadID = ThreadUpdater.thread.ID;
+ length = $$('.thread > .postContainer', ThreadUpdater.root).length;
+ return Fourchan.parseThread(threadID, length - count, length);
+ });
+ }
+ return $.event('ThreadUpdate', {
+ 404: false,
+ thread: ThreadUpdater.thread,
+ newPosts: posts,
+ deletedPosts: deletedPosts,
+ deletedFiles: deletedFiles,
+ postCount: OP.replies + 1,
+ fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead)
+ });
+ }
+ };
+
+ ThreadWatcher = {
+ init: function() {
+ if (!Conf['Thread Watcher']) {
return;
}
- this.threaded = "" + g.BOARD + "." + keys[0];
- return this.cb = QuoteThreading.nodeinsert;
+ this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', 'Thread Watcher
');
+ $.on(d, 'QRPostSuccessful', this.cb.post);
+ $.on(d, '4chanXInitFinished', this.ready);
+ $.sync('WatchedThreads', this.refresh);
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Watcher',
+ cb: this.node
+ });
},
- nodeinsert: function() {
- var bottom, height, posts, qpost, qroot, threadContainer, top, _ref;
+ node: function() {
+ var favicon,
+ _this = this;
- posts = g.posts;
- qpost = posts[this.threaded];
- delete this.threaded;
- delete this.cb;
- if (this.thread.OP === qpost) {
- return false;
+ favicon = $.el('img', {
+ className: 'favicon'
+ });
+ $.on(favicon, 'click', ThreadWatcher.cb.toggle);
+ $.before($('input', this.OP.nodes.post), favicon);
+ if (g.VIEW !== 'thread') {
+ return;
}
- if (QuoteThreading.hasRun) {
- height = doc.clientHeight;
- _ref = qpost.nodes.root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top;
- if (!(Unread.posts.contains(qpost) || ((bottom < height) && (top > 0)))) {
+ return $.get('AutoWatch', 0, function(item) {
+ if (item['AutoWatch'] !== _this.ID) {
+ return;
+ }
+ ThreadWatcher.watch(_this);
+ return $["delete"]('AutoWatch');
+ });
+ },
+ ready: function() {
+ $.off(d, '4chanXInitFinished', ThreadWatcher.ready);
+ if (!Main.isThisPageLegit()) {
+ return;
+ }
+ ThreadWatcher.refresh();
+ return $.add(d.body, ThreadWatcher.dialog);
+ },
+ refresh: function(watched) {
+ var ID, board, div, favicon, id, link, nodes, props, thread, x, _ref, _ref1;
+
+ if (!watched) {
+ $.get('WatchedThreads', {}, function(item) {
+ return ThreadWatcher.refresh(item['WatchedThreads']);
+ });
+ return;
+ }
+ nodes = [$('.move', ThreadWatcher.dialog)];
+ for (board in watched) {
+ _ref = watched[board];
+ for (id in _ref) {
+ props = _ref[id];
+ x = $.el('a', {
+ textContent: '×',
+ href: 'javascript:;'
+ });
+ $.on(x, 'click', ThreadWatcher.cb.x);
+ link = $.el('a', props);
+ link.title = link.textContent;
+ div = $.el('div');
+ $.add(div, [x, $.tn(' '), link]);
+ nodes.push(div);
+ }
+ }
+ $.rmAll(ThreadWatcher.dialog);
+ $.add(ThreadWatcher.dialog, nodes);
+ watched = watched[g.BOARD] || {};
+ _ref1 = g.BOARD.threads;
+ for (ID in _ref1) {
+ thread = _ref1[ID];
+ favicon = $('.favicon', thread.OP.nodes.post);
+ favicon.src = ID in watched ? Favicon["default"] : Favicon.empty;
+ }
+ },
+ cb: {
+ toggle: function() {
+ return ThreadWatcher.toggle(Get.postFromNode(this).thread);
+ },
+ x: function() {
+ var thread;
+
+ thread = this.nextElementSibling.pathname.split('/');
+ return ThreadWatcher.unwatch(thread[1], thread[3]);
+ },
+ post: function(e) {
+ var board, postID, threadID, _ref;
+
+ _ref = e.detail, board = _ref.board, postID = _ref.postID, threadID = _ref.threadID;
+ if (postID === threadID) {
+ if (Conf['Auto Watch']) {
+ return $.set('AutoWatch', threadID);
+ }
+ } else if (Conf['Auto Watch Reply']) {
+ return ThreadWatcher.watch(board.threads[threadID]);
+ }
+ }
+ },
+ toggle: function(thread) {
+ if ($('.favicon', thread.OP.nodes.post).src === Favicon.empty) {
+ return ThreadWatcher.watch(thread);
+ } else {
+ return ThreadWatcher.unwatch(thread.board, thread.ID);
+ }
+ },
+ unwatch: function(board, threadID) {
+ return $.get('WatchedThreads', {}, function(item) {
+ var watched;
+
+ watched = item['WatchedThreads'];
+ delete watched[board][threadID];
+ if (!Object.keys(watched[board]).length) {
+ delete watched[board];
+ }
+ ThreadWatcher.refresh(watched);
+ return $.set('WatchedThreads', watched);
+ });
+ },
+ watch: function(thread) {
+ return $.get('WatchedThreads', {}, function(item) {
+ var watched, _name;
+
+ watched = item['WatchedThreads'];
+ watched[_name = thread.board] || (watched[_name] = {});
+ watched[thread.board][thread] = {
+ href: "/" + thread.board + "/res/" + thread,
+ textContent: Get.threadExcerpt(thread)
+ };
+ ThreadWatcher.refresh(watched);
+ return $.set('WatchedThreads', watched);
+ });
+ }
+ };
+
+ Unread = {
+ init: function() {
+ if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon']) {
+ return;
+ }
+ this.db = new DataBoard('lastReadPosts', this.sync);
+ this.hr = $.el('hr', {
+ id: 'unread-line'
+ });
+ this.posts = [];
+ this.postsQuotingYou = [];
+ return Thread.prototype.callbacks.push({
+ name: 'Unread',
+ cb: this.node
+ });
+ },
+ node: function() {
+ Unread.thread = this;
+ Unread.title = d.title;
+ Unread.lastReadPost = Unread.db.get({
+ boardID: this.board.ID,
+ threadID: this.ID,
+ defaultValue: 0
+ });
+ $.on(d, '4chanXInitFinished', Unread.ready);
+ $.on(d, 'ThreadUpdate', Unread.onUpdate);
+ $.on(d, 'scroll visibilitychange', Unread.read);
+ if (Conf['Unread Line']) {
+ $.on(d, 'visibilitychange', Unread.setLine);
+ }
+ if (Conf['Scroll to Last Read Post']) {
+ return $.on(window, 'load', Unread.scroll);
+ }
+ },
+ ready: function() {
+ var ID, post, posts, _ref;
+
+ $.off(d, '4chanXInitFinished', Unread.ready);
+ posts = [];
+ _ref = Unread.thread.posts;
+ for (ID in _ref) {
+ post = _ref[ID];
+ if (post.isReply) {
+ posts.push(post);
+ }
+ }
+ return Unread.addPosts(posts);
+ },
+ scroll: function() {
+ var hash, post, posts, prevID, root;
+
+ if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
+ return;
+ }
+ if (Unread.posts.length) {
+ prevID = 0;
+ while (root = $.x('preceding-sibling::div[contains(@class,"postContainer")][1]', Unread.posts[0].nodes.root)) {
+ post = Get.postFromRoot(root);
+ if (prevID === post.ID) {
+ break;
+ }
+ prevID = post.ID;
+ if (!post.isHidden) {
+ break;
+ }
+ }
+ root.scrollIntoView(false);
+ return;
+ }
+ posts = Object.keys(Unread.thread.posts);
+ return Header.scrollToPost(Unread.thread.posts[posts[posts.length - 1]].nodes.root);
+ },
+ sync: function() {
+ var lastReadPost;
+
+ lastReadPost = Unread.db.get({
+ boardID: Unread.thread.board.ID,
+ threadID: Unread.thread.ID,
+ defaultValue: 0
+ });
+ if (!(Unread.lastReadPost < lastReadPost)) {
+ return;
+ }
+ Unread.lastReadPost = lastReadPost;
+ Unread.readArray(Unread.posts);
+ Unread.readArray(Unread.postsQuotingYou);
+ Unread.setLine();
+ return Unread.update();
+ },
+ addPosts: function(newPosts) {
+ var ID, data, post, _i, _len;
+
+ for (_i = 0, _len = newPosts.length; _i < _len; _i++) {
+ post = newPosts[_i];
+ ID = post.ID;
+ if (ID <= Unread.lastReadPost || post.isHidden) {
+ continue;
+ }
+ if (QR.db) {
+ data = {
+ boardID: post.board.ID,
+ threadID: post.thread.ID,
+ postID: post.ID
+ };
+ if (QR.db.get(data)) {
+ continue;
+ }
+ }
+ Unread.posts.push(post);
+ Unread.addPostQuotingYou(post);
+ }
+ if (Conf['Unread Line']) {
+ Unread.setLine(newPosts.contains(Unread.posts[0]));
+ }
+ Unread.read();
+ return Unread.update();
+ },
+ addPostQuotingYou: function(post) {
+ var quotelink, _i, _len, _ref;
+
+ if (!QR.db) {
+ return;
+ }
+ _ref = post.nodes.quotelinks;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ quotelink = _ref[_i];
+ if (QR.db.get(Get.postDataFromLink(quotelink))) {
+ Unread.postsQuotingYou.push(post);
+ }
+ }
+ },
+ onUpdate: function(e) {
+ if (e.detail[404]) {
+ return Unread.update();
+ } else {
+ return Unread.addPosts(e.detail.newPosts);
+ }
+ },
+ readSinglePost: function(post) {
+ var i;
+
+ if ((i = Unread.posts.indexOf(post)) === -1) {
+ return;
+ }
+ Unread.posts.splice(i, 1);
+ if (i === 0) {
+ Unread.lastReadPost = post.ID;
+ Unread.saveLastReadPost();
+ }
+ if ((i = Unread.postsQuotingYou.indexOf(post)) !== -1) {
+ Unread.postsQuotingYou.splice(i, 1);
+ }
+ return Unread.update();
+ },
+ readArray: function(arr) {
+ var i, post, _i, _len;
+
+ for (i = _i = 0, _len = arr.length; _i < _len; i = ++_i) {
+ post = arr[i];
+ if (post.ID > Unread.lastReadPost) {
+ break;
+ }
+ }
+ return arr.splice(0, i);
+ },
+ read: $.debounce(50, function(e) {
+ var ID, bottom, height, i, post, posts, read;
+
+ if (d.hidden || !Unread.posts.length) {
+ return;
+ }
+ height = doc.clientHeight;
+ posts = Unread.posts;
+ read = [];
+ i = posts.length;
+ while (post = posts[--i]) {
+ bottom = post.nodes.root.getBoundingClientRect().bottom;
+ if (bottom < height) {
+ ID = post.ID;
+ posts.remove(post);
+ }
+ }
+ if (!ID) {
+ return;
+ }
+ Unread.lastReadPost = ID;
+ Unread.saveLastReadPost();
+ Unread.readArray(Unread.postsQuotingYou);
+ if (e) {
+ return Unread.update();
+ }
+ }),
+ saveLastReadPost: $.debounce(2 * $.SECOND, function() {
+ return Unread.db.set({
+ boardID: Unread.thread.board.ID,
+ threadID: Unread.thread.ID,
+ val: Unread.lastReadPost
+ });
+ }),
+ setLine: function(force) {
+ var post, root;
+
+ if (!(d.hidden || force === true)) {
+ return;
+ }
+ if (post = Unread.posts[0]) {
+ root = post.nodes.root;
+ if (root !== $('.thread > .replyContainer', root.parentNode)) {
+ return $.before(root, Unread.hr);
+ }
+ } else {
+ return $.rm(Unread.hr);
+ }
+ },
+ update: function() {
+ var count;
+
+ count = Unread.posts.length;
+ if (Conf['Unread Count']) {
+ d.title = "" + (count || !Conf['Hide Unread Count at (0)'] ? "(" + count + ") " : '') + (g.DEAD ? "/" + g.BOARD + "/ - 404" : "" + Unread.title);
+ }
+ if (!Conf['Unread Favicon']) {
+ return;
+ }
+ Favicon.el.href = g.DEAD ? Unread.postsQuotingYou.length ? Favicon.unreadDeadY : count ? Favicon.unreadDead : Favicon.dead : count ? Unread.postsQuotingYou.length ? Favicon.unreadY : Favicon.unread : Favicon["default"];
+ return $.add(d.head, Favicon.el);
+ }
+ };
+
+ Redirect = {
+ init: function() {
+ return $.sync('archs', this.updateArchives);
+ },
+ updateArchives: function() {
+ return $.get('archivers', {}, function(_arg) {
+ var archivers;
+
+ archivers = _arg.archivers;
+ return Conf['archivers'] = archivers;
+ });
+ },
+ image: function(boardID, filename) {
+ switch (boardID) {
+ case 'a':
+ case 'gd':
+ case 'jp':
+ case 'm':
+ case 'q':
+ case 'tg':
+ case 'vg':
+ case 'vp':
+ case 'vr':
+ case 'wsg':
+ return "//archive.foolz.us/" + boardID + "/full_image/" + filename;
+ case 'u':
+ return "//nsfw.foolz.us/" + boardID + "/full_image/" + filename;
+ case 'po':
+ return "//archive.thedarkcave.org/" + boardID + "/full_image/" + filename;
+ case 'hr':
+ case 'tv':
+ return "http://archive.4plebs.org/" + boardID + "/full_image/" + filename;
+ case 'ck':
+ case 'fa':
+ case 'lit':
+ case 's4s':
+ return "//fuuka.warosu.org/" + boardID + "/full_image/" + filename;
+ case 'cgl':
+ case 'g':
+ case 'mu':
+ case 'w':
+ return "//rbt.asia/" + boardID + "/full_image/" + filename;
+ case 'an':
+ case 'k':
+ case 'toy':
+ case 'x':
+ return "http://archive.heinessen.com/" + boardID + "/full_image/" + filename;
+ case 'c':
+ return "//archive.nyafuu.org/" + boardID + "/full_image/" + filename;
+ }
+ },
+ post: function(boardID, postID) {
+ var archive, name, _base, _ref;
+
+ if (Redirect.post[boardID] == null) {
+ _ref = this.archiver;
+ for (name in _ref) {
+ archive = _ref[name];
+ if (archive.type === 'foolfuuka' && archive.boards.contains(boardID)) {
+ Redirect.post[boardID] = archive.base;
+ break;
+ }
+ }
+ (_base = Redirect.post)[boardID] || (_base[boardID] = false);
+ }
+ if (Redirect.post[boardID]) {
+ return "" + Redirect.post[boardID] + "/_/api/chan/post/?board=" + boardID + "&num=" + postID;
+ } else {
+ return null;
+ }
+ },
+ select: function(board) {
+ var archive, name, _ref, _results;
+
+ _ref = this.archiver;
+ _results = [];
+ for (name in _ref) {
+ archive = _ref[name];
+ if (!archive.boards.contains(board)) {
+ continue;
+ }
+ _results.push(name);
+ }
+ return _results;
+ },
+ to: function(data) {
+ var arch, archive, boardID;
+
+ boardID = data.boardID;
+ if ((arch = Conf.archivers[boardID]) == null) {
+ Conf.archivers[boardID] = arch = this.select(boardID)[0];
+ $.set('archivers', Conf.archivers);
+ }
+ return (arch && (archive = this.archiver[arch]) ? Redirect.path(archive.base, archive.type, data) : data.threadID ? "//boards.4chan.org/" + boardID + "/" : null);
+ },
+ archiver: {
+ 'Foolz': {
+ base: 'https://archive.foolz.us',
+ boards: ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'v', 'vg', 'vp', 'vr', 'wsg'],
+ type: 'foolfuuka'
+ },
+ 'NSFWFoolz': {
+ base: 'https://nsfw.foolz.us',
+ boards: ['u'],
+ type: 'foolfuuka'
+ },
+ 'TheDarkCave': {
+ base: 'http://archive.thedarkcave.org',
+ boards: ['c', 'int', 'out', 'po'],
+ type: 'foolfuuka'
+ },
+ '4plebs': {
+ base: 'http://archive.4plebs.org',
+ boards: ['hr', 'tg', 'tv', 'x'],
+ base: 'foolfuuka'
+ },
+ 'Warosu': {
+ base: '//fuuka.warosu.org',
+ boards: ['cgl', 'ck', 'fa', 'jp', 'lit', 's4s', 'q', 'tg'],
+ type: 'fuuka'
+ },
+ 'InstallGentoo': {
+ base: '//archive.installgentoo.net',
+ boards: ['diy', 'g', 'sci'],
+ type: 'fuuka'
+ },
+ 'RebeccaBlackTech': {
+ base: '//rbt.asia',
+ boards: ['an', 'cgl', 'g', 'mu', 'w'],
+ type: 'fuuka_mail'
+ },
+ 'Heinessen': {
+ base: 'http://archive.heinessen.com',
+ boards: ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x'],
+ type: 'fuuka'
+ },
+ 'Cliche': {
+ base: '//www.cliché.net/4chan/cgi-board.pl',
+ boards: ['e'],
+ type: 'fuuka'
+ },
+ 'NyaFuu': {
+ base: '//archive.nyafuu.org',
+ boards: ['c', 'w'],
+ type: 'fuuka'
+ }
+ },
+ path: function(base, archiver, data) {
+ var boardID, path, postID, threadID, type, value;
+
+ if (data.isSearch) {
+ boardID = data.boardID, type = data.type, value = data.value;
+ type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type;
+ value = encodeURIComponent(value);
+ if (archiver === 'foolfuuka') {
+ return "" + base + "/" + boardID + "/search/" + type + "/" + value;
+ } else if (type === 'image') {
+ return "" + base + "/" + boardID + "/?task=search2&search_media_hash=" + value;
+ } else {
+ return "" + base + "/" + boardID + "/?task=search2&search_" + type + "=" + value;
+ }
+ }
+ boardID = data.boardID, threadID = data.threadID, postID = data.postID;
+ path = threadID ? "" + boardID + "/thread/" + threadID : "" + boardID + "/post/" + postID;
+ if (archiver === 'foolfuuka') {
+ path += '/';
+ }
+ if (threadID && postID) {
+ path += archiver === 'foolfuuka' ? "#" + postID : "#p" + postID;
+ }
+ return "" + base + "/" + path;
+ }
+ };
+
+ PSAHiding = {
+ init: function() {
+ var entry;
+
+ if (!Conf['Announcement Hiding']) {
+ return;
+ }
+ entry = {
+ type: 'header',
+ el: $.el('a', {
+ textContent: 'Show announcement',
+ className: 'show-announcement',
+ href: 'javascript:;'
+ }),
+ order: 50,
+ open: function() {
+ var _ref;
+
+ if ((_ref = $.id('globalMessage')) != null ? _ref.hidden : void 0) {
+ return true;
+ }
return false;
}
+ };
+ $.event('AddMenuEntry', entry);
+ $.on(entry.el, 'click', PSAHiding.toggle);
+ $.addClass(doc, 'hide-announcement');
+ return $.on(d, '4chanXInitFinished', this.setup);
+ },
+ setup: function() {
+ var btn, psa;
+
+ $.off(d, '4chanXInitFinished', PSAHiding.setup);
+ if (!(psa = $.id('globalMessage'))) {
+ $.rmClass(doc, 'hide-announcement');
+ return;
}
- qroot = qpost.nodes.root;
- if (!$.hasClass(qroot, 'threadOP')) {
- $.addClass(qroot, 'threadOP');
- threadContainer = $.el('div', {
- className: 'threadContainer'
- });
- $.after(qroot, threadContainer);
- } else {
- threadContainer = qroot.nextSibling;
+ PSAHiding.btn = btn = $.el('a', {
+ innerHTML: '[ - ]',
+ title: 'Hide announcement.',
+ className: 'hide-announcement',
+ href: 'javascript:;'
+ });
+ $.on(btn, 'click', PSAHiding.toggle);
+ $.get('hiddenPSAs', [], function(item) {
+ PSAHiding.sync(item['hiddenPSAs']);
+ $.before(psa, btn);
+ return $.rmClass(doc, 'hide-announcement');
+ });
+ return $.sync('hiddenPSAs', PSAHiding.sync);
+ },
+ toggle: function(e) {
+ var hide, text;
+
+ hide = $.hasClass(this, 'hide-announcement');
+ text = PSAHiding.trim($.id('globalMessage'));
+ return $.get('hiddenPSAs', [], function(_arg) {
+ var hiddenPSAs, i;
+
+ hiddenPSAs = _arg.hiddenPSAs;
+ if (hide) {
+ hiddenPSAs.push(text);
+ hiddenPSAs = hiddenPSAs.slice(-5);
+ } else {
+ $.event('CloseMenu');
+ i = hiddenPSAs.indexOf(text);
+ hiddenPSAs.splice(i, 1);
+ }
+ PSAHiding.sync(hiddenPSAs);
+ return $.set('hiddenPSAs', hiddenPSAs);
+ });
+ },
+ sync: function(hiddenPSAs) {
+ var hr, psa, _ref;
+
+ psa = $.id('globalMessage');
+ psa.hidden = PSAHiding.btn.hidden = (_ref = PSAHiding.trim(psa), __indexOf.call(hiddenPSAs, _ref) >= 0) ? true : false;
+ if ((hr = psa.nextElementSibling) && hr.nodeName === 'HR') {
+ return hr.hidden = psa.hidden;
}
- $.add(threadContainer, this.nodes.root);
- return true;
+ },
+ trim: function(psa) {
+ return psa.textContent.replace(/\W+/g, '').toLowerCase();
+ }
+ };
+
+ CatalogLinks = {
+ init: function() {
+ var el, input;
+
+ if (!Conf['Catalog Links']) {
+ return;
+ }
+ el = $.el('label', {
+ id: 'toggleCatalog',
+ href: 'javascript:;',
+ innerHTML: "Catalog Links",
+ title: "Turn catalog links " + (Conf['Header catalog links'] ? 'off' : 'on') + "."
+ });
+ input = $('input', el);
+ $.on(input, 'change', this.toggle);
+ $.sync('Header catalog links', CatalogLinks.set);
+ $.event('AddMenuEntry', {
+ type: 'header',
+ el: el,
+ order: 95
+ });
+ return $.on(d, '4chanXInitFinished', function() {
+ return CatalogLinks.set(Conf['Header catalog links']);
+ });
},
toggle: function() {
- var container, containers, node, nodes, replies, reply, thread, _i, _j, _len, _len1;
+ var useCatalog;
- thread = $('.thread');
- replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread);
- QuoteThreading.enabled = this.checked;
- if (this.checked) {
- nodes = (function() {
- var _i, _len, _results;
-
- _results = [];
- for (_i = 0, _len = replies.length; _i < _len; _i++) {
- reply = replies[_i];
- _results.push(Get.postFromNode(reply));
- }
- return _results;
- })();
- for (_i = 0, _len = nodes.length; _i < _len; _i++) {
- node = nodes[_i];
- QuoteThreading.node(node);
- }
- } else {
- replies.sort(function(a, b) {
- var aID, bID;
-
- aID = Number(a.id.slice(2));
- bID = Number(b.id.slice(2));
- return aID - bID;
- });
- $.add(thread, replies);
- containers = $$('.threadContainer', thread);
- for (_j = 0, _len1 = containers.length; _j < _len1; _j++) {
- container = containers[_j];
- $.rm(container);
- }
- Unread.update(true);
- }
+ $.event('CloseMenu');
+ $.set('Header catalog links', useCatalog = this.checked);
+ return CatalogLinks.set(useCatalog);
},
- kb: function() {
- var control;
+ set: function(useCatalog) {
+ var a, board, path, _i, _len, _ref;
- control = $.id('threadingControl');
- return control.click();
- }
- };
-
- QuoteYou = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Mark Quotes of You'] || !Conf['Quick Reply']) {
- return;
- }
- this.text = '\u00A0(You)';
- return Post.prototype.callbacks.push({
- name: 'Mark Quotes of You',
- cb: this.node
- });
- },
- node: function() {
- var quotelink, quotelinks, quotes, _i, _len;
-
- if (this.isClone) {
- return;
- }
- if (this.info.yours) {
- $.addClass(this.nodes.root, 'yourPost');
- }
- if (Conf['Highlight Own Posts']) {
- $.addClass(doc, 'highlight-own');
- }
- if (!(quotes = this.quotes).length) {
- return;
- }
- quotelinks = this.nodes.quotelinks;
- for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
- quotelink = quotelinks[_i];
- if (QR.db.get(Get.postDataFromLink(quotelink))) {
- $.add(quotelink, $.tn(QuoteYou.text));
- }
- }
- }
- };
-
- Quotify = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Resurrect Quotes']) {
- return;
- }
- if (Conf['Comment Expansion']) {
- ExpandComment.callbacks.push(this.node);
- }
- return Post.prototype.callbacks.push({
- name: 'Resurrect Quotes',
- cb: this.node
- });
- },
- node: function() {
- var deadlink, _i, _len, _ref;
-
- _ref = $$('.deadlink', this.nodes.comment);
+ path = useCatalog ? 'catalog' : '';
+ _ref = $$("#board-list a[href*=\"boards.4chan.org\"],\n#boardNavDesktop a[href*=\"boards.4chan.org\"],\n#boardNavDesktopFoot a[href*=\"boards.4chan.org\"]");
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- deadlink = _ref[_i];
- if (this.isClone) {
- if ($.hasClass(deadlink, 'quotelink')) {
- this.nodes.quotelinks.push(deadlink);
- }
- } else {
- Quotify.parseDeadlink.call(this, deadlink);
+ a = _ref[_i];
+ board = a.pathname.split('/')[1];
+ if (['f', 'status', '4chan'].contains(board) || !board) {
+ continue;
}
+ if (Conf['External Catalog']) {
+ a.href = useCatalog ? CatalogLinks.external(board) : "//boards.4chan.org/" + board + "/";
+ } else {
+ a.pathname = "/" + board + "/" + path;
+ }
+ a.title = useCatalog ? "" + a.title + " - Catalog" : a.title.replace(/\ -\ Catalog$/, '');
+ }
+ return this.title = "Turn catalog links " + (useCatalog ? 'off' : 'on') + ".";
+ },
+ external: function(board) {
+ return (['a', 'c', 'g', 'co', 'k', 'm', 'o', 'p', 'v', 'vg', 'w', 'cm', '3', 'adv', 'an', 'cgl', 'ck', 'diy', 'fa', 'fit', 'int', 'jp', 'mlp', 'lit', 'mu', 'n', 'po', 'sci', 'toy', 'trv', 'tv', 'vp', 'x', 'q'].contains(board) ? "http://catalog.neet.tv/" + board : ['d', 'e', 'gif', 'h', 'hr', 'hc', 'r9k', 's', 'pol', 'soc', 'u', 'i', 'ic', 'hm', 'r', 'w', 'wg', 'wsg', 't', 'y'].contains(board) ? "http://4index.gropes.us/" + board : "//boards.4chan.org/" + board + "/catalog");
+ }
+ };
+
+ IDColor = {
+ init: function() {
+ if (!Conf['Color User IDs']) {
+ return;
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Reveal Spoilers',
+ cb: this.node
+ });
+ },
+ node: function(post) {
+ var str, uid;
+
+ if (!(uid = $('.hand', this.nodes.uniqueID))) {
+ return;
+ }
+ str = this.info.uniqueID;
+ if (uid.nodeName === 'SPAN') {
+ return uid.style.cssText = IDColor.apply.call(str);
}
},
- parseDeadlink: function(deadlink) {
- var a, boardID, m, post, postID, quote, quoteID, redirect, _ref;
+ ids: {},
+ compute: function(str) {
+ var hash, rgb;
- if (deadlink.parentNode.className === 'prettyprint') {
- $.replace(deadlink, __slice.call(deadlink.childNodes));
- return;
- }
- quote = deadlink.textContent;
- if (!(postID = (_ref = quote.match(/\d+$/)) != null ? _ref[0] : void 0)) {
- return;
- }
- boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID;
- quoteID = "" + boardID + "." + postID;
- if (post = g.posts[quoteID]) {
- if (!post.isDead) {
- a = $.el('a', {
- href: "/" + boardID + "/" + post.thread + "/res/#p" + postID,
- className: 'quotelink',
- textContent: quote
- });
- } else {
- a = $.el('a', {
- href: "/" + boardID + "/" + post.thread + "/res/#p" + postID,
- className: 'quotelink deadlink',
- target: '_blank',
- textContent: "" + quote + "\u00A0(Dead)"
- });
- a.setAttribute('data-boardid', boardID);
- a.setAttribute('data-threadid', post.thread.ID);
- a.setAttribute('data-postid', postID);
- }
- } else if (redirect = Redirect.to({
- boardID: boardID,
- threadID: 0,
- postID: postID
- })) {
- a = $.el('a', {
- href: redirect,
- className: 'deadlink',
- target: '_blank',
- textContent: "" + quote + "\u00A0(Dead)"
- });
- if (Redirect.post(boardID, postID)) {
- $.addClass(a, 'quotelink');
- a.setAttribute('data-boardid', boardID);
- a.setAttribute('data-postid', postID);
- }
- }
- if (__indexOf.call(this.quotes, quoteID) < 0) {
- this.quotes.push(quoteID);
- }
- if (!a) {
- deadlink.textContent = "" + quote + "\u00A0(Dead)";
- return;
- }
- $.replace(deadlink, a);
- if ($.hasClass(a, 'quotelink')) {
- return this.nodes.quotelinks.push(a);
+ hash = this.hash(str);
+ rgb = [(hash >> 24) & 0xFF, (hash >> 16) & 0xFF, (hash >> 8) & 0xFF];
+ rgb[3] = ((rgb[0] * 0.299) + (rgb[1] * 0.587) + (rgb[2] * 0.114)) > 125;
+ this.ids[str] = rgb;
+ return rgb;
+ },
+ apply: function() {
+ var rgb;
+
+ rgb = IDColor.ids[this] || IDColor.compute(this);
+ return ("background-color: rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "); color: ") + (rgb[3] ? "black;" : "white; border-radius: 3px; padding: 0px 2px;");
+ },
+ hash: function(str) {
+ var i, j, msg;
+
+ msg = 0;
+ i = 0;
+ j = str.length;
+ while (i < j) {
+ msg = ((msg << 5) - msg) + str.charCodeAt(i);
+ ++i;
}
+ return msg;
}
};
@@ -8959,6 +7793,1172 @@
}
};
+ Emoji = {
+ init: function() {
+ var css, icon, name, pos, _ref;
+
+ if (!Conf['Emoji']) {
+ return;
+ }
+ pos = Conf['emojiPos'];
+ css = ["a.useremail[href]:last-of-type::" + pos + " {\n vertical-align: top;\n margin-" + (pos === "before" ? "right" : "left") + ": 5px;\n}\n"];
+ this.icons["PlanNine"] = Emoji.icons["Plan9"];
+ this.icons['Sage'] = Emoji.sage[Conf['sageEmoji']];
+ _ref = this.icons;
+ for (name in _ref) {
+ icon = _ref[name];
+ if (!this.icons.hasOwnProperty(name)) {
+ continue;
+ }
+ css.push("a.useremail[href*='" + name + "']:last-of-type::" + pos + ",\na.useremail[href*='" + (name.toLowerCase()) + "']:last-of-type::" + pos + ",\na.useremail[href*='" + (name.toUpperCase()) + "']:last-of-type::" + pos + " {\n content: url('data:image/png;base64," + icon + "');\n}\n");
+ }
+ return $.addStyle(css.join(""), 'emoji');
+ },
+ sage: {
+ '4chan SS': 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAYAAACZ3F9/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAa9JREFUKFOdkt0rg2EUwM95b2zlL0CRRLngksznXrJsNtYW1tjYhM3mY6+IXZAbikhTKJp8XZAp81UmWYhIRHHhUi60e7s6ntdCa2449es8PfU7z+k5B6AbyuE/wQlc4BcO2d06unAUBCgFE0hianOd3NHIcy8NPwrUf9NBPZcOEi7ayXZiea/1V7+ljaXeYAfOgg2So2TOwQWGnwQafOgi962TnMFmatozUeNu4yetASspVvgXiUvii5K5Nm6z56ol3Hdtpy+cwSYy+HRUt1nLsoEato0kXyh6wTac+24brThWv6MNOYNW9prlG/uxmbRrFaT0VrCspZoNPSUNJNyCBcoiLZuhLH0o9U6UrAfGKCz7RlLM81Q8XUwqr4oKPLIQmnA8IupBigacVy7yrya/2JouhryJHJJNykg+UxLGOtz6+SQNpEiMcduls4Wvoli9WklVKz+ol5SU4U6ngql8Qj2eRI+GyajBhSRH4r3cUxhSeRVhsYBmWUWiyM+UMDmDUI2nsfuSC1I27nLgYZJlP8jhjJ3PY8iE+L8tWx4kQC6MQA5b1D9HNiRCFhx8AF/e2qh92VnKAAAAAElFTkSuQmCC',
+ 'appchan': 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAABa1BMVEUAAACqrKiCgYIAAAAAAAAAAACHmX5pgl5NUEx/hnx4hXRSUVMiIyKwrbFzn19SbkZ1d3OvtqtpaWhcX1ooMyRsd2aWkZddkEV8vWGcpZl+kHd7jHNdYFuRmI4bHRthaV5WhUFsfGZReUBFZjdJazpGVUBnamYfHB9TeUMzSSpHgS1cY1k1NDUyOC8yWiFywVBoh1lDSEAZHBpucW0ICQgUHhBjfFhCRUA+QTtEQUUBAQFyo1praWspKigWFRZHU0F6j3E9Oz5VWFN0j2hncWONk4sAAABASDxJWkJKTUgAAAAvNC0fJR0DAwMAAAA9QzoWGhQAAAA8YytvrFOJsnlqyT9oqExqtkdrsExpsUsqQx9rpVJDbzBBbi5utk9jiFRuk11iqUR64k5Wf0JIZTpadk5om1BkyjmF1GRNY0FheFdXpjVXhz86XSp2yFJwslR3w1NbxitbtDWW5nNnilhFXTtYqDRwp1dSijiJ7H99AAAAUnRSTlMAJTgNGQml71ypu3cPEN/RDh8HBbOwQN7wVg4CAQZ28vs9EDluXjo58Ge8xwMy0P3+rV8cT73sawEdTv63NAa3rQwo4cUdAl3hWQSWvS8qqYsjEDiCzAAAAIVJREFUeNpFx7GKAQAYAOD/A7GbZVAWZTBZFGQw6LyCF/MIkiTdcOmWSzYbJVE2u1KX0J1v+8QDv/EkyS0yXF/NgeEILiHfyc74mICTQltqYXBeAWU9HGxU09YqqEvAElGjyZYjPyLqitjzHSEiGkrsfMWr0VLe+oy/djGP//YwfbeP8bN3Or0bkqEVblAAAAAASUVORK5CYII='
+ },
+ icons: {
+ 'Plan9': 'iVBORw0KGgoAAAANSUhEUgAAAAwAAAAPCAYAAAGn5h7fAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAzE15J1s7QAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAACAElEQVQoz3WSz4sSARTHvzMjygpqYg3+KIhkE83DKtKlf0C9SrTRuZNEx0VowU6CuSeJNlwwpEO2kJ6SQBiIUAzFjRDF4wrjKosnGx3HmdehFDfpe/2+z/s++D5gU7IsEwRByICIiAEAIiIAYAFAXsjYVr/fLxMRNVvN+prJ5/OA3+/XERFNf02JyeVyDx0OxyvLNQsnimLKfcf9KRQKXQAAnE6nlf5qMpnQycnbP/kAoKoqsSwLAJhOp+AAwOv1otvtpqxWq73dbt/r9XqvEQ6HUalUEvF4XLd5IpvNZqlerzd5nlf6/f6tTCZjBACk0+nb+XxeW4UrikLJZPImAGA0Gq0NIqJyuSyyANDr9Q5Wu1utFvR6/SULAI1G4+vK8Pv90DTtGwsAJpPpaGUYDAZ0Op3PHAAEg8H3tVqtbrtu21sqyxuRSOQJk0ql9IvF4r7b7f7pcrlejkaj57IsH58Pzp8dvjhc/lsBk0gkbLFYrFqtVvd27+4qOk733ePxPDCbzVBVFfP5fCiK4rvhxfDN/qP9wSasGwwGMv1HiqJQsVg8ZlfTHMepkiR1t05gGJBGmM/nMBqNj9nN9kql0lNN064ARISzH2cQBAGz2ewLu2na7XYLwzBbvxYIBBCNRrFj3BmsAZ/PZ+J5/kOhUIAkSVeA8XiMZqt5efrx9OA3GfcgvyVno9cAAAAASUVORK5CYII=',
+ 'Neko': 'iVBORw0KGgoAAAANSUhEUgAAABMAAAARCAMAAAAIRmf1AAACoFBMVEUAAABnUFZoUVddU1T6+PvFwLzn4eFXVlT/+vZpZGCgm5dKU1Cfnpz//flbWljr5uLp5OCalpNZWFb//f3r6+n28ff9+PRaVVH59Pr//vr38vj57/Dp7eyjn5zq8O5aVVJbYV9nVFhjUFRiWFlZVlFgZGOboJzm5uZhamfz9/bt8fDw6+drb26bl5j/8/lkX1z06uldWFS5r61UT0tfWlbDwr3Ew76moqNRTU7Mx8P75OpeY19pWl1XW1qzr6x5eHaLiojv7+1UT0xIU0uzqadVS0nV0MxkZGT5+PPk497///ra29Xq5eFtY2H28e2hnJignJlUUE1dXV2vrqxkY2FkYF/m3d5vZmfDuruhl5aZlJHx8O75+PZWVVP29vT/9fTj3trv6ubh5eRdXFqTkpBOTUtqZmX88/RMQ0T78vPEvr7HwcHDwsDq6ef///3Gx8H++fXEv7tZWVedmZZXXVudnJp0c3FZU1f79fnb1dlXUVVjXWFrZmy8t7359/qLj455e3q4s69vamZjX1zy4+avpaReWFz/+f1NR0vu6Ozp4+f48/lnYmi8ur3Iw7/69fHz7+xbV1SZmJZVUk1ZV1zq5ez++f/c196uqbDn4uj9+P7z7vRVVVXt6ORiXl/OycXHw8CPi4ihoJ5aWF3/+v/k3+axrLOsp67LzMZYU1m2sq9dWF5WUU1WUk/Au7eYlJGqpqObmphYVV749f7p5Or38fPu6OpiXFz38fH79vLz7urv6+hhYF5cWWKal6D//f/Z09Xg29exraqbl5RqaW6kpKTq5uPv7Of/+PDj29D//vP18Ozs5+OloJymoZ1ZVVJZWVlkYF2hnpmblIyspJmVjYKQi4enop5STUlRTUpcWUhqY1BgWT9ZUjhcV1NiXVkkhke3AAAABHRSTlMA5vjapJ+a9wAAAP9JREFUGBk9wA1EAwEAhuHv3dTQAkLiUlJFJWF0QDLFYDRXIMkomBgxNIYxhOk4wwCqQhQjxgxSGIsALFA5BiYbMZHajz1oJlx51sBJpf6Gd3zONcrqm/r1W8ByK0r+XV1LXyOLLnjW6hMGpu0u1IzPSdO17DgrGC6AadrVodGcDQYbhguP6wAvAaC0BRZQalkUQ8UQDz5tAof0XbejOFcV5xiUoCfjj3O/nf0ZbqAMPYmzU18KSDaRQ08qnfw+B2JNdAEQt2O5vctUGjhoIBU4ygPsj2Vh5zYopDK73hsirdkPTwGCbSHpiYFwYVVC/17pCFSBeUmoqwYQuZtWxx+BVEz0LeVKIQAAAABJRU5ErkJggg==',
+ 'Madotsuki': 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAMAAADTRh9nAAAALVBMVEUAAAC3iopWLTtWPkHnvqUcBxx5GCZyAAARERGbdXJrRUyGRUyYbY23coZFGDRFGEYfAAAAAXRSTlMAQObYZgAAAGhJREFUeF5Vy1kOQyEMQ1Fshzd12P9y61AixLX4yJFo1cvVUfT23GaflF0HPLln6bhnZVKCcrIWGqpCUcKYSP3JSIRySKTtULPNwMaD8/NC8tsyqsd1hR+6qeqIDHc3LD0B3KdtV1f2A+LJBBIHSgcEAAAAAElFTkSuQmCC',
+ 'Sega': 'iVBORw0KGgoAAAANSUhEUgAAACwAAAALBAMAAAD2A3K8AAAAMFBMVEUAAACMjpOChImytLmdnqMrKzDIyM55dnkODQ94foQ7PkXm5Olsb3VUUVVhZmw8Sl6klHLxAAAAAXRSTlMAQObYZgAAANFJREFUGJVjYIACRiUlJUUGDHBk4syTkxQwhO3/rQ/4ZYsuymi3YEFUqAhC4LCJZJGIi1uimKKjk3KysbOxsaMnAwNLyqoopaXhttf2it1anrJqke1pr1DlBAZhicLnM5YXZ4RWlIYoezx0zrjYqG6czCDsYRzxIko6Q/qFaKy0690Ij0MxN8K2MIhJXF+hsfxJxuwdpYGVaUU3Mm5bqgKFOZOFit3Vp23J3pgsqLxFUXpLtlD5bgcGBs45794dn6mkOVFQUOjNmXPPz8ysOcAAANw6SHLtrqolAAAAAElFTkSuQmCC',
+ 'Sakamoto': 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAYAAADwMZRfAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAxVJREFUOE+Nk19IU1EYwK+GQQTVQ39egh6ibKlzw91z7rn3bvfOmddNszl1bjKXc5rJJGmBUr7Yg9qTD0IalFgRBEYg6EDQQB+GovQyQgiaUZsoLcgHMcr069w7MgcGXfi453zn+37fv3MYZt/n99e76tzVj4JN/hP79fvXnV3hnNabwUBjoOHcgTYOu/JQspgTzsqKgn9BfD4vkWTzur287PqLVy+zM+yePB7KsRXLywTjnSpnZctBkPCdW8ccDuU55vBO8RXbkC/oP5ph19V5+7LIky0OY1BKbZEbLcFSt7u6pN7jLmltCVrr3DV5jY3+KovFEsccB1KJNVpefe10BqS2tqqO4/AuphBB4L/LkrRqNgtJs1lMypLls1kU38mytMLz/E8VIlutqVqX6/weZG52OttRXjbE0cP/FYLRlpVjDXuQ/r77x2XZPKkCHA4HBAIBkCQpAygIAvh8Pu2MZgO0Lz+QSa/sQfwN9RfpVN66XC6Ynp6GhYUFGBwczAC1t7fD0tISxONx6O7upgHILmsqvLcHodOggfiV/v5+SCaT4HQ6IRaLgdfr1bIRRREmJyfBZrNBNBqF+fl5sNsdgE2GiAbp6bmbdbXC7qWQbxMTE7C2tgY6nQ5SqRSEw2ENopaoZpCXlwdTU1NaoECgCbgiU6y8QH+ECYWaTymK7TWdys7MzIwGaWtrg42NDejo6AB1WjU1NZo+FArB2NgYrK6uQrAlCASxn2z6wkuMp87VIAhkE2MEAwMDkEgkYHx8HBYXF0HtkQpRy1BLiEQisLy8rPVNKSsFjEzrXH4+z1hlS4xDhKadNu7t7YPR0VHweDzAEVWfHru6HxkZgeHhYVAURYNjkylVWKArZjjMzqmdVi+QCsLUkQiEjvDvncEkvU7/qQ0Vgukeo48Go87IiCJnZNmipxiz7wXEbVDnbUxQOgM12h9n6qTq6NvapRdtkwaP0XK8RmPuYSbxYfaQ/sJJhjfknuFRURUi7AMOozcCwl94hLZp5F+EioDQVwqYI6jomZU1NFtM+rOSxZjVazcyvwHr/p/Kws1jegAAAABJRU5ErkJggg==',
+ 'Baka': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA0pJREFUOE91k3tI01EUx39JOpA0H4jNx0pbD3XTalISWf8YFlEgldqDsBLLyqjEKBCiLLWiggh6/KEV1WZ7OaelLZvDdDafNW1JFraWe/32+01FrUZ9uy4ylLpw4Z5z7/nc77n3HIqaMRIjZJyEcNX+uFCFeGmI/GZciEIsCFJUTvoAzDz+1y7K76MSwhX5hXl6z+WSbrzU2KB8YEGDwgrTaxZ3b7xHcaHhR3xw7Z5/UviB1ReP5XSg3+TAqYJOxMzWISFIC0GQDomhTVA9skCnsaAwp/vnMq66dBokNuBR9uFd7T9Z1zCunjci0qcRJUVdoJ3DYOhRnC/qBZ+jQbfeCc+37yjY2UEg0iwvJE0k9l8Z+8xqHmTgot0QLdQgTaQFQ2AsOzlHvOu1S5pwOLsHHo8HjHMCq2MazNvTlByKHyrJLDvdR25jMWRxYx5HjeMH2r1BDOOeguRua4OI14jx8a8YH5tA+al3EHKlW6mYOapb2oZBOOwMbEMseAE12L+jjUh3w+VipyAZ65oxn1NP/GMYGR6Ftn4Qsf7qa9S82Y/l/X122G0uL2TbxmZEz1WhXW8mUol8moXu+SCi/OoQ6VsDh3UUwyQ1k9GOaI5MTkX4yWTGHutvgI1F28sviAlRgxeoRm62HvsyW8En9pZ1TYgi6TntoyQtFm86rVgUoJZRvDnKMmXVAGxWmkAYOBwudBqGcHCvHulrGpGT2Uy+z4yT+QYsCXtCUpp8GxbKhx8gDK0ro+KjJGvzdjfDZnN6VdisLD5/JjArQ2zW66PJOj2lEZtStaBphkwah7K6kMJ/GEulp1bMWhAmMbTozOQRaWRtfoZVgjo4iRra4SYgGi26TwjxVeDKhR7Y7U606ixICq9tr7hd7+OthRWL7yUnJ1WPmXotqLhpRICPHCePtuFV6xdUPTAhcWEtRHEqfHpPyto4hPXLXnzflSEJnFaN3OCKDcsFsrEntR9RUmxARLAUgT5iBPuJsXWDBj0dZjRU9yNV+PTbpjTp9OA/pOSk24nRkXf1J462oPxcJ65f6ULlHSMulepRerYDgvj7A0cKpNz/tyTZqbzXO4t0ZZGQJ34RH11lFHIlA8LIqreCCMUZRY3cd2bwL/5/RmjNSXqtAAAAAElFTkSuQmCC',
+ 'Ponyo': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAuNJREFUOE+Nk3tI01EUx39BTytConQTt1am07m5abi5KT5S8z2dj1yOEMUC7aUgIoimlmUEWX9kBZGWaamEmE6U1BI1XNPNGTrnHs33IwuSXrL4NgcJ0mNdOHDh3PPhnPP9XoKwcroJYvMQiRSicHCQKCgUyZC9/T5rNet5KUFs0zCZbZMsFmZ9fTEjEEBDp4/KSSSb/4JoGIyWaTYbiykpWEhOxhSHAzWD0aqkUGhWAcVkW58xlvuPhfh4zItEmOHxYDR3MhcdDaNAsKJydAz5IySKRNjEUmy88vjOVaU8F0iPCqCNjEBHkC/UYaGYFwqxmJoKLYOhkxPElg0QsbNtTlmox9yjRD9UCbnoOR+J/lwRWtOCcdXfDc2BPpg0d7CQlIQZPh9KKlVkAQjJ2x2zmOSsQu7hpzUJfBhLjsNQmADjxcT10Bcl4rE4EHc5LjBEhEPn7f1WTqXSLQB/s1Tp7vslsoIkyPPiMJAbi86McBguiaHKjoEqR4jJy2K0nAxApzMN5iUGrclrKVaz2fUvuF4tRbxDKA90w5VjTFyLZKHpTBSq4/1QnxGB2qxoVIZx0JopRCPHFSNOThfWZzfrXDcZEowH4iA05ATg68hDtBaL0HAuCm3lJ9Bfcx2fFNUoi/DCjRgfNHHd1wCZA2TyXjNkE6F0cBDpPFiojeNi8EkJdFoN3vXch0nbBJOhDd907dANv8JITxNqziag3ZsJbUDAwLin50Q9QWwl1qSYoNOVvUcOoqOqAAa9Fu9H2/F9+B5WZLcwOyxFX18flLI+VASyMGVeoJHD+Tzq5BS1PoaKRrNT8127P74swsq4FCa9FKvqBqwaOiz3hdEuLKueYSyECT2LNW0eIfo3E/WmEbvnG1MUJnWdpWhDGDvxQXZHo+RR0uW2tnv+auPX+TvtJm7zKpaen/4y2yjBUlcxlvtvmvT16ZWDpQeoVv3/60F/NrHjTf4ugazIXtJ8ivjnz/sJ+yGQRjcqUdIAAAAASUVORK5CYII=',
+ 'Rabite': 'iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAD/0lEQVR4Xl2MXUxbdQDFz/9+9Lb3tkBLCxTKhzgoOOZAsokbJmZxDFHnd+LL4hKVzBgfNCY++ODbjDEaZowvErOM6HRu6hKZY2rIAOkCY4OSDTpFaAsrlJa2t5+39+NvjT7tnJzknIfzI98Nf/C6TuXdguWBd1q9rcb8/CwsZiu2Ywm4nDVo3VWLZCKDaDwJq9mCg31PgjAMKKUwmcyYvTbek9iJRDm6M/XswEDjwNz6plWW6wdZhjUAintFCEEhn0N04zYskljaDLaj8ar49oUrsYR6mrFJNj322w46H8y+mitM/ZJKZmyE4XAvjJSsazpyuSzslVZIkgWKOvvRgQ6Xrdlhqmds7o7bFZoLkctreKxf7GtuCE7IyUQjBQcQ8j/lvxCGQJZz0IoCVpamTtzfIh9nwiaIrCQyjNg8mq11oDLUhNXRJfT1Ozr3tS/PqpnQ80qRgjAmKIqBfK4ItbSLKoOZqR/6neLkENlSUAIhlktvEf+sD2rkm8nWTHtvZCGMVON1ePuaoBER31/MXGly1wSqq9Uug6FluYyWXJiPqFXmjd4Dh9oF9ZKKimYXRtYCx8lmMIDIxlIPGz591av0mtanF7FcCEN6iMXeox2wOJ0QJAmUAoRQaIqCnWAQY1/ewKNGNeQuYXkm0d2NC2e+wvmRr/Hx+6+8PHayrbDyyQBNDb9As3PHKDWG6MTM23RoeJAWsqeoWvyUUv0UHf7pBB0fe4OeeXe3/vmHbx3+8dwIGJ4IsFpMMFe0fbtAn+nwZePr1u4MBK8XIALG/Rt479wYrs2vgeNNAMNgMbiNzybuoKVvn+Gs9kbr6qpBfJfGYHFIkJUCoGwfqcoMX/b27EGhwgOjoCADDlP+CA51ugFFRzoB8FYNaQ1oqKD44+eNL+wNj7zJGQSIhe8+jgQ9thk+27v/KRY6L4FSCkVOwtlQj6P73Qgt/o1ERoKt4iUkE7+jrZMHyzIoK9cOBFfT4LbWAk+0a7ZLnvqHcTNdACgFScfAcjxEdy00VQclHGo7dqGeYxHbvIo6hwhSghCehb3G5p6eW7VxXC5/xGWToMgrKKoaCnIalI9CIARasQAqloMI/x4BWrLLYwE1AEPTwCGHaGjz7pw/leZUNV8wNm9BLy6CxsvxZ1kMbaY4TKIIXlNBsynoVjvAC4CuAoYOVi+CMfLYCUfg95tPHuzZB0YtKzsb58RMucWE/fZmhCbdOP9rNnLnxko6GVoB8lFwyVVw8b/AyeulHoJyN4Rb19dTFyeqBlu6njvfsWcvOJvLs7DMmw/7bvpeE4pU2OIcgcqmp4fGAgt2Txwvqr7lTp5V7LquZxXC6+BqEvGcY5pyjaM1tffJbk89NE3FP5VQ6y7a+paZAAAAAElFTkSuQmCC',
+ 'Arch': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABCFBMVEUAAAAA//8rqtVAqtUQj88tpdIYks46otwVldUbktEaldMjldM2qNcXk9IWktQZkdIYlc8mnNUXlNEZktEZlNIYktIWlNMXktE7o9klmdMXktFHqdkXk9EWk9EYk9IlmtQXlNEXktAWk9AWlNEYlNFDptkZldMYk9E4otg/p9kXktEXk9AXlNA4otclmdQXk9IYktEXlNEwn9YXk9IXk9FFp9o3otgXk9FPrdwXk9E2otdCptkXk9E/ptkcldIXk9Edl9IXk9EjmdUXk9EXk9EXk9EbldIcldIjmdMmmtQsndUvntYyn9YyoNYzoNc0odc1odc2odc6pNg7pNg9pdlDp9pJqttOrdzlYlFbAAAARXRSTlMAAQYMEBEVFhgcHR0mLS8zNTY3PT4/RU1kdXp6e3+Cg4WIiYqMjZGXl5mbnqSnrbS3zMzV3OPk7Ozv8fT29vf4+fz8/f7SyXIjAAAAmUlEQVR4XlXI1WLCUBQF0YM3SHB3a1B3l7Bx1///E6ANkDtva0jKbCW2XIH1z2hiZEZ4uUgxo7JedTQye/KN/Sb5tbJ+7V9OXd1n+O+38257TL+tah3mADAwSMM7wzQWF4Hff6ubQIZIAIb6vxEF4CZyATXhZa4HwEnEA+2QgoiyQDnIEWkjVSBBZBqXbCRlKYo8+Rwkyx54AOYfFe7HhFa7AAAAAElFTkSuQmCC',
+ 'CentOS': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAB5lBMVEUAAADy8tng4Ovs9tnk5O3c7bX44LLduNO1tdDh7r/eutj43q2kocX23az07N+qqsvUqcmXl7331ZXJj7r40o/Pn8T42qP63KjNw9n21p3Y387Ml7732JzR55z05MSxtMLGn8TC4Hx8eqt8e62Af6/B4HnG4oPC4HzH44fBf7LCgbOkoMTcsrmtn8PWqcfFtKrj4Jvs2ZOz2FnMqLXT3KfY5p60Z6NUU5XRuqHzwWSywqDn3JaiiLWahrWhkry5zJjRmqm1Z6P1wmb1y319fK632mK5cKi5nH+73Gu73Gy73W283W+9eK17e6y1yZS3aqRZWJdcW5ldXJplXZppaKBwb6VwcKV5eKswL306OYNPTpGkfK+m0kGpUJWq1EnEqIuXK3+Xh7ahP4qhkryMfK6BgK+CdpGMaKKMa6O9ea2+eq6+oYW/eq+NbqWVlL2Wlr7AjanA4HnA4HrBkqbBlafB33rCgbLCmKjCxIzC1mSs1UytV5mtxIWt1lCuz2evWpuvXJywxYzHjrvH4oXIjrrN2HXO5pTO5pXUlYnUlYvVl5Hb0G7e0XTg03rhr5fpzHPpzXTp0Hvtz3/wrDHytknyt0zyuE3yuVHzvVr0wGP1x3T1yHf1yXe0ZaL2zYP30o730pD31ZeRIcF5AAAAQ3RSTlMAFBkbHEhJS0xMTk5UWWBsd4SEiIiPkJCVlZaam6CjpK29wMPDxMTFxcnK193e3+Dg4uTn5+fo6e/v8/P4+fn7/P7+J4XBAAAAAOBJREFUeF5Vj1OvAwEYBb/yGlu717atLW0b17Zt2/6nze42TTpvMw8nOZCAmwUpiIY6c5IiLi9tPX64GairqszHQ4X2VB64v1Cs6PxMPJSdHM777s6/jyaMRGiRLyyrb88OpjZ3CzAXrm1sqzSNNeN7kVBPNgB7cG51abE5l9cXDces7emQ1uadHhutFUg6gpPKkSIqQGavwz7r7O/+/3t/rSdjI9XDM3qz4fr3B/3iA0aJTG9x71+9oR/PLDwUe2wm19bly+fTIxHyEETatbPewGEw6Mk/tKZCEqSQQUlIHB/QNBEjjVN1AAAAAElFTkSuQmCC',
+ 'Debian': 'iVBORw0KGgoAAAANSUhEUgAAAA0AAAAQCAYAAADNo/U5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAZ5JREFUOE+Nkk0oBHEYxv8fu5GQj3JwcaDkIAc5IpR87M7MKnIVJVKclaIQ5Sy5OLkgR7n5OigcSNpmd2c2Vyfl4KT8/muWiVU79TTv+7zv837NCBF6PG1X+NpZyEYSD9mIc+tHnBPe23B9xKrCuTmbQA/JKfABrhBswa1hH4A38IwfOxPdX1qcjiCQxO5NyrjKV70TnSbeRPwJvGN3i4yyqnEucPY8ZZX9GSEgGK+RvFfyjk2VKZxzBNG8wJWWgh/xtDOeUXZ7Slr6TrSLYL9N4SMgYTTcwdc2ArvJcElhSVcM6mCNSV8n9hA59yTU5UWMG6HIbLhIWlglgWiC2L4Z79qTdo40D6ISuOWwKCWHyk9Fv8ldpUHOuGTuynwSBUynddPdlbEosVpP9Eu4FnOsRzUYNTsdmZN/d5LDiqM0w+2CMdAFFsFGWgfXxZnheqe/z+0puwEM0HHYV3Z9Sgz8TEz7GkQvpuJ/36ggj2AaHLrSlkULWV5x+h2E8xkZL16YVjGNaAUscfZ/f6c/k9ywLKI2MMcRWl0RLy007idmRbQJ7RIfDAAAAABJRU5ErkJggg==',
+ 'Fedora': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABPlBMVEUAAAApQXIpQXIpQXIqQ3UpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIqQ3QpQXIpQXIqRHYpQXIpQXIqQ3QqRHYpQXI8brT///8uTYMpQnM5Zqg5ZqnS1+I4ZaY4ZactSn8uRnYrQ3MrRXgsRHUsR3s8bbM8brMtSX4wUosxVI01XZw2X50vUIguToQvR3c6X5o6aKs6aq08Un8qQnM9VIFDWINJXohKcKlXapEqQ3UvUIc2X55bhcBdcJVgcpdhfapmd5tuk8dxgqJ1hKR5jbB6iah/m8Shudq3v9C4wNG/x9bFy9nFzNnFzNrIz9zK0NzK0t/O2+3P1eA2YaDU2eTb3+jb4Oje4urj6fHm6e/s7/Tz9fj3+fz7/P38/f3+/v83YaEa/NNxAAAAHnRSTlMABAoVGyY1SVlpeIuQsLfDzdHW4+3y8/b39/n6+vr4+ns8AAAAyklEQVR4XiWN5XrDMAxF75KOknYdZJS0klNmHjMzMzO9/wvMcH7I37mSJShsJ+5NjMT6umDoHyXDcI/2qJadh++P3cle1de+9yPe3/bTY92wzfzr7wGtP3JrAI72BZGVtcAdQlwHy+JS1pDbBE9qamZF3BYrjQxPEXwKc6dC8bXFm0QIpmt8kn0Rn093q82UCtK8oXZckwFJzuulV8bHkajPyXdbnJnARfDHs0trz+JQ+5AFvzp/L0+cL2qPAINUPrq5OC6p/64F/AMnrST+Dq/r7QAAAABJRU5ErkJggg==',
+ 'FreeBSD': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAABIAAAASABGyWs+AAAABmJLR0QA/wD/AP+gvaeTAAADXklEQVQYGQXBS2wUZQDA8f83j33M9rF9d7u4loaWklaDpkSo9KDGaIKUaGxshD2YSPRiuDVeTDyhBxosJCoa40ktpAkPDcUqAYVIpUSUPrAulEdD2bbb7e7ObGcfM/P5+4kwKDvq6yJ1FYYcvb+YAkqAHo/HQ7FYrFIoCiurq9ZXJ06YSOkA+kBzfX06bys3zHxS9EL0tXDVyZfefacqV+X/ZSJx5+qLbx98LhaL9RiGEZWlEsWC/Thd9q6Pf3vs2u6Orc83rFsvTwwfLf5obgywT1Vjh2Hh+rbNsnTssJdNLedK5aIrpSuldKVXKsnH4+Pyn6FDXn5tMef9O+3NvdkvP1V4+EYw2AoQ+KSx8dRYS6NXXnwovaItXduSrrkinWxGOmZWJi9OyOK9m1LmsjIz9IH8QUMOd3WfAQwNKCy2tJwbHB5+XasPaxIHmc4g7WWEZ1MquBiRFlJTf1E7+Tl/H/8asavPzTY1nWd2ZkMDRPeBeHPz5ojwsilEQCBvTSKunCF3M8FSNkBGVTHDYYrLj8jVNhDZ2SMa2zo3MTamaIC/u6Ojr3DtrOrvP0BpdATnyBeIhTxpR5ABUlKSUlXS1dWstbVxdz6hPL0l1quGqkLaKwNvVcjEXNRd/4mit4Z19DjefBEPyCKxgQJQcF28dBrHNDGTSZSezsjeff0hraa2Vs2vrvit81O4vj9xLJcC4ADrQA7YAGqBGsAql/EtLdFQE/L7dF1XZmdnSrbPMJfXoLDmolQK8gJyQBowgQhQDRQBD+hsraVhd4e5MH+/oExfvWLJ9q3/3S7qMpNH2hsS40kFS4EUUAMA2IANRIBXv4uzuO67c2PykqkA5YmZ6bN18YPi0Yoknxc4AsJPCMLVAk2BLKDosCWqs/PZaulkuxk9fekcUBAAQGDks5FT0W++3NuYuC0DVUL4DIEdlIQDAj0IRkigaMjArkFx0tf523sffrQHyKsAgHPhwoXLL+yP9/kePNhk5ExUTyKFkJVAUAiCFZrQup4Rv9ftuLV/6ONBYBVABQAArMvJ5MXW7duD6P62sD8UrPAFRU1TpeCpCnGvPZr7WW///v0jpw+VC9ZdAAABAAAAAMLo7drWrmQyPWG/r8tnaGIjaM05ujr16x/ZBFh5AACA/wGZnIuw4Z4A3AAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxMi0wNy0wNFQxMDowOTo0OS0wNDowMOPVpFwAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTItMDctMDRUMTA6MDk6NDktMDQ6MDCSiBzgAAAAAElFTkSuQmCC',
+ 'Gentoo': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAB9VBMVEUAAAD///+AgICqqv+AgIC/v9+Ojqqii9GAgKptYZKQkOmPj/ddUYBgW4eVjeCTgfiWjO5wbJaZkvPBvepkXomYkNldV4Bzbpl6dJ+Uj7ynoO6Vi+1qZI63se2mnudjXYjOy+GCfaqZjvWlm/Pc2e+Oh7NeWIOWjfeXjeW1sd+gl+diXIfp5/KHgKnn5/F2cZx6c6ZgWoXc2e6dltrAvNu0scrX1eTOyujCvup4c5qpovVpY43///+6uPPJyPXq6fvm5vrz8/z8/P7+/v/d3PixqvmxrPSyrfe0sPO0sfS3tMve2/3r6vy6ufPz8/3d3fi3tM63tPO4tsu5tsu5tvO6tfe6t/Vva5KRjKy7tvW7t/W9vPO/vM+/vvPCwfPEw/TFwvTFxOfGxfTGxvTHxvTIx/TJx/aTiOrNzPXNzfXQzfnRzuHS0fbS0vbT0uHU0e/U0uTU0/bW0+zW1ffX1vfY1/jZ2Pjb2/jc2uSTiemVkLSlnvbe3PTe3vng3fzg3f3g4Pnh4Pnh4fri4enj4/nk5Prl5Prm4/ymn/bn5vro5/rp6O/p6funoPWsqs3t7Pvt7fXv7vzv7v3w7/nx7/3y8f3y8v3z8vytqPWuqPX09P319P319P719f339v739/34+P35+f37+/+uqev9/f6vqvSwrPQAR0dcAAAAPHRSTlMAAQIDBAgJCwwVFyAsNUFHSVBneH+Bh4mVmZmanKCxsrK2tr3ExtDW19rb4ODl5u3t7u/w8/T6+/z9/f4MkNJ1AAAA8ElEQVR4XjXNw5aDURSE0YrRtm3b54+dtm3btm3bz9k3Wek9+2pSYFwT8ibzE93hwAtdJqK3nZo4J9hFXbP+vFHOthV6gnGzstZq94wdCs4UCCDymQ2v7X0LdYoSQ0MIENRYzJbRlPTTHu73ZNAL8vivmVui98PpzuqffX0mIPHJGtOQenukteJ+aS3b9htNpDnT9TeZH1bHAwBRMhGpd6e6uNrLoRgxBKmsX47nBlp678ojpEA40fejcmW4e/No0V8IIPfj6eKgbEJ3ZUnzgE1OqWp9Q3VeWRAsg51f1dZ8c31RmAsc+N5JGbG+zvj3BzDCPrzMDC9SAAAAAElFTkSuQmCC',
+ 'Mint': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAACVVBMVEUAAADh4eEAAAAAAAAAAAAAAAAAAAAsLCyXl5dgYGCnp6eTk5N3d3fBwcGqqqq8vLzNzc3Ozs7Ozs7Pz8/Pz9DQ0NHR0dLS0tLS0tPT09Pf3t/Pz8/i4eLb29vZ2drZ2tna2dra2trf3t/u7O/u7e/u7O/r6+vt7O/w7/Lw8PDy8fTz8fXz8fbx8fHz8/P19fb49/j49/n6+vuPxlmWyGOx437h9NDr9eD6/fj////+/v75/vTA5Jv6/fb7/fnL5bDL5q+AxjeDxUCEzTyGxUaGzjyHxkiHzz6J0D+Kxk6K0kCLyE2M00WNy06P00mSz1OUyF+W2FGX1FiY0F6Z02CZ21ac0Wiez2yfz2+f2mOh4GCi4GOi4WKi4mOk12+k3Wul32um1Hin0nun4G6n5Gin5Wmo23Op2Huq1n+q43Cr526s4Hit23+v6XSw34Cw34Gw6nWx4IKy4IOy44Cy63ez146z34az4IWz4YW03Y217nu38H2625e645G74pK83pu98Iq984W+4ZjA4px0tzDA5ZrB8ZDC5p7D55/E947F6KHF+JHH4qvH6qTI46/K5LLL5LN1tzLL5bN1uTDL57DM5bPM6qzM66/N5rTP6LbP6bTR6rfS573T67vT7LrV7r3X68XX7MHX773Y77/Y9rvZ8cHa7cjd88bi88/j8tTk8djk9tHm8trn89vo89zo9N3p9N3p9d7p9tvq9d/s+93s/dzy+erz+O73+vT4/PX5/fT5/fX5/vN1uzB3vTD6/ff6/fh5uTj8/fv9/vr9/vx8wjV/xDmrMRH0AAAAOXRSTlMAAAECAwQJDzk/RUlNU3F0kpSVlpeYmpucnaKjpKWqqqqtu8LExMTEzdTU1NXY4evy8vP+/v7+/v6LaR1mAAABD0lEQVR4XiXI03bEABAA0KltW9kaW3eSZW3btm3btm3b/q4mp/fxgqKOtpamhrqaqoqykrQYABh+PVMU9fjE5Xp8o54kgPHN0EBHU2N5YXZykiua0HHd2759VF2Sk5IYE5GGsmCEWLV1kVWwt5O+3x/qpgsy8k4ja+cJl2/v5C22tlgCAHtw9TQSa4s+AzfPSm0BRNl9SydhWJzLC567KrNhgrNwHIJ5qTz/2f9w7Jw/DNqIjVr04exW0AEOXcN3Ab7enr9eDW2VTJgehONyc2Z8XP5YdD0Tcuhcc4/r45OjGX51TEjYPbh8THRPvbz+CHusgSZlT7rP8PkCwfQKaQUi9Igr6JsRBMFiWZgb/AHKElRzKopZJQAAAABJRU5ErkJggg==',
+ 'Osx': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABrVBMVEUAAAD///////+qqqr///+ZmZn///+qqqqAgID///////+tra339/eAgICoqKjx8fGMjIzm5ubh4eGPj4/g4ODIyMiAgICSkpKLi4vS1tbPz8+Xl5eMjIypqanIyMjW1tZ2dnbR0dGamprFxcV3d3d+fn60tbV3d3dcXFx3d3epqal7fHxxcXF+foCnp6hYWFhyc3Ojo6SMjI5fX196enp+fn6Li4xERERqamqgoKFpaWmFhoeen6A/Pz9QUFCWlpeSk5SUlZWUlZaOjo+Tk5RHR0cuLi5YWFgwMDAeHh40NDQ3Nzc6OjpcXF1rbG0XFxdSU1NVVVVXV1dZWVlbW1tnZ2lwcHABAQEEBAQXFxchISI+P0BISUpaW1xHR0kNDg4qKyszNDU1NTY9Pj8NDQ1cXF4XFxhSU1QSEhIDAwMrKywtLS4uLi4wMDFHSElISEggISE0NDVJSktNTU1FRUVWVlhGRkYEBAVBQUE0NTZQUVJQUVMFBQUqKitWV1lXV1daWlpaWlw+Pj8bGxtcXV9dXV1fX19fYGFgYGBkZGRlZmhpaWlsbGxwcHB2dna844Y9AAAAV3RSTlMAAQIDAwUFBggMDhkeICMkKCgqMDIzPj9ERFBib4CCg4iMjZCcnp+jqamrw83W1tvb3ePl6Ojp6+vs7u7v8PHy9PT09PT3+vr7/f39/f39/v7+/v7+/v50ou7NAAAA30lEQVR4XkXIY3vDYABG4SepMdq2bRSz/capzdm2fvOuDO397Rw0Ly4tz2QAQPbcxuZ2E/STJwfxPhWgG355fRrVAIVb1zeP9UDLfiSwkAcADe8fn7tFxWuEXFRDoer/OgoMTRBCumj8yJwPBo8Zhpk14U856/HI8n0ZUtpZ1udrSzfVneA4roNKjdrwpcMRilb8d8G60+lKnrpWcn9bO+B23w2O8Tzfq4aiNSZJqzn5O4Kw16h06fPZ+VUlUHfo97+VAEb7rSh2UgDd4/U+TBlQY7FMj5gBIGvcarVVfQPVPTG94D0j9QAAAABJRU5ErkJggg==',
+ 'Rhel': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABj1BMVEUAAAD///////8AAAD///////8AAAD///8AAAD///////8AAAD///8AAAD+/v4AAAAAAAAAAAArKysAAAD///////8AAAAAAAAAAAAAAAD///8AAAAAAAAAAAD///8AAAD///8AAAAAAAAAAAAAAAB5eXn+/v5JSUnKysrS0tJ5eXmqqqqxsrL+/v4ZCgknJyeHh4eIiIjo6OgZCAdOTk7t7e3///8GCwwPAAArKyv19fX29vb9/f0EAAD////+/v4AAAAGBgYHAAAJAAAMAAANAQAPAQAVAQFyCQV9fX2pIRzmEQjn5+cBAAAFAAAAAADnEQjvEgn////uEQjyEgnsEQjzEgnxEgljBwPaEAj9EwnwEglHBQJHBQNNBQIBAAB3CQR5CQSHCgWLCgWRCgWTCwadDAWmDAapDAa/DgfKDwjWEAgGAADh4eHiEQjmEQjmEQkKAADoEQgLAQDtEQgMAQDuEQnvEQjvEQkPAQAfAgEuAwEvAwE8BAL1Egn3Egn4Egn6Egk+BAL+/v5CBQJrB0muAAAAT3RSTlMAAAMEBAkYGhsbMTRLUmpvcHeIjLe6vcHCxM3P0NbW3Ojp6u/w9ff5+fn6+vr6+/v7+/v8/Pz9/f39/f39/f7+/v7+/v7+/v7+/v7+/v7+Q8UoNAAAAO5JREFUeF4tiwVPA0EYRL9SXIsWl+LuxfcOd2Z3764quLu788NZNrxkksmbDP2R7vH6GioLs+iffEzNXd4+TqPErUUpVqMOvwgdzMPn1rv5vPsVeufBTaBK/bH2FPvkEUuIG5jIIc+sHYn/HJ3dC/Hxuo4y8s44dzwBbFkisHN8bVIdXs6jb+H97aCwbHEIqgcml64CD7YllNkAVQC940MLYe5YzvIeQAXNrd19Roc5MdzfdQLUUKaUYyuG9I8y1g4gj6hIak4X5cBIT2MquZJrJdOqpY11ZpAiqVwbY/C7KY1cRCrZxX4pWXVuiuq/hs49kg4OyP4AAAAASUVORK5CYII=',
+ 'Sabayon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABvFBMVEUAAAAcUaYdVKwAAAAAAAUABAwWRY4YSZYhZtIhaNYHDx0KCgoFDBcKCgoRMmYSNm0fXL0fXb8AAAAYS5gaTp8fXLwgXsEGBgYFBQUZSpgZTZ4JFSgODg4IEiIOJkwOKVIkW7EnXbQLGzUTExMKGC8LHjwMIkITExMiIiIPEBEPJ00QEhMXOXAaPncOJEgoXbApXbEcHBwwMDAEAgAfHRgQDgo3NC8AAAAHBwcKCgoLCwsJCQkaGhofHx8lJSUwMDA0NDQ4ODiRkZEICQocHBweHh4GBgYHCg8mJiYnJycpKSkrKystLS0uLi4ICAgODg43NzcRERF1dXUUFBSjo6O1tbUbGxsEBAMLGS8MDA0iIiIjIyMkJCQNDQ0NHTYKCQkoKCgPDw8QEBArMDkKCgkRERIREhMxMTEyMjISIz00Njk1NTU2NjYCAgIVFRU5OTo5P0c8PD0+Pj4/QURAQEBHR0dKSkpMTExSUlJiYmJlZWVnZ2cWFhZ2dnZ4eHh8fHx9fX2FhYUXFxeVlZWXl5eYmJiZmZmcnJwZGRmlpaWrq6usrKyvr68KFiq/v7/FxcXY2Nji4uLn5+ft7e0yif9uAAAAN3RSTlMAAAApKSkqKioqg4OEhISEhoa1tra3t7y9vr7S09PT09TU+Pj5+fn5+/v7+/v7+/v7/v7+/v7+70RY/wAAAPpJREFUeF4dyWNjw2AUBeC7dfYyorM6rx1exKltzLZt2/rDa/J8OgBVVlFDX39jcTZoUqCse251a2dvu6ccUtWlanLQ4Vpel+ThlWq1l3wEz58tx4dOt1dMlAJk9A5gMjG75LHwo46hzkwosGOMbejumoRvubC9EOrMviT0E0Us9fvN9dA6zxJCNv6+ECGsb6oNWsgmpZT9/UTUZo3Em6AW34guTL4jiAudiCM1kLcw8/SmHERfT1/eueBiDqR1GK1n9w+K8nglxYxd6QAML4ztXoQuj8YFgWcgqdJp8qzty26vaboCNIxBCshyQDKov0aXr29v1ufq1PwPx5Q7bCoh6eoAAAAASUVORK5CYII=',
+ 'Slackware': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AcEDi0qZWWDgAAAAx1JREFUOMt9kktoXHUchb/ffc1M7rySSdJMOknFPMRitLgoNKKI8ZHGKkgrjU8SitidimSh2UkXoQmoO1dGQSxJjdvOtqSaqlR0USEGSjVJGxuSmWR6M3fu4/93YX0g4rc9HA6cc4Q7DI+fpzz7PA8++2mxvZAeBZ4xhHtFcJRmXWsWvb36/OLcyxf5B/KHeYHy7DmGx1+YSDjmWTdlobTGMAStQGkNoLXS4tXDq7u7tUcWz49tA8jR8QUuzB5n5NTCV13F9JEo1JJwTLKuzU61QiOMcd0UDb+BncwQK3Rl15eNja3ui/Njq8aF2eMcO/XlBz0H8oO2ZUkum6A13WB99TtyzXlaCi24SaFa+ZFCzsG2DNnfkdbFjsI1APPhk+d6ujqznycdCxFozadYWvyMpx47wa+bPkGksKwUNnsk3TaCGASRXDZh5LpHXPPg4Rcni+3uYBxrtBbQghlscOVKmYHeEm0ZIZ9xyLffw41ND6VAa43SmjiMByzHYtjzwr9arfshxf5jOKlvKZfn8es77N2uks24PPfSFD/9Uvt7AtPKWmEU9d645eHYJo5tcKi/FX/zG+zmQxQH+rANk862DOW5N/hhaY64cJSa5xNFCgDDILZACMKYWAmh73HmzFsMlBQJ06LeiMinE1S3KzRCm5rXIIoUIoKIYCVM36urZFbEoiBLNMIhAE6/NsSB7h6SKZdL8xsUOnpx9j1KbTdARACIowArYe1ergfNT2i0mIbJys0GI6PT3N1/hJvrPxOFdRJNBQIy/FapI4Bpgohgcjuw+jq8jy8tV55MNBWI4ohS802CpizKv8q+FgALZAfYgSyAZtNro1oLaU1VvxCA029Oraxs7u/tKnXiNjn8HyKwur6lI++6vPK4V7IA7u+1Dyu1tr183ddNbkHuXP8/zEIYeFqiLRl6YO/p0bHJdflT/PD9qZa1W+ry99fcvlAlcZwUpuUAglIRYVgnDEIOlna4q0M/NPnuO1/PzMwg/045O/XeibUt5/Xangx6viSVFpK2jtMpvdyWCz+5ryf10clX3/amp6eZmJjgd441URWWJY8BAAAAAElFTkSuQmCC',
+ 'Trisquel': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABjFBMVEX///8AAAAAAAAAAAAAADMAAGYAAAAAHFUAGWYAF10AImYAIGAAHloAHGMAKGsAGmYAJmYAJGEAKnUAJ1gAMXYAJnEAJGQAI2EAK28AK3cAGTEAMHgALXEALXgALG0AFUAAI2oAK3EAMngANoYALXMANIAAM4IANIIAL3gANIcANokANoQANYQAOY0ANIYANooAN4kAN40AOY0APZMANIUAOY0AO5AAPZUAPJAAP5MAPpQAQJUAOYsAPpYANoUAPpoAPpUAM4AAQJkAPZIAPJEAQpgAN4cAPpQAPZUAPJEAO4oAOosAOo8AQJoAOYsAO44AQpsAO48AQp0AP5UAQpoARJwAQ58ARaAAQZgAQ54AQ50AQpgARaIARqMARaMARaIAR6QARaIARaEASakARKEAR6MASqsARKEASKcAR6MARqYAR6UATbEATa8ARqUARKAAR6oARqMASKgATK8AR6QATbIATbAASq0AR6cASKgASqwAR6UASKcATa8ASqoASqwAS6wASKoAS60ATbHn4CTpAAAAhHRSTlMAAQIFBQUGCQoLDxAREhMUFBUYGhobHB0eHh8gIiIjJCQkJCYoLC0xMTE0NDo6Oz1BQUNHSUxOVFVVVldaWl5iY2RkZWZoamtsb3FycnR1ent9f4KDhIiJioyNkJGYm5+foqOkpqamqKmqrKytsLKzs7e4uLy8v8TFxcXGx8rO0NXY2eZc4XYcAAAA00lEQVR4XkWN1VoCUQAG/3NWtwh7CTsQJOyk7BaDxuxA6bbrxf32gt25m7kZqDRYxziooDV7+1AalMUavQh2AsEZoWvzigLun+T17/c8QiJZ7qu2QKiNmyZthdcR1/as353jIeU1GxMHo5XHdqPFeX8IaDMdHPYN6dRN7LR4qQewdTa35HWkyh+fbxERAMjwlAWJv3CPSKDQ+H7XvHdkV4Pua3Gtm4sPKIF/WV8dop4VKBw/NU33B3x1JbTt+XwhkJQoqRfWvHOy28uqH8JIdomR/R+s9yR3Cso77AAAAABJRU5ErkJggg==',
+ 'Ubuntu': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABKVBMVEX////ojFzplGf1zbnqnHLvs5P10b3yuZv1xKrytZXvtJXys5LysI32waT0n3HxiVHwg0jxhk31kFn0h0zxf0P0hUrveTv2iU3yfkD1hEfyejv5eDLybSX0aR7zZxvyayH6ZxnxZBj4YhH7XAb5WALlUQLeTwHgUAHeTgHfTwD65NzdTQDdTQHdTgD31MfcTgLcTADcTQD////xt5/31Mf54dfmfE/dUAbeVQ/jcUDcTgHeWBnnflHohFvpjGbqkGztnX342Mz53dLgXiP65d399PHdUgrtoYLyu6Xzvaf76eLfXB/rkm/fWhvupojwrpTeVhTgYSfgYynzwa30xbL1ybnngFT31snngljhZS3539XhZzDiajbibDn77OX88Ovrl3X99vTjbz1fisGCAAAAMHRSTlMABgYGBwcHJiorMDA1NXGHjY2Nl5mZmZyfn6O5u8XHzc3X193j9fj4+vr6/f39/f08OUojAAAAx0lEQVR4Xi3HZVbDYBhGwQctWqzFPXiQ+36pu+LubvtfBKcN82/UEhld2vWXxyL6F92gbTPabse8hU/uHMx1SZoyyJWPTwq1Rs7GpYE9+Cg+OJcs1MHvU9y4fnrN31yUm18vMCIPjtw3QMndw4rs8ieVzAAcBlewpe1KM3uaBuD3Dda1BhWXAsi6AFY1a2SqifxZ+rnxWYcJDRkUS3fO1R5vwe+XZgw4D4L3RAJiknoXCVX3WeiUpJ5pIxTvVmg45pl5k4Ot/AGV2iqZBWgJJAAAAABJRU5ErkJggg==',
+ 'Windows': 'iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA+pJREFUOE+F0n84FHYcB3CWSsL9ojo/6ik64c6PnTjmSS0limmrpBm2G002y++xzXRz6zE0R4nbw+RnTj/WD4sbanLkkAe55ccYlyNme4SrO9u9d13PI3/saZ+/vs/3831ez+f9eb5aWsuqy2mjRYeNUa7YmtjfTico7jNJ8z0eG24NB9vvnDrvufzpq89Npnr8VjMddNmuRh9rDfp36mFg91oM7qPIc5JdbDJq3An/JfCu7Hl53W2lpS220pP2OuniN299jAYbYizSENIoAgbCTdrTKtxOJVdvGo8psUwKy7Vxe4ez1YEVudGP8YEZzyveInFJ6mZRHHqYazDspw/pJwTIuERM5JIwmUdGdyo9K7/BszGzzg6fXzZHGJ8KvzQqXKOpoIeZLjofWR++BPWyCEnPY4xFGEKWQcLjMjKmr1MwfcMYwmz/Y4KOgNki0V5k1dkjUWCK93Kp2PMFFawos8cm1gZ2GqjLXktL4mbQPHLQ4B9ZDFE5+S356fQlyuJMqzH++HnTo6ui2OO1ko9Ul+4fxfd3d4F7k4YTReqpuFS88bGZUE2QNNDobuIq8Q5CduHb7lFJaTnvnym9ergjMWD/FG8zf+aKS3G9JO5C01Asah6wUXrvALKEDoitMMHhDKrKJdg8RU2s0EB2EWWur8dd7PDPFv6dUC0Gv3kAN36VPRGP/5k5NS6lljWxG0TDiSr1VKhoPwhevRMSqkwRxDObc/DavGtpP6zoi8XOyZfhnyNEvKANBU0P8VPfI/wyNCGXSn7wlEmyA9KrgmOKGth3eDVvPfyywq2dnUEv2R9qG2rLsH7xJXziKnWcI8tlTvEC7Mu8hROlImTU9aKqcwQ1vWOihWFu+sJknmph5CvxQh87c7bNh/NXo03hrMCosyvLmMNgMF7TQL6J1dsZIUVwjKqEO+cajp5vxPN439U/gKBt8PTcYHzL/BgHCyOf4unAISj6mFC2bYC82kB5Ls460NHRUVsDeYSXpGw7UgC7sAtwShDgzdM38W7BbURXtqpqhfmB8sEQuXwoCM/6faGQuGCxyxyKWhIm+PrSD495WL3cT0hhi8Whc3NbAs9KaOyCTvrJ8qkdX19XBeTUDU00+55USFzVU2yHstcaix0mUAjJkJeuRU868Ucmk0lcguiBnMAVxjbbdHV1yeq8+u4Hgo22huSG+iQXp83ftaxW3lsPZcs6KG5T8OwaAfJiPcxlrVRVRhvF02i0F/t5VbHZ7JWDfErKTLnhE3mFPuRFepg/uxqz6TqLv6euGj3ut87t/4ylvre3t3ZehOWWO1zjSFEqMVP4GfGb/DBykJcjmaZOoLsc+hcVY/LaAgcTQAAAAABJRU5ErkJggg==',
+ 'OpenBSD': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAykIPu64pQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADTklEQVQ4y32RXUxTdxjGn3N6eujoKT3SUkuk3VoBGfVjgFXAsZ7WkipyYXQbuu3CzUXZmGRbssnFEseFkWzgcGzGXky9MWL8TsC4IeFgtK4oAqOnG5vMVl1pCMVWQD7b/y5M6jLdflfvxfPked/nBQA0NDSChqnGVrLuGkES742NhJAdhAKAuk9yyUs5Gry7RQMZAARCWgivpQiPe71P5DUfH0xaqTL7m/iiLkJmphawa+e4SM2PvUyC4yUIBu8CnAQKAK53rCA5OUtQtStVpJ4Gw/FOBddZVKhCfq4MP4n6+at+DUsJm/e0G9JZzYEvI2tHwlEYjDxomkZ+3nG8WroRtHihZVOhVlorDQzh0okhcByDP4ZGcf+X9XAsvY5/RsBa7Kq5H/CqLctKyl/g08S2i6fq8W/MS3P34T9wNDVYSeDX1eTD9xhiLXbtB/Akwmmv6Kr+ICFkLpGhtNSM3qsSstS3oX8lSsmsxS6ZVn3j6PvVVqhUcvC8AtPxVPxwygVKvngN89WOjgVprggGA4eenjB4nsXsTASpC63I0wVTZYPR11FoKRB8Ax54PCFk6BhMTk5CPR3GSbHouGzknr/bYFq9EAvfc9Tu1sLjHcXNKxLuTOTgzOlOe7IHBc/beAXWpWmXlz8a84nhcLQ+ecVzsAEQrMWuMX+f9HZF2YPZ28FVSNfoPWqOzMUmqYMAJm7+/OOzXQFwHGpyEV+vi+yvtxBC9pDmpgJC4tvI3mo9GTitIxvW24nT7ug67HY/3eDs2bbyrVsrY2day70rV6kRfDAHk5lDLJqAmmeRiD9GJDKHvwb74R8G0mkTPjrQTTG122xkTTbwaV2b1H4u16JQKXGr7yG2b8/H1MQ09IsTSEmRwzf4CCwzD+dmE1re8CI7wwi5XNlFf9vaTXX4dWJg4LLl7h05fpNGwNAMWpp9CIVYNO/tRCzGwpDFQaVMQTS2CKY0BWr3GVGWNSXKACDDaA4Mh976pq9f5Sy09GgKlmeAMIBKzUKpU+BFoxJecRhUfAbMxDi4eADfHVmE79v7q575gvvYeVvjZ58LD5mwsKUyX0hnf0feslnQCWD4zxnc6reKisxsfH2oscqcmTmK/+Ow252cna7K52r+Bky6PqmoT5HBAAAAAElFTkSuQmCC',
+ 'Gnu': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAywUV5gQrwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADcElEQVQ4y43Tb0jjBRzH8c9v+7nNMebcUW21Cc78g/wcuhByIScoMRwoTBmFlZCmIJ14axqkgoYIkXIqKIVBEuJNUBEUPRlpqDC3Q2Ex0nTezun2YOaPLXNIv7Vvj7zgiOj1+PPk/eADjuNEuHN6ekqMw+H4IzMz8xChUCjV1NT0JbO7uxtfXFy8NZvNr21tbd0AAEQikY6I0m1tbQbx2NjYZiqV+vn29jY+PDw8xhYWFj45PDzcb25uhlQqfSTief6X0dFRpqKigvF4PPPipaWlY7lcXhCLxXJnZmY+ZTY2NnzX19ePGxsbHw0MDLivrq5mc3Jy2pPJZLVWq/2cdbvdDSzLholoNJ1OMy6Xq0Ymk5HNZktOTU29qMgA8HYqlaKDgwNKp9M0PT09BgAM/iGuqqoimUx2yPP8U5/P9wEAMB0dHRUKheJHiUTyeGhoqAUAnE7nR0qlsjcQCLwjlsvlz+bm5mQWi0VSWlr6bXV1tU6hUMj6+/vfN5lMN0xxcfG1zWZ7SETTSqWSGhoamPHxcajV6s+8Xu9Xou7u7t9VKtW00+mkSCTC6PV6aDQa8Dw/Wl9fP8UAQCgUosvLSyovL2eWl5dRUFBw7Ha7v9vc3By5K3g1EAg8FQSBiIguLi4IgBwA2LtEjuPuJxKJ62AwKFpdXf0eQBIvYVmW/cLlchEAWK1WAADT09NzX6PR/OTz+eKVlZUzKpVqTyqVvsnzfLCkpGSrtrb2t97eXnFeXl5ZKpWyZ2RkPPP7/UUnJyefGI3GU+zt7aU4jotOTk7mAUBfX1+b1Wq9kcvlBIAcDgctLCyQxWKhoqIi6uzs/BoAVlZW3qqpqbllZmdnf1hfX//Q4/HEzWbzX+3t7fcMBgMFg0EYjUYmEolAEAREo1Hk5+fT+fk5Mzg4GD86OpJ0dXXJGQBoaWl5Ra/XP6yrq3tQVlam2N7ehslkAsuySCaTUKvVSCQS2NnZSXAcJxYEQTEyMvKeIAhLDADY7fZ7BoPhm6ysLFpbWzuan5//WKvVvsHzPEWjUSYSiSA3N5d0Oh0TjUaf+/1+S2Nj46/4FwYAr7e2tnbF4/E/iYjC4TCFw+F0LBaj/f19mpiYeID/IAagAyABYLXb7cLZ2Rml02nyer3POY6rwv8hEr34u0IkEk1mZ2cTgGMA7768/RtL5JKsGzrLIgAAAABJRU5ErkJggg==',
+ 'CrunchBang': 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAQCAQAAAC45EetAAAA8ElEQVR4XnWOsUpCYQBGz1TIHYu2Qix6g0DEtSeQu/UIISJtUS8gJq61F1wcdMohcBDxKUR8hsz1xA/y44/cs3znbB+RJ0Skl3pSkeFQbUs79VAPzrwPFRmN1Ja0Ug/16I93+1oi4lKte+zMXv32WuoAm43lXMrqzbFncgWw21lORf4+/PREKpAhYqZuPXZ+T/3yXbZEajV1JavUQ104sRcq0myqc5mnHurWqc/7yhExVwuPncl+C4Bu13L60ueAwcByOtLhgAIRCzU38fRGTmSxUBvSSD3Ui1NvQkXWa7Uq1dRD9R17HiqyRUSy1NP6B7e1Yu2GtlUKAAAAAElFTkSuQmCC',
+ 'Yuno': 'iVBORw0KGgoAAAANSUhEUgAAABgAAAAPCAYAAAD+pA/bAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAABDtJREFUOE+FlHtMm1UYxrtsi8aEgCb+oTFmZur+WNS5RaPERU10C2qGaBgb6hgwLwMmHTIKlIKlQIHSQrmU24BSSmnpBVooUmihtEC5yKWDjVu5uOkcEca4lG5E93j6EQmELX7Jky/fOed9fu973vMdGu0xT3Cgz57yXMZLDdXcy821PFWLKmuA6HqLMqtLX5POl4iYb2ukWW8IOOFe/qfe3/M4n0eOjwyZD8//bldODOk37N1yDJgl+LVdjEGLFKO9KkzZm8hbje7mIrTXZ7sMtTydrJh15H8hHW11XvN/jGS7VudcD5w34ZZzeQYb67fwYO03LN4exo1+LWzNxbA05O5QuzbHqRYn+++CHDx4YK9WLfaedfQzV5em54g5Zbi8OIml+VFMDLWQ7GXoaSmFWZsDZVGCO2u0EbkhHTrhFqi9PmelSsQ8tAtSVch60dpUeGe4kxgZxegzVkBzlQ2NKBG2+iJIMqMok9r8OLRIMqApToSqmAWTmk9B2+o2YW79oshU7ABcuvAFrVGWXkVKpBYoSaBSxIS2mINpiwbjZiUMZRloVfJQyaXDKObBpimBScpHFe8KmmXpaKhK3arGrBVuVBclHN2CiPNin1OVs1tVJYlQlyZBxA6DviQVo6ZaOKd7sTplw53BVugruBBzfsRslw7rZPxaczWutSpQV/gzJPxo1JexyfaxKBBpuiEx+tw+CpKdEvGWTprGlhcwqbIzL5/DYKMYndpK3L1hxf3ZfkrzwybUZjPhnOqmvlcmutFF1jis9QSShOrcWNSXJ1MA0ou/NZWc8Ddfe4VGO3bk0JON1dyMMlK+gmxNrZCFhZF2Kng7YNO0awt4b7wLNp2EqtAsF6ImP56SG0B6siovTYpIjg15gapCVhAfJRUyIBFEo6k8AyuTtkcC/qvG/XbDexulWJvqgYH0o0nKhVHFJ40XwFQnWM5OCX+XMg86c3KvVMSMapCmPpSTIygTxGKZZOcOXhrr3Mp4uzkFuG6B3ajE3TELDDU8qEmsmvRATxquKkxAnSTFjwKEfv3JU9JC5unG6rQ1bTkbQ4Yq/DVgxOqwBWt2K9Yne3ZCZvrgHO2k5paHzOhSiVCZSkdNTgzy40JRlPgDhDHBCxUZdCs91G8fLeK87zOl6XSOICZYXMGNhDqX9fDP/mbK2DXVi/szm03eLpejl5pzOfqwOt4JBT8OeYwQt/4R/BR0OzXiLCM5LOCji/4nXt46rpywgG+zor5RxgSdupBzJdglSY+5ZZbl3XNY6mbn7W0Lcx06zBg1WBjtcC6OmG+OmRTrFrnIUZESZeVeCpwh8TpiPsQ47/tloM97T+/6m8mg55mT3tStyL54mhlwwtszNvjzD8/6HH8i7PvvPPRioZdRWuDBZUR6pEWG7I8P9Xs1Jsj36MfvvO5J/+rTw58dP7afJPfBgeef3XGz/gskFVpJc4HwGwAAAABJRU5ErkJggg=='
+ }
+ };
+
+ ExpandComment = {
+ init: function() {
+ if (g.VIEW !== 'index' || !Conf['Comment Expansion']) {
+ return;
+ }
+ if (g.BOARD.ID === 'g') {
+ this.callbacks.push(Fourchan.code);
+ }
+ if (g.BOARD.ID === 'sci') {
+ this.callbacks.push(Fourchan.math);
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Comment Expansion',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var a;
+
+ if (a = $('.abbr > a', this.nodes.comment)) {
+ return $.on(a, 'click', ExpandComment.cb);
+ }
+ },
+ callbacks: [],
+ cb: function(e) {
+ var post;
+
+ e.preventDefault();
+ post = Get.postFromNode(this);
+ return ExpandComment.expand(post);
+ },
+ expand: function(post) {
+ var a;
+
+ if (post.nodes.longComment && !post.nodes.longComment.parentNode) {
+ $.replace(post.nodes.shortComment, post.nodes.longComment);
+ post.nodes.comment = post.nodes.longComment;
+ return;
+ }
+ if (!(a = $('.abbr > a', post.nodes.comment))) {
+ return;
+ }
+ a.textContent = "Post No." + post + " Loading...";
+ return $.cache("//api.4chan.org" + a.pathname + ".json", function() {
+ return ExpandComment.parse(this, a, post);
+ });
+ },
+ contract: function(post) {
+ var a;
+
+ if (!post.nodes.shortComment) {
+ return;
+ }
+ a = $('.abbr > a', post.nodes.shortComment);
+ a.textContent = 'here';
+ $.replace(post.nodes.longComment, post.nodes.shortComment);
+ return post.nodes.comment = post.nodes.shortComment;
+ },
+ parse: function(req, a, post) {
+ var callback, clone, comment, href, postObj, posts, quote, spoilerRange, status, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
+
+ status = req.status;
+ if (![200, 304].contains(status)) {
+ a.textContent = "Error " + req.statusText + " (" + status + ")";
+ return;
+ }
+ posts = JSON.parse(req.response).posts;
+ if (spoilerRange = posts[0].custom_spoiler) {
+ Build.spoilerRange[g.BOARD] = spoilerRange;
+ }
+ for (_i = 0, _len = posts.length; _i < _len; _i++) {
+ postObj = posts[_i];
+ if (postObj.no === post.ID) {
+ break;
+ }
+ }
+ if (postObj.no !== post.ID) {
+ a.textContent = "Post No." + post + " not found.";
+ return;
+ }
+ comment = post.nodes.comment;
+ clone = comment.cloneNode(false);
+ clone.innerHTML = postObj.com;
+ _ref = $$('.quotelink', clone);
+ for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
+ quote = _ref[_j];
+ href = quote.getAttribute('href');
+ if (href[0] === '/') {
+ continue;
+ }
+ quote.href = "/" + post.board + "/res/" + href;
+ }
+ post.nodes.shortComment = comment;
+ $.replace(comment, clone);
+ post.nodes.comment = post.nodes.longComment = clone;
+ post.parseComment();
+ post.parseQuotes();
+ _ref1 = ExpandComment.callbacks;
+ for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
+ callback = _ref1[_k];
+ callback.call(post);
+ }
+ }
+ };
+
+ ExpandThread = {
+ init: function() {
+ if (g.VIEW !== 'index' || !Conf['Thread Expansion']) {
+ return;
+ }
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Expansion',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var a, span;
+
+ if (!(span = $('.summary', this.OP.nodes.root.parentNode))) {
+ return;
+ }
+ a = $.el('a', {
+ textContent: "+ " + span.textContent,
+ className: 'summary',
+ href: 'javascript:;'
+ });
+ $.on(a, 'click', ExpandThread.cbToggle);
+ return $.replace(span, a);
+ },
+ cbToggle: function() {
+ var op;
+
+ op = Get.postFromRoot(this.previousElementSibling);
+ return ExpandThread.toggle(op.thread);
+ },
+ toggle: function(thread) {
+ var a, inlined, num, post, replies, reply, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
+
+ threadRoot = thread.OP.nodes.root.parentNode;
+ a = $('.summary', threadRoot);
+ switch (thread.isExpanded) {
+ case false:
+ case void 0:
+ thread.isExpanded = 'loading';
+ _ref = $$('.thread > .postContainer', threadRoot);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ post = _ref[_i];
+ ExpandComment.expand(Get.postFromRoot(post));
+ }
+ if (!a) {
+ thread.isExpanded = true;
+ return;
+ }
+ thread.isExpanded = 'loading';
+ a.textContent = a.textContent.replace('+', '× Loading...');
+ $.cache("//api.4chan.org/" + thread.board + "/res/" + thread + ".json", function() {
+ return ExpandThread.parse(this, thread, a);
+ });
+ break;
+ case 'loading':
+ thread.isExpanded = false;
+ if (!a) {
+ return;
+ }
+ a.textContent = a.textContent.replace('× Loading...', '+');
+ break;
+ case true:
+ thread.isExpanded = false;
+ if (a) {
+ a.textContent = a.textContent.replace('-', '+');
+ num = (function() {
+ if (thread.isSticky) {
+ return 1;
+ } else {
+ switch (g.BOARD.ID) {
+ case 'b':
+ case 'vg':
+ case 'q':
+ return 3;
+ case 't':
+ return 1;
+ default:
+ return 5;
+ }
+ }
+ })();
+ replies = $$('.thread > .replyContainer', threadRoot).slice(0, -num);
+ for (_j = 0, _len1 = replies.length; _j < _len1; _j++) {
+ reply = replies[_j];
+ if (Conf['Quote Inlining']) {
+ while (inlined = $('.inlined', reply)) {
+ inlined.click();
+ }
+ }
+ $.rm(reply);
+ }
+ }
+ _ref1 = $$('.thread > .postContainer', threadRoot);
+ for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
+ post = _ref1[_k];
+ ExpandComment.contract(Get.postFromRoot(post));
+ }
+ }
+ },
+ parse: function(req, thread, a) {
+ var link, node, nodes, post, posts, replies, reply, spoilerRange, status, _i, _len;
+
+ if (a.textContent[0] === '+') {
+ return;
+ }
+ status = req.status;
+ if (![200, 304].contains(status)) {
+ a.textContent = "Error " + req.statusText + " (" + status + ")";
+ $.off(a, 'click', ExpandThread.cb.toggle);
+ return;
+ }
+ thread.isExpanded = true;
+ a.textContent = a.textContent.replace('× Loading...', '-');
+ posts = JSON.parse(req.response).posts;
+ if (spoilerRange = posts[0].custom_spoiler) {
+ Build.spoilerRange[g.BOARD] = spoilerRange;
+ }
+ replies = posts.slice(1);
+ posts = [];
+ nodes = [];
+ for (_i = 0, _len = replies.length; _i < _len; _i++) {
+ reply = replies[_i];
+ if (post = thread.posts[reply.no]) {
+ nodes.push(post.nodes.root);
+ continue;
+ }
+ node = Build.postFromObject(reply, thread.board);
+ post = new Post(node, thread, thread.board);
+ link = $('a[title="Highlight this post"]', node);
+ link.href = "res/" + thread + "#p" + post;
+ link.nextSibling.href = "res/" + thread + "#q" + post;
+ posts.push(post);
+ nodes.push(node);
+ }
+ Main.callbackNodes(Post, posts);
+ $.after(a, nodes);
+ return Fourchan.parseThread(thread.ID, 1, nodes.length);
+ }
+ };
+
+ FileInfo = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['File Info Formatting']) {
+ return;
+ }
+ this.funk = this.createFunc(Conf['fileInfo']);
+ return Post.prototype.callbacks.push({
+ name: 'File Info Formatting',
+ cb: this.node
+ });
+ },
+ node: function() {
+ if (!this.file || this.isClone) {
+ return;
+ }
+ return this.file.text.innerHTML = FileInfo.funk(FileInfo, this);
+ },
+ createFunc: function(format) {
+ var code;
+
+ code = format.replace(/%(.)/g, function(s, c) {
+ if (c in FileInfo.formatters) {
+ return "' + FileInfo.formatters." + c + ".call(post) + '";
+ } else {
+ return s;
+ }
+ });
+ return Function('FileInfo', 'post', "return '" + code + "'");
+ },
+ convertUnit: function(size, unit) {
+ var i;
+
+ if (unit === 'B') {
+ return "" + (size.toFixed()) + " Bytes";
+ }
+ i = 1 + ['KB', 'MB'].indexOf(unit);
+ while (i--) {
+ size /= 1024;
+ }
+ size = unit === 'MB' ? Math.round(size * 100) / 100 : size.toFixed();
+ return "" + size + " " + unit;
+ },
+ escape: function(name) {
+ return name.replace(/<|>/g, function(c) {
+ return c === '<' && '<' || '>';
+ });
+ },
+ formatters: {
+ t: function() {
+ return this.file.URL.match(/\d+\..+$/)[0];
+ },
+ T: function() {
+ return "" + (FileInfo.formatters.t.call(this)) + "";
+ },
+ l: function() {
+ return "" + (FileInfo.formatters.n.call(this)) + "";
+ },
+ L: function() {
+ return "" + (FileInfo.formatters.N.call(this)) + "";
+ },
+ n: function() {
+ var fullname, shortname;
+
+ fullname = this.file.name;
+ shortname = Build.shortFilename(this.file.name, this.isReply);
+ if (fullname === shortname) {
+ return FileInfo.escape(fullname);
+ } else {
+ return "" + (FileInfo.escape(shortname)) + "" + (FileInfo.escape(fullname)) + "";
+ }
+ },
+ N: function() {
+ return FileInfo.escape(this.file.name);
+ },
+ p: function() {
+ if (this.file.isSpoiler) {
+ return 'Spoiler, ';
+ } else {
+ return '';
+ }
+ },
+ s: function() {
+ return this.file.size;
+ },
+ B: function() {
+ return FileInfo.convertUnit(this.file.sizeInBytes, 'B');
+ },
+ K: function() {
+ return FileInfo.convertUnit(this.file.sizeInBytes, 'KB');
+ },
+ M: function() {
+ return FileInfo.convertUnit(this.file.sizeInBytes, 'MB');
+ },
+ r: function() {
+ if (this.file.isImage) {
+ return this.file.dimensions;
+ } else {
+ return 'PDF';
+ }
+ }
+ }
+ };
+
+ Fourchan = {
+ init: function() {
+ var board;
+
+ if (g.VIEW === 'catalog') {
+ return;
+ }
+ board = g.BOARD.ID;
+ if (board === 'g') {
+ $.globalEval("window.addEventListener('prettyprint', function(e) {\n var pre = e.detail;\n pre.innerHTML = prettyPrintOne(pre.innerHTML);\n}, false);");
+ Post.prototype.callbacks.push({
+ name: 'Parse /g/ code',
+ cb: this.code
+ });
+ }
+ if (board === 'sci') {
+ $.globalEval("window.addEventListener('jsmath', function(e) {\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(e.detail);\n } else {\n // load jsMath and process whole document\n jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);\n jsMath.Autoload.LoadJsMath();\n }\n}, false);");
+ return Post.prototype.callbacks.push({
+ name: 'Parse /sci/ math',
+ cb: this.math
+ });
+ }
+ },
+ code: function() {
+ var pre, _i, _len, _ref;
+
+ if (this.isClone) {
+ return;
+ }
+ _ref = $$('.prettyprint', this.nodes.comment);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ pre = _ref[_i];
+ $.event('prettyprint', pre, window);
+ }
+ },
+ math: function() {
+ if (this.isClone || !$('.math', this.nodes.comment)) {
+ return;
+ }
+ return $.event('jsmath', this.nodes.post, window);
+ },
+ parseThread: function(threadID, offset, limit) {
+ return $.event('4chanParsingDone', {
+ threadId: threadID,
+ offset: offset,
+ limit: limit
+ });
+ }
+ };
+
+ Keybinds = {
+ init: function() {
+ var init;
+
+ if (g.VIEW === 'catalog' || !Conf['Keybinds']) {
+ return;
+ }
+ init = function() {
+ var node, _i, _len, _ref;
+
+ $.off(d, '4chanXInitFinished', init);
+ $.on(d, 'keydown', Keybinds.keydown);
+ _ref = $$('[accesskey]');
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ node = _ref[_i];
+ node.removeAttribute('accesskey');
+ }
+ };
+ return $.on(d, '4chanXInitFinished', init);
+ },
+ keydown: function(e) {
+ var form, key, notification, notifications, op, target, thread, threadRoot, _i, _len;
+
+ if (!(key = Keybinds.keyCode(e))) {
+ return;
+ }
+ target = e.target;
+ if (['INPUT', 'TEXTAREA'].contains(target.nodeName)) {
+ if (!/(Esc|Alt|Ctrl|Meta)/.test(key)) {
+ return;
+ }
+ }
+ threadRoot = Nav.getThread();
+ if (op = $('.op', threadRoot)) {
+ thread = Get.postFromNode(op).thread;
+ }
+ switch (key) {
+ case Conf['Toggle board list']:
+ if (Conf['Custom Board Navigation']) {
+ Header.toggleBoardList();
+ }
+ break;
+ case Conf['Open empty QR']:
+ Keybinds.qr(threadRoot);
+ break;
+ case Conf['Open QR']:
+ Keybinds.qr(threadRoot, true);
+ break;
+ case Conf['Open settings']:
+ Settings.open();
+ break;
+ case Conf['Close']:
+ if (Settings.dialog) {
+ Settings.close();
+ } else if ((notifications = $$('.notification')).length) {
+ for (_i = 0, _len = notifications.length; _i < _len; _i++) {
+ notification = notifications[_i];
+ $('.close', notification).click();
+ }
+ } else if (QR.nodes) {
+ QR.close();
+ }
+ break;
+ case Conf['Spoiler tags']:
+ if (target.nodeName !== 'TEXTAREA') {
+ return;
+ }
+ Keybinds.tags('spoiler', target);
+ break;
+ case Conf['Code tags']:
+ if (target.nodeName !== 'TEXTAREA') {
+ return;
+ }
+ Keybinds.tags('code', target);
+ break;
+ case Conf['Eqn tags']:
+ if (target.nodeName !== 'TEXTAREA') {
+ return;
+ }
+ Keybinds.tags('eqn', target);
+ break;
+ case Conf['Math tags']:
+ if (target.nodeName !== 'TEXTAREA') {
+ return;
+ }
+ Keybinds.tags('math', target);
+ break;
+ case Conf['Toggle sage']:
+ if (QR.nodes) {
+ Keybinds.sage();
+ }
+ break;
+ case Conf['Submit QR']:
+ if (QR.nodes && !QR.status()) {
+ QR.submit();
+ }
+ break;
+ case Conf['Watch']:
+ ThreadWatcher.toggle(thread);
+ break;
+ case Conf['Update']:
+ ThreadUpdater.update();
+ break;
+ case Conf['Expand image']:
+ Keybinds.img(threadRoot);
+ break;
+ case Conf['Expand images']:
+ Keybinds.img(threadRoot, true);
+ break;
+ case Conf['fappeTyme']:
+ if (!$('#menu.left')) {
+ Header.menuButton.click();
+ }
+ FappeTyme.input.click();
+ break;
+ case Conf['Front page']:
+ window.location = "/" + g.BOARD + "/0#delform";
+ break;
+ case Conf['Open front page']:
+ $.open("/" + g.BOARD + "/#delform");
+ break;
+ case Conf['Next page']:
+ if (form = $('.next form')) {
+ window.location = form.action;
+ }
+ break;
+ case Conf['Previous page']:
+ if (form = $('.prev form')) {
+ window.location = form.action;
+ }
+ break;
+ case Conf['Open catalog']:
+ if (Conf['External Catalog']) {
+ window.location = CatalogLinks.external(g.BOARD.ID);
+ } else {
+ window.location = "/" + g.BOARD + "/catalog";
+ }
+ break;
+ case Conf['Next thread']:
+ if (g.VIEW === 'thread') {
+ return;
+ }
+ Nav.scroll(+1);
+ break;
+ case Conf['Previous thread']:
+ if (g.VIEW === 'thread') {
+ return;
+ }
+ Nav.scroll(-1);
+ break;
+ case Conf['Expand thread']:
+ ExpandThread.toggle(thread);
+ break;
+ case Conf['Open thread']:
+ Keybinds.open(thread);
+ break;
+ case Conf['Open thread tab']:
+ Keybinds.open(thread, true);
+ break;
+ case Conf['Next reply']:
+ Keybinds.hl(+1, threadRoot);
+ break;
+ case Conf['Previous reply']:
+ Keybinds.hl(-1, threadRoot);
+ break;
+ case Conf['Hide']:
+ if (g.VIEW === 'index') {
+ ThreadHiding.toggle(thread);
+ }
+ break;
+ default:
+ return;
+ }
+ e.preventDefault();
+ return e.stopPropagation();
+ },
+ keyCode: function(e) {
+ var kc, key;
+
+ key = (function() {
+ switch (kc = e.keyCode) {
+ case 8:
+ return '';
+ case 13:
+ return 'Enter';
+ case 27:
+ return 'Esc';
+ case 37:
+ return 'Left';
+ case 38:
+ return 'Up';
+ case 39:
+ return 'Right';
+ case 40:
+ return 'Down';
+ default:
+ if ((48 <= kc && kc <= 57) || (65 <= kc && kc <= 90)) {
+ return String.fromCharCode(kc).toLowerCase();
+ } else {
+ return null;
+ }
+ }
+ })();
+ if (key) {
+ if (e.altKey) {
+ key = 'Alt+' + key;
+ }
+ if (e.ctrlKey) {
+ key = 'Ctrl+' + key;
+ }
+ if (e.metaKey) {
+ key = 'Meta+' + key;
+ }
+ if (e.shiftKey) {
+ key = 'Shift+' + key;
+ }
+ }
+ return key;
+ },
+ qr: function(thread, quote) {
+ if (!(Conf['Quick Reply'] && QR.postingIsEnabled)) {
+ return;
+ }
+ QR.open();
+ if (quote) {
+ QR.quote.call($('input', $('.post.highlight', thread) || thread));
+ }
+ QR.nodes.com.focus();
+ if (Conf['QR Shortcut']) {
+ return $.rmClass($('.qr-shortcut'), 'disabled');
+ }
+ },
+ tags: function(tag, ta) {
+ var range, selEnd, selStart, value;
+
+ value = ta.value;
+ selStart = ta.selectionStart;
+ selEnd = ta.selectionEnd;
+ ta.value = value.slice(0, selStart) + ("[" + tag + "]") + value.slice(selStart, selEnd) + ("[/" + tag + "]") + value.slice(selEnd);
+ range = ("[" + tag + "]").length + selEnd;
+ ta.setSelectionRange(range, range);
+ return $.event('input', null, ta);
+ },
+ sage: function() {
+ var isSage;
+
+ isSage = /sage/i.test(QR.nodes.email.value);
+ return QR.nodes.email.value = isSage ? "" : "sage";
+ },
+ img: function(thread, all) {
+ var post;
+
+ if (all) {
+ return ImageExpand.cb.toggleAll();
+ } else {
+ post = Get.postFromNode($('.post.highlight', thread) || $('.op', thread));
+ return ImageExpand.toggle(post);
+ }
+ },
+ open: function(thread, tab) {
+ var url;
+
+ if (g.VIEW !== 'index') {
+ return;
+ }
+ url = "/" + thread.board + "/res/" + thread;
+ if (tab) {
+ return $.open(url);
+ } else {
+ return location.href = url;
+ }
+ },
+ hl: function(delta, thread) {
+ var headRect, next, postEl, rect, replies, reply, root, topMargin, _i, _len;
+
+ if (Conf['Fixed Header'] && Conf['Bottom header']) {
+ topMargin = 0;
+ } else {
+ headRect = Header.bar.getBoundingClientRect();
+ topMargin = headRect.top + headRect.height;
+ }
+ if (postEl = $('.reply.highlight', thread)) {
+ $.rmClass(postEl, 'highlight');
+ rect = postEl.getBoundingClientRect();
+ if (rect.bottom >= topMargin && rect.top <= doc.clientHeight) {
+ root = postEl.parentNode;
+ next = $.x('child::div[contains(@class,"post reply")]', delta === +1 ? root.nextElementSibling : root.previousElementSibling);
+ if (!next) {
+ this.focus(postEl);
+ return;
+ }
+ if (!(g.VIEW === 'thread' || $.x('ancestor::div[parent::div[@class="board"]]', next) === thread)) {
+ return;
+ }
+ rect = next.getBoundingClientRect();
+ if (rect.top < 0 || rect.bottom > doc.clientHeight) {
+ if (delta === -1) {
+ window.scrollBy(0, rect.top - topMargin);
+ } else {
+ next.scrollIntoView(false);
+ }
+ }
+ this.focus(next);
+ return;
+ }
+ }
+ replies = $$('.reply', thread);
+ if (delta === -1) {
+ replies.reverse();
+ }
+ for (_i = 0, _len = replies.length; _i < _len; _i++) {
+ reply = replies[_i];
+ rect = reply.getBoundingClientRect();
+ if (delta === +1 && rect.top >= topMargin || delta === -1 && rect.bottom <= doc.clientHeight) {
+ this.focus(reply);
+ return;
+ }
+ }
+ },
+ focus: function(post) {
+ return $.addClass(post, 'highlight');
+ }
+ };
+
+ Nav = {
+ init: function() {
+ var append, next, prev, span;
+
+ switch (g.VIEW) {
+ case 'index':
+ if (!Conf['Index Navigation']) {
+ return;
+ }
+ break;
+ case 'thread':
+ if (!Conf['Reply Navigation']) {
+ return;
+ }
+ break;
+ default:
+ return;
+ }
+ span = $.el('span', {
+ id: 'navlinks'
+ });
+ prev = $.el('a', {
+ textContent: '▲',
+ href: 'javascript:;'
+ });
+ next = $.el('a', {
+ textContent: '▼',
+ href: 'javascript:;'
+ });
+ $.on(prev, 'click', this.prev);
+ $.on(next, 'click', this.next);
+ $.add(span, [prev, $.tn(' '), next]);
+ append = function() {
+ $.off(d, '4chanXInitFinished', append);
+ return $.add(d.body, span);
+ };
+ return $.on(d, '4chanXInitFinished', append);
+ },
+ prev: function() {
+ if (g.VIEW === 'thread') {
+ return window.scrollTo(0, 0);
+ } else {
+ return Nav.scroll(-1);
+ }
+ },
+ next: function() {
+ if (g.VIEW === 'thread') {
+ return window.scrollTo(0, d.body.scrollHeight);
+ } else {
+ return Nav.scroll(+1);
+ }
+ },
+ getThread: function(full) {
+ var headRect, i, rect, thread, threads, topMargin, _i, _len;
+
+ if (Conf['Bottom header']) {
+ topMargin = 0;
+ } else {
+ headRect = Header.bar.getBoundingClientRect();
+ topMargin = headRect.top + headRect.height;
+ }
+ threads = $$('.thread:not([hidden])');
+ for (i = _i = 0, _len = threads.length; _i < _len; i = ++_i) {
+ thread = threads[i];
+ rect = thread.getBoundingClientRect();
+ if (rect.bottom > topMargin) {
+ if (full) {
+ return [threads, thread, i, rect, topMargin];
+ } else {
+ return thread;
+ }
+ }
+ }
+ return $('.board');
+ },
+ scroll: function(delta) {
+ var i, rect, thread, threads, top, topMargin, _ref, _ref1;
+
+ _ref = Nav.getThread(true), threads = _ref[0], thread = _ref[1], i = _ref[2], rect = _ref[3], topMargin = _ref[4];
+ top = rect.top - topMargin;
+ if (!((delta === -1 && Math.ceil(top) < 0) || (delta === +1 && top > 1))) {
+ i += delta;
+ }
+ top = ((_ref1 = threads[i]) != null ? _ref1.getBoundingClientRect().top : void 0) - topMargin;
+ return window.scrollBy(0, top);
+ }
+ };
+
+ RelativeDates = {
+ INTERVAL: $.MINUTE / 2,
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Relative Post Dates']) {
+ return;
+ }
+ $.on(d, 'visibilitychange ThreadUpdate', this.flush);
+ this.flush();
+ return Post.prototype.callbacks.push({
+ name: 'Relative Post Dates',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var dateEl;
+
+ if (this.isClone) {
+ return;
+ }
+ dateEl = this.nodes.date;
+ dateEl.title = dateEl.textContent;
+ return RelativeDates.setUpdate(this);
+ },
+ relative: function(diff, now, date) {
+ var days, months, number, rounded, unit, years;
+
+ unit = (number = diff / $.DAY) >= 1 ? (years = now.getYear() - date.getYear(), months = now.getMonth() - date.getMonth(), days = now.getDate() - date.getDate(), years > 1 ? (number = years - (months < 0 || months === 0 && days < 0), 'year') : years === 1 && (months > 0 || months === 0 && days >= 0) ? (number = years, 'year') : (months = (months + 12) % 12) > 1 ? (number = months - (days < 0), 'month') : months === 1 && days >= 0 ? (number = months, 'month') : 'day') : (number = diff / $.HOUR) >= 1 ? 'hour' : (number = diff / $.MINUTE) >= 1 ? 'minute' : (number = Math.max(0, diff) / $.SECOND, 'second');
+ rounded = Math.round(number);
+ if (rounded !== 1) {
+ unit += 's';
+ }
+ return "" + rounded + " " + unit + " ago";
+ },
+ stale: [],
+ flush: function() {
+ var now, update, _i, _len, _ref;
+
+ if (d.hidden) {
+ return;
+ }
+ now = new Date();
+ _ref = RelativeDates.stale;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ update = _ref[_i];
+ update(now);
+ }
+ RelativeDates.stale = [];
+ clearTimeout(RelativeDates.timeout);
+ return RelativeDates.timeout = setTimeout(RelativeDates.flush, RelativeDates.INTERVAL);
+ },
+ setUpdate: function(post) {
+ var markStale, setOwnTimeout, update;
+
+ setOwnTimeout = function(diff) {
+ var delay;
+
+ delay = diff < $.MINUTE ? $.SECOND - (diff + $.SECOND / 2) % $.SECOND : diff < $.HOUR ? $.MINUTE - (diff + $.MINUTE / 2) % $.MINUTE : diff < $.DAY ? $.HOUR - (diff + $.HOUR / 2) % $.HOUR : $.DAY - (diff + $.DAY / 2) % $.DAY;
+ return setTimeout(markStale, delay);
+ };
+ update = function(now) {
+ var date, diff, relative, singlePost, _i, _len, _ref;
+
+ date = post.info.date;
+ diff = now - date;
+ relative = RelativeDates.relative(diff, now, date);
+ _ref = [post].concat(post.clones);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ singlePost = _ref[_i];
+ singlePost.nodes.date.firstChild.textContent = relative;
+ }
+ return setOwnTimeout(diff);
+ };
+ markStale = function() {
+ return RelativeDates.stale.push(update);
+ };
+ return update(new Date());
+ }
+ };
+
+ RemoveSpoilers = {
+ init: function() {
+ if (!Conf['Remove Spoilers']) {
+ return;
+ }
+ if (Conf['Indicate Spoilers']) {
+ this.wrapper = function(text) {
+ return "[spoiler]" + text + "[/spoiler]";
+ };
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Reveal Spoilers',
+ cb: this.node
+ });
+ },
+ wrapper: function(text) {
+ return text;
+ },
+ node: function(post) {
+ var spoiler, spoilers, _i, _len;
+
+ spoilers = $$('s', this.nodes.comment);
+ for (_i = 0, _len = spoilers.length; _i < _len; _i++) {
+ spoiler = spoilers[_i];
+ $.replace(spoiler, $.tn(RemoveSpoilers.wrapper(spoiler.textContent)));
+ }
+ }
+ };
+
+ Report = {
+ init: function() {
+ if (!/report/.test(location.search)) {
+ return;
+ }
+ return $.ready(this.ready);
+ },
+ ready: function() {
+ var field, form;
+
+ form = $('form');
+ field = $.id('recaptcha_response_field');
+ $.on(field, 'keydown', function(e) {
+ if (e.keyCode === 8 && !field.value) {
+ return $.globalEval('Recaptcha.reload("t")');
+ }
+ });
+ return $.on(form, 'submit', function(e) {
+ var response;
+
+ e.preventDefault();
+ response = field.value.trim();
+ if (!/\s/.test(response)) {
+ field.value = "" + response + " " + response;
+ }
+ return form.submit();
+ });
+ }
+ };
+
+ Sauce = {
+ init: function() {
+ var link, links, _i, _len, _ref;
+
+ if (g.VIEW === 'catalog' || !Conf['Sauce']) {
+ return;
+ }
+ links = [];
+ _ref = Conf['sauces'].split('\n');
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ link = _ref[_i];
+ if (link[0] === '#') {
+ continue;
+ }
+ links.push(this.createSauceLink(link.trim()));
+ }
+ if (!links.length) {
+ return;
+ }
+ this.links = links;
+ this.link = $.el('a', {
+ target: '_blank'
+ });
+ return Post.prototype.callbacks.push({
+ name: 'Sauce',
+ cb: this.node
+ });
+ },
+ createSauceLink: function(link) {
+ var m, text;
+
+ link = link.replace(/%(T?URL|MD5|board)/ig, function(parameter) {
+ switch (parameter) {
+ case '%TURL':
+ return "' + encodeURIComponent(post.file.thumbURL) + '";
+ case '%URL':
+ return "' + encodeURIComponent(post.file.URL) + '";
+ case '%MD5':
+ return "' + encodeURIComponent(post.file.MD5) + '";
+ case '%board':
+ return "' + encodeURIComponent(post.board) + '";
+ default:
+ return parameter;
+ }
+ });
+ text = (m = link.match(/;text:(.+)$/)) ? m[1] : link.match(/(\w+)\.\w+\//)[1];
+ link = link.replace(/;text:.+$/, '');
+ return Function('post', 'a', "a.href = '" + link + "';\na.textContent = '" + text + "';\nreturn a;");
+ },
+ node: function() {
+ var link, nodes, _i, _len, _ref;
+
+ if (this.isClone || !this.file) {
+ return;
+ }
+ nodes = [];
+ _ref = Sauce.links;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ link = _ref[_i];
+ nodes.push($.tn('\u00A0'), link(this, Sauce.link.cloneNode(true)));
+ }
+ return $.add(this.file.info, nodes);
+ }
+ };
+
+ Time = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Time Formatting']) {
+ return;
+ }
+ this.funk = this.createFunc(Conf['time']);
+ return Post.prototype.callbacks.push({
+ name: 'Time Formatting',
+ cb: this.node
+ });
+ },
+ node: function() {
+ if (this.isClone) {
+ return;
+ }
+ return this.nodes.date.textContent = Time.funk(Time, this.info.date);
+ },
+ createFunc: function(format) {
+ var code;
+
+ code = format.replace(/%([A-Za-z])/g, function(s, c) {
+ if (c in Time.formatters) {
+ return "' + Time.formatters." + c + ".call(date) + '";
+ } else {
+ return s;
+ }
+ });
+ return Function('Time', 'date', "return '" + code + "'");
+ },
+ day: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
+ month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
+ zeroPad: function(n) {
+ if (n < 10) {
+ return "0" + n;
+ } else {
+ return n;
+ }
+ },
+ formatters: {
+ a: function() {
+ return Time.day[this.getDay()].slice(0, 3);
+ },
+ A: function() {
+ return Time.day[this.getDay()];
+ },
+ b: function() {
+ return Time.month[this.getMonth()].slice(0, 3);
+ },
+ B: function() {
+ return Time.month[this.getMonth()];
+ },
+ d: function() {
+ return Time.zeroPad(this.getDate());
+ },
+ e: function() {
+ return this.getDate();
+ },
+ H: function() {
+ return Time.zeroPad(this.getHours());
+ },
+ I: function() {
+ return Time.zeroPad(this.getHours() % 12 || 12);
+ },
+ k: function() {
+ return this.getHours();
+ },
+ l: function() {
+ return this.getHours() % 12 || 12;
+ },
+ m: function() {
+ return Time.zeroPad(this.getMonth() + 1);
+ },
+ M: function() {
+ return Time.zeroPad(this.getMinutes());
+ },
+ p: function() {
+ if (this.getHours() < 12) {
+ return 'AM';
+ } else {
+ return 'PM';
+ }
+ },
+ P: function() {
+ if (this.getHours() < 12) {
+ return 'am';
+ } else {
+ return 'pm';
+ }
+ },
+ S: function() {
+ return Time.zeroPad(this.getSeconds());
+ },
+ y: function() {
+ return this.getFullYear() - 2000;
+ }
+ }
+ };
+
Settings = {
init: function() {
var link, settings;
diff --git a/builds/crx/script.js b/builds/crx/script.js
index bad35abf9..0917e57da 100644
--- a/builds/crx/script.js
+++ b/builds/crx/script.js
@@ -1,3 +1,92 @@
+/*
+* 4chan X - Version 1.1.1 - 2013-04-26
+*
+* Licensed under the MIT license.
+* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
+*
+* Appchan X Copyright © 2013-2013 Zixaphir
+* http://zixaphir.github.io/appchan-x/
+* 4chan x Copyright © 2009-2011 James Campos
+* https://github.com/aeosynth/4chan-x
+* 4chan x Copyright © 2012-2013 Nicolas Stepien
+* https://4chan-x.just-believe.in/
+* 4chan x Copyright © 2013-2013 Jordan Bates
+* http://seaweedchan.github.io/4chan-x/
+* 4chan x Copyright © 2012-2013 ihavenoface
+* http://ihavenoface.github.io/4chan-x/
+* 4chan SS Copyright © 2011-2013 Ahodesuka
+* https://github.com/ahodesuka/4chan-Style-Script/
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+* OTHER DEALINGS IN THE SOFTWARE.
+*
+* Contributors:
+* aeosynth
+* mayhemydg
+* noface
+* !K.WeEabo0o
+* blaise
+* that4chanwolf
+* desuwa
+* seaweed
+* e000
+* ahodesuka
+* Shou
+* ferongr
+* xat
+* Ongpot
+* thisisanon
+* Anonymous
+* Seiba
+* herpaderpderp
+* WakiMiko
+* btmcsweeney
+* AppleBloom
+*
+* All the people who've taken the time to write bug reports.
+*
+* Thank you.
+*/
+
+/*
+* Contains data from external sources:
+*
+* audio/beep.wav from http://freesound.org/people/pierrecartoons1979/sounds/90112/
+* cc-by-nc-3.0
+*
+* 4chan/4chan-JS (https://github.com/4chan/4chan-JS)
+* Copyright (c) 2012-2013, 4chan LLC
+* All rights reserved.
+*
+* license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
+*
+* Linkify: (http://userscripts.org/scripts/show/1352)
+* Copyright (c) 2011, Anthony Lieuallen
+* All rights reserved.
+* Originally written by Anthony Lieuallen of http://arantius.com/
+* Licensed for unlimited modification and redistribution as long as
+* this notice is kept intact.
+*
+* license: http://userscripts.org/scripts/review/1352
+*
+*/
(function() {
var $, $$, Anonymize, ArchiveLink, Board, Build, CatalogLinks, Clone, Conf, Config, CustomCSS, DataBoard, DataBoards, DeleteLink, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Fourchan, Get, Header, IDColor, ImageExpand, ImageHover, ImageReplace, Keybinds, Linkify, Main, Menu, Nav, Notification, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, Recursive, Redirect, RelativeDates, RemoveSpoilers, Report, ReportLink, RevealSpoilers, Sauce, Settings, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, g,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
@@ -723,159 +812,6 @@
return __slice.call(root.querySelectorAll(selector));
};
- Build = {
- spoilerRange: {},
- shortFilename: function(filename, isReply) {
- var threshold;
-
- threshold = isReply ? 30 : 40;
- if (filename.length - 4 > threshold) {
- return "" + filename.slice(0, threshold - 5) + "(...)." + filename.slice(-3);
- } else {
- return filename;
- }
- },
- postFromObject: function(data, boardID) {
- var o;
-
- o = {
- postID: data.no,
- threadID: data.resto || data.no,
- boardID: boardID,
- name: data.name,
- capcode: data.capcode,
- tripcode: data.trip,
- uniqueID: data.id,
- email: data.email ? encodeURI(data.email.replace(/"/g, '"')) : '',
- subject: data.sub,
- flagCode: data.country,
- flagName: data.country_name,
- date: data.now,
- dateUTC: data.time,
- comment: data.com,
- isSticky: !!data.sticky,
- isClosed: !!data.closed
- };
- if (data.ext || data.filedeleted) {
- o.file = {
- name: data.filename + data.ext,
- timestamp: "" + data.tim + data.ext,
- url: "//images.4chan.org/" + boardID + "/src/" + data.tim + data.ext,
- height: data.h,
- width: data.w,
- MD5: data.md5,
- size: data.fsize,
- turl: "//thumbs.4chan.org/" + boardID + "/thumb/" + data.tim + "s.jpg",
- theight: data.tn_h,
- twidth: data.tn_w,
- isSpoiler: !!data.spoiler,
- isDeleted: !!data.filedeleted
- };
- }
- return Build.post(o);
- },
- post: function(o, isArchived) {
- /*
- This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS).
- @license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
- */
-
- var a, boardID, capcode, capcodeClass, capcodeStart, closed, comment, container, date, dateUTC, email, emailEnd, emailStart, ext, file, fileDims, fileHTML, fileInfo, fileSize, fileThumb, filename, flag, flagCode, flagName, href, imgSrc, isClosed, isOP, isSticky, name, postID, quote, shortFilename, spoilerRange, staticPath, sticky, subject, threadID, tripcode, uniqueID, userID, _i, _len, _ref;
-
- postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, comment = o.comment, file = o.file;
- isOP = postID === threadID;
- staticPath = '//static.4chan.org';
- if (email) {
- emailStart = '';
- emailEnd = '';
- } else {
- emailStart = '';
- emailEnd = '';
- }
- subject = "" + (subject || '') + "";
- userID = !capcode && uniqueID ? (" (ID: ") + ("" + uniqueID + ") ") : '';
- switch (capcode) {
- case 'admin':
- case 'admin_highlight':
- capcodeClass = " capcodeAdmin";
- capcodeStart = " ## Admin";
- capcode = ("
";
- break;
- case 'mod':
- capcodeClass = " capcodeMod";
- capcodeStart = " ## Mod";
- capcode = ("
";
- break;
- case 'developer':
- capcodeClass = " capcodeDeveloper";
- capcodeStart = " ## Developer";
- capcode = ("
";
- break;
- default:
- capcodeClass = '';
- capcodeStart = '';
- capcode = '';
- }
- flag = flagCode ? ("
") : '';
- if (file != null ? file.isDeleted : void 0) {
- fileHTML = isOP ? ("") + ("
") + " " : ("") + ("
") + " ";
- } else if (file) {
- ext = file.name.slice(-3);
- if (!file.twidth && !file.theight && ext === 'gif') {
- file.twidth = file.width;
- file.theight = file.height;
- }
- fileSize = $.bytesToString(file.size);
- fileThumb = file.turl;
- if (file.isSpoiler) {
- fileSize = "Spoiler Image, " + fileSize;
- if (!isArchived) {
- fileThumb = '//static.4chan.org/image/spoiler';
- if (spoilerRange = Build.spoilerRange[boardID]) {
- fileThumb += ("-" + boardID) + Math.floor(1 + spoilerRange * Math.random());
- }
- fileThumb += '.png';
- file.twidth = file.theight = 100;
- }
- }
- if (boardID.ID !== 'f') {
- imgSrc = ("") + ("
");
- }
- a = $.el('a', {
- innerHTML: file.name
- });
- filename = a.textContent.replace(/%22/g, '"');
- a.textContent = Build.shortFilename(filename);
- shortFilename = a.innerHTML;
- a.textContent = filename;
- filename = a.innerHTML.replace(/'/g, ''');
- fileDims = ext === 'pdf' ? 'PDF' : "" + file.width + "x" + file.height;
- fileInfo = ("File: " + file.timestamp + "") + ("-(" + fileSize + ", " + fileDims + (file.isSpoiler ? '' : ", " + shortFilename + "")) + ")";
- fileHTML = "" + fileInfo + "
" + imgSrc + "
";
- } else {
- fileHTML = '';
- }
- tripcode = tripcode ? " " + tripcode + "" : '';
- sticky = isSticky ? '
' : '';
- closed = isClosed ? '
' : '';
- container = $.el('div', {
- id: "pc" + postID,
- className: "postContainer " + (isOP ? 'op' : 'reply') + "Container",
- innerHTML: (isOP ? '' : ">>
") + ("") + ("
") + ("
") + ("" + (name || '') + "") + tripcode + capcodeStart + capcode + userID + flag + sticky + closed + ("
" + subject) + ("" + date) + ("No.") + ("" + postID + "") + '' + '
' + (isOP ? fileHTML : '') + ("
") + ("
") + ("" + subject + " ") + ("
") + emailStart + ("" + (name || '') + "") + tripcode + capcodeStart + emailEnd + capcode + userID + flag + sticky + closed + ' ' + ("
" + date + " ") + "
" + ("No.") + ("" + postID + "") + '' + '
' + (isOP ? '' : fileHTML) + ("
" + (comment || '') + "
") + '
'
- });
- _ref = $$('.quotelink', container);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quote = _ref[_i];
- href = quote.getAttribute('href');
- if (href[0] === '/') {
- continue;
- }
- quote.href = "/" + boardID + "/res/" + href;
- }
- return container;
- }
- };
-
Board = (function() {
Board.prototype.toString = function() {
return this.ID;
@@ -1457,6 +1393,517 @@
})();
+ Polyfill = {
+ init: function() {
+ return Polyfill.visibility();
+ },
+ visibility: function() {
+ var event, prefix, property;
+
+ if ('visibilityState' in document || !(prefix = ('webkitVisibilityState' in document ? 'webkit' : 'mozVisibilityState' in document ? 'moz' : void 0))) {
+ return;
+ }
+ property = prefix + 'VisibilityState';
+ event = prefix + 'visibilitychange';
+ d.visibilityState = d[property];
+ d.hidden = d.visibilityState === 'hidden';
+ return $.on(d, event, function() {
+ d.visibilityState = d[property];
+ d.hidden = d.visibilityState === 'hidden';
+ return $.event('visibilitychange');
+ });
+ }
+ };
+
+ Header = {
+ init: function() {
+ var barFixedToggler, barPositionToggler, customNavToggler, editCustomNav, footerToggler, headerToggler,
+ _this = this;
+
+ this.menu = new UI.Menu('header');
+ this.menuButton = $.el('span', {
+ className: 'menu-button',
+ innerHTML: ''
+ });
+ barFixedToggler = $.el('label', {
+ innerHTML: ' Fixed Header'
+ });
+ headerToggler = $.el('label', {
+ innerHTML: ' Auto-hide header'
+ });
+ barPositionToggler = $.el('label', {
+ innerHTML: ' Bottom header'
+ });
+ customNavToggler = $.el('label', {
+ innerHTML: ' Custom board navigation'
+ });
+ footerToggler = $.el('label', {
+ innerHTML: " Hide bottom board list"
+ });
+ editCustomNav = $.el('a', {
+ textContent: 'Edit custom board navigation',
+ href: 'javascript:;'
+ });
+ this.barFixedToggler = barFixedToggler.firstElementChild;
+ this.barPositionToggler = barPositionToggler.firstElementChild;
+ this.headerToggler = headerToggler.firstElementChild;
+ this.footerToggler = footerToggler.firstElementChild;
+ this.customNavToggler = customNavToggler.firstElementChild;
+ $.on(this.menuButton, 'click', this.menuToggle);
+ $.on(this.barFixedToggler, 'change', this.toggleBarFixed);
+ $.on(this.barPositionToggler, 'change', this.toggleBarPosition);
+ $.on(this.headerToggler, 'change', this.toggleBarVisibility);
+ $.on(this.footerToggler, 'change', this.toggleFooterVisibility);
+ $.on(this.customNavToggler, 'change', this.toggleCustomNav);
+ $.on(editCustomNav, 'click', this.editCustomNav);
+ this.setBarFixed(Conf['Fixed Header']);
+ this.setBarVisibility(Conf['Header auto-hide']);
+ $.sync('Fixed Header', Header.setBarFixed);
+ $.sync('Bottom Header', Header.setBarPosition);
+ $.sync('Header auto-hide', Header.setBarVisibility);
+ this.addShortcut(Header.menuButton);
+ $.event('AddMenuEntry', {
+ type: 'header',
+ el: $.el('span', {
+ textContent: 'Header'
+ }),
+ order: 107,
+ subEntries: [
+ {
+ el: barFixedToggler
+ }, {
+ el: headerToggler
+ }, {
+ el: barPositionToggler
+ }, {
+ el: footerToggler
+ }, {
+ el: customNavToggler
+ }, {
+ el: editCustomNav
+ }
+ ]
+ });
+ $.on(window, 'load hashchange', Header.hashScroll);
+ $.on(d, 'CreateNotification', this.createNotification);
+ $.asap((function() {
+ return d.body;
+ }), function() {
+ if (!Main.isThisPageLegit()) {
+ return;
+ }
+ $.asap((function() {
+ return $.id('boardNavMobile') || d.readyState === 'complete';
+ }), Header.setBoardList);
+ $.prepend(d.body, _this.bar);
+ $.add(d.body, Header.hover);
+ return _this.setBarPosition(Conf['Bottom Header']);
+ });
+ return $.ready(function() {
+ var a, cs;
+
+ _this.footer = $.id('boardNavDesktopFoot');
+ if (a = $("a[href*='/" + g.BOARD + "/']", $.id('boardNavDesktopFoot'))) {
+ a.className = 'current';
+ }
+ cs = $.id('settingsWindowLink');
+ cs.textContent = 'Catalog Settings';
+ if (g.VIEW === 'catalog') {
+ _this.addShortcut(cs);
+ }
+ Header.setFooterVisibility(Conf['Bottom Board List']);
+ return $.sync('Bottom Board List', Header.setFooterVisibility);
+ });
+ },
+ bar: $.el('div', {
+ id: 'header-bar'
+ }),
+ notify: $.el('div', {
+ id: 'notifications'
+ }),
+ shortcuts: $.el('span', {
+ id: 'shortcuts'
+ }),
+ hover: $.el('div', {
+ id: 'hoverUI'
+ }),
+ toggle: $.el('div', {
+ id: 'scroll-marker'
+ }),
+ setBoardList: function() {
+ var a, boardList, btn, fourchannav, fullBoardList;
+
+ fourchannav = $.id('boardNavDesktop');
+ if (a = $("a[href*='/" + g.BOARD + "/']", fourchannav)) {
+ a.className = 'current';
+ }
+ boardList = $.el('span', {
+ id: 'board-list',
+ innerHTML: "[ - ] " + fourchannav.innerHTML + ""
+ });
+ fullBoardList = $('#full-board-list', boardList);
+ btn = $('.hide-board-list-button', fullBoardList);
+ $.on(btn, 'click', Header.toggleBoardList);
+ $.rm($('#navtopright', fullBoardList));
+ $.add(boardList, fullBoardList);
+ $.add(Header.bar, [boardList, Header.shortcuts, Header.notify, Header.toggle]);
+ Header.setCustomNav(Conf['Custom Board Navigation']);
+ Header.generateBoardList(Conf['boardnav']);
+ $.sync('Custom Board Navigation', Header.setCustomNav);
+ return $.sync('boardnav', Header.generateBoardList);
+ },
+ generateBoardList: function(text) {
+ var as, list, nodes;
+
+ list = $('#custom-board-list', Header.bar);
+ $.rmAll(list);
+ if (!text) {
+ return;
+ }
+ as = $$('#full-board-list a', Header.bar);
+ nodes = text.match(/[\w@]+(-(all|title|replace|full|index|catalog|text:"[^"]+"))*|[^\w@]+/g).map(function(t) {
+ var a, board, m, _i, _len;
+
+ if (/^[^\w@]/.test(t)) {
+ return $.tn(t);
+ }
+ if (/^toggle-all/.test(t)) {
+ a = $.el('a', {
+ className: 'show-board-list-button',
+ textContent: (t.match(/-text:"(.+)"/) || [null, '+'])[1],
+ href: 'javascript:;'
+ });
+ $.on(a, 'click', Header.toggleBoardList);
+ return a;
+ }
+ board = /^current/.test(t) ? g.BOARD.ID : t.match(/^[^-]+/)[0];
+ for (_i = 0, _len = as.length; _i < _len; _i++) {
+ a = as[_i];
+ if (a.textContent === board) {
+ a = a.cloneNode(true);
+ if (/-title/.test(t)) {
+ a.textContent = a.title;
+ } else if (/-replace/.test(t)) {
+ if ($.hasClass(a, 'current')) {
+ a.textContent = a.title;
+ }
+ } else if (/-full/.test(t)) {
+ a.textContent = "/" + board + "/ - " + a.title;
+ } else if (/-(index|catalog|text)/.test(t)) {
+ if (m = t.match(/-(index|catalog)/)) {
+ a.setAttribute('data-only', m[1]);
+ a.href = "//boards.4chan.org/" + board + "/";
+ if (m[1] === 'catalog') {
+ a.href += 'catalog';
+ }
+ }
+ if (m = t.match(/-text:"(.+)"/)) {
+ a.textContent = m[1];
+ }
+ } else if (board === '@') {
+ $.addClass(a, 'navSmall');
+ }
+ return a;
+ }
+ }
+ return $.tn(t);
+ });
+ return $.add(list, nodes);
+ },
+ toggleBoardList: function() {
+ var bar, custom, full, showBoardList;
+
+ bar = Header.bar;
+ custom = $('#custom-board-list', bar);
+ full = $('#full-board-list', bar);
+ showBoardList = !full.hidden;
+ custom.hidden = !showBoardList;
+ return full.hidden = showBoardList;
+ },
+ setBarPosition: function(bottom) {
+ Header.barPositionToggler.checked = bottom;
+ if (bottom) {
+ $.rmClass(doc, 'top');
+ $.addClass(doc, 'bottom');
+ return $.after(Header.bar, Header.notify);
+ } else {
+ $.rmClass(doc, 'bottom');
+ $.addClass(doc, 'top');
+ return $.add(Header.bar, Header.notify);
+ }
+ },
+ toggleBarPosition: function() {
+ $.event('CloseMenu');
+ Header.setBarPosition(this.checked);
+ Conf['Bottom Header'] = this.checked;
+ return $.set('Bottom Header', this.checked);
+ },
+ setBarFixed: function(fixed) {
+ Header.barFixedToggler.checked = fixed;
+ if (fixed) {
+ $.addClass(doc, 'fixed');
+ return $.addClass(Header.bar, 'dialog');
+ } else {
+ $.rmClass(doc, 'fixed');
+ return $.rmClass(Header.bar, 'dialog');
+ }
+ },
+ toggleBarFixed: function() {
+ $.event('CloseMenu');
+ Header.setBarFixed(this.checked);
+ Conf['Fixed Header'] = this.checked;
+ return $.set('Fixed Header', this.checked);
+ },
+ setBarVisibility: function(hide) {
+ Header.headerToggler.checked = hide;
+ $.event('CloseMenu');
+ (hide ? $.addClass : $.rmClass)(Header.bar, 'autohide');
+ return (hide ? $.addClass : $.rmClass)(doc, 'autohide');
+ },
+ toggleBarVisibility: function(e) {
+ var hide, message;
+
+ if (e.type === 'mousedown' && e.button !== 0) {
+ return;
+ }
+ hide = this.nodeName === 'INPUT' ? this.checked : !$.hasClass(Header.bar, 'autohide');
+ Conf['Header auto-hide'] = hide;
+ $.set('Header auto-hide', hide);
+ Header.setBarVisibility(hide);
+ message = hide ? 'The header bar will automatically hide itself.' : 'The header bar will remain visible.';
+ return new Notification('info', message, 2);
+ },
+ setFooterVisibility: function(hide) {
+ Header.footerToggler.checked = hide;
+ return Header.footer.hidden = hide;
+ },
+ toggleFooterVisibility: function() {
+ var hide, message;
+
+ $.event('CloseMenu');
+ hide = this.nodeName === 'INPUT' ? this.checked : !!Header.footer.hidden;
+ Header.setFooterVisibility(hide);
+ $.set('Bottom Board List', hide);
+ message = hide ? 'The bottom navigation will now be hidden.' : 'The bottom navigation will remain visible.';
+ return new Notification('info', message, 2);
+ },
+ setCustomNav: function(show) {
+ var btn, cust, full, _ref;
+
+ Header.customNavToggler.checked = show;
+ cust = $('#custom-board-list', Header.bar);
+ full = $('#full-board-list', Header.bar);
+ btn = $('.hide-board-list-button', full);
+ return _ref = show ? [false, true] : [true, false], cust.hidden = _ref[0], full.hidden = _ref[1], _ref;
+ },
+ toggleCustomNav: function() {
+ $.cb.checked.call(this);
+ return Header.setCustomNav(this.checked);
+ },
+ editCustomNav: function() {
+ var settings;
+
+ Settings.open('Advanced');
+ settings = $.id('fourchanx-settings');
+ return $('input[name=boardnav]', settings).focus();
+ },
+ hashScroll: function() {
+ var hash, post;
+
+ if (!((hash = this.location.hash) && (post = $.id(hash.slice(1))))) {
+ return;
+ }
+ if ((Get.postFromRoot(post)).isHidden) {
+ return;
+ }
+ return Header.scrollToPost(post);
+ },
+ scrollToPost: function(post) {
+ var headRect, top;
+
+ top = post.getBoundingClientRect().top;
+ if (Conf['Fixed Header'] && !Conf['Bottom Header']) {
+ headRect = Header.bar.getBoundingClientRect();
+ top += -headRect.top - headRect.height;
+ }
+ return ($.engine === 'webkit' ? d.body : doc).scrollTop += top;
+ },
+ addShortcut: function(el) {
+ var shortcut;
+
+ shortcut = $.el('span', {
+ className: 'shortcut'
+ });
+ $.add(shortcut, [$.tn(' ['), el, $.tn(']')]);
+ return $.prepend(Header.shortcuts, shortcut);
+ },
+ menuToggle: function(e) {
+ return Header.menu.toggle(e, this, g);
+ },
+ createNotification: function(e) {
+ var cb, content, lifetime, notif, type, _ref;
+
+ _ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb;
+ notif = new Notification(type, content, lifetime);
+ if (cb) {
+ return cb(notif);
+ }
+ }
+ };
+
+ Build = {
+ spoilerRange: {},
+ shortFilename: function(filename, isReply) {
+ var threshold;
+
+ threshold = isReply ? 30 : 40;
+ if (filename.length - 4 > threshold) {
+ return "" + filename.slice(0, threshold - 5) + "(...)." + filename.slice(-3);
+ } else {
+ return filename;
+ }
+ },
+ postFromObject: function(data, boardID) {
+ var o;
+
+ o = {
+ postID: data.no,
+ threadID: data.resto || data.no,
+ boardID: boardID,
+ name: data.name,
+ capcode: data.capcode,
+ tripcode: data.trip,
+ uniqueID: data.id,
+ email: data.email ? encodeURI(data.email.replace(/"/g, '"')) : '',
+ subject: data.sub,
+ flagCode: data.country,
+ flagName: data.country_name,
+ date: data.now,
+ dateUTC: data.time,
+ comment: data.com,
+ isSticky: !!data.sticky,
+ isClosed: !!data.closed
+ };
+ if (data.ext || data.filedeleted) {
+ o.file = {
+ name: data.filename + data.ext,
+ timestamp: "" + data.tim + data.ext,
+ url: "//images.4chan.org/" + boardID + "/src/" + data.tim + data.ext,
+ height: data.h,
+ width: data.w,
+ MD5: data.md5,
+ size: data.fsize,
+ turl: "//thumbs.4chan.org/" + boardID + "/thumb/" + data.tim + "s.jpg",
+ theight: data.tn_h,
+ twidth: data.tn_w,
+ isSpoiler: !!data.spoiler,
+ isDeleted: !!data.filedeleted
+ };
+ }
+ return Build.post(o);
+ },
+ post: function(o, isArchived) {
+ /*
+ This function contains code from 4chan-JS (https://github.com/4chan/4chan-JS).
+ @license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
+ */
+
+ var a, boardID, capcode, capcodeClass, capcodeStart, closed, comment, container, date, dateUTC, email, emailEnd, emailStart, ext, file, fileDims, fileHTML, fileInfo, fileSize, fileThumb, filename, flag, flagCode, flagName, href, imgSrc, isClosed, isOP, isSticky, name, postID, quote, shortFilename, spoilerRange, staticPath, sticky, subject, threadID, tripcode, uniqueID, userID, _i, _len, _ref;
+
+ postID = o.postID, threadID = o.threadID, boardID = o.boardID, name = o.name, capcode = o.capcode, tripcode = o.tripcode, uniqueID = o.uniqueID, email = o.email, subject = o.subject, flagCode = o.flagCode, flagName = o.flagName, date = o.date, dateUTC = o.dateUTC, isSticky = o.isSticky, isClosed = o.isClosed, comment = o.comment, file = o.file;
+ isOP = postID === threadID;
+ staticPath = '//static.4chan.org';
+ if (email) {
+ emailStart = '';
+ emailEnd = '';
+ } else {
+ emailStart = '';
+ emailEnd = '';
+ }
+ subject = "" + (subject || '') + "";
+ userID = !capcode && uniqueID ? (" (ID: ") + ("" + uniqueID + ") ") : '';
+ switch (capcode) {
+ case 'admin':
+ case 'admin_highlight':
+ capcodeClass = " capcodeAdmin";
+ capcodeStart = " ## Admin";
+ capcode = ("
";
+ break;
+ case 'mod':
+ capcodeClass = " capcodeMod";
+ capcodeStart = " ## Mod";
+ capcode = ("
";
+ break;
+ case 'developer':
+ capcodeClass = " capcodeDeveloper";
+ capcodeStart = " ## Developer";
+ capcode = ("
";
+ break;
+ default:
+ capcodeClass = '';
+ capcodeStart = '';
+ capcode = '';
+ }
+ flag = flagCode ? ("
") : '';
+ if (file != null ? file.isDeleted : void 0) {
+ fileHTML = isOP ? ("") + ("
") + " " : ("") + ("
") + " ";
+ } else if (file) {
+ ext = file.name.slice(-3);
+ if (!file.twidth && !file.theight && ext === 'gif') {
+ file.twidth = file.width;
+ file.theight = file.height;
+ }
+ fileSize = $.bytesToString(file.size);
+ fileThumb = file.turl;
+ if (file.isSpoiler) {
+ fileSize = "Spoiler Image, " + fileSize;
+ if (!isArchived) {
+ fileThumb = '//static.4chan.org/image/spoiler';
+ if (spoilerRange = Build.spoilerRange[boardID]) {
+ fileThumb += ("-" + boardID) + Math.floor(1 + spoilerRange * Math.random());
+ }
+ fileThumb += '.png';
+ file.twidth = file.theight = 100;
+ }
+ }
+ if (boardID.ID !== 'f') {
+ imgSrc = ("") + ("
");
+ }
+ a = $.el('a', {
+ innerHTML: file.name
+ });
+ filename = a.textContent.replace(/%22/g, '"');
+ a.textContent = Build.shortFilename(filename);
+ shortFilename = a.innerHTML;
+ a.textContent = filename;
+ filename = a.innerHTML.replace(/'/g, ''');
+ fileDims = ext === 'pdf' ? 'PDF' : "" + file.width + "x" + file.height;
+ fileInfo = ("File: " + file.timestamp + "") + ("-(" + fileSize + ", " + fileDims + (file.isSpoiler ? '' : ", " + shortFilename + "")) + ")";
+ fileHTML = "" + fileInfo + "
" + imgSrc + "
";
+ } else {
+ fileHTML = '';
+ }
+ tripcode = tripcode ? " " + tripcode + "" : '';
+ sticky = isSticky ? '
' : '';
+ closed = isClosed ? '
' : '';
+ container = $.el('div', {
+ id: "pc" + postID,
+ className: "postContainer " + (isOP ? 'op' : 'reply') + "Container",
+ innerHTML: (isOP ? '' : ">>
") + ("") + ("
") + ("
") + ("" + (name || '') + "") + tripcode + capcodeStart + capcode + userID + flag + sticky + closed + ("
" + subject) + ("" + date) + ("No.") + ("" + postID + "") + '' + '
' + (isOP ? fileHTML : '') + ("
") + ("
") + ("" + subject + " ") + ("
") + emailStart + ("" + (name || '') + "") + tripcode + capcodeStart + emailEnd + capcode + userID + flag + sticky + closed + ' ' + ("
" + date + " ") + "
" + ("No.") + ("" + postID + "") + '' + '
' + (isOP ? '' : fileHTML) + ("
" + (comment || '') + "
") + '
'
+ });
+ _ref = $$('.quotelink', container);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ quote = _ref[_i];
+ href = quote.getAttribute('href');
+ if (href[0] === '/') {
+ continue;
+ }
+ quote.href = "/" + boardID + "/res/" + href;
+ }
+ return container;
+ }
+ };
+
Get = {
threadExcerpt: function(thread) {
var OP, excerpt, _ref;
@@ -1713,28 +2160,6 @@
}
};
- Polyfill = {
- init: function() {
- return Polyfill.visibility();
- },
- visibility: function() {
- var event, prefix, property;
-
- if ('visibilityState' in document || !(prefix = ('webkitVisibilityState' in document ? 'webkit' : 'mozVisibilityState' in document ? 'moz' : void 0))) {
- return;
- }
- property = prefix + 'VisibilityState';
- event = prefix + 'visibilitychange';
- d.visibilityState = d[property];
- d.hidden = d.visibilityState === 'hidden';
- return $.on(d, event, function() {
- d.visibilityState = d[property];
- d.hidden = d.visibilityState === 'hidden';
- return $.event('visibilitychange');
- });
- }
- };
-
UI = (function() {
var Menu, dialog, drag, dragend, dragstart, hover, hoverend, hoverstart, touchend, touchmove;
@@ -2464,76 +2889,6 @@
}
};
- Recursive = {
- recursives: {},
- init: function() {
- if (g.VIEW === 'catalog') {
- return;
- }
- return Post.prototype.callbacks.push({
- name: 'Recursive',
- cb: this.node
- });
- },
- node: function() {
- var i, obj, quote, recursive, _i, _j, _len, _len1, _ref, _ref1;
-
- if (this.isClone) {
- return;
- }
- _ref = this.quotes;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quote = _ref[_i];
- if (obj = Recursive.recursives[quote]) {
- _ref1 = obj.recursives;
- for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
- recursive = _ref1[i];
- recursive.apply(null, [this].concat(__slice.call(obj.args[i])));
- }
- }
- }
- },
- add: function() {
- var args, obj, post, recursive, _base, _name;
-
- recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
- obj = (_base = Recursive.recursives)[_name = post.fullID] || (_base[_name] = {
- recursives: [],
- args: []
- });
- obj.recursives.push(recursive);
- return obj.args.push(args);
- },
- rm: function(recursive, post) {
- var i, obj, rec, _i, _len, _ref;
-
- if (!(obj = Recursive.recursives[post.fullID])) {
- return;
- }
- _ref = obj.recursives;
- for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
- rec = _ref[i];
- if (rec === recursive) {
- obj.recursives.splice(i, 1);
- obj.args.splice(i, 1);
- }
- }
- },
- apply: function() {
- var ID, args, fullID, post, recursive, _ref;
-
- recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
- fullID = post.fullID;
- _ref = g.posts;
- for (ID in _ref) {
- post = _ref[ID];
- if (post.quotes.contains(fullID)) {
- recursive.apply(null, [post].concat(__slice.call(args)));
- }
- }
- }
- };
-
PostHiding = {
init: function() {
if (g.VIEW === 'catalog' || !Conf['Reply Hiding Buttons'] && !Conf['Reply Hiding Link']) {
@@ -2812,28 +3167,71 @@
}
};
- QuoteStrikeThrough = {
+ Recursive = {
+ recursives: {},
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Reply Hiding Buttons'] && !Conf['Reply Hiding Link'] && !Conf['Filter']) {
+ if (g.VIEW === 'catalog') {
return;
}
return Post.prototype.callbacks.push({
- name: 'Strike-through Quotes',
+ name: 'Recursive',
cb: this.node
});
},
node: function() {
- var boardID, postID, quotelink, _i, _len, _ref, _ref1, _ref2;
+ var i, obj, quote, recursive, _i, _j, _len, _len1, _ref, _ref1;
if (this.isClone) {
return;
}
- _ref = this.nodes.quotelinks;
+ _ref = this.quotes;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quotelink = _ref[_i];
- _ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, postID = _ref1.postID;
- if ((_ref2 = g.posts["" + boardID + "." + postID]) != null ? _ref2.isHidden : void 0) {
- $.addClass(quotelink, 'filtered');
+ quote = _ref[_i];
+ if (obj = Recursive.recursives[quote]) {
+ _ref1 = obj.recursives;
+ for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
+ recursive = _ref1[i];
+ recursive.apply(null, [this].concat(__slice.call(obj.args[i])));
+ }
+ }
+ }
+ },
+ add: function() {
+ var args, obj, post, recursive, _base, _name;
+
+ recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
+ obj = (_base = Recursive.recursives)[_name = post.fullID] || (_base[_name] = {
+ recursives: [],
+ args: []
+ });
+ obj.recursives.push(recursive);
+ return obj.args.push(args);
+ },
+ rm: function(recursive, post) {
+ var i, obj, rec, _i, _len, _ref;
+
+ if (!(obj = Recursive.recursives[post.fullID])) {
+ return;
+ }
+ _ref = obj.recursives;
+ for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
+ rec = _ref[i];
+ if (rec === recursive) {
+ obj.recursives.splice(i, 1);
+ obj.args.splice(i, 1);
+ }
+ }
+ },
+ apply: function() {
+ var ID, args, fullID, post, recursive, _ref;
+
+ recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
+ fullID = post.fullID;
+ _ref = g.posts;
+ for (ID in _ref) {
+ post = _ref[ID];
+ if (post.quotes.contains(fullID)) {
+ recursive.apply(null, [post].concat(__slice.call(args)));
}
}
}
@@ -3066,455 +3464,646 @@
}
};
- FappeTyme = {
+ QuoteBacklink = {
init: function() {
- var el, input;
+ var format;
- if (!Conf['Fappe Tyme'] || g.VIEW === 'catalog' || g.BOARD === 'f') {
+ if (g.VIEW === 'catalog' || !Conf['Quote Backlinks']) {
return;
}
- el = $.el('label', {
- innerHTML: " Fappe Tyme",
- title: 'Fappe Tyme'
- });
- FappeTyme.input = input = el.firstElementChild;
- $.on(input, 'change', FappeTyme.toggle);
- $.event('AddMenuEntry', {
- type: 'header',
- el: el,
- order: 97
+ format = Conf['backlink'].replace(/%id/g, "' + id + '");
+ this.funk = Function('id', "return '" + format + "'");
+ this.containers = {};
+ Post.prototype.callbacks.push({
+ name: 'Quote Backlinking Part 1',
+ cb: this.firstNode
});
return Post.prototype.callbacks.push({
- name: 'Fappe Tyme',
- cb: this.node
+ name: 'Quote Backlinking Part 2',
+ cb: this.secondNode
});
},
- node: function() {
- if (this.file) {
+ firstNode: function() {
+ var a, clone, container, containers, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
+
+ if (this.isClone || !this.quotes.length) {
return;
}
- return $.addClass(this.nodes.root, "noFile");
+ a = $.el('a', {
+ href: "/" + this.board + "/res/" + this.thread + "#p" + this,
+ className: this.isHidden ? 'filtered backlink' : 'backlink',
+ textContent: (QuoteBacklink.funk(this.ID)) + (Conf['Mark Quotes of You'] && this.info.yours ? QuoteYou.text : '')
+ });
+ _ref = this.quotes;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ quote = _ref[_i];
+ containers = [QuoteBacklink.getContainer(quote)];
+ if ((post = g.posts[quote]) && post.nodes.backlinkContainer) {
+ _ref1 = post.clones;
+ for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
+ clone = _ref1[_j];
+ containers.push(clone.nodes.backlinkContainer);
+ }
+ }
+ for (_k = 0, _len2 = containers.length; _k < _len2; _k++) {
+ container = containers[_k];
+ link = a.cloneNode(true);
+ if (Conf['Quote Previewing']) {
+ $.on(link, 'mouseover', QuotePreview.mouseover);
+ }
+ if (Conf['Quote Inlining']) {
+ $.on(link, 'click', QuoteInline.toggle);
+ }
+ $.add(container, [$.tn(' '), link]);
+ }
+ }
},
- toggle: function() {
- $.event('CloseMenu');
- return (this.checked ? $.addClass : $.rmClass)(doc, 'fappeTyme');
+ secondNode: function() {
+ var container;
+
+ if (this.isClone && (this.origin.isReply || Conf['OP Backlinks'])) {
+ this.nodes.backlinkContainer = $('.container', this.nodes.info);
+ return;
+ }
+ if (!(this.isReply || Conf['OP Backlinks'])) {
+ return;
+ }
+ container = QuoteBacklink.getContainer(this.fullID);
+ this.nodes.backlinkContainer = container;
+ return $.add(this.nodes.info, container);
+ },
+ getContainer: function(id) {
+ var _base;
+
+ return (_base = this.containers)[id] || (_base[id] = $.el('span', {
+ className: 'container'
+ }));
}
};
- ImageExpand = {
+ QuoteCT = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
+ if (g.VIEW === 'catalog' || !Conf['Mark Cross-thread Quotes']) {
return;
}
- this.EAI = $.el('a', {
- className: 'expand-all-shortcut',
- textContent: 'EAI',
- title: 'Expand All Images',
- href: 'javascript:;'
- });
- $.on(this.EAI, 'click', ImageExpand.cb.toggleAll);
- Header.addShortcut(this.EAI);
+ if (Conf['Comment Expansion']) {
+ ExpandComment.callbacks.push(this.node);
+ }
+ this.text = '\u00A0(Cross-thread)';
return Post.prototype.callbacks.push({
- name: 'Image Expansion',
+ name: 'Mark Cross-thread Quotes',
cb: this.node
});
},
node: function() {
- var thumb, _ref;
+ var board, boardID, quotelink, quotelinks, quotes, thread, threadID, _i, _len, _ref, _ref1;
- if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ if (this.isClone && this.thread === this.context.thread) {
return;
}
- thumb = this.file.thumb;
- $.on(thumb.parentNode, 'click', ImageExpand.cb.toggle);
- if (this.isClone && $.hasClass(thumb, 'expanding')) {
- ImageExpand.contract(this);
- ImageExpand.expand(this);
+ if (!(quotes = this.quotes).length) {
return;
}
- if (ImageExpand.on && !this.isHidden) {
- return ImageExpand.expand(this);
- }
- },
- cb: {
- toggle: function(e) {
- if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
- return;
+ quotelinks = this.nodes.quotelinks;
+ _ref = this.isClone ? this.context : this, board = _ref.board, thread = _ref.thread;
+ for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
+ quotelink = quotelinks[_i];
+ _ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, threadID = _ref1.threadID;
+ if (!threadID) {
+ continue;
}
- e.preventDefault();
- return ImageExpand.toggle(Get.postFromNode(this));
- },
- toggleAll: function() {
- var ID, file, func, post, _i, _len, _ref, _ref1;
-
- $.event('CloseMenu');
- if (ImageExpand.on = $.hasClass(ImageExpand.EAI, 'expand-all-shortcut')) {
- ImageExpand.EAI.className = 'contract-all-shortcut';
- ImageExpand.EAI.title = 'Contract All Images';
- func = ImageExpand.expand;
- } else {
- ImageExpand.EAI.className = 'expand-all-shortcut';
- ImageExpand.EAI.title = 'Expand All Images';
- func = ImageExpand.contract;
+ if (this.isClone) {
+ quotelink.textContent = quotelink.textContent.replace(QuoteCT.text, '');
}
- _ref = g.posts;
- for (ID in _ref) {
- post = _ref[ID];
- _ref1 = [post].concat(post.clones);
- for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
- post = _ref1[_i];
- file = post.file;
- if (!(file && file.isImage && doc.contains(post.nodes.root))) {
- continue;
- }
- if (ImageExpand.on && (!Conf['Expand spoilers'] && file.isSpoiler || Conf['Expand from here'] && file.thumb.getBoundingClientRect().top < 0)) {
- continue;
- }
- $.queueTask(func, post);
- }
- }
- },
- setFitness: function() {
- var checked;
-
- checked = this.checked;
- (checked ? $.addClass : $.rmClass)(doc, this.name.toLowerCase().replace(/\s+/g, '-'));
- if (this.name !== 'Fit height') {
- return;
- }
- if (checked) {
- $.on(window, 'resize', ImageExpand.resize);
- if (!ImageExpand.style) {
- ImageExpand.style = $.addStyle(null);
- }
- return ImageExpand.resize();
- } else {
- return $.off(window, 'resize', ImageExpand.resize);
+ if (boardID === this.board.ID && threadID !== thread.ID) {
+ $.add(quotelink, $.tn(QuoteCT.text));
}
}
- },
- toggle: function(post) {
- var headRect, rect, root, thumb, top;
-
- thumb = post.file.thumb;
- if (!(post.file.isExpanded || $.hasClass(thumb, 'expanding'))) {
- ImageExpand.expand(post);
- return;
- }
- ImageExpand.contract(post);
- rect = post.nodes.root.getBoundingClientRect();
- if (!(rect.top <= 0 || rect.left <= 0)) {
- return;
- }
- top = rect.top;
- if (Conf['Fixed Header'] && !Conf['Bottom Header']) {
- headRect = Header.bar.getBoundingClientRect();
- top += -headRect.top - headRect.height;
- }
- root = d.body;
- if (rect.top < 0) {
- root.scrollTop += top;
- }
- if (rect.left < 0) {
- return root.scrollLeft = 0;
- }
- },
- contract: function(post) {
- $.rmClass(post.nodes.root, 'expanded-image');
- $.rmClass(post.file.thumb, 'expanding');
- return post.file.isExpanded = false;
- },
- expand: function(post, src) {
- var img, thumb;
-
- thumb = post.file.thumb;
- if (post.isHidden || post.file.isExpanded || $.hasClass(thumb, 'expanding')) {
- return;
- }
- $.addClass(thumb, 'expanding');
- if (post.file.fullImage) {
- $.asap((function() {
- return post.file.fullImage.naturalHeight;
- }), function() {
- return ImageExpand.completeExpand(post);
- });
- return;
- }
- post.file.fullImage = img = $.el('img', {
- className: 'full-image',
- src: src || post.file.URL
- });
- $.on(img, 'error', ImageExpand.error);
- $.asap((function() {
- return post.file.fullImage.naturalHeight;
- }), function() {
- return ImageExpand.completeExpand(post);
- });
- return $.after(thumb, img);
- },
- completeExpand: function(post) {
- var prev, thumb;
-
- thumb = post.file.thumb;
- if (!$.hasClass(thumb, 'expanding')) {
- return;
- }
- post.file.isExpanded = true;
- if (!post.nodes.root.parentNode) {
- $.addClass(post.nodes.root, 'expanded-image');
- $.rmClass(post.file.thumb, 'expanding');
- return;
- }
- prev = post.nodes.root.getBoundingClientRect();
- return $.queueTask(function() {
- var curr, root;
-
- $.addClass(post.nodes.root, 'expanded-image');
- $.rmClass(post.file.thumb, 'expanding');
- if (!(prev.top + prev.height <= 0)) {
- return;
- }
- root = d.body;
- curr = post.nodes.root.getBoundingClientRect();
- return root.scrollTop += curr.height - prev.height + curr.top - prev.top;
- });
- },
- error: function() {
- var URL, post, src, timeoutID;
-
- post = Get.postFromNode(this);
- $.rm(this);
- delete post.file.fullImage;
- if (!($.hasClass(post.file.thumb, 'expanding') || $.hasClass(post.nodes.root, 'expanded-image'))) {
- return;
- }
- ImageExpand.contract(post);
- src = this.src.split('/');
- if (src[2] === 'images.4chan.org') {
- if (URL = Redirect.image(src[3], src[5])) {
- setTimeout(ImageExpand.expand, 10000, post, URL);
- return;
- }
- if (g.DEAD || post.isDead || post.file.isDead) {
- return;
- }
- }
- timeoutID = setTimeout(ImageExpand.expand, 10000, post);
- return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", {
- onload: function() {
- var postObj, _i, _len, _ref;
-
- if (this.status !== 200) {
- return;
- }
- _ref = JSON.parse(this.response).posts;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- postObj = _ref[_i];
- if (postObj.no === post.ID) {
- break;
- }
- }
- if (postObj.no !== post.ID) {
- clearTimeout(timeoutID);
- return post.kill();
- } else if (postObj.filedeleted) {
- clearTimeout(timeoutID);
- return post.kill(true);
- }
- }
- });
- },
- menu: {
- init: function() {
- var conf, createSubEntry, el, key, subEntries, _ref;
-
- if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
- return;
- }
- el = $.el('span', {
- textContent: 'Image Expansion',
- className: 'image-expansion-link'
- });
- createSubEntry = ImageExpand.menu.createSubEntry;
- subEntries = [];
- _ref = Config.imageExpansion;
- for (key in _ref) {
- conf = _ref[key];
- subEntries.push(createSubEntry(key, conf));
- }
- return $.event('AddMenuEntry', {
- type: 'header',
- el: el,
- order: 105,
- subEntries: subEntries
- });
- },
- createSubEntry: function(type, config) {
- var input, label;
-
- label = $.el('label', {
- innerHTML: " " + type
- });
- input = label.firstElementChild;
- if (type === 'Fit width' || type === 'Fit height') {
- $.on(input, 'change', ImageExpand.cb.setFitness);
- }
- if (config) {
- label.title = config[1];
- input.checked = Conf[type];
- $.event('change', null, input);
- $.on(input, 'change', $.cb.checked);
- }
- return {
- el: label
- };
- }
- },
- resize: function() {
- return ImageExpand.style.textContent = ":root.fit-height .full-image {max-height:" + doc.clientHeight + "px}";
- },
- menuToggle: function(e) {
- return ImageExpand.opmenu.toggle(e, this, g);
}
};
- ImageHover = {
+ QuoteInline = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Image Hover']) {
+ if (g.VIEW === 'catalog' || !Conf['Quote Inlining']) {
return;
}
+ if (Conf['Comment Expansion']) {
+ ExpandComment.callbacks.push(this.node);
+ }
return Post.prototype.callbacks.push({
- name: 'Image Hover',
+ name: 'Quote Inlining',
cb: this.node
});
},
node: function() {
- var _ref;
+ var link, _i, _len, _ref;
- if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ link = _ref[_i];
+ $.on(link, 'click', QuoteInline.toggle);
+ }
+ },
+ toggle: function(e) {
+ var boardID, context, postID, threadID, _ref;
+
+ if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
return;
}
- return $.on(this.file.thumb, 'mouseover', ImageHover.mouseover);
+ e.preventDefault();
+ _ref = Get.postDataFromLink(this), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
+ context = Get.contextFromLink(this);
+ if ($.hasClass(this, 'inlined')) {
+ QuoteInline.rm(this, boardID, threadID, postID, context);
+ } else {
+ if ($.x("ancestor::div[@id='p" + postID + "']", this)) {
+ return;
+ }
+ QuoteInline.add(this, boardID, threadID, postID, context);
+ }
+ return this.classList.toggle('inlined');
+ },
+ findRoot: function(quotelink, isBacklink) {
+ if (isBacklink) {
+ return quotelink.parentNode.parentNode;
+ } else {
+ return $.x('ancestor-or-self::*[parent::blockquote][1]', quotelink);
+ }
+ },
+ add: function(quotelink, boardID, threadID, postID, context) {
+ var inline, isBacklink, post;
+
+ isBacklink = $.hasClass(quotelink, 'backlink');
+ inline = $.el('div', {
+ id: "i" + postID,
+ className: 'inline'
+ });
+ $.after(QuoteInline.findRoot(quotelink, isBacklink), inline);
+ Get.postClone(boardID, threadID, postID, inline, context);
+ if (!((post = g.posts["" + boardID + "." + postID]) && context.thread === post.thread)) {
+ return;
+ }
+ if (isBacklink && Conf['Forward Hiding']) {
+ $.addClass(post.nodes.root, 'forwarded');
+ post.forwarded++ || (post.forwarded = 1);
+ }
+ if (!Unread.posts) {
+ return;
+ }
+ return Unread.readSinglePost(post);
+ },
+ rm: function(quotelink, boardID, threadID, postID, context) {
+ var el, inlined, isBacklink, post, root, _ref;
+
+ isBacklink = $.hasClass(quotelink, 'backlink');
+ root = QuoteInline.findRoot(quotelink, isBacklink);
+ root = $.x("following-sibling::div[@id='i" + postID + "'][1]", root);
+ $.rm(root);
+ if (!(el = root.firstElementChild)) {
+ return;
+ }
+ post = g.posts["" + boardID + "." + postID];
+ post.rmClone(el.dataset.clone);
+ if (Conf['Forward Hiding'] && isBacklink && context.thread === g.threads["" + boardID + "." + threadID] && !--post.forwarded) {
+ delete post.forwarded;
+ $.rmClass(post.nodes.root, 'forwarded');
+ }
+ while (inlined = $('.inlined', el)) {
+ _ref = Get.postDataFromLink(inlined), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
+ QuoteInline.rm(inlined, boardID, threadID, postID, context);
+ $.rmClass(inlined, 'inlined');
+ }
+ }
+ };
+
+ QuoteOP = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Mark OP Quotes']) {
+ return;
+ }
+ if (Conf['Comment Expansion']) {
+ ExpandComment.callbacks.push(this.node);
+ }
+ this.text = '\u00A0(OP)';
+ return Post.prototype.callbacks.push({
+ name: 'Mark OP Quotes',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var boardID, op, postID, quotelink, quotelinks, quotes, _i, _j, _len, _len1, _ref;
+
+ if (this.isClone && this.thread === this.context.thread) {
+ return;
+ }
+ if (!(quotes = this.quotes).length) {
+ return;
+ }
+ quotelinks = this.nodes.quotelinks;
+ if (this.isClone && quotes.contains(this.thread.fullID)) {
+ for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
+ quotelink = quotelinks[_i];
+ quotelink.textContent = quotelink.textContent.replace(QuoteOP.text, '');
+ }
+ }
+ op = (this.isClone ? this.context : this).thread.fullID;
+ if (!quotes.contains(op)) {
+ return;
+ }
+ for (_j = 0, _len1 = quotelinks.length; _j < _len1; _j++) {
+ quotelink = quotelinks[_j];
+ _ref = Get.postDataFromLink(quotelink), boardID = _ref.boardID, postID = _ref.postID;
+ if (("" + boardID + "." + postID) === op) {
+ $.add(quotelink, $.tn(QuoteOP.text));
+ }
+ }
+ }
+ };
+
+ QuotePreview = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Quote Previewing']) {
+ return;
+ }
+ if (Conf['Comment Expansion']) {
+ ExpandComment.callbacks.push(this.node);
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Quote Previewing',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var link, _i, _len, _ref;
+
+ _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ link = _ref[_i];
+ $.on(link, 'mouseover', QuotePreview.mouseover);
+ }
},
mouseover: function(e) {
- var el, post;
+ var boardID, clone, origin, post, postID, posts, qp, quote, quoterID, threadID, _i, _j, _len, _len1, _ref, _ref1;
- post = Get.postFromNode(this);
- el = $.el('img', {
- id: 'ihover',
- src: post.file.URL
+ if ($.hasClass(this, 'inlined')) {
+ return;
+ }
+ _ref = Get.postDataFromLink(this), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
+ qp = $.el('div', {
+ id: 'qp',
+ className: 'dialog'
});
- el.setAttribute('data-fullid', post.fullID);
- $.add(Header.hover, el);
+ $.add(Header.hover, qp);
+ Get.postClone(boardID, threadID, postID, qp, Get.contextFromLink(this));
UI.hover({
root: this,
- el: el,
+ el: qp,
latestEvent: e,
endEvents: 'mouseout click',
+ cb: QuotePreview.mouseout,
asapTest: function() {
- return el.naturalHeight;
+ return qp.firstElementChild;
}
});
- return $.on(el, 'error', ImageHover.error);
- },
- error: function() {
- var URL, post, src, timeoutID,
- _this = this;
-
- if (!doc.contains(this)) {
+ if (!(origin = g.posts["" + boardID + "." + postID])) {
return;
}
- post = g.posts[this.dataset.fullid];
- src = this.src.split('/');
- if (src[2] === 'images.4chan.org') {
- if (URL = Redirect.image(src[3], src[5].replace(/\?.+$/, ''))) {
- this.src = URL;
- return;
- }
- if (g.DEAD || post.isDead || post.file.isDead) {
- return;
+ if (Conf['Quote Highlighting']) {
+ posts = [origin].concat(origin.clones);
+ posts.pop();
+ for (_i = 0, _len = posts.length; _i < _len; _i++) {
+ post = posts[_i];
+ $.addClass(post.nodes.post, 'qphl');
}
}
- timeoutID = setTimeout((function() {
- return _this.src = post.file.URL + '?' + Date.now();
- }), 3000);
- return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", {
- onload: function() {
- var postObj, _i, _len, _ref;
-
- if (this.status !== 200) {
- return;
- }
- _ref = JSON.parse(this.response).posts;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- postObj = _ref[_i];
- if (postObj.no === post.ID) {
- break;
- }
- }
- if (postObj.no !== post.ID) {
- clearTimeout(timeoutID);
- return post.kill();
- } else if (postObj.filedeleted) {
- clearTimeout(timeoutID);
- return post.kill(true);
- }
+ quoterID = $.x('ancestor::*[@id][1]', this).id.match(/\d+$/)[0];
+ clone = Get.postFromRoot(qp.firstChild);
+ _ref1 = clone.nodes.quotelinks.concat(__slice.call(clone.nodes.backlinks));
+ for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
+ quote = _ref1[_j];
+ if (quote.hash.slice(2) === quoterID) {
+ $.addClass(quote, 'forwardlink');
}
- });
+ }
+ },
+ mouseout: function() {
+ var clone, post, root, _i, _len, _ref;
+
+ if (!(root = this.el.firstElementChild)) {
+ return;
+ }
+ clone = Get.postFromRoot(root);
+ post = clone.origin;
+ post.rmClone(root.dataset.clone);
+ if (!Conf['Quote Highlighting']) {
+ return;
+ }
+ _ref = [post].concat(post.clones);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ post = _ref[_i];
+ $.rmClass(post.nodes.post, 'qphl');
+ }
}
};
- ImageReplace = {
+ QuoteStrikeThrough = {
init: function() {
- if (g.VIEW === 'catalog') {
+ if (g.VIEW === 'catalog' || !Conf['Reply Hiding Buttons'] && !Conf['Reply Hiding Link'] && !Conf['Filter']) {
return;
}
return Post.prototype.callbacks.push({
- name: 'Image Replace',
+ name: 'Strike-through Quotes',
cb: this.node
});
},
node: function() {
- var URL, img, style, thumb, type, _ref, _ref1;
+ var boardID, postID, quotelink, _i, _len, _ref, _ref1, _ref2;
- if (this.isClone || this.isHidden || this.thread.isHidden || !((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ if (this.isClone) {
return;
}
- _ref1 = this.file, thumb = _ref1.thumb, URL = _ref1.URL;
- if (!(Conf["Replace " + ((type = (URL.match(/\w{3}$/))[0].toUpperCase()) === 'PEG' ? 'JPG' : type)] && !/spoiler/.test(thumb.src))) {
- return;
+ _ref = this.nodes.quotelinks;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ quotelink = _ref[_i];
+ _ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, postID = _ref1.postID;
+ if ((_ref2 = g.posts["" + boardID + "." + postID]) != null ? _ref2.isHidden : void 0) {
+ $.addClass(quotelink, 'filtered');
+ }
}
- if (this.file.isSpoiler) {
- style = thumb.style;
- style.maxHeight = style.maxWidth = this.isReply ? '125px' : '250px';
- }
- img = $.el('img');
- $.on(img, 'load', function() {
- return thumb.src = URL;
- });
- return img.src = URL;
}
};
- RevealSpoilers = {
+ /*
+ <3 aeosynth
+ */
+
+
+ QuoteThreading = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Reveal Spoilers']) {
+ var input;
+
+ if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
return;
}
+ this.enabled = true;
+ this.controls = $.el('span', {
+ innerHTML: ''
+ });
+ input = $('input', this.controls);
+ $.on(input, 'change', QuoteThreading.toggle);
+ $.event('AddMenuEntry', {
+ type: 'header',
+ el: this.controls,
+ order: 98
+ });
+ $.on(d, '4chanXInitFinished', this.setup);
return Post.prototype.callbacks.push({
- name: 'Reveal Spoilers',
+ name: 'Quote Threading',
+ cb: this.node
+ });
+ },
+ setup: function() {
+ var ID, post, posts;
+
+ $.off(d, '4chanXInitFinished', QuoteThreading.setup);
+ posts = g.posts;
+ for (ID in posts) {
+ post = posts[ID];
+ if (post.cb) {
+ post.cb.call(post);
+ }
+ }
+ return QuoteThreading.hasRun = true;
+ },
+ node: function() {
+ var ID, fullID, keys, len, post, posts, qid, quote, quotes, uniq, _i, _len;
+
+ if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) {
+ return;
+ }
+ quotes = this.quotes, ID = this.ID, fullID = this.fullID;
+ posts = g.posts;
+ if (!(post = posts[fullID]) || post.isHidden) {
+ return;
+ }
+ uniq = {};
+ len = ("" + g.BOARD).length + 1;
+ for (_i = 0, _len = quotes.length; _i < _len; _i++) {
+ quote = quotes[_i];
+ qid = quote;
+ if (!(qid.slice(len) < ID)) {
+ continue;
+ }
+ if (qid in posts) {
+ uniq[qid.slice(len)] = true;
+ }
+ }
+ keys = Object.keys(uniq);
+ if (keys.length !== 1) {
+ return;
+ }
+ this.threaded = "" + g.BOARD + "." + keys[0];
+ return this.cb = QuoteThreading.nodeinsert;
+ },
+ nodeinsert: function() {
+ var bottom, height, posts, qpost, qroot, threadContainer, top, _ref;
+
+ posts = g.posts;
+ qpost = posts[this.threaded];
+ delete this.threaded;
+ delete this.cb;
+ if (this.thread.OP === qpost) {
+ return false;
+ }
+ if (QuoteThreading.hasRun) {
+ height = doc.clientHeight;
+ _ref = qpost.nodes.root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top;
+ if (!(Unread.posts.contains(qpost) || ((bottom < height) && (top > 0)))) {
+ return false;
+ }
+ }
+ qroot = qpost.nodes.root;
+ if (!$.hasClass(qroot, 'threadOP')) {
+ $.addClass(qroot, 'threadOP');
+ threadContainer = $.el('div', {
+ className: 'threadContainer'
+ });
+ $.after(qroot, threadContainer);
+ } else {
+ threadContainer = qroot.nextSibling;
+ }
+ $.add(threadContainer, this.nodes.root);
+ return true;
+ },
+ toggle: function() {
+ var container, containers, node, nodes, replies, reply, thread, _i, _j, _len, _len1;
+
+ thread = $('.thread');
+ replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread);
+ QuoteThreading.enabled = this.checked;
+ if (this.checked) {
+ nodes = (function() {
+ var _i, _len, _results;
+
+ _results = [];
+ for (_i = 0, _len = replies.length; _i < _len; _i++) {
+ reply = replies[_i];
+ _results.push(Get.postFromNode(reply));
+ }
+ return _results;
+ })();
+ for (_i = 0, _len = nodes.length; _i < _len; _i++) {
+ node = nodes[_i];
+ QuoteThreading.node(node);
+ }
+ } else {
+ replies.sort(function(a, b) {
+ var aID, bID;
+
+ aID = Number(a.id.slice(2));
+ bID = Number(b.id.slice(2));
+ return aID - bID;
+ });
+ $.add(thread, replies);
+ containers = $$('.threadContainer', thread);
+ for (_j = 0, _len1 = containers.length; _j < _len1; _j++) {
+ container = containers[_j];
+ $.rm(container);
+ }
+ Unread.update(true);
+ }
+ },
+ kb: function() {
+ var control;
+
+ control = $.id('threadingControl');
+ return control.click();
+ }
+ };
+
+ QuoteYou = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Mark Quotes of You'] || !Conf['Quick Reply']) {
+ return;
+ }
+ this.text = '\u00A0(You)';
+ return Post.prototype.callbacks.push({
+ name: 'Mark Quotes of You',
cb: this.node
});
},
node: function() {
- var thumb, _ref;
+ var quotelink, quotelinks, quotes, _i, _len;
- if (this.isClone || !((_ref = this.file) != null ? _ref.isSpoiler : void 0)) {
+ if (this.isClone) {
return;
}
- thumb = this.file.thumb;
- thumb.removeAttribute('style');
- return thumb.src = this.file.thumbURL;
+ if (this.info.yours) {
+ $.addClass(this.nodes.root, 'yourPost');
+ }
+ if (Conf['Highlight Own Posts']) {
+ $.addClass(doc, 'highlight-own');
+ }
+ if (!(quotes = this.quotes).length) {
+ return;
+ }
+ quotelinks = this.nodes.quotelinks;
+ for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
+ quotelink = quotelinks[_i];
+ if (QR.db.get(Get.postDataFromLink(quotelink))) {
+ $.add(quotelink, $.tn(QuoteYou.text));
+ }
+ }
+ }
+ };
+
+ Quotify = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Resurrect Quotes']) {
+ return;
+ }
+ if (Conf['Comment Expansion']) {
+ ExpandComment.callbacks.push(this.node);
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Resurrect Quotes',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var deadlink, _i, _len, _ref;
+
+ _ref = $$('.deadlink', this.nodes.comment);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ deadlink = _ref[_i];
+ if (this.isClone) {
+ if ($.hasClass(deadlink, 'quotelink')) {
+ this.nodes.quotelinks.push(deadlink);
+ }
+ } else {
+ Quotify.parseDeadlink.call(this, deadlink);
+ }
+ }
+ },
+ parseDeadlink: function(deadlink) {
+ var a, boardID, m, post, postID, quote, quoteID, redirect, _ref;
+
+ if (deadlink.parentNode.className === 'prettyprint') {
+ $.replace(deadlink, __slice.call(deadlink.childNodes));
+ return;
+ }
+ quote = deadlink.textContent;
+ if (!(postID = (_ref = quote.match(/\d+$/)) != null ? _ref[0] : void 0)) {
+ return;
+ }
+ boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID;
+ quoteID = "" + boardID + "." + postID;
+ if (post = g.posts[quoteID]) {
+ if (!post.isDead) {
+ a = $.el('a', {
+ href: "/" + boardID + "/" + post.thread + "/res/#p" + postID,
+ className: 'quotelink',
+ textContent: quote
+ });
+ } else {
+ a = $.el('a', {
+ href: "/" + boardID + "/" + post.thread + "/res/#p" + postID,
+ className: 'quotelink deadlink',
+ target: '_blank',
+ textContent: "" + quote + "\u00A0(Dead)"
+ });
+ a.setAttribute('data-boardid', boardID);
+ a.setAttribute('data-threadid', post.thread.ID);
+ a.setAttribute('data-postid', postID);
+ }
+ } else if (redirect = Redirect.to({
+ boardID: boardID,
+ threadID: 0,
+ postID: postID
+ })) {
+ a = $.el('a', {
+ href: redirect,
+ className: 'deadlink',
+ target: '_blank',
+ textContent: "" + quote + "\u00A0(Dead)"
+ });
+ if (Redirect.post(boardID, postID)) {
+ $.addClass(a, 'quotelink');
+ a.setAttribute('data-boardid', boardID);
+ a.setAttribute('data-postid', postID);
+ }
+ }
+ if (__indexOf.call(this.quotes, quoteID) < 0) {
+ this.quotes.push(quoteID);
+ }
+ if (!a) {
+ deadlink.textContent = "" + quote + "\u00A0(Dead)";
+ return;
+ }
+ $.replace(deadlink, a);
+ if ($.hasClass(a, 'quotelink')) {
+ return this.nodes.quotelinks.push(a);
+ }
}
};
@@ -3804,3086 +4393,6 @@
}
};
- ArchiveLink = {
- init: function() {
- var div, entry, type, _i, _len, _ref;
-
- if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Archive Link']) {
- return;
- }
- div = $.el('div', {
- textContent: 'Archive'
- });
- entry = {
- type: 'post',
- el: div,
- order: 90,
- open: function(_arg) {
- var ID, board, redirect, thread;
-
- ID = _arg.ID, thread = _arg.thread, board = _arg.board;
- redirect = Redirect.to({
- postID: ID,
- threadID: thread.ID,
- boardID: board.ID
- });
- return redirect !== ("//boards.4chan.org/" + board + "/");
- },
- subEntries: []
- };
- _ref = [['Post', 'post'], ['Name', 'name'], ['Tripcode', 'tripcode'], ['E-mail', 'email'], ['Subject', 'subject'], ['Filename', 'filename'], ['Image MD5', 'MD5']];
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- type = _ref[_i];
- entry.subEntries.push(this.createSubEntry(type[0], type[1]));
- }
- return $.event('AddMenuEntry', entry);
- },
- createSubEntry: function(text, type) {
- var el, open;
-
- el = $.el('a', {
- textContent: text,
- target: '_blank'
- });
- open = type === 'post' ? function(_arg) {
- var ID, board, thread;
-
- ID = _arg.ID, thread = _arg.thread, board = _arg.board;
- el.href = Redirect.to({
- postID: ID,
- threadID: thread.ID,
- boardID: board.ID
- });
- return true;
- } : function(post) {
- var value;
-
- value = Filter[type](post);
- if (!value) {
- return false;
- }
- el.href = Redirect.to({
- boardID: post.board.ID,
- type: type,
- value: value,
- isSearch: true
- });
- return true;
- };
- return {
- el: el,
- open: open
- };
- }
- };
-
- DeleteLink = {
- init: function() {
- var div, fileEl, fileEntry, postEl, postEntry;
-
- if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Delete Link']) {
- return;
- }
- div = $.el('div', {
- className: 'delete-link',
- textContent: 'Delete'
- });
- postEl = $.el('a', {
- className: 'delete-post',
- href: 'javascript:;'
- });
- fileEl = $.el('a', {
- className: 'delete-file',
- href: 'javascript:;'
- });
- postEntry = {
- el: postEl,
- open: function() {
- postEl.textContent = 'Post';
- $.on(postEl, 'click', DeleteLink["delete"]);
- return true;
- }
- };
- fileEntry = {
- el: fileEl,
- open: function(_arg) {
- var file;
-
- file = _arg.file;
- if (!file || file.isDead) {
- return false;
- }
- fileEl.textContent = 'File';
- $.on(fileEl, 'click', DeleteLink["delete"]);
- return true;
- }
- };
- return $.event('AddMenuEntry', {
- type: 'post',
- el: div,
- order: 40,
- open: function(post) {
- var node;
-
- if (post.isDead) {
- return false;
- }
- DeleteLink.post = post;
- node = div.firstChild;
- node.textContent = 'Delete';
- DeleteLink.cooldown.start(post, node);
- return true;
- },
- subEntries: [postEntry, fileEntry]
- });
- },
- "delete": function() {
- var fileOnly, form, link, m, post, pwd;
-
- post = DeleteLink.post;
- if (DeleteLink.cooldown.counting === post) {
- return;
- }
- $.off(this, 'click', DeleteLink["delete"]);
- this.textContent = "Deleting " + this.textContent + "...";
- pwd = (m = d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : $.id('delPassword').value;
- fileOnly = $.hasClass(this, 'delete-file');
- form = {
- mode: 'usrdel',
- onlyimgdel: fileOnly,
- pwd: pwd
- };
- form[post.ID] = 'delete';
- link = this;
- return $.ajax($.id('delform').action.replace("/" + g.BOARD + "/", "/" + post.board + "/"), {
- onload: function() {
- return DeleteLink.load(link, post, fileOnly, this.response);
- },
- onerror: function() {
- return DeleteLink.error(link);
- }
- }, {
- cred: true,
- form: $.formData(form)
- });
- },
- load: function(link, post, fileOnly, html) {
- var msg, s, tmpDoc;
-
- tmpDoc = d.implementation.createHTMLDocument('');
- tmpDoc.documentElement.innerHTML = html;
- if (tmpDoc.title === '4chan - Banned') {
- s = 'Banned!';
- } else if (msg = tmpDoc.getElementById('errmsg')) {
- s = msg.textContent;
- $.on(link, 'click', DeleteLink["delete"]);
- } else {
- if (tmpDoc.title === 'Updating index...') {
- (post.origin || post).kill(fileOnly);
- }
- s = 'Deleted';
- }
- return link.textContent = s;
- },
- error: function(link) {
- link.textContent = 'Connection error, please retry.';
- return $.on(link, 'click', DeleteLink["delete"]);
- },
- cooldown: {
- start: function(post, node) {
- var length, seconds, _ref;
-
- if (!((_ref = QR.db) != null ? _ref.get({
- boardID: post.board.ID,
- threadID: post.thread.ID,
- postID: post.ID
- }) : void 0)) {
- delete DeleteLink.cooldown.counting;
- return;
- }
- DeleteLink.cooldown.counting = post;
- length = post.board.ID === 'q' ? 600 : 30;
- seconds = Math.ceil((length * $.SECOND - (Date.now() - post.info.date)) / $.SECOND);
- return DeleteLink.cooldown.count(post, seconds, length, node);
- },
- count: function(post, seconds, length, node) {
- if (DeleteLink.cooldown.counting !== post) {
- return;
- }
- if (!((0 <= seconds && seconds <= length))) {
- if (DeleteLink.cooldown.counting === post) {
- node.textContent = 'Delete';
- delete DeleteLink.cooldown.counting;
- }
- return;
- }
- setTimeout(DeleteLink.cooldown.count, 1000, post, seconds - 1, length, node);
- return node.textContent = "Delete (" + seconds + ")";
- }
- }
- };
-
- DownloadLink = {
- init: function() {
- var a;
-
- if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Download Link']) {
- return;
- }
- a = $.el('a', {
- className: 'download-link',
- textContent: 'Download file'
- });
- return $.event('AddMenuEntry', {
- type: 'post',
- el: a,
- order: 70,
- open: function(_arg) {
- var file;
-
- file = _arg.file;
- if (!file) {
- return false;
- }
- a.href = file.URL;
- a.download = file.name;
- return true;
- }
- });
- }
- };
-
- Menu = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Menu']) {
- return;
- }
- this.menu = new UI.Menu('post');
- return Post.prototype.callbacks.push({
- name: 'Menu',
- cb: this.node
- });
- },
- node: function() {
- var button;
-
- button = Menu.makeButton(this);
- if (this.isClone) {
- $.replace($('.menu-button', this.nodes.info), button);
- return;
- }
- return $.add(this.nodes.info, [$.tn('\u00A0'), button]);
- },
- makeButton: (function() {
- var a;
-
- a = null;
- return function(post) {
- var clone;
-
- a || (a = $.el('a', {
- className: 'menu-button',
- innerHTML: '[]',
- href: 'javascript:;'
- }));
- clone = a.cloneNode(true);
- clone.setAttribute('data-postid', post.fullID);
- if (post.isClone) {
- clone.setAttribute('data-clone', true);
- }
- $.on(clone, 'click', Menu.toggle);
- return clone;
- };
- })(),
- toggle: function(e) {
- var post;
-
- post = this.dataset.clone ? Get.postFromNode(this) : g.posts[this.dataset.postid];
- return Menu.menu.toggle(e, this, post);
- }
- };
-
- ReportLink = {
- init: function() {
- var a;
-
- if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Report Link']) {
- return;
- }
- a = $.el('a', {
- className: 'report-link',
- href: 'javascript:;',
- textContent: 'Report this post'
- });
- $.on(a, 'click', ReportLink.report);
- return $.event('AddMenuEntry', {
- type: 'post',
- el: a,
- order: 10,
- open: function(post) {
- ReportLink.post = post;
- return !post.isDead;
- }
- });
- },
- report: function() {
- var id, post, set, url;
-
- post = ReportLink.post;
- url = "//sys.4chan.org/" + post.board + "/imgboard.php?mode=report&no=" + post;
- id = Date.now();
- set = "toolbar=0,scrollbars=0,location=0,status=1,menubar=0,resizable=1,width=685,height=200";
- return window.open(url, id, set);
- }
- };
-
- PSAHiding = {
- init: function() {
- var entry;
-
- if (!Conf['Announcement Hiding']) {
- return;
- }
- entry = {
- type: 'header',
- el: $.el('a', {
- textContent: 'Show announcement',
- className: 'show-announcement',
- href: 'javascript:;'
- }),
- order: 50,
- open: function() {
- var _ref;
-
- if ((_ref = $.id('globalMessage')) != null ? _ref.hidden : void 0) {
- return true;
- }
- return false;
- }
- };
- $.event('AddMenuEntry', entry);
- $.on(entry.el, 'click', PSAHiding.toggle);
- $.addClass(doc, 'hide-announcement');
- return $.on(d, '4chanXInitFinished', this.setup);
- },
- setup: function() {
- var btn, psa;
-
- $.off(d, '4chanXInitFinished', PSAHiding.setup);
- if (!(psa = $.id('globalMessage'))) {
- $.rmClass(doc, 'hide-announcement');
- return;
- }
- PSAHiding.btn = btn = $.el('a', {
- innerHTML: '[ - ]',
- title: 'Hide announcement.',
- className: 'hide-announcement',
- href: 'javascript:;'
- });
- $.on(btn, 'click', PSAHiding.toggle);
- $.get('hiddenPSAs', [], function(item) {
- PSAHiding.sync(item['hiddenPSAs']);
- $.before(psa, btn);
- return $.rmClass(doc, 'hide-announcement');
- });
- return $.sync('hiddenPSAs', PSAHiding.sync);
- },
- toggle: function(e) {
- var hide, text;
-
- hide = $.hasClass(this, 'hide-announcement');
- text = PSAHiding.trim($.id('globalMessage'));
- return $.get('hiddenPSAs', [], function(_arg) {
- var hiddenPSAs, i;
-
- hiddenPSAs = _arg.hiddenPSAs;
- if (hide) {
- hiddenPSAs.push(text);
- hiddenPSAs = hiddenPSAs.slice(-5);
- } else {
- $.event('CloseMenu');
- i = hiddenPSAs.indexOf(text);
- hiddenPSAs.splice(i, 1);
- }
- PSAHiding.sync(hiddenPSAs);
- return $.set('hiddenPSAs', hiddenPSAs);
- });
- },
- sync: function(hiddenPSAs) {
- var hr, psa, _ref;
-
- psa = $.id('globalMessage');
- psa.hidden = PSAHiding.btn.hidden = (_ref = PSAHiding.trim(psa), __indexOf.call(hiddenPSAs, _ref) >= 0) ? true : false;
- if ((hr = psa.nextElementSibling) && hr.nodeName === 'HR') {
- return hr.hidden = psa.hidden;
- }
- },
- trim: function(psa) {
- return psa.textContent.replace(/\W+/g, '').toLowerCase();
- }
- };
-
- CatalogLinks = {
- init: function() {
- var el, input;
-
- if (!Conf['Catalog Links']) {
- return;
- }
- el = $.el('label', {
- id: 'toggleCatalog',
- href: 'javascript:;',
- innerHTML: "Catalog Links",
- title: "Turn catalog links " + (Conf['Header catalog links'] ? 'off' : 'on') + "."
- });
- input = $('input', el);
- $.on(input, 'change', this.toggle);
- $.sync('Header catalog links', CatalogLinks.set);
- $.event('AddMenuEntry', {
- type: 'header',
- el: el,
- order: 95
- });
- return $.on(d, '4chanXInitFinished', function() {
- return CatalogLinks.set(Conf['Header catalog links']);
- });
- },
- toggle: function() {
- var useCatalog;
-
- $.event('CloseMenu');
- $.set('Header catalog links', useCatalog = this.checked);
- return CatalogLinks.set(useCatalog);
- },
- set: function(useCatalog) {
- var a, board, path, _i, _len, _ref;
-
- path = useCatalog ? 'catalog' : '';
- _ref = $$("#board-list a[href*=\"boards.4chan.org\"],\n#boardNavDesktop a[href*=\"boards.4chan.org\"],\n#boardNavDesktopFoot a[href*=\"boards.4chan.org\"]");
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- a = _ref[_i];
- board = a.pathname.split('/')[1];
- if (['f', 'status', '4chan'].contains(board) || !board) {
- continue;
- }
- if (Conf['External Catalog']) {
- a.href = useCatalog ? CatalogLinks.external(board) : "//boards.4chan.org/" + board + "/";
- } else {
- a.pathname = "/" + board + "/" + path;
- }
- a.title = useCatalog ? "" + a.title + " - Catalog" : a.title.replace(/\ -\ Catalog$/, '');
- }
- return this.title = "Turn catalog links " + (useCatalog ? 'off' : 'on') + ".";
- },
- external: function(board) {
- return (['a', 'c', 'g', 'co', 'k', 'm', 'o', 'p', 'v', 'vg', 'w', 'cm', '3', 'adv', 'an', 'cgl', 'ck', 'diy', 'fa', 'fit', 'int', 'jp', 'mlp', 'lit', 'mu', 'n', 'po', 'sci', 'toy', 'trv', 'tv', 'vp', 'x', 'q'].contains(board) ? "http://catalog.neet.tv/" + board : ['d', 'e', 'gif', 'h', 'hr', 'hc', 'r9k', 's', 'pol', 'soc', 'u', 'i', 'ic', 'hm', 'r', 'w', 'wg', 'wsg', 't', 'y'].contains(board) ? "http://4index.gropes.us/" + board : "//boards.4chan.org/" + board + "/catalog");
- }
- };
-
- IDColor = {
- init: function() {
- if (!Conf['Color User IDs']) {
- return;
- }
- return Post.prototype.callbacks.push({
- name: 'Reveal Spoilers',
- cb: this.node
- });
- },
- node: function(post) {
- var str, uid;
-
- if (!(uid = $('.hand', this.nodes.uniqueID))) {
- return;
- }
- str = this.info.uniqueID;
- if (uid.nodeName === 'SPAN') {
- return uid.style.cssText = IDColor.apply.call(str);
- }
- },
- ids: {},
- compute: function(str) {
- var hash, rgb;
-
- hash = this.hash(str);
- rgb = [(hash >> 24) & 0xFF, (hash >> 16) & 0xFF, (hash >> 8) & 0xFF];
- rgb[3] = ((rgb[0] * 0.299) + (rgb[1] * 0.587) + (rgb[2] * 0.114)) > 125;
- this.ids[str] = rgb;
- return rgb;
- },
- apply: function() {
- var rgb;
-
- rgb = IDColor.ids[this] || IDColor.compute(this);
- return ("background-color: rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "); color: ") + (rgb[3] ? "black;" : "white; border-radius: 3px; padding: 0px 2px;");
- },
- hash: function(str) {
- var i, j, msg;
-
- msg = 0;
- i = 0;
- j = str.length;
- while (i < j) {
- msg = ((msg << 5) - msg) + str.charCodeAt(i);
- ++i;
- }
- return msg;
- }
- };
-
- Emoji = {
- init: function() {
- var css, icon, name, pos, _ref;
-
- if (!Conf['Emoji']) {
- return;
- }
- pos = Conf['emojiPos'];
- css = ["a.useremail[href]:last-of-type::" + pos + " {\n vertical-align: top;\n margin-" + (pos === "before" ? "right" : "left") + ": 5px;\n}\n"];
- this.icons["PlanNine"] = Emoji.icons["Plan9"];
- this.icons['Sage'] = Emoji.sage[Conf['sageEmoji']];
- _ref = this.icons;
- for (name in _ref) {
- icon = _ref[name];
- if (!this.icons.hasOwnProperty(name)) {
- continue;
- }
- css.push("a.useremail[href*='" + name + "']:last-of-type::" + pos + ",\na.useremail[href*='" + (name.toLowerCase()) + "']:last-of-type::" + pos + ",\na.useremail[href*='" + (name.toUpperCase()) + "']:last-of-type::" + pos + " {\n content: url('data:image/png;base64," + icon + "');\n}\n");
- }
- return $.addStyle(css.join(""), 'emoji');
- },
- sage: {
- '4chan SS': 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAYAAACZ3F9/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAa9JREFUKFOdkt0rg2EUwM95b2zlL0CRRLngksznXrJsNtYW1tjYhM3mY6+IXZAbikhTKJp8XZAp81UmWYhIRHHhUi60e7s6ntdCa2449es8PfU7z+k5B6AbyuE/wQlc4BcO2d06unAUBCgFE0hianOd3NHIcy8NPwrUf9NBPZcOEi7ayXZiea/1V7+ljaXeYAfOgg2So2TOwQWGnwQafOgi962TnMFmatozUeNu4yetASspVvgXiUvii5K5Nm6z56ol3Hdtpy+cwSYy+HRUt1nLsoEato0kXyh6wTac+24brThWv6MNOYNW9prlG/uxmbRrFaT0VrCspZoNPSUNJNyCBcoiLZuhLH0o9U6UrAfGKCz7RlLM81Q8XUwqr4oKPLIQmnA8IupBigacVy7yrya/2JouhryJHJJNykg+UxLGOtz6+SQNpEiMcduls4Wvoli9WklVKz+ol5SU4U6ngql8Qj2eRI+GyajBhSRH4r3cUxhSeRVhsYBmWUWiyM+UMDmDUI2nsfuSC1I27nLgYZJlP8jhjJ3PY8iE+L8tWx4kQC6MQA5b1D9HNiRCFhx8AF/e2qh92VnKAAAAAElFTkSuQmCC',
- 'appchan': 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAABa1BMVEUAAACqrKiCgYIAAAAAAAAAAACHmX5pgl5NUEx/hnx4hXRSUVMiIyKwrbFzn19SbkZ1d3OvtqtpaWhcX1ooMyRsd2aWkZddkEV8vWGcpZl+kHd7jHNdYFuRmI4bHRthaV5WhUFsfGZReUBFZjdJazpGVUBnamYfHB9TeUMzSSpHgS1cY1k1NDUyOC8yWiFywVBoh1lDSEAZHBpucW0ICQgUHhBjfFhCRUA+QTtEQUUBAQFyo1praWspKigWFRZHU0F6j3E9Oz5VWFN0j2hncWONk4sAAABASDxJWkJKTUgAAAAvNC0fJR0DAwMAAAA9QzoWGhQAAAA8YytvrFOJsnlqyT9oqExqtkdrsExpsUsqQx9rpVJDbzBBbi5utk9jiFRuk11iqUR64k5Wf0JIZTpadk5om1BkyjmF1GRNY0FheFdXpjVXhz86XSp2yFJwslR3w1NbxitbtDWW5nNnilhFXTtYqDRwp1dSijiJ7H99AAAAUnRSTlMAJTgNGQml71ypu3cPEN/RDh8HBbOwQN7wVg4CAQZ28vs9EDluXjo58Ge8xwMy0P3+rV8cT73sawEdTv63NAa3rQwo4cUdAl3hWQSWvS8qqYsjEDiCzAAAAIVJREFUeNpFx7GKAQAYAOD/A7GbZVAWZTBZFGQw6LyCF/MIkiTdcOmWSzYbJVE2u1KX0J1v+8QDv/EkyS0yXF/NgeEILiHfyc74mICTQltqYXBeAWU9HGxU09YqqEvAElGjyZYjPyLqitjzHSEiGkrsfMWr0VLe+oy/djGP//YwfbeP8bN3Or0bkqEVblAAAAAASUVORK5CYII='
- },
- icons: {
- 'Plan9': 'iVBORw0KGgoAAAANSUhEUgAAAAwAAAAPCAYAAAGn5h7fAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAzE15J1s7QAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAACAElEQVQoz3WSz4sSARTHvzMjygpqYg3+KIhkE83DKtKlf0C9SrTRuZNEx0VowU6CuSeJNlwwpEO2kJ6SQBiIUAzFjRDF4wrjKosnGx3HmdehFDfpe/2+z/s++D5gU7IsEwRByICIiAEAIiIAYAFAXsjYVr/fLxMRNVvN+prJ5/OA3+/XERFNf02JyeVyDx0OxyvLNQsnimLKfcf9KRQKXQAAnE6nlf5qMpnQycnbP/kAoKoqsSwLAJhOp+AAwOv1otvtpqxWq73dbt/r9XqvEQ6HUalUEvF4XLd5IpvNZqlerzd5nlf6/f6tTCZjBACk0+nb+XxeW4UrikLJZPImAGA0Gq0NIqJyuSyyANDr9Q5Wu1utFvR6/SULAI1G4+vK8Pv90DTtGwsAJpPpaGUYDAZ0Op3PHAAEg8H3tVqtbrtu21sqyxuRSOQJk0ql9IvF4r7b7f7pcrlejkaj57IsH58Pzp8dvjhc/lsBk0gkbLFYrFqtVvd27+4qOk733ePxPDCbzVBVFfP5fCiK4rvhxfDN/qP9wSasGwwGMv1HiqJQsVg8ZlfTHMepkiR1t05gGJBGmM/nMBqNj9nN9kql0lNN064ARISzH2cQBAGz2ewLu2na7XYLwzBbvxYIBBCNRrFj3BmsAZ/PZ+J5/kOhUIAkSVeA8XiMZqt5efrx9OA3GfcgvyVno9cAAAAASUVORK5CYII=',
- 'Neko': 'iVBORw0KGgoAAAANSUhEUgAAABMAAAARCAMAAAAIRmf1AAACoFBMVEUAAABnUFZoUVddU1T6+PvFwLzn4eFXVlT/+vZpZGCgm5dKU1Cfnpz//flbWljr5uLp5OCalpNZWFb//f3r6+n28ff9+PRaVVH59Pr//vr38vj57/Dp7eyjn5zq8O5aVVJbYV9nVFhjUFRiWFlZVlFgZGOboJzm5uZhamfz9/bt8fDw6+drb26bl5j/8/lkX1z06uldWFS5r61UT0tfWlbDwr3Ew76moqNRTU7Mx8P75OpeY19pWl1XW1qzr6x5eHaLiojv7+1UT0xIU0uzqadVS0nV0MxkZGT5+PPk497///ra29Xq5eFtY2H28e2hnJignJlUUE1dXV2vrqxkY2FkYF/m3d5vZmfDuruhl5aZlJHx8O75+PZWVVP29vT/9fTj3trv6ubh5eRdXFqTkpBOTUtqZmX88/RMQ0T78vPEvr7HwcHDwsDq6ef///3Gx8H++fXEv7tZWVedmZZXXVudnJp0c3FZU1f79fnb1dlXUVVjXWFrZmy8t7359/qLj455e3q4s69vamZjX1zy4+avpaReWFz/+f1NR0vu6Ozp4+f48/lnYmi8ur3Iw7/69fHz7+xbV1SZmJZVUk1ZV1zq5ez++f/c196uqbDn4uj9+P7z7vRVVVXt6ORiXl/OycXHw8CPi4ihoJ5aWF3/+v/k3+axrLOsp67LzMZYU1m2sq9dWF5WUU1WUk/Au7eYlJGqpqObmphYVV749f7p5Or38fPu6OpiXFz38fH79vLz7urv6+hhYF5cWWKal6D//f/Z09Xg29exraqbl5RqaW6kpKTq5uPv7Of/+PDj29D//vP18Ozs5+OloJymoZ1ZVVJZWVlkYF2hnpmblIyspJmVjYKQi4enop5STUlRTUpcWUhqY1BgWT9ZUjhcV1NiXVkkhke3AAAABHRSTlMA5vjapJ+a9wAAAP9JREFUGBk9wA1EAwEAhuHv3dTQAkLiUlJFJWF0QDLFYDRXIMkomBgxNIYxhOk4wwCqQhQjxgxSGIsALFA5BiYbMZHajz1oJlx51sBJpf6Gd3zONcrqm/r1W8ByK0r+XV1LXyOLLnjW6hMGpu0u1IzPSdO17DgrGC6AadrVodGcDQYbhguP6wAvAaC0BRZQalkUQ8UQDz5tAof0XbejOFcV5xiUoCfjj3O/nf0ZbqAMPYmzU18KSDaRQ08qnfw+B2JNdAEQt2O5vctUGjhoIBU4ygPsj2Vh5zYopDK73hsirdkPTwGCbSHpiYFwYVVC/17pCFSBeUmoqwYQuZtWxx+BVEz0LeVKIQAAAABJRU5ErkJggg==',
- 'Madotsuki': 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAMAAADTRh9nAAAALVBMVEUAAAC3iopWLTtWPkHnvqUcBxx5GCZyAAARERGbdXJrRUyGRUyYbY23coZFGDRFGEYfAAAAAXRSTlMAQObYZgAAAGhJREFUeF5Vy1kOQyEMQ1Fshzd12P9y61AixLX4yJFo1cvVUfT23GaflF0HPLln6bhnZVKCcrIWGqpCUcKYSP3JSIRySKTtULPNwMaD8/NC8tsyqsd1hR+6qeqIDHc3LD0B3KdtV1f2A+LJBBIHSgcEAAAAAElFTkSuQmCC',
- 'Sega': 'iVBORw0KGgoAAAANSUhEUgAAACwAAAALBAMAAAD2A3K8AAAAMFBMVEUAAACMjpOChImytLmdnqMrKzDIyM55dnkODQ94foQ7PkXm5Olsb3VUUVVhZmw8Sl6klHLxAAAAAXRSTlMAQObYZgAAANFJREFUGJVjYIACRiUlJUUGDHBk4syTkxQwhO3/rQ/4ZYsuymi3YEFUqAhC4LCJZJGIi1uimKKjk3KysbOxsaMnAwNLyqoopaXhttf2it1anrJqke1pr1DlBAZhicLnM5YXZ4RWlIYoezx0zrjYqG6czCDsYRzxIko6Q/qFaKy0690Ij0MxN8K2MIhJXF+hsfxJxuwdpYGVaUU3Mm5bqgKFOZOFit3Vp23J3pgsqLxFUXpLtlD5bgcGBs45794dn6mkOVFQUOjNmXPPz8ysOcAAANw6SHLtrqolAAAAAElFTkSuQmCC',
- 'Sakamoto': 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAYAAADwMZRfAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAxVJREFUOE+Nk19IU1EYwK+GQQTVQ39egh6ibKlzw91z7rn3bvfOmddNszl1bjKXc5rJJGmBUr7Yg9qTD0IalFgRBEYg6EDQQB+GovQyQgiaUZsoLcgHMcr069w7MgcGXfi453zn+37fv3MYZt/n99e76tzVj4JN/hP79fvXnV3hnNabwUBjoOHcgTYOu/JQspgTzsqKgn9BfD4vkWTzur287PqLVy+zM+yePB7KsRXLywTjnSpnZctBkPCdW8ccDuU55vBO8RXbkC/oP5ph19V5+7LIky0OY1BKbZEbLcFSt7u6pN7jLmltCVrr3DV5jY3+KovFEsccB1KJNVpefe10BqS2tqqO4/AuphBB4L/LkrRqNgtJs1lMypLls1kU38mytMLz/E8VIlutqVqX6/weZG52OttRXjbE0cP/FYLRlpVjDXuQ/r77x2XZPKkCHA4HBAIBkCQpAygIAvh8Pu2MZgO0Lz+QSa/sQfwN9RfpVN66XC6Ynp6GhYUFGBwczAC1t7fD0tISxONx6O7upgHILmsqvLcHodOggfiV/v5+SCaT4HQ6IRaLgdfr1bIRRREmJyfBZrNBNBqF+fl5sNsdgE2GiAbp6bmbdbXC7qWQbxMTE7C2tgY6nQ5SqRSEw2ENopaoZpCXlwdTU1NaoECgCbgiU6y8QH+ECYWaTymK7TWdys7MzIwGaWtrg42NDejo6AB1WjU1NZo+FArB2NgYrK6uQrAlCASxn2z6wkuMp87VIAhkE2MEAwMDkEgkYHx8HBYXF0HtkQpRy1BLiEQisLy8rPVNKSsFjEzrXH4+z1hlS4xDhKadNu7t7YPR0VHweDzAEVWfHru6HxkZgeHhYVAURYNjkylVWKArZjjMzqmdVi+QCsLUkQiEjvDvncEkvU7/qQ0Vgukeo48Go87IiCJnZNmipxiz7wXEbVDnbUxQOgM12h9n6qTq6NvapRdtkwaP0XK8RmPuYSbxYfaQ/sJJhjfknuFRURUi7AMOozcCwl94hLZp5F+EioDQVwqYI6jomZU1NFtM+rOSxZjVazcyvwHr/p/Kws1jegAAAABJRU5ErkJggg==',
- 'Baka': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA0pJREFUOE91k3tI01EUx39JOpA0H4jNx0pbD3XTalISWf8YFlEgldqDsBLLyqjEKBCiLLWiggh6/KEV1WZ7OaelLZvDdDafNW1JFraWe/32+01FrUZ9uy4ylLpw4Z5z7/nc77n3HIqaMRIjZJyEcNX+uFCFeGmI/GZciEIsCFJUTvoAzDz+1y7K76MSwhX5hXl6z+WSbrzU2KB8YEGDwgrTaxZ3b7xHcaHhR3xw7Z5/UviB1ReP5XSg3+TAqYJOxMzWISFIC0GQDomhTVA9skCnsaAwp/vnMq66dBokNuBR9uFd7T9Z1zCunjci0qcRJUVdoJ3DYOhRnC/qBZ+jQbfeCc+37yjY2UEg0iwvJE0k9l8Z+8xqHmTgot0QLdQgTaQFQ2AsOzlHvOu1S5pwOLsHHo8HjHMCq2MazNvTlByKHyrJLDvdR25jMWRxYx5HjeMH2r1BDOOeguRua4OI14jx8a8YH5tA+al3EHKlW6mYOapb2oZBOOwMbEMseAE12L+jjUh3w+VipyAZ65oxn1NP/GMYGR6Ftn4Qsf7qa9S82Y/l/X122G0uL2TbxmZEz1WhXW8mUol8moXu+SCi/OoQ6VsDh3UUwyQ1k9GOaI5MTkX4yWTGHutvgI1F28sviAlRgxeoRm62HvsyW8En9pZ1TYgi6TntoyQtFm86rVgUoJZRvDnKMmXVAGxWmkAYOBwudBqGcHCvHulrGpGT2Uy+z4yT+QYsCXtCUpp8GxbKhx8gDK0ro+KjJGvzdjfDZnN6VdisLD5/JjArQ2zW66PJOj2lEZtStaBphkwah7K6kMJ/GEulp1bMWhAmMbTozOQRaWRtfoZVgjo4iRra4SYgGi26TwjxVeDKhR7Y7U606ixICq9tr7hd7+OthRWL7yUnJ1WPmXotqLhpRICPHCePtuFV6xdUPTAhcWEtRHEqfHpPyto4hPXLXnzflSEJnFaN3OCKDcsFsrEntR9RUmxARLAUgT5iBPuJsXWDBj0dZjRU9yNV+PTbpjTp9OA/pOSk24nRkXf1J462oPxcJ65f6ULlHSMulepRerYDgvj7A0cKpNz/tyTZqbzXO4t0ZZGQJ34RH11lFHIlA8LIqreCCMUZRY3cd2bwL/5/RmjNSXqtAAAAAElFTkSuQmCC',
- 'Ponyo': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAuNJREFUOE+Nk3tI01EUx39BTytConQTt1am07m5abi5KT5S8z2dj1yOEMUC7aUgIoimlmUEWX9kBZGWaamEmE6U1BI1XNPNGTrnHs33IwuSXrL4NgcJ0mNdOHDh3PPhnPP9XoKwcroJYvMQiRSicHCQKCgUyZC9/T5rNet5KUFs0zCZbZMsFmZ9fTEjEEBDp4/KSSSb/4JoGIyWaTYbiykpWEhOxhSHAzWD0aqkUGhWAcVkW58xlvuPhfh4zItEmOHxYDR3MhcdDaNAsKJydAz5IySKRNjEUmy88vjOVaU8F0iPCqCNjEBHkC/UYaGYFwqxmJoKLYOhkxPElg0QsbNtTlmox9yjRD9UCbnoOR+J/lwRWtOCcdXfDc2BPpg0d7CQlIQZPh9KKlVkAQjJ2x2zmOSsQu7hpzUJfBhLjsNQmADjxcT10Bcl4rE4EHc5LjBEhEPn7f1WTqXSLQB/s1Tp7vslsoIkyPPiMJAbi86McBguiaHKjoEqR4jJy2K0nAxApzMN5iUGrclrKVaz2fUvuF4tRbxDKA90w5VjTFyLZKHpTBSq4/1QnxGB2qxoVIZx0JopRCPHFSNOThfWZzfrXDcZEowH4iA05ATg68hDtBaL0HAuCm3lJ9Bfcx2fFNUoi/DCjRgfNHHd1wCZA2TyXjNkE6F0cBDpPFiojeNi8EkJdFoN3vXch0nbBJOhDd907dANv8JITxNqziag3ZsJbUDAwLin50Q9QWwl1qSYoNOVvUcOoqOqAAa9Fu9H2/F9+B5WZLcwOyxFX18flLI+VASyMGVeoJHD+Tzq5BS1PoaKRrNT8127P74swsq4FCa9FKvqBqwaOiz3hdEuLKueYSyECT2LNW0eIfo3E/WmEbvnG1MUJnWdpWhDGDvxQXZHo+RR0uW2tnv+auPX+TvtJm7zKpaen/4y2yjBUlcxlvtvmvT16ZWDpQeoVv3/60F/NrHjTf4ugazIXtJ8ivjnz/sJ+yGQRjcqUdIAAAAASUVORK5CYII=',
- 'Rabite': 'iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAD/0lEQVR4Xl2MXUxbdQDFz/9+9Lb3tkBLCxTKhzgoOOZAsokbJmZxDFHnd+LL4hKVzBgfNCY++ODbjDEaZowvErOM6HRu6hKZY2rIAOkCY4OSDTpFaAsrlJa2t5+39+NvjT7tnJzknIfzI98Nf/C6TuXdguWBd1q9rcb8/CwsZiu2Ywm4nDVo3VWLZCKDaDwJq9mCg31PgjAMKKUwmcyYvTbek9iJRDm6M/XswEDjwNz6plWW6wdZhjUAintFCEEhn0N04zYskljaDLaj8ar49oUrsYR6mrFJNj322w46H8y+mitM/ZJKZmyE4XAvjJSsazpyuSzslVZIkgWKOvvRgQ6Xrdlhqmds7o7bFZoLkctreKxf7GtuCE7IyUQjBQcQ8j/lvxCGQJZz0IoCVpamTtzfIh9nwiaIrCQyjNg8mq11oDLUhNXRJfT1Ozr3tS/PqpnQ80qRgjAmKIqBfK4ItbSLKoOZqR/6neLkENlSUAIhlktvEf+sD2rkm8nWTHtvZCGMVON1ePuaoBER31/MXGly1wSqq9Uug6FluYyWXJiPqFXmjd4Dh9oF9ZKKimYXRtYCx8lmMIDIxlIPGz591av0mtanF7FcCEN6iMXeox2wOJ0QJAmUAoRQaIqCnWAQY1/ewKNGNeQuYXkm0d2NC2e+wvmRr/Hx+6+8PHayrbDyyQBNDb9As3PHKDWG6MTM23RoeJAWsqeoWvyUUv0UHf7pBB0fe4OeeXe3/vmHbx3+8dwIGJ4IsFpMMFe0fbtAn+nwZePr1u4MBK8XIALG/Rt479wYrs2vgeNNAMNgMbiNzybuoKVvn+Gs9kbr6qpBfJfGYHFIkJUCoGwfqcoMX/b27EGhwgOjoCADDlP+CA51ugFFRzoB8FYNaQ1oqKD44+eNL+wNj7zJGQSIhe8+jgQ9thk+27v/KRY6L4FSCkVOwtlQj6P73Qgt/o1ERoKt4iUkE7+jrZMHyzIoK9cOBFfT4LbWAk+0a7ZLnvqHcTNdACgFScfAcjxEdy00VQclHGo7dqGeYxHbvIo6hwhSghCehb3G5p6eW7VxXC5/xGWToMgrKKoaCnIalI9CIARasQAqloMI/x4BWrLLYwE1AEPTwCGHaGjz7pw/leZUNV8wNm9BLy6CxsvxZ1kMbaY4TKIIXlNBsynoVjvAC4CuAoYOVi+CMfLYCUfg95tPHuzZB0YtKzsb58RMucWE/fZmhCbdOP9rNnLnxko6GVoB8lFwyVVw8b/AyeulHoJyN4Rb19dTFyeqBlu6njvfsWcvOJvLs7DMmw/7bvpeE4pU2OIcgcqmp4fGAgt2Txwvqr7lTp5V7LquZxXC6+BqEvGcY5pyjaM1tffJbk89NE3FP5VQ6y7a+paZAAAAAElFTkSuQmCC',
- 'Arch': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABCFBMVEUAAAAA//8rqtVAqtUQj88tpdIYks46otwVldUbktEaldMjldM2qNcXk9IWktQZkdIYlc8mnNUXlNEZktEZlNIYktIWlNMXktE7o9klmdMXktFHqdkXk9EWk9EYk9IlmtQXlNEXktAWk9AWlNEYlNFDptkZldMYk9E4otg/p9kXktEXk9AXlNA4otclmdQXk9IYktEXlNEwn9YXk9IXk9FFp9o3otgXk9FPrdwXk9E2otdCptkXk9E/ptkcldIXk9Edl9IXk9EjmdUXk9EXk9EXk9EbldIcldIjmdMmmtQsndUvntYyn9YyoNYzoNc0odc1odc2odc6pNg7pNg9pdlDp9pJqttOrdzlYlFbAAAARXRSTlMAAQYMEBEVFhgcHR0mLS8zNTY3PT4/RU1kdXp6e3+Cg4WIiYqMjZGXl5mbnqSnrbS3zMzV3OPk7Ozv8fT29vf4+fz8/f7SyXIjAAAAmUlEQVR4XlXI1WLCUBQF0YM3SHB3a1B3l7Bx1///E6ANkDtva0jKbCW2XIH1z2hiZEZ4uUgxo7JedTQye/KN/Sb5tbJ+7V9OXd1n+O+38257TL+tah3mADAwSMM7wzQWF4Hff6ubQIZIAIb6vxEF4CZyATXhZa4HwEnEA+2QgoiyQDnIEWkjVSBBZBqXbCRlKYo8+Rwkyx54AOYfFe7HhFa7AAAAAElFTkSuQmCC',
- 'CentOS': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAB5lBMVEUAAADy8tng4Ovs9tnk5O3c7bX44LLduNO1tdDh7r/eutj43q2kocX23az07N+qqsvUqcmXl7331ZXJj7r40o/Pn8T42qP63KjNw9n21p3Y387Ml7732JzR55z05MSxtMLGn8TC4Hx8eqt8e62Af6/B4HnG4oPC4HzH44fBf7LCgbOkoMTcsrmtn8PWqcfFtKrj4Jvs2ZOz2FnMqLXT3KfY5p60Z6NUU5XRuqHzwWSywqDn3JaiiLWahrWhkry5zJjRmqm1Z6P1wmb1y319fK632mK5cKi5nH+73Gu73Gy73W283W+9eK17e6y1yZS3aqRZWJdcW5ldXJplXZppaKBwb6VwcKV5eKswL306OYNPTpGkfK+m0kGpUJWq1EnEqIuXK3+Xh7ahP4qhkryMfK6BgK+CdpGMaKKMa6O9ea2+eq6+oYW/eq+NbqWVlL2Wlr7AjanA4HnA4HrBkqbBlafB33rCgbLCmKjCxIzC1mSs1UytV5mtxIWt1lCuz2evWpuvXJywxYzHjrvH4oXIjrrN2HXO5pTO5pXUlYnUlYvVl5Hb0G7e0XTg03rhr5fpzHPpzXTp0Hvtz3/wrDHytknyt0zyuE3yuVHzvVr0wGP1x3T1yHf1yXe0ZaL2zYP30o730pD31ZeRIcF5AAAAQ3RSTlMAFBkbHEhJS0xMTk5UWWBsd4SEiIiPkJCVlZaam6CjpK29wMPDxMTFxcnK193e3+Dg4uTn5+fo6e/v8/P4+fn7/P7+J4XBAAAAAOBJREFUeF5Vj1OvAwEYBb/yGlu717atLW0b17Zt2/6nze42TTpvMw8nOZCAmwUpiIY6c5IiLi9tPX64GairqszHQ4X2VB64v1Cs6PxMPJSdHM777s6/jyaMRGiRLyyrb88OpjZ3CzAXrm1sqzSNNeN7kVBPNgB7cG51abE5l9cXDces7emQ1uadHhutFUg6gpPKkSIqQGavwz7r7O/+/3t/rSdjI9XDM3qz4fr3B/3iA0aJTG9x71+9oR/PLDwUe2wm19bly+fTIxHyEETatbPewGEw6Mk/tKZCEqSQQUlIHB/QNBEjjVN1AAAAAElFTkSuQmCC',
- 'Debian': 'iVBORw0KGgoAAAANSUhEUgAAAA0AAAAQCAYAAADNo/U5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAZ5JREFUOE+Nkk0oBHEYxv8fu5GQj3JwcaDkIAc5IpR87M7MKnIVJVKclaIQ5Sy5OLkgR7n5OigcSNpmd2c2Vyfl4KT8/muWiVU79TTv+7zv837NCBF6PG1X+NpZyEYSD9mIc+tHnBPe23B9xKrCuTmbQA/JKfABrhBswa1hH4A38IwfOxPdX1qcjiCQxO5NyrjKV70TnSbeRPwJvGN3i4yyqnEucPY8ZZX9GSEgGK+RvFfyjk2VKZxzBNG8wJWWgh/xtDOeUXZ7Slr6TrSLYL9N4SMgYTTcwdc2ArvJcElhSVcM6mCNSV8n9hA59yTU5UWMG6HIbLhIWlglgWiC2L4Z79qTdo40D6ISuOWwKCWHyk9Fv8ldpUHOuGTuynwSBUynddPdlbEosVpP9Eu4FnOsRzUYNTsdmZN/d5LDiqM0w+2CMdAFFsFGWgfXxZnheqe/z+0puwEM0HHYV3Z9Sgz8TEz7GkQvpuJ/36ggj2AaHLrSlkULWV5x+h2E8xkZL16YVjGNaAUscfZ/f6c/k9ywLKI2MMcRWl0RLy007idmRbQJ7RIfDAAAAABJRU5ErkJggg==',
- 'Fedora': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABPlBMVEUAAAApQXIpQXIpQXIqQ3UpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIqQ3QpQXIpQXIqRHYpQXIpQXIqQ3QqRHYpQXI8brT///8uTYMpQnM5Zqg5ZqnS1+I4ZaY4ZactSn8uRnYrQ3MrRXgsRHUsR3s8bbM8brMtSX4wUosxVI01XZw2X50vUIguToQvR3c6X5o6aKs6aq08Un8qQnM9VIFDWINJXohKcKlXapEqQ3UvUIc2X55bhcBdcJVgcpdhfapmd5tuk8dxgqJ1hKR5jbB6iah/m8Shudq3v9C4wNG/x9bFy9nFzNnFzNrIz9zK0NzK0t/O2+3P1eA2YaDU2eTb3+jb4Oje4urj6fHm6e/s7/Tz9fj3+fz7/P38/f3+/v83YaEa/NNxAAAAHnRSTlMABAoVGyY1SVlpeIuQsLfDzdHW4+3y8/b39/n6+vr4+ns8AAAAyklEQVR4XiWN5XrDMAxF75KOknYdZJS0klNmHjMzMzO9/wvMcH7I37mSJShsJ+5NjMT6umDoHyXDcI/2qJadh++P3cle1de+9yPe3/bTY92wzfzr7wGtP3JrAI72BZGVtcAdQlwHy+JS1pDbBE9qamZF3BYrjQxPEXwKc6dC8bXFm0QIpmt8kn0Rn093q82UCtK8oXZckwFJzuulV8bHkajPyXdbnJnARfDHs0trz+JQ+5AFvzp/L0+cL2qPAINUPrq5OC6p/64F/AMnrST+Dq/r7QAAAABJRU5ErkJggg==',
- 'FreeBSD': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAABIAAAASABGyWs+AAAABmJLR0QA/wD/AP+gvaeTAAADXklEQVQYGQXBS2wUZQDA8f83j33M9rF9d7u4loaWklaDpkSo9KDGaIKUaGxshD2YSPRiuDVeTDyhBxosJCoa40ktpAkPDcUqAYVIpUSUPrAulEdD2bbb7e7ObGcfM/P5+4kwKDvq6yJ1FYYcvb+YAkqAHo/HQ7FYrFIoCiurq9ZXJ06YSOkA+kBzfX06bys3zHxS9EL0tXDVyZfefacqV+X/ZSJx5+qLbx98LhaL9RiGEZWlEsWC/Thd9q6Pf3vs2u6Orc83rFsvTwwfLf5obgywT1Vjh2Hh+rbNsnTssJdNLedK5aIrpSuldKVXKsnH4+Pyn6FDXn5tMef9O+3NvdkvP1V4+EYw2AoQ+KSx8dRYS6NXXnwovaItXduSrrkinWxGOmZWJi9OyOK9m1LmsjIz9IH8QUMOd3WfAQwNKCy2tJwbHB5+XasPaxIHmc4g7WWEZ1MquBiRFlJTf1E7+Tl/H/8asavPzTY1nWd2ZkMDRPeBeHPz5ojwsilEQCBvTSKunCF3M8FSNkBGVTHDYYrLj8jVNhDZ2SMa2zo3MTamaIC/u6Ojr3DtrOrvP0BpdATnyBeIhTxpR5ABUlKSUlXS1dWstbVxdz6hPL0l1quGqkLaKwNvVcjEXNRd/4mit4Z19DjefBEPyCKxgQJQcF28dBrHNDGTSZSezsjeff0hraa2Vs2vrvit81O4vj9xLJcC4ADrQA7YAGqBGsAql/EtLdFQE/L7dF1XZmdnSrbPMJfXoLDmolQK8gJyQBowgQhQDRQBD+hsraVhd4e5MH+/oExfvWLJ9q3/3S7qMpNH2hsS40kFS4EUUAMA2IANRIBXv4uzuO67c2PykqkA5YmZ6bN18YPi0Yoknxc4AsJPCMLVAk2BLKDosCWqs/PZaulkuxk9fekcUBAAQGDks5FT0W++3NuYuC0DVUL4DIEdlIQDAj0IRkigaMjArkFx0tf523sffrQHyKsAgHPhwoXLL+yP9/kePNhk5ExUTyKFkJVAUAiCFZrQup4Rv9ftuLV/6ONBYBVABQAArMvJ5MXW7duD6P62sD8UrPAFRU1TpeCpCnGvPZr7WW///v0jpw+VC9ZdAAABAAAAAMLo7drWrmQyPWG/r8tnaGIjaM05ujr16x/ZBFh5AACA/wGZnIuw4Z4A3AAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxMi0wNy0wNFQxMDowOTo0OS0wNDowMOPVpFwAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTItMDctMDRUMTA6MDk6NDktMDQ6MDCSiBzgAAAAAElFTkSuQmCC',
- 'Gentoo': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAB9VBMVEUAAAD///+AgICqqv+AgIC/v9+Ojqqii9GAgKptYZKQkOmPj/ddUYBgW4eVjeCTgfiWjO5wbJaZkvPBvepkXomYkNldV4Bzbpl6dJ+Uj7ynoO6Vi+1qZI63se2mnudjXYjOy+GCfaqZjvWlm/Pc2e+Oh7NeWIOWjfeXjeW1sd+gl+diXIfp5/KHgKnn5/F2cZx6c6ZgWoXc2e6dltrAvNu0scrX1eTOyujCvup4c5qpovVpY43///+6uPPJyPXq6fvm5vrz8/z8/P7+/v/d3PixqvmxrPSyrfe0sPO0sfS3tMve2/3r6vy6ufPz8/3d3fi3tM63tPO4tsu5tsu5tvO6tfe6t/Vva5KRjKy7tvW7t/W9vPO/vM+/vvPCwfPEw/TFwvTFxOfGxfTGxvTHxvTIx/TJx/aTiOrNzPXNzfXQzfnRzuHS0fbS0vbT0uHU0e/U0uTU0/bW0+zW1ffX1vfY1/jZ2Pjb2/jc2uSTiemVkLSlnvbe3PTe3vng3fzg3f3g4Pnh4Pnh4fri4enj4/nk5Prl5Prm4/ymn/bn5vro5/rp6O/p6funoPWsqs3t7Pvt7fXv7vzv7v3w7/nx7/3y8f3y8v3z8vytqPWuqPX09P319P319P719f339v739/34+P35+f37+/+uqev9/f6vqvSwrPQAR0dcAAAAPHRSTlMAAQIDBAgJCwwVFyAsNUFHSVBneH+Bh4mVmZmanKCxsrK2tr3ExtDW19rb4ODl5u3t7u/w8/T6+/z9/f4MkNJ1AAAA8ElEQVR4XjXNw5aDURSE0YrRtm3b54+dtm3btm3bz9k3Wek9+2pSYFwT8ibzE93hwAtdJqK3nZo4J9hFXbP+vFHOthV6gnGzstZq94wdCs4UCCDymQ2v7X0LdYoSQ0MIENRYzJbRlPTTHu73ZNAL8vivmVui98PpzuqffX0mIPHJGtOQenukteJ+aS3b9htNpDnT9TeZH1bHAwBRMhGpd6e6uNrLoRgxBKmsX47nBlp678ojpEA40fejcmW4e/No0V8IIPfj6eKgbEJ3ZUnzgE1OqWp9Q3VeWRAsg51f1dZ8c31RmAsc+N5JGbG+zvj3BzDCPrzMDC9SAAAAAElFTkSuQmCC',
- 'Mint': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAACVVBMVEUAAADh4eEAAAAAAAAAAAAAAAAAAAAsLCyXl5dgYGCnp6eTk5N3d3fBwcGqqqq8vLzNzc3Ozs7Ozs7Pz8/Pz9DQ0NHR0dLS0tLS0tPT09Pf3t/Pz8/i4eLb29vZ2drZ2tna2dra2trf3t/u7O/u7e/u7O/r6+vt7O/w7/Lw8PDy8fTz8fXz8fbx8fHz8/P19fb49/j49/n6+vuPxlmWyGOx437h9NDr9eD6/fj////+/v75/vTA5Jv6/fb7/fnL5bDL5q+AxjeDxUCEzTyGxUaGzjyHxkiHzz6J0D+Kxk6K0kCLyE2M00WNy06P00mSz1OUyF+W2FGX1FiY0F6Z02CZ21ac0Wiez2yfz2+f2mOh4GCi4GOi4WKi4mOk12+k3Wul32um1Hin0nun4G6n5Gin5Wmo23Op2Huq1n+q43Cr526s4Hit23+v6XSw34Cw34Gw6nWx4IKy4IOy44Cy63ez146z34az4IWz4YW03Y217nu38H2625e645G74pK83pu98Iq984W+4ZjA4px0tzDA5ZrB8ZDC5p7D55/E947F6KHF+JHH4qvH6qTI46/K5LLL5LN1tzLL5bN1uTDL57DM5bPM6qzM66/N5rTP6LbP6bTR6rfS573T67vT7LrV7r3X68XX7MHX773Y77/Y9rvZ8cHa7cjd88bi88/j8tTk8djk9tHm8trn89vo89zo9N3p9N3p9d7p9tvq9d/s+93s/dzy+erz+O73+vT4/PX5/fT5/fX5/vN1uzB3vTD6/ff6/fh5uTj8/fv9/vr9/vx8wjV/xDmrMRH0AAAAOXRSTlMAAAECAwQJDzk/RUlNU3F0kpSVlpeYmpucnaKjpKWqqqqtu8LExMTEzdTU1NXY4evy8vP+/v7+/v6LaR1mAAABD0lEQVR4XiXI03bEABAA0KltW9kaW3eSZW3btm3btm3b/q4mp/fxgqKOtpamhrqaqoqykrQYABh+PVMU9fjE5Xp8o54kgPHN0EBHU2N5YXZykiua0HHd2759VF2Sk5IYE5GGsmCEWLV1kVWwt5O+3x/qpgsy8k4ja+cJl2/v5C22tlgCAHtw9TQSa4s+AzfPSm0BRNl9SydhWJzLC567KrNhgrNwHIJ5qTz/2f9w7Jw/DNqIjVr04exW0AEOXcN3Ab7enr9eDW2VTJgehONyc2Z8XP5YdD0Tcuhcc4/r45OjGX51TEjYPbh8THRPvbz+CHusgSZlT7rP8PkCwfQKaQUi9Igr6JsRBMFiWZgb/AHKElRzKopZJQAAAABJRU5ErkJggg==',
- 'Osx': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABrVBMVEUAAAD///////+qqqr///+ZmZn///+qqqqAgID///////+tra339/eAgICoqKjx8fGMjIzm5ubh4eGPj4/g4ODIyMiAgICSkpKLi4vS1tbPz8+Xl5eMjIypqanIyMjW1tZ2dnbR0dGamprFxcV3d3d+fn60tbV3d3dcXFx3d3epqal7fHxxcXF+foCnp6hYWFhyc3Ojo6SMjI5fX196enp+fn6Li4xERERqamqgoKFpaWmFhoeen6A/Pz9QUFCWlpeSk5SUlZWUlZaOjo+Tk5RHR0cuLi5YWFgwMDAeHh40NDQ3Nzc6OjpcXF1rbG0XFxdSU1NVVVVXV1dZWVlbW1tnZ2lwcHABAQEEBAQXFxchISI+P0BISUpaW1xHR0kNDg4qKyszNDU1NTY9Pj8NDQ1cXF4XFxhSU1QSEhIDAwMrKywtLS4uLi4wMDFHSElISEggISE0NDVJSktNTU1FRUVWVlhGRkYEBAVBQUE0NTZQUVJQUVMFBQUqKitWV1lXV1daWlpaWlw+Pj8bGxtcXV9dXV1fX19fYGFgYGBkZGRlZmhpaWlsbGxwcHB2dna844Y9AAAAV3RSTlMAAQIDAwUFBggMDhkeICMkKCgqMDIzPj9ERFBib4CCg4iMjZCcnp+jqamrw83W1tvb3ePl6Ojp6+vs7u7v8PHy9PT09PT3+vr7/f39/f39/v7+/v7+/v50ou7NAAAA30lEQVR4XkXIY3vDYABG4SepMdq2bRSz/capzdm2fvOuDO397Rw0Ly4tz2QAQPbcxuZ2E/STJwfxPhWgG355fRrVAIVb1zeP9UDLfiSwkAcADe8fn7tFxWuEXFRDoer/OgoMTRBCumj8yJwPBo8Zhpk14U856/HI8n0ZUtpZ1udrSzfVneA4roNKjdrwpcMRilb8d8G60+lKnrpWcn9bO+B23w2O8Tzfq4aiNSZJqzn5O4Kw16h06fPZ+VUlUHfo97+VAEb7rSh2UgDd4/U+TBlQY7FMj5gBIGvcarVVfQPVPTG94D0j9QAAAABJRU5ErkJggg==',
- 'Rhel': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABj1BMVEUAAAD///////8AAAD///////8AAAD///8AAAD///////8AAAD///8AAAD+/v4AAAAAAAAAAAArKysAAAD///////8AAAAAAAAAAAAAAAD///8AAAAAAAAAAAD///8AAAD///8AAAAAAAAAAAAAAAB5eXn+/v5JSUnKysrS0tJ5eXmqqqqxsrL+/v4ZCgknJyeHh4eIiIjo6OgZCAdOTk7t7e3///8GCwwPAAArKyv19fX29vb9/f0EAAD////+/v4AAAAGBgYHAAAJAAAMAAANAQAPAQAVAQFyCQV9fX2pIRzmEQjn5+cBAAAFAAAAAADnEQjvEgn////uEQjyEgnsEQjzEgnxEgljBwPaEAj9EwnwEglHBQJHBQNNBQIBAAB3CQR5CQSHCgWLCgWRCgWTCwadDAWmDAapDAa/DgfKDwjWEAgGAADh4eHiEQjmEQjmEQkKAADoEQgLAQDtEQgMAQDuEQnvEQjvEQkPAQAfAgEuAwEvAwE8BAL1Egn3Egn4Egn6Egk+BAL+/v5CBQJrB0muAAAAT3RSTlMAAAMEBAkYGhsbMTRLUmpvcHeIjLe6vcHCxM3P0NbW3Ojp6u/w9ff5+fn6+vr6+/v7+/v8/Pz9/f39/f39/f7+/v7+/v7+/v7+/v7+/v7+Q8UoNAAAAO5JREFUeF4tiwVPA0EYRL9SXIsWl+LuxfcOd2Z3764quLu788NZNrxkksmbDP2R7vH6GioLs+iffEzNXd4+TqPErUUpVqMOvwgdzMPn1rv5vPsVeufBTaBK/bH2FPvkEUuIG5jIIc+sHYn/HJ3dC/Hxuo4y8s44dzwBbFkisHN8bVIdXs6jb+H97aCwbHEIqgcml64CD7YllNkAVQC940MLYe5YzvIeQAXNrd19Roc5MdzfdQLUUKaUYyuG9I8y1g4gj6hIak4X5cBIT2MquZJrJdOqpY11ZpAiqVwbY/C7KY1cRCrZxX4pWXVuiuq/hs49kg4OyP4AAAAASUVORK5CYII=',
- 'Sabayon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABvFBMVEUAAAAcUaYdVKwAAAAAAAUABAwWRY4YSZYhZtIhaNYHDx0KCgoFDBcKCgoRMmYSNm0fXL0fXb8AAAAYS5gaTp8fXLwgXsEGBgYFBQUZSpgZTZ4JFSgODg4IEiIOJkwOKVIkW7EnXbQLGzUTExMKGC8LHjwMIkITExMiIiIPEBEPJ00QEhMXOXAaPncOJEgoXbApXbEcHBwwMDAEAgAfHRgQDgo3NC8AAAAHBwcKCgoLCwsJCQkaGhofHx8lJSUwMDA0NDQ4ODiRkZEICQocHBweHh4GBgYHCg8mJiYnJycpKSkrKystLS0uLi4ICAgODg43NzcRERF1dXUUFBSjo6O1tbUbGxsEBAMLGS8MDA0iIiIjIyMkJCQNDQ0NHTYKCQkoKCgPDw8QEBArMDkKCgkRERIREhMxMTEyMjISIz00Njk1NTU2NjYCAgIVFRU5OTo5P0c8PD0+Pj4/QURAQEBHR0dKSkpMTExSUlJiYmJlZWVnZ2cWFhZ2dnZ4eHh8fHx9fX2FhYUXFxeVlZWXl5eYmJiZmZmcnJwZGRmlpaWrq6usrKyvr68KFiq/v7/FxcXY2Nji4uLn5+ft7e0yif9uAAAAN3RSTlMAAAApKSkqKioqg4OEhISEhoa1tra3t7y9vr7S09PT09TU+Pj5+fn5+/v7+/v7+/v7/v7+/v7+70RY/wAAAPpJREFUeF4dyWNjw2AUBeC7dfYyorM6rx1exKltzLZt2/rDa/J8OgBVVlFDX39jcTZoUqCse251a2dvu6ccUtWlanLQ4Vpel+ThlWq1l3wEz58tx4dOt1dMlAJk9A5gMjG75LHwo46hzkwosGOMbejumoRvubC9EOrMviT0E0Us9fvN9dA6zxJCNv6+ECGsb6oNWsgmpZT9/UTUZo3Em6AW34guTL4jiAudiCM1kLcw8/SmHERfT1/eueBiDqR1GK1n9w+K8nglxYxd6QAML4ztXoQuj8YFgWcgqdJp8qzty26vaboCNIxBCshyQDKov0aXr29v1ufq1PwPx5Q7bCoh6eoAAAAASUVORK5CYII=',
- 'Slackware': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AcEDi0qZWWDgAAAAx1JREFUOMt9kktoXHUchb/ffc1M7rySSdJMOknFPMRitLgoNKKI8ZHGKkgrjU8SitidimSh2UkXoQmoO1dGQSxJjdvOtqSaqlR0USEGSjVJGxuSmWR6M3fu4/93YX0g4rc9HA6cc4Q7DI+fpzz7PA8++2mxvZAeBZ4xhHtFcJRmXWsWvb36/OLcyxf5B/KHeYHy7DmGx1+YSDjmWTdlobTGMAStQGkNoLXS4tXDq7u7tUcWz49tA8jR8QUuzB5n5NTCV13F9JEo1JJwTLKuzU61QiOMcd0UDb+BncwQK3Rl15eNja3ui/Njq8aF2eMcO/XlBz0H8oO2ZUkum6A13WB99TtyzXlaCi24SaFa+ZFCzsG2DNnfkdbFjsI1APPhk+d6ujqznycdCxFozadYWvyMpx47wa+bPkGksKwUNnsk3TaCGASRXDZh5LpHXPPg4Rcni+3uYBxrtBbQghlscOVKmYHeEm0ZIZ9xyLffw41ND6VAa43SmjiMByzHYtjzwr9arfshxf5jOKlvKZfn8es77N2uks24PPfSFD/9Uvt7AtPKWmEU9d645eHYJo5tcKi/FX/zG+zmQxQH+rANk862DOW5N/hhaY64cJSa5xNFCgDDILZACMKYWAmh73HmzFsMlBQJ06LeiMinE1S3KzRCm5rXIIoUIoKIYCVM36urZFbEoiBLNMIhAE6/NsSB7h6SKZdL8xsUOnpx9j1KbTdARACIowArYe1ergfNT2i0mIbJys0GI6PT3N1/hJvrPxOFdRJNBQIy/FapI4Bpgohgcjuw+jq8jy8tV55MNBWI4ohS802CpizKv8q+FgALZAfYgSyAZtNro1oLaU1VvxCA029Oraxs7u/tKnXiNjn8HyKwur6lI++6vPK4V7IA7u+1Dyu1tr183ddNbkHuXP8/zEIYeFqiLRl6YO/p0bHJdflT/PD9qZa1W+ry99fcvlAlcZwUpuUAglIRYVgnDEIOlna4q0M/NPnuO1/PzMwg/045O/XeibUt5/Xangx6viSVFpK2jtMpvdyWCz+5ryf10clX3/amp6eZmJjgd441URWWJY8BAAAAAElFTkSuQmCC',
- 'Trisquel': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABjFBMVEX///8AAAAAAAAAAAAAADMAAGYAAAAAHFUAGWYAF10AImYAIGAAHloAHGMAKGsAGmYAJmYAJGEAKnUAJ1gAMXYAJnEAJGQAI2EAK28AK3cAGTEAMHgALXEALXgALG0AFUAAI2oAK3EAMngANoYALXMANIAAM4IANIIAL3gANIcANokANoQANYQAOY0ANIYANooAN4kAN40AOY0APZMANIUAOY0AO5AAPZUAPJAAP5MAPpQAQJUAOYsAPpYANoUAPpoAPpUAM4AAQJkAPZIAPJEAQpgAN4cAPpQAPZUAPJEAO4oAOosAOo8AQJoAOYsAO44AQpsAO48AQp0AP5UAQpoARJwAQ58ARaAAQZgAQ54AQ50AQpgARaIARqMARaMARaIAR6QARaIARaEASakARKEAR6MASqsARKEASKcAR6MARqYAR6UATbEATa8ARqUARKAAR6oARqMASKgATK8AR6QATbIATbAASq0AR6cASKgASqwAR6UASKcATa8ASqoASqwAS6wASKoAS60ATbHn4CTpAAAAhHRSTlMAAQIFBQUGCQoLDxAREhMUFBUYGhobHB0eHh8gIiIjJCQkJCYoLC0xMTE0NDo6Oz1BQUNHSUxOVFVVVldaWl5iY2RkZWZoamtsb3FycnR1ent9f4KDhIiJioyNkJGYm5+foqOkpqamqKmqrKytsLKzs7e4uLy8v8TFxcXGx8rO0NXY2eZc4XYcAAAA00lEQVR4XkWN1VoCUQAG/3NWtwh7CTsQJOyk7BaDxuxA6bbrxf32gt25m7kZqDRYxziooDV7+1AalMUavQh2AsEZoWvzigLun+T17/c8QiJZ7qu2QKiNmyZthdcR1/as353jIeU1GxMHo5XHdqPFeX8IaDMdHPYN6dRN7LR4qQewdTa35HWkyh+fbxERAMjwlAWJv3CPSKDQ+H7XvHdkV4Pua3Gtm4sPKIF/WV8dop4VKBw/NU33B3x1JbTt+XwhkJQoqRfWvHOy28uqH8JIdomR/R+s9yR3Cso77AAAAABJRU5ErkJggg==',
- 'Ubuntu': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABKVBMVEX////ojFzplGf1zbnqnHLvs5P10b3yuZv1xKrytZXvtJXys5LysI32waT0n3HxiVHwg0jxhk31kFn0h0zxf0P0hUrveTv2iU3yfkD1hEfyejv5eDLybSX0aR7zZxvyayH6ZxnxZBj4YhH7XAb5WALlUQLeTwHgUAHeTgHfTwD65NzdTQDdTQHdTgD31MfcTgLcTADcTQD////xt5/31Mf54dfmfE/dUAbeVQ/jcUDcTgHeWBnnflHohFvpjGbqkGztnX342Mz53dLgXiP65d399PHdUgrtoYLyu6Xzvaf76eLfXB/rkm/fWhvupojwrpTeVhTgYSfgYynzwa30xbL1ybnngFT31snngljhZS3539XhZzDiajbibDn77OX88Ovrl3X99vTjbz1fisGCAAAAMHRSTlMABgYGBwcHJiorMDA1NXGHjY2Nl5mZmZyfn6O5u8XHzc3X193j9fj4+vr6/f39/f08OUojAAAAx0lEQVR4Xi3HZVbDYBhGwQctWqzFPXiQ+36pu+LubvtfBKcN82/UEhld2vWXxyL6F92gbTPabse8hU/uHMx1SZoyyJWPTwq1Rs7GpYE9+Cg+OJcs1MHvU9y4fnrN31yUm18vMCIPjtw3QMndw4rs8ieVzAAcBlewpe1KM3uaBuD3Dda1BhWXAsi6AFY1a2SqifxZ+rnxWYcJDRkUS3fO1R5vwe+XZgw4D4L3RAJiknoXCVX3WeiUpJ5pIxTvVmg45pl5k4Ot/AGV2iqZBWgJJAAAAABJRU5ErkJggg==',
- 'Windows': 'iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA+pJREFUOE+F0n84FHYcB3CWSsL9ojo/6ik64c6PnTjmSS0limmrpBm2G002y++xzXRz6zE0R4nbw+RnTj/WD4sbanLkkAe55ccYlyNme4SrO9u9d13PI3/saZ+/vs/3831ez+f9eb5aWsuqy2mjRYeNUa7YmtjfTico7jNJ8z0eG24NB9vvnDrvufzpq89Npnr8VjMddNmuRh9rDfp36mFg91oM7qPIc5JdbDJq3An/JfCu7Hl53W2lpS220pP2OuniN299jAYbYizSENIoAgbCTdrTKtxOJVdvGo8psUwKy7Vxe4ez1YEVudGP8YEZzyveInFJ6mZRHHqYazDspw/pJwTIuERM5JIwmUdGdyo9K7/BszGzzg6fXzZHGJ8KvzQqXKOpoIeZLjofWR++BPWyCEnPY4xFGEKWQcLjMjKmr1MwfcMYwmz/Y4KOgNki0V5k1dkjUWCK93Kp2PMFFawos8cm1gZ2GqjLXktL4mbQPHLQ4B9ZDFE5+S356fQlyuJMqzH++HnTo6ui2OO1ko9Ul+4fxfd3d4F7k4YTReqpuFS88bGZUE2QNNDobuIq8Q5CduHb7lFJaTnvnym9ergjMWD/FG8zf+aKS3G9JO5C01Asah6wUXrvALKEDoitMMHhDKrKJdg8RU2s0EB2EWWur8dd7PDPFv6dUC0Gv3kAN36VPRGP/5k5NS6lljWxG0TDiSr1VKhoPwhevRMSqkwRxDObc/DavGtpP6zoi8XOyZfhnyNEvKANBU0P8VPfI/wyNCGXSn7wlEmyA9KrgmOKGth3eDVvPfyywq2dnUEv2R9qG2rLsH7xJXziKnWcI8tlTvEC7Mu8hROlImTU9aKqcwQ1vWOihWFu+sJknmph5CvxQh87c7bNh/NXo03hrMCosyvLmMNgMF7TQL6J1dsZIUVwjKqEO+cajp5vxPN439U/gKBt8PTcYHzL/BgHCyOf4unAISj6mFC2bYC82kB5Ls460NHRUVsDeYSXpGw7UgC7sAtwShDgzdM38W7BbURXtqpqhfmB8sEQuXwoCM/6faGQuGCxyxyKWhIm+PrSD495WL3cT0hhi8Whc3NbAs9KaOyCTvrJ8qkdX19XBeTUDU00+55USFzVU2yHstcaix0mUAjJkJeuRU868Ucmk0lcguiBnMAVxjbbdHV1yeq8+u4Hgo22huSG+iQXp83ftaxW3lsPZcs6KG5T8OwaAfJiPcxlrVRVRhvF02i0F/t5VbHZ7JWDfErKTLnhE3mFPuRFepg/uxqz6TqLv6euGj3ut87t/4ylvre3t3ZehOWWO1zjSFEqMVP4GfGb/DBykJcjmaZOoLsc+hcVY/LaAgcTQAAAAABJRU5ErkJggg==',
- 'OpenBSD': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAykIPu64pQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADTklEQVQ4y32RXUxTdxjGn3N6eujoKT3SUkuk3VoBGfVjgFXAsZ7WkipyYXQbuu3CzUXZmGRbssnFEseFkWzgcGzGXky9MWL8TsC4IeFgtK4oAqOnG5vMVl1pCMVWQD7b/y5M6jLdflfvxfPked/nBQA0NDSChqnGVrLuGkES742NhJAdhAKAuk9yyUs5Gry7RQMZAARCWgivpQiPe71P5DUfH0xaqTL7m/iiLkJmphawa+e4SM2PvUyC4yUIBu8CnAQKAK53rCA5OUtQtStVpJ4Gw/FOBddZVKhCfq4MP4n6+at+DUsJm/e0G9JZzYEvI2tHwlEYjDxomkZ+3nG8WroRtHihZVOhVlorDQzh0okhcByDP4ZGcf+X9XAsvY5/RsBa7Kq5H/CqLctKyl/g08S2i6fq8W/MS3P34T9wNDVYSeDX1eTD9xhiLXbtB/Akwmmv6Kr+ICFkLpGhtNSM3qsSstS3oX8lSsmsxS6ZVn3j6PvVVqhUcvC8AtPxVPxwygVKvngN89WOjgVprggGA4eenjB4nsXsTASpC63I0wVTZYPR11FoKRB8Ax54PCFk6BhMTk5CPR3GSbHouGzknr/bYFq9EAvfc9Tu1sLjHcXNKxLuTOTgzOlOe7IHBc/beAXWpWmXlz8a84nhcLQ+ecVzsAEQrMWuMX+f9HZF2YPZ28FVSNfoPWqOzMUmqYMAJm7+/OOzXQFwHGpyEV+vi+yvtxBC9pDmpgJC4tvI3mo9GTitIxvW24nT7ug67HY/3eDs2bbyrVsrY2day70rV6kRfDAHk5lDLJqAmmeRiD9GJDKHvwb74R8G0mkTPjrQTTG122xkTTbwaV2b1H4u16JQKXGr7yG2b8/H1MQ09IsTSEmRwzf4CCwzD+dmE1re8CI7wwi5XNlFf9vaTXX4dWJg4LLl7h05fpNGwNAMWpp9CIVYNO/tRCzGwpDFQaVMQTS2CKY0BWr3GVGWNSXKACDDaA4Mh976pq9f5Sy09GgKlmeAMIBKzUKpU+BFoxJecRhUfAbMxDi4eADfHVmE79v7q575gvvYeVvjZ58LD5mwsKUyX0hnf0feslnQCWD4zxnc6reKisxsfH2oscqcmTmK/+Ow252cna7K52r+Bky6PqmoT5HBAAAAAElFTkSuQmCC',
- 'Gnu': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAywUV5gQrwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADcElEQVQ4y43Tb0jjBRzH8c9v+7nNMebcUW21Cc78g/wcuhByIScoMRwoTBmFlZCmIJ14axqkgoYIkXIqKIVBEuJNUBEUPRlpqDC3Q2Ex0nTezun2YOaPLXNIv7Vvj7zgiOj1+PPk/eADjuNEuHN6ekqMw+H4IzMz8xChUCjV1NT0JbO7uxtfXFy8NZvNr21tbd0AAEQikY6I0m1tbQbx2NjYZiqV+vn29jY+PDw8xhYWFj45PDzcb25uhlQqfSTief6X0dFRpqKigvF4PPPipaWlY7lcXhCLxXJnZmY+ZTY2NnzX19ePGxsbHw0MDLivrq5mc3Jy2pPJZLVWq/2cdbvdDSzLholoNJ1OMy6Xq0Ymk5HNZktOTU29qMgA8HYqlaKDgwNKp9M0PT09BgAM/iGuqqoimUx2yPP8U5/P9wEAMB0dHRUKheJHiUTyeGhoqAUAnE7nR0qlsjcQCLwjlsvlz+bm5mQWi0VSWlr6bXV1tU6hUMj6+/vfN5lMN0xxcfG1zWZ7SETTSqWSGhoamPHxcajV6s+8Xu9Xou7u7t9VKtW00+mkSCTC6PV6aDQa8Dw/Wl9fP8UAQCgUosvLSyovL2eWl5dRUFBw7Ha7v9vc3By5K3g1EAg8FQSBiIguLi4IgBwA2LtEjuPuJxKJ62AwKFpdXf0eQBIvYVmW/cLlchEAWK1WAADT09NzX6PR/OTz+eKVlZUzKpVqTyqVvsnzfLCkpGSrtrb2t97eXnFeXl5ZKpWyZ2RkPPP7/UUnJyefGI3GU+zt7aU4jotOTk7mAUBfX1+b1Wq9kcvlBIAcDgctLCyQxWKhoqIi6uzs/BoAVlZW3qqpqbllZmdnf1hfX//Q4/HEzWbzX+3t7fcMBgMFg0EYjUYmEolAEAREo1Hk5+fT+fk5Mzg4GD86OpJ0dXXJGQBoaWl5Ra/XP6yrq3tQVlam2N7ehslkAsuySCaTUKvVSCQS2NnZSXAcJxYEQTEyMvKeIAhLDADY7fZ7BoPhm6ysLFpbWzuan5//WKvVvsHzPEWjUSYSiSA3N5d0Oh0TjUaf+/1+S2Nj46/4FwYAr7e2tnbF4/E/iYjC4TCFw+F0LBaj/f19mpiYeID/IAagAyABYLXb7cLZ2Rml02nyer3POY6rwv8hEr34u0IkEk1mZ2cTgGMA7768/RtL5JKsGzrLIgAAAABJRU5ErkJggg==',
- 'CrunchBang': 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAQCAQAAAC45EetAAAA8ElEQVR4XnWOsUpCYQBGz1TIHYu2Qix6g0DEtSeQu/UIISJtUS8gJq61F1wcdMohcBDxKUR8hsz1xA/y44/cs3znbB+RJ0Skl3pSkeFQbUs79VAPzrwPFRmN1Ja0Ug/16I93+1oi4lKte+zMXv32WuoAm43lXMrqzbFncgWw21lORf4+/PREKpAhYqZuPXZ+T/3yXbZEajV1JavUQ104sRcq0myqc5mnHurWqc/7yhExVwuPncl+C4Bu13L60ueAwcByOtLhgAIRCzU38fRGTmSxUBvSSD3Ui1NvQkXWa7Uq1dRD9R17HiqyRUSy1NP6B7e1Yu2GtlUKAAAAAElFTkSuQmCC',
- 'Yuno': 'iVBORw0KGgoAAAANSUhEUgAAABgAAAAPCAYAAAD+pA/bAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAABDtJREFUOE+FlHtMm1UYxrtsi8aEgCb+oTFmZur+WNS5RaPERU10C2qGaBgb6hgwLwMmHTIKlIKlQIHSQrmU24BSSmnpBVooUmihtEC5yKWDjVu5uOkcEca4lG5E93j6EQmELX7Jky/fOed9fu973vMdGu0xT3Cgz57yXMZLDdXcy821PFWLKmuA6HqLMqtLX5POl4iYb2ukWW8IOOFe/qfe3/M4n0eOjwyZD8//bldODOk37N1yDJgl+LVdjEGLFKO9KkzZm8hbje7mIrTXZ7sMtTydrJh15H8hHW11XvN/jGS7VudcD5w34ZZzeQYb67fwYO03LN4exo1+LWzNxbA05O5QuzbHqRYn+++CHDx4YK9WLfaedfQzV5em54g5Zbi8OIml+VFMDLWQ7GXoaSmFWZsDZVGCO2u0EbkhHTrhFqi9PmelSsQ8tAtSVch60dpUeGe4kxgZxegzVkBzlQ2NKBG2+iJIMqMok9r8OLRIMqApToSqmAWTmk9B2+o2YW79oshU7ABcuvAFrVGWXkVKpBYoSaBSxIS2mINpiwbjZiUMZRloVfJQyaXDKObBpimBScpHFe8KmmXpaKhK3arGrBVuVBclHN2CiPNin1OVs1tVJYlQlyZBxA6DviQVo6ZaOKd7sTplw53BVugruBBzfsRslw7rZPxaczWutSpQV/gzJPxo1JexyfaxKBBpuiEx+tw+CpKdEvGWTprGlhcwqbIzL5/DYKMYndpK3L1hxf3ZfkrzwybUZjPhnOqmvlcmutFF1jis9QSShOrcWNSXJ1MA0ou/NZWc8Ddfe4VGO3bk0JON1dyMMlK+gmxNrZCFhZF2Kng7YNO0awt4b7wLNp2EqtAsF6ImP56SG0B6siovTYpIjg15gapCVhAfJRUyIBFEo6k8AyuTtkcC/qvG/XbDexulWJvqgYH0o0nKhVHFJ40XwFQnWM5OCX+XMg86c3KvVMSMapCmPpSTIygTxGKZZOcOXhrr3Mp4uzkFuG6B3ajE3TELDDU8qEmsmvRATxquKkxAnSTFjwKEfv3JU9JC5unG6rQ1bTkbQ4Yq/DVgxOqwBWt2K9Yne3ZCZvrgHO2k5paHzOhSiVCZSkdNTgzy40JRlPgDhDHBCxUZdCs91G8fLeK87zOl6XSOICZYXMGNhDqX9fDP/mbK2DXVi/szm03eLpejl5pzOfqwOt4JBT8OeYwQt/4R/BR0OzXiLCM5LOCji/4nXt46rpywgG+zor5RxgSdupBzJdglSY+5ZZbl3XNY6mbn7W0Lcx06zBg1WBjtcC6OmG+OmRTrFrnIUZESZeVeCpwh8TpiPsQ47/tloM97T+/6m8mg55mT3tStyL54mhlwwtszNvjzD8/6HH8i7PvvPPRioZdRWuDBZUR6pEWG7I8P9Xs1Jsj36MfvvO5J/+rTw58dP7afJPfBgeef3XGz/gskFVpJc4HwGwAAAABJRU5ErkJggg=='
- }
- };
-
- ExpandComment = {
- init: function() {
- if (g.VIEW !== 'index' || !Conf['Comment Expansion']) {
- return;
- }
- if (g.BOARD.ID === 'g') {
- this.callbacks.push(Fourchan.code);
- }
- if (g.BOARD.ID === 'sci') {
- this.callbacks.push(Fourchan.math);
- }
- return Post.prototype.callbacks.push({
- name: 'Comment Expansion',
- cb: this.node
- });
- },
- node: function() {
- var a;
-
- if (a = $('.abbr > a', this.nodes.comment)) {
- return $.on(a, 'click', ExpandComment.cb);
- }
- },
- callbacks: [],
- cb: function(e) {
- var post;
-
- e.preventDefault();
- post = Get.postFromNode(this);
- return ExpandComment.expand(post);
- },
- expand: function(post) {
- var a;
-
- if (post.nodes.longComment && !post.nodes.longComment.parentNode) {
- $.replace(post.nodes.shortComment, post.nodes.longComment);
- post.nodes.comment = post.nodes.longComment;
- return;
- }
- if (!(a = $('.abbr > a', post.nodes.comment))) {
- return;
- }
- a.textContent = "Post No." + post + " Loading...";
- return $.cache("//api.4chan.org" + a.pathname + ".json", function() {
- return ExpandComment.parse(this, a, post);
- });
- },
- contract: function(post) {
- var a;
-
- if (!post.nodes.shortComment) {
- return;
- }
- a = $('.abbr > a', post.nodes.shortComment);
- a.textContent = 'here';
- $.replace(post.nodes.longComment, post.nodes.shortComment);
- return post.nodes.comment = post.nodes.shortComment;
- },
- parse: function(req, a, post) {
- var callback, clone, comment, href, postObj, posts, quote, spoilerRange, status, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
-
- status = req.status;
- if (![200, 304].contains(status)) {
- a.textContent = "Error " + req.statusText + " (" + status + ")";
- return;
- }
- posts = JSON.parse(req.response).posts;
- if (spoilerRange = posts[0].custom_spoiler) {
- Build.spoilerRange[g.BOARD] = spoilerRange;
- }
- for (_i = 0, _len = posts.length; _i < _len; _i++) {
- postObj = posts[_i];
- if (postObj.no === post.ID) {
- break;
- }
- }
- if (postObj.no !== post.ID) {
- a.textContent = "Post No." + post + " not found.";
- return;
- }
- comment = post.nodes.comment;
- clone = comment.cloneNode(false);
- clone.innerHTML = postObj.com;
- _ref = $$('.quotelink', clone);
- for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
- quote = _ref[_j];
- href = quote.getAttribute('href');
- if (href[0] === '/') {
- continue;
- }
- quote.href = "/" + post.board + "/res/" + href;
- }
- post.nodes.shortComment = comment;
- $.replace(comment, clone);
- post.nodes.comment = post.nodes.longComment = clone;
- post.parseComment();
- post.parseQuotes();
- _ref1 = ExpandComment.callbacks;
- for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
- callback = _ref1[_k];
- callback.call(post);
- }
- }
- };
-
- ExpandThread = {
- init: function() {
- if (g.VIEW !== 'index' || !Conf['Thread Expansion']) {
- return;
- }
- return Thread.prototype.callbacks.push({
- name: 'Thread Expansion',
- cb: this.node
- });
- },
- node: function() {
- var a, span;
-
- if (!(span = $('.summary', this.OP.nodes.root.parentNode))) {
- return;
- }
- a = $.el('a', {
- textContent: "+ " + span.textContent,
- className: 'summary',
- href: 'javascript:;'
- });
- $.on(a, 'click', ExpandThread.cbToggle);
- return $.replace(span, a);
- },
- cbToggle: function() {
- var op;
-
- op = Get.postFromRoot(this.previousElementSibling);
- return ExpandThread.toggle(op.thread);
- },
- toggle: function(thread) {
- var a, inlined, num, post, replies, reply, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
-
- threadRoot = thread.OP.nodes.root.parentNode;
- a = $('.summary', threadRoot);
- switch (thread.isExpanded) {
- case false:
- case void 0:
- thread.isExpanded = 'loading';
- _ref = $$('.thread > .postContainer', threadRoot);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- post = _ref[_i];
- ExpandComment.expand(Get.postFromRoot(post));
- }
- if (!a) {
- thread.isExpanded = true;
- return;
- }
- thread.isExpanded = 'loading';
- a.textContent = a.textContent.replace('+', '× Loading...');
- $.cache("//api.4chan.org/" + thread.board + "/res/" + thread + ".json", function() {
- return ExpandThread.parse(this, thread, a);
- });
- break;
- case 'loading':
- thread.isExpanded = false;
- if (!a) {
- return;
- }
- a.textContent = a.textContent.replace('× Loading...', '+');
- break;
- case true:
- thread.isExpanded = false;
- if (a) {
- a.textContent = a.textContent.replace('-', '+');
- num = (function() {
- if (thread.isSticky) {
- return 1;
- } else {
- switch (g.BOARD.ID) {
- case 'b':
- case 'vg':
- case 'q':
- return 3;
- case 't':
- return 1;
- default:
- return 5;
- }
- }
- })();
- replies = $$('.thread > .replyContainer', threadRoot).slice(0, -num);
- for (_j = 0, _len1 = replies.length; _j < _len1; _j++) {
- reply = replies[_j];
- if (Conf['Quote Inlining']) {
- while (inlined = $('.inlined', reply)) {
- inlined.click();
- }
- }
- $.rm(reply);
- }
- }
- _ref1 = $$('.thread > .postContainer', threadRoot);
- for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
- post = _ref1[_k];
- ExpandComment.contract(Get.postFromRoot(post));
- }
- }
- },
- parse: function(req, thread, a) {
- var link, node, nodes, post, posts, replies, reply, spoilerRange, status, _i, _len;
-
- if (a.textContent[0] === '+') {
- return;
- }
- status = req.status;
- if (![200, 304].contains(status)) {
- a.textContent = "Error " + req.statusText + " (" + status + ")";
- $.off(a, 'click', ExpandThread.cb.toggle);
- return;
- }
- thread.isExpanded = true;
- a.textContent = a.textContent.replace('× Loading...', '-');
- posts = JSON.parse(req.response).posts;
- if (spoilerRange = posts[0].custom_spoiler) {
- Build.spoilerRange[g.BOARD] = spoilerRange;
- }
- replies = posts.slice(1);
- posts = [];
- nodes = [];
- for (_i = 0, _len = replies.length; _i < _len; _i++) {
- reply = replies[_i];
- if (post = thread.posts[reply.no]) {
- nodes.push(post.nodes.root);
- continue;
- }
- node = Build.postFromObject(reply, thread.board);
- post = new Post(node, thread, thread.board);
- link = $('a[title="Highlight this post"]', node);
- link.href = "res/" + thread + "#p" + post;
- link.nextSibling.href = "res/" + thread + "#q" + post;
- posts.push(post);
- nodes.push(node);
- }
- Main.callbackNodes(Post, posts);
- $.after(a, nodes);
- return Fourchan.parseThread(thread.ID, 1, nodes.length);
- }
- };
-
- FileInfo = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['File Info Formatting']) {
- return;
- }
- this.funk = this.createFunc(Conf['fileInfo']);
- return Post.prototype.callbacks.push({
- name: 'File Info Formatting',
- cb: this.node
- });
- },
- node: function() {
- if (!this.file || this.isClone) {
- return;
- }
- return this.file.text.innerHTML = FileInfo.funk(FileInfo, this);
- },
- createFunc: function(format) {
- var code;
-
- code = format.replace(/%(.)/g, function(s, c) {
- if (c in FileInfo.formatters) {
- return "' + FileInfo.formatters." + c + ".call(post) + '";
- } else {
- return s;
- }
- });
- return Function('FileInfo', 'post', "return '" + code + "'");
- },
- convertUnit: function(size, unit) {
- var i;
-
- if (unit === 'B') {
- return "" + (size.toFixed()) + " Bytes";
- }
- i = 1 + ['KB', 'MB'].indexOf(unit);
- while (i--) {
- size /= 1024;
- }
- size = unit === 'MB' ? Math.round(size * 100) / 100 : size.toFixed();
- return "" + size + " " + unit;
- },
- escape: function(name) {
- return name.replace(/<|>/g, function(c) {
- return c === '<' && '<' || '>';
- });
- },
- formatters: {
- t: function() {
- return this.file.URL.match(/\d+\..+$/)[0];
- },
- T: function() {
- return "" + (FileInfo.formatters.t.call(this)) + "";
- },
- l: function() {
- return "" + (FileInfo.formatters.n.call(this)) + "";
- },
- L: function() {
- return "" + (FileInfo.formatters.N.call(this)) + "";
- },
- n: function() {
- var fullname, shortname;
-
- fullname = this.file.name;
- shortname = Build.shortFilename(this.file.name, this.isReply);
- if (fullname === shortname) {
- return FileInfo.escape(fullname);
- } else {
- return "" + (FileInfo.escape(shortname)) + "" + (FileInfo.escape(fullname)) + "";
- }
- },
- N: function() {
- return FileInfo.escape(this.file.name);
- },
- p: function() {
- if (this.file.isSpoiler) {
- return 'Spoiler, ';
- } else {
- return '';
- }
- },
- s: function() {
- return this.file.size;
- },
- B: function() {
- return FileInfo.convertUnit(this.file.sizeInBytes, 'B');
- },
- K: function() {
- return FileInfo.convertUnit(this.file.sizeInBytes, 'KB');
- },
- M: function() {
- return FileInfo.convertUnit(this.file.sizeInBytes, 'MB');
- },
- r: function() {
- if (this.file.isImage) {
- return this.file.dimensions;
- } else {
- return 'PDF';
- }
- }
- }
- };
-
- Fourchan = {
- init: function() {
- var board;
-
- if (g.VIEW === 'catalog') {
- return;
- }
- board = g.BOARD.ID;
- if (board === 'g') {
- $.globalEval("window.addEventListener('prettyprint', function(e) {\n var pre = e.detail;\n pre.innerHTML = prettyPrintOne(pre.innerHTML);\n}, false);");
- Post.prototype.callbacks.push({
- name: 'Parse /g/ code',
- cb: this.code
- });
- }
- if (board === 'sci') {
- $.globalEval("window.addEventListener('jsmath', function(e) {\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(e.detail);\n } else {\n // load jsMath and process whole document\n jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);\n jsMath.Autoload.LoadJsMath();\n }\n}, false);");
- return Post.prototype.callbacks.push({
- name: 'Parse /sci/ math',
- cb: this.math
- });
- }
- },
- code: function() {
- var pre, _i, _len, _ref;
-
- if (this.isClone) {
- return;
- }
- _ref = $$('.prettyprint', this.nodes.comment);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- pre = _ref[_i];
- $.event('prettyprint', pre, window);
- }
- },
- math: function() {
- if (this.isClone || !$('.math', this.nodes.comment)) {
- return;
- }
- return $.event('jsmath', this.nodes.post, window);
- },
- parseThread: function(threadID, offset, limit) {
- return $.event('4chanParsingDone', {
- threadId: threadID,
- offset: offset,
- limit: limit
- });
- }
- };
-
- Header = {
- init: function() {
- var barFixedToggler, barPositionToggler, customNavToggler, editCustomNav, footerToggler, headerToggler,
- _this = this;
-
- this.menu = new UI.Menu('header');
- this.menuButton = $.el('span', {
- className: 'menu-button',
- innerHTML: ''
- });
- barFixedToggler = $.el('label', {
- innerHTML: ' Fixed Header'
- });
- headerToggler = $.el('label', {
- innerHTML: ' Auto-hide header'
- });
- barPositionToggler = $.el('label', {
- innerHTML: ' Bottom header'
- });
- customNavToggler = $.el('label', {
- innerHTML: ' Custom board navigation'
- });
- footerToggler = $.el('label', {
- innerHTML: " Hide bottom board list"
- });
- editCustomNav = $.el('a', {
- textContent: 'Edit custom board navigation',
- href: 'javascript:;'
- });
- this.barFixedToggler = barFixedToggler.firstElementChild;
- this.barPositionToggler = barPositionToggler.firstElementChild;
- this.headerToggler = headerToggler.firstElementChild;
- this.footerToggler = footerToggler.firstElementChild;
- this.customNavToggler = customNavToggler.firstElementChild;
- $.on(this.menuButton, 'click', this.menuToggle);
- $.on(this.barFixedToggler, 'change', this.toggleBarFixed);
- $.on(this.barPositionToggler, 'change', this.toggleBarPosition);
- $.on(this.headerToggler, 'change', this.toggleBarVisibility);
- $.on(this.footerToggler, 'change', this.toggleFooterVisibility);
- $.on(this.customNavToggler, 'change', this.toggleCustomNav);
- $.on(editCustomNav, 'click', this.editCustomNav);
- this.setBarFixed(Conf['Fixed Header']);
- this.setBarVisibility(Conf['Header auto-hide']);
- $.sync('Fixed Header', Header.setBarFixed);
- $.sync('Bottom Header', Header.setBarPosition);
- $.sync('Header auto-hide', Header.setBarVisibility);
- this.addShortcut(Header.menuButton);
- $.event('AddMenuEntry', {
- type: 'header',
- el: $.el('span', {
- textContent: 'Header'
- }),
- order: 107,
- subEntries: [
- {
- el: barFixedToggler
- }, {
- el: headerToggler
- }, {
- el: barPositionToggler
- }, {
- el: footerToggler
- }, {
- el: customNavToggler
- }, {
- el: editCustomNav
- }
- ]
- });
- $.on(window, 'load hashchange', Header.hashScroll);
- $.on(d, 'CreateNotification', this.createNotification);
- $.asap((function() {
- return d.body;
- }), function() {
- if (!Main.isThisPageLegit()) {
- return;
- }
- $.asap((function() {
- return $.id('boardNavMobile') || d.readyState === 'complete';
- }), Header.setBoardList);
- $.prepend(d.body, _this.bar);
- $.add(d.body, Header.hover);
- return _this.setBarPosition(Conf['Bottom Header']);
- });
- return $.ready(function() {
- var a, cs;
-
- _this.footer = $.id('boardNavDesktopFoot');
- if (a = $("a[href*='/" + g.BOARD + "/']", $.id('boardNavDesktopFoot'))) {
- a.className = 'current';
- }
- cs = $.id('settingsWindowLink');
- cs.textContent = 'Catalog Settings';
- if (g.VIEW === 'catalog') {
- _this.addShortcut(cs);
- }
- Header.setFooterVisibility(Conf['Bottom Board List']);
- return $.sync('Bottom Board List', Header.setFooterVisibility);
- });
- },
- bar: $.el('div', {
- id: 'header-bar'
- }),
- notify: $.el('div', {
- id: 'notifications'
- }),
- shortcuts: $.el('span', {
- id: 'shortcuts'
- }),
- hover: $.el('div', {
- id: 'hoverUI'
- }),
- toggle: $.el('div', {
- id: 'scroll-marker'
- }),
- setBoardList: function() {
- var a, boardList, btn, fourchannav, fullBoardList;
-
- fourchannav = $.id('boardNavDesktop');
- if (a = $("a[href*='/" + g.BOARD + "/']", fourchannav)) {
- a.className = 'current';
- }
- boardList = $.el('span', {
- id: 'board-list',
- innerHTML: "[ - ] " + fourchannav.innerHTML + ""
- });
- fullBoardList = $('#full-board-list', boardList);
- btn = $('.hide-board-list-button', fullBoardList);
- $.on(btn, 'click', Header.toggleBoardList);
- $.rm($('#navtopright', fullBoardList));
- $.add(boardList, fullBoardList);
- $.add(Header.bar, [boardList, Header.shortcuts, Header.notify, Header.toggle]);
- Header.setCustomNav(Conf['Custom Board Navigation']);
- Header.generateBoardList(Conf['boardnav']);
- $.sync('Custom Board Navigation', Header.setCustomNav);
- return $.sync('boardnav', Header.generateBoardList);
- },
- generateBoardList: function(text) {
- var as, list, nodes;
-
- list = $('#custom-board-list', Header.bar);
- $.rmAll(list);
- if (!text) {
- return;
- }
- as = $$('#full-board-list a', Header.bar);
- nodes = text.match(/[\w@]+(-(all|title|replace|full|index|catalog|text:"[^"]+"))*|[^\w@]+/g).map(function(t) {
- var a, board, m, _i, _len;
-
- if (/^[^\w@]/.test(t)) {
- return $.tn(t);
- }
- if (/^toggle-all/.test(t)) {
- a = $.el('a', {
- className: 'show-board-list-button',
- textContent: (t.match(/-text:"(.+)"/) || [null, '+'])[1],
- href: 'javascript:;'
- });
- $.on(a, 'click', Header.toggleBoardList);
- return a;
- }
- board = /^current/.test(t) ? g.BOARD.ID : t.match(/^[^-]+/)[0];
- for (_i = 0, _len = as.length; _i < _len; _i++) {
- a = as[_i];
- if (a.textContent === board) {
- a = a.cloneNode(true);
- if (/-title/.test(t)) {
- a.textContent = a.title;
- } else if (/-replace/.test(t)) {
- if ($.hasClass(a, 'current')) {
- a.textContent = a.title;
- }
- } else if (/-full/.test(t)) {
- a.textContent = "/" + board + "/ - " + a.title;
- } else if (/-(index|catalog|text)/.test(t)) {
- if (m = t.match(/-(index|catalog)/)) {
- a.setAttribute('data-only', m[1]);
- a.href = "//boards.4chan.org/" + board + "/";
- if (m[1] === 'catalog') {
- a.href += 'catalog';
- }
- }
- if (m = t.match(/-text:"(.+)"/)) {
- a.textContent = m[1];
- }
- } else if (board === '@') {
- $.addClass(a, 'navSmall');
- }
- return a;
- }
- }
- return $.tn(t);
- });
- return $.add(list, nodes);
- },
- toggleBoardList: function() {
- var bar, custom, full, showBoardList;
-
- bar = Header.bar;
- custom = $('#custom-board-list', bar);
- full = $('#full-board-list', bar);
- showBoardList = !full.hidden;
- custom.hidden = !showBoardList;
- return full.hidden = showBoardList;
- },
- setBarPosition: function(bottom) {
- Header.barPositionToggler.checked = bottom;
- if (bottom) {
- $.rmClass(doc, 'top');
- $.addClass(doc, 'bottom');
- return $.after(Header.bar, Header.notify);
- } else {
- $.rmClass(doc, 'bottom');
- $.addClass(doc, 'top');
- return $.add(Header.bar, Header.notify);
- }
- },
- toggleBarPosition: function() {
- $.event('CloseMenu');
- Header.setBarPosition(this.checked);
- Conf['Bottom Header'] = this.checked;
- return $.set('Bottom Header', this.checked);
- },
- setBarFixed: function(fixed) {
- Header.barFixedToggler.checked = fixed;
- if (fixed) {
- $.addClass(doc, 'fixed');
- return $.addClass(Header.bar, 'dialog');
- } else {
- $.rmClass(doc, 'fixed');
- return $.rmClass(Header.bar, 'dialog');
- }
- },
- toggleBarFixed: function() {
- $.event('CloseMenu');
- Header.setBarFixed(this.checked);
- Conf['Fixed Header'] = this.checked;
- return $.set('Fixed Header', this.checked);
- },
- setBarVisibility: function(hide) {
- Header.headerToggler.checked = hide;
- $.event('CloseMenu');
- (hide ? $.addClass : $.rmClass)(Header.bar, 'autohide');
- return (hide ? $.addClass : $.rmClass)(doc, 'autohide');
- },
- toggleBarVisibility: function(e) {
- var hide, message;
-
- if (e.type === 'mousedown' && e.button !== 0) {
- return;
- }
- hide = this.nodeName === 'INPUT' ? this.checked : !$.hasClass(Header.bar, 'autohide');
- Conf['Header auto-hide'] = hide;
- $.set('Header auto-hide', hide);
- Header.setBarVisibility(hide);
- message = hide ? 'The header bar will automatically hide itself.' : 'The header bar will remain visible.';
- return new Notification('info', message, 2);
- },
- setFooterVisibility: function(hide) {
- Header.footerToggler.checked = hide;
- return Header.footer.hidden = hide;
- },
- toggleFooterVisibility: function() {
- var hide, message;
-
- $.event('CloseMenu');
- hide = this.nodeName === 'INPUT' ? this.checked : !!Header.footer.hidden;
- Header.setFooterVisibility(hide);
- $.set('Bottom Board List', hide);
- message = hide ? 'The bottom navigation will now be hidden.' : 'The bottom navigation will remain visible.';
- return new Notification('info', message, 2);
- },
- setCustomNav: function(show) {
- var btn, cust, full, _ref;
-
- Header.customNavToggler.checked = show;
- cust = $('#custom-board-list', Header.bar);
- full = $('#full-board-list', Header.bar);
- btn = $('.hide-board-list-button', full);
- return _ref = show ? [false, true] : [true, false], cust.hidden = _ref[0], full.hidden = _ref[1], _ref;
- },
- toggleCustomNav: function() {
- $.cb.checked.call(this);
- return Header.setCustomNav(this.checked);
- },
- editCustomNav: function() {
- var settings;
-
- Settings.open('Advanced');
- settings = $.id('fourchanx-settings');
- return $('input[name=boardnav]', settings).focus();
- },
- hashScroll: function() {
- var hash, post;
-
- if (!((hash = this.location.hash) && (post = $.id(hash.slice(1))))) {
- return;
- }
- if ((Get.postFromRoot(post)).isHidden) {
- return;
- }
- return Header.scrollToPost(post);
- },
- scrollToPost: function(post) {
- var headRect, top;
-
- top = post.getBoundingClientRect().top;
- if (Conf['Fixed Header'] && !Conf['Bottom Header']) {
- headRect = Header.bar.getBoundingClientRect();
- top += -headRect.top - headRect.height;
- }
- return ($.engine === 'webkit' ? d.body : doc).scrollTop += top;
- },
- addShortcut: function(el) {
- var shortcut;
-
- shortcut = $.el('span', {
- className: 'shortcut'
- });
- $.add(shortcut, [$.tn(' ['), el, $.tn(']')]);
- return $.prepend(Header.shortcuts, shortcut);
- },
- menuToggle: function(e) {
- return Header.menu.toggle(e, this, g);
- },
- createNotification: function(e) {
- var cb, content, lifetime, notif, type, _ref;
-
- _ref = e.detail, type = _ref.type, content = _ref.content, lifetime = _ref.lifetime, cb = _ref.cb;
- notif = new Notification(type, content, lifetime);
- if (cb) {
- return cb(notif);
- }
- }
- };
-
- Keybinds = {
- init: function() {
- var init;
-
- if (g.VIEW === 'catalog' || !Conf['Keybinds']) {
- return;
- }
- init = function() {
- var node, _i, _len, _ref;
-
- $.off(d, '4chanXInitFinished', init);
- $.on(d, 'keydown', Keybinds.keydown);
- _ref = $$('[accesskey]');
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- node = _ref[_i];
- node.removeAttribute('accesskey');
- }
- };
- return $.on(d, '4chanXInitFinished', init);
- },
- keydown: function(e) {
- var form, key, notification, notifications, op, target, thread, threadRoot, _i, _len;
-
- if (!(key = Keybinds.keyCode(e))) {
- return;
- }
- target = e.target;
- if (['INPUT', 'TEXTAREA'].contains(target.nodeName)) {
- if (!/(Esc|Alt|Ctrl|Meta)/.test(key)) {
- return;
- }
- }
- threadRoot = Nav.getThread();
- if (op = $('.op', threadRoot)) {
- thread = Get.postFromNode(op).thread;
- }
- switch (key) {
- case Conf['Toggle board list']:
- if (Conf['Custom Board Navigation']) {
- Header.toggleBoardList();
- }
- break;
- case Conf['Open empty QR']:
- Keybinds.qr(threadRoot);
- break;
- case Conf['Open QR']:
- Keybinds.qr(threadRoot, true);
- break;
- case Conf['Open settings']:
- Settings.open();
- break;
- case Conf['Close']:
- if (Settings.dialog) {
- Settings.close();
- } else if ((notifications = $$('.notification')).length) {
- for (_i = 0, _len = notifications.length; _i < _len; _i++) {
- notification = notifications[_i];
- $('.close', notification).click();
- }
- } else if (QR.nodes) {
- QR.close();
- }
- break;
- case Conf['Spoiler tags']:
- if (target.nodeName !== 'TEXTAREA') {
- return;
- }
- Keybinds.tags('spoiler', target);
- break;
- case Conf['Code tags']:
- if (target.nodeName !== 'TEXTAREA') {
- return;
- }
- Keybinds.tags('code', target);
- break;
- case Conf['Eqn tags']:
- if (target.nodeName !== 'TEXTAREA') {
- return;
- }
- Keybinds.tags('eqn', target);
- break;
- case Conf['Math tags']:
- if (target.nodeName !== 'TEXTAREA') {
- return;
- }
- Keybinds.tags('math', target);
- break;
- case Conf['Toggle sage']:
- if (QR.nodes) {
- Keybinds.sage();
- }
- break;
- case Conf['Submit QR']:
- if (QR.nodes && !QR.status()) {
- QR.submit();
- }
- break;
- case Conf['Watch']:
- ThreadWatcher.toggle(thread);
- break;
- case Conf['Update']:
- ThreadUpdater.update();
- break;
- case Conf['Expand image']:
- Keybinds.img(threadRoot);
- break;
- case Conf['Expand images']:
- Keybinds.img(threadRoot, true);
- break;
- case Conf['fappeTyme']:
- if (!$('#menu.left')) {
- Header.menuButton.click();
- }
- FappeTyme.input.click();
- break;
- case Conf['Front page']:
- window.location = "/" + g.BOARD + "/0#delform";
- break;
- case Conf['Open front page']:
- $.open("/" + g.BOARD + "/#delform");
- break;
- case Conf['Next page']:
- if (form = $('.next form')) {
- window.location = form.action;
- }
- break;
- case Conf['Previous page']:
- if (form = $('.prev form')) {
- window.location = form.action;
- }
- break;
- case Conf['Open catalog']:
- if (Conf['External Catalog']) {
- window.location = CatalogLinks.external(g.BOARD.ID);
- } else {
- window.location = "/" + g.BOARD + "/catalog";
- }
- break;
- case Conf['Next thread']:
- if (g.VIEW === 'thread') {
- return;
- }
- Nav.scroll(+1);
- break;
- case Conf['Previous thread']:
- if (g.VIEW === 'thread') {
- return;
- }
- Nav.scroll(-1);
- break;
- case Conf['Expand thread']:
- ExpandThread.toggle(thread);
- break;
- case Conf['Open thread']:
- Keybinds.open(thread);
- break;
- case Conf['Open thread tab']:
- Keybinds.open(thread, true);
- break;
- case Conf['Next reply']:
- Keybinds.hl(+1, threadRoot);
- break;
- case Conf['Previous reply']:
- Keybinds.hl(-1, threadRoot);
- break;
- case Conf['Hide']:
- if (g.VIEW === 'index') {
- ThreadHiding.toggle(thread);
- }
- break;
- default:
- return;
- }
- e.preventDefault();
- return e.stopPropagation();
- },
- keyCode: function(e) {
- var kc, key;
-
- key = (function() {
- switch (kc = e.keyCode) {
- case 8:
- return '';
- case 13:
- return 'Enter';
- case 27:
- return 'Esc';
- case 37:
- return 'Left';
- case 38:
- return 'Up';
- case 39:
- return 'Right';
- case 40:
- return 'Down';
- default:
- if ((48 <= kc && kc <= 57) || (65 <= kc && kc <= 90)) {
- return String.fromCharCode(kc).toLowerCase();
- } else {
- return null;
- }
- }
- })();
- if (key) {
- if (e.altKey) {
- key = 'Alt+' + key;
- }
- if (e.ctrlKey) {
- key = 'Ctrl+' + key;
- }
- if (e.metaKey) {
- key = 'Meta+' + key;
- }
- if (e.shiftKey) {
- key = 'Shift+' + key;
- }
- }
- return key;
- },
- qr: function(thread, quote) {
- if (!(Conf['Quick Reply'] && QR.postingIsEnabled)) {
- return;
- }
- QR.open();
- if (quote) {
- QR.quote.call($('input', $('.post.highlight', thread) || thread));
- }
- QR.nodes.com.focus();
- if (Conf['QR Shortcut']) {
- return $.rmClass($('.qr-shortcut'), 'disabled');
- }
- },
- tags: function(tag, ta) {
- var range, selEnd, selStart, value;
-
- value = ta.value;
- selStart = ta.selectionStart;
- selEnd = ta.selectionEnd;
- ta.value = value.slice(0, selStart) + ("[" + tag + "]") + value.slice(selStart, selEnd) + ("[/" + tag + "]") + value.slice(selEnd);
- range = ("[" + tag + "]").length + selEnd;
- ta.setSelectionRange(range, range);
- return $.event('input', null, ta);
- },
- sage: function() {
- var isSage;
-
- isSage = /sage/i.test(QR.nodes.email.value);
- return QR.nodes.email.value = isSage ? "" : "sage";
- },
- img: function(thread, all) {
- var post;
-
- if (all) {
- return ImageExpand.cb.toggleAll();
- } else {
- post = Get.postFromNode($('.post.highlight', thread) || $('.op', thread));
- return ImageExpand.toggle(post);
- }
- },
- open: function(thread, tab) {
- var url;
-
- if (g.VIEW !== 'index') {
- return;
- }
- url = "/" + thread.board + "/res/" + thread;
- if (tab) {
- return $.open(url);
- } else {
- return location.href = url;
- }
- },
- hl: function(delta, thread) {
- var headRect, next, postEl, rect, replies, reply, root, topMargin, _i, _len;
-
- if (Conf['Fixed Header'] && Conf['Bottom header']) {
- topMargin = 0;
- } else {
- headRect = Header.bar.getBoundingClientRect();
- topMargin = headRect.top + headRect.height;
- }
- if (postEl = $('.reply.highlight', thread)) {
- $.rmClass(postEl, 'highlight');
- rect = postEl.getBoundingClientRect();
- if (rect.bottom >= topMargin && rect.top <= doc.clientHeight) {
- root = postEl.parentNode;
- next = $.x('child::div[contains(@class,"post reply")]', delta === +1 ? root.nextElementSibling : root.previousElementSibling);
- if (!next) {
- this.focus(postEl);
- return;
- }
- if (!(g.VIEW === 'thread' || $.x('ancestor::div[parent::div[@class="board"]]', next) === thread)) {
- return;
- }
- rect = next.getBoundingClientRect();
- if (rect.top < 0 || rect.bottom > doc.clientHeight) {
- if (delta === -1) {
- window.scrollBy(0, rect.top - topMargin);
- } else {
- next.scrollIntoView(false);
- }
- }
- this.focus(next);
- return;
- }
- }
- replies = $$('.reply', thread);
- if (delta === -1) {
- replies.reverse();
- }
- for (_i = 0, _len = replies.length; _i < _len; _i++) {
- reply = replies[_i];
- rect = reply.getBoundingClientRect();
- if (delta === +1 && rect.top >= topMargin || delta === -1 && rect.bottom <= doc.clientHeight) {
- this.focus(reply);
- return;
- }
- }
- },
- focus: function(post) {
- return $.addClass(post, 'highlight');
- }
- };
-
- Redirect = {
- init: function() {
- return $.sync('archs', this.updateArchives);
- },
- updateArchives: function() {
- return $.get('archivers', {}, function(_arg) {
- var archivers;
-
- archivers = _arg.archivers;
- return Conf['archivers'] = archivers;
- });
- },
- image: function(boardID, filename) {
- switch (boardID) {
- case 'a':
- case 'gd':
- case 'jp':
- case 'm':
- case 'q':
- case 'tg':
- case 'vg':
- case 'vp':
- case 'vr':
- case 'wsg':
- return "//archive.foolz.us/" + boardID + "/full_image/" + filename;
- case 'u':
- return "//nsfw.foolz.us/" + boardID + "/full_image/" + filename;
- case 'po':
- return "//archive.thedarkcave.org/" + boardID + "/full_image/" + filename;
- case 'hr':
- case 'tv':
- return "http://archive.4plebs.org/" + boardID + "/full_image/" + filename;
- case 'ck':
- case 'fa':
- case 'lit':
- case 's4s':
- return "//fuuka.warosu.org/" + boardID + "/full_image/" + filename;
- case 'cgl':
- case 'g':
- case 'mu':
- case 'w':
- return "//rbt.asia/" + boardID + "/full_image/" + filename;
- case 'an':
- case 'k':
- case 'toy':
- case 'x':
- return "http://archive.heinessen.com/" + boardID + "/full_image/" + filename;
- case 'c':
- return "//archive.nyafuu.org/" + boardID + "/full_image/" + filename;
- }
- },
- post: function(boardID, postID) {
- var archive, name, _base, _ref;
-
- if (Redirect.post[boardID] == null) {
- _ref = this.archiver;
- for (name in _ref) {
- archive = _ref[name];
- if (archive.type === 'foolfuuka' && archive.boards.contains(boardID)) {
- Redirect.post[boardID] = archive.base;
- break;
- }
- }
- (_base = Redirect.post)[boardID] || (_base[boardID] = false);
- }
- if (Redirect.post[boardID]) {
- return "" + Redirect.post[boardID] + "/_/api/chan/post/?board=" + boardID + "&num=" + postID;
- } else {
- return null;
- }
- },
- select: function(board) {
- var archive, name, _ref, _results;
-
- _ref = this.archiver;
- _results = [];
- for (name in _ref) {
- archive = _ref[name];
- if (!archive.boards.contains(board)) {
- continue;
- }
- _results.push(name);
- }
- return _results;
- },
- to: function(data) {
- var arch, archive, boardID;
-
- boardID = data.boardID;
- if ((arch = Conf.archivers[boardID]) == null) {
- Conf.archivers[boardID] = arch = this.select(boardID)[0];
- $.set('archivers', Conf.archivers);
- }
- return (arch && (archive = this.archiver[arch]) ? Redirect.path(archive.base, archive.type, data) : data.threadID ? "//boards.4chan.org/" + boardID + "/" : null);
- },
- archiver: {
- 'Foolz': {
- base: 'https://archive.foolz.us',
- boards: ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'v', 'vg', 'vp', 'vr', 'wsg'],
- type: 'foolfuuka'
- },
- 'NSFWFoolz': {
- base: 'https://nsfw.foolz.us',
- boards: ['u'],
- type: 'foolfuuka'
- },
- 'TheDarkCave': {
- base: 'http://archive.thedarkcave.org',
- boards: ['c', 'int', 'out', 'po'],
- type: 'foolfuuka'
- },
- '4plebs': {
- base: 'http://archive.4plebs.org',
- boards: ['hr', 'tg', 'tv', 'x'],
- base: 'foolfuuka'
- },
- 'Warosu': {
- base: '//fuuka.warosu.org',
- boards: ['cgl', 'ck', 'fa', 'jp', 'lit', 's4s', 'q', 'tg'],
- type: 'fuuka'
- },
- 'InstallGentoo': {
- base: '//archive.installgentoo.net',
- boards: ['diy', 'g', 'sci'],
- type: 'fuuka'
- },
- 'RebeccaBlackTech': {
- base: '//rbt.asia',
- boards: ['an', 'cgl', 'g', 'mu', 'w'],
- type: 'fuuka_mail'
- },
- 'Heinessen': {
- base: 'http://archive.heinessen.com',
- boards: ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x'],
- type: 'fuuka'
- },
- 'Cliche': {
- base: '//www.cliché.net/4chan/cgi-board.pl',
- boards: ['e'],
- type: 'fuuka'
- },
- 'NyaFuu': {
- base: '//archive.nyafuu.org',
- boards: ['c', 'w'],
- type: 'fuuka'
- }
- },
- path: function(base, archiver, data) {
- var boardID, path, postID, threadID, type, value;
-
- if (data.isSearch) {
- boardID = data.boardID, type = data.type, value = data.value;
- type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type;
- value = encodeURIComponent(value);
- if (archiver === 'foolfuuka') {
- return "" + base + "/" + boardID + "/search/" + type + "/" + value;
- } else if (type === 'image') {
- return "" + base + "/" + boardID + "/?task=search2&search_media_hash=" + value;
- } else {
- return "" + base + "/" + boardID + "/?task=search2&search_" + type + "=" + value;
- }
- }
- boardID = data.boardID, threadID = data.threadID, postID = data.postID;
- path = threadID ? "" + boardID + "/thread/" + threadID : "" + boardID + "/post/" + postID;
- if (archiver === 'foolfuuka') {
- path += '/';
- }
- if (threadID && postID) {
- path += archiver === 'foolfuuka' ? "#" + postID : "#p" + postID;
- }
- return "" + base + "/" + path;
- }
- };
-
- RelativeDates = {
- INTERVAL: $.MINUTE / 2,
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Relative Post Dates']) {
- return;
- }
- $.on(d, 'visibilitychange ThreadUpdate', this.flush);
- this.flush();
- return Post.prototype.callbacks.push({
- name: 'Relative Post Dates',
- cb: this.node
- });
- },
- node: function() {
- var dateEl;
-
- if (this.isClone) {
- return;
- }
- dateEl = this.nodes.date;
- dateEl.title = dateEl.textContent;
- return RelativeDates.setUpdate(this);
- },
- relative: function(diff, now, date) {
- var days, months, number, rounded, unit, years;
-
- unit = (number = diff / $.DAY) >= 1 ? (years = now.getYear() - date.getYear(), months = now.getMonth() - date.getMonth(), days = now.getDate() - date.getDate(), years > 1 ? (number = years - (months < 0 || months === 0 && days < 0), 'year') : years === 1 && (months > 0 || months === 0 && days >= 0) ? (number = years, 'year') : (months = (months + 12) % 12) > 1 ? (number = months - (days < 0), 'month') : months === 1 && days >= 0 ? (number = months, 'month') : 'day') : (number = diff / $.HOUR) >= 1 ? 'hour' : (number = diff / $.MINUTE) >= 1 ? 'minute' : (number = Math.max(0, diff) / $.SECOND, 'second');
- rounded = Math.round(number);
- if (rounded !== 1) {
- unit += 's';
- }
- return "" + rounded + " " + unit + " ago";
- },
- stale: [],
- flush: function() {
- var now, update, _i, _len, _ref;
-
- if (d.hidden) {
- return;
- }
- now = new Date();
- _ref = RelativeDates.stale;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- update = _ref[_i];
- update(now);
- }
- RelativeDates.stale = [];
- clearTimeout(RelativeDates.timeout);
- return RelativeDates.timeout = setTimeout(RelativeDates.flush, RelativeDates.INTERVAL);
- },
- setUpdate: function(post) {
- var markStale, setOwnTimeout, update;
-
- setOwnTimeout = function(diff) {
- var delay;
-
- delay = diff < $.MINUTE ? $.SECOND - (diff + $.SECOND / 2) % $.SECOND : diff < $.HOUR ? $.MINUTE - (diff + $.MINUTE / 2) % $.MINUTE : diff < $.DAY ? $.HOUR - (diff + $.HOUR / 2) % $.HOUR : $.DAY - (diff + $.DAY / 2) % $.DAY;
- return setTimeout(markStale, delay);
- };
- update = function(now) {
- var date, diff, relative, singlePost, _i, _len, _ref;
-
- date = post.info.date;
- diff = now - date;
- relative = RelativeDates.relative(diff, now, date);
- _ref = [post].concat(post.clones);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- singlePost = _ref[_i];
- singlePost.nodes.date.firstChild.textContent = relative;
- }
- return setOwnTimeout(diff);
- };
- markStale = function() {
- return RelativeDates.stale.push(update);
- };
- return update(new Date());
- }
- };
-
- RemoveSpoilers = {
- init: function() {
- if (!Conf['Remove Spoilers']) {
- return;
- }
- if (Conf['Indicate Spoilers']) {
- this.wrapper = function(text) {
- return "[spoiler]" + text + "[/spoiler]";
- };
- }
- return Post.prototype.callbacks.push({
- name: 'Reveal Spoilers',
- cb: this.node
- });
- },
- wrapper: function(text) {
- return text;
- },
- node: function(post) {
- var spoiler, spoilers, _i, _len;
-
- spoilers = $$('s', this.nodes.comment);
- for (_i = 0, _len = spoilers.length; _i < _len; _i++) {
- spoiler = spoilers[_i];
- $.replace(spoiler, $.tn(RemoveSpoilers.wrapper(spoiler.textContent)));
- }
- }
- };
-
- Report = {
- init: function() {
- if (!/report/.test(location.search)) {
- return;
- }
- return $.ready(this.ready);
- },
- ready: function() {
- var field, form;
-
- form = $('form');
- field = $.id('recaptcha_response_field');
- $.on(field, 'keydown', function(e) {
- if (e.keyCode === 8 && !field.value) {
- return $.globalEval('Recaptcha.reload("t")');
- }
- });
- return $.on(form, 'submit', function(e) {
- var response;
-
- e.preventDefault();
- response = field.value.trim();
- if (!/\s/.test(response)) {
- field.value = "" + response + " " + response;
- }
- return form.submit();
- });
- }
- };
-
- Nav = {
- init: function() {
- var append, next, prev, span;
-
- switch (g.VIEW) {
- case 'index':
- if (!Conf['Index Navigation']) {
- return;
- }
- break;
- case 'thread':
- if (!Conf['Reply Navigation']) {
- return;
- }
- break;
- default:
- return;
- }
- span = $.el('span', {
- id: 'navlinks'
- });
- prev = $.el('a', {
- textContent: '▲',
- href: 'javascript:;'
- });
- next = $.el('a', {
- textContent: '▼',
- href: 'javascript:;'
- });
- $.on(prev, 'click', this.prev);
- $.on(next, 'click', this.next);
- $.add(span, [prev, $.tn(' '), next]);
- append = function() {
- $.off(d, '4chanXInitFinished', append);
- return $.add(d.body, span);
- };
- return $.on(d, '4chanXInitFinished', append);
- },
- prev: function() {
- if (g.VIEW === 'thread') {
- return window.scrollTo(0, 0);
- } else {
- return Nav.scroll(-1);
- }
- },
- next: function() {
- if (g.VIEW === 'thread') {
- return window.scrollTo(0, d.body.scrollHeight);
- } else {
- return Nav.scroll(+1);
- }
- },
- getThread: function(full) {
- var headRect, i, rect, thread, threads, topMargin, _i, _len;
-
- if (Conf['Bottom header']) {
- topMargin = 0;
- } else {
- headRect = Header.bar.getBoundingClientRect();
- topMargin = headRect.top + headRect.height;
- }
- threads = $$('.thread:not([hidden])');
- for (i = _i = 0, _len = threads.length; _i < _len; i = ++_i) {
- thread = threads[i];
- rect = thread.getBoundingClientRect();
- if (rect.bottom > topMargin) {
- if (full) {
- return [threads, thread, i, rect, topMargin];
- } else {
- return thread;
- }
- }
- }
- return $('.board');
- },
- scroll: function(delta) {
- var i, rect, thread, threads, top, topMargin, _ref, _ref1;
-
- _ref = Nav.getThread(true), threads = _ref[0], thread = _ref[1], i = _ref[2], rect = _ref[3], topMargin = _ref[4];
- top = rect.top - topMargin;
- if (!((delta === -1 && Math.ceil(top) < 0) || (delta === +1 && top > 1))) {
- i += delta;
- }
- top = ((_ref1 = threads[i]) != null ? _ref1.getBoundingClientRect().top : void 0) - topMargin;
- return window.scrollBy(0, top);
- }
- };
-
- Sauce = {
- init: function() {
- var link, links, _i, _len, _ref;
-
- if (g.VIEW === 'catalog' || !Conf['Sauce']) {
- return;
- }
- links = [];
- _ref = Conf['sauces'].split('\n');
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- link = _ref[_i];
- if (link[0] === '#') {
- continue;
- }
- links.push(this.createSauceLink(link.trim()));
- }
- if (!links.length) {
- return;
- }
- this.links = links;
- this.link = $.el('a', {
- target: '_blank'
- });
- return Post.prototype.callbacks.push({
- name: 'Sauce',
- cb: this.node
- });
- },
- createSauceLink: function(link) {
- var m, text;
-
- link = link.replace(/%(T?URL|MD5|board)/ig, function(parameter) {
- switch (parameter) {
- case '%TURL':
- return "' + encodeURIComponent(post.file.thumbURL) + '";
- case '%URL':
- return "' + encodeURIComponent(post.file.URL) + '";
- case '%MD5':
- return "' + encodeURIComponent(post.file.MD5) + '";
- case '%board':
- return "' + encodeURIComponent(post.board) + '";
- default:
- return parameter;
- }
- });
- text = (m = link.match(/;text:(.+)$/)) ? m[1] : link.match(/(\w+)\.\w+\//)[1];
- link = link.replace(/;text:.+$/, '');
- return Function('post', 'a', "a.href = '" + link + "';\na.textContent = '" + text + "';\nreturn a;");
- },
- node: function() {
- var link, nodes, _i, _len, _ref;
-
- if (this.isClone || !this.file) {
- return;
- }
- nodes = [];
- _ref = Sauce.links;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- link = _ref[_i];
- nodes.push($.tn('\u00A0'), link(this, Sauce.link.cloneNode(true)));
- }
- return $.add(this.file.info, nodes);
- }
- };
-
- Time = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Time Formatting']) {
- return;
- }
- this.funk = this.createFunc(Conf['time']);
- return Post.prototype.callbacks.push({
- name: 'Time Formatting',
- cb: this.node
- });
- },
- node: function() {
- if (this.isClone) {
- return;
- }
- return this.nodes.date.textContent = Time.funk(Time, this.info.date);
- },
- createFunc: function(format) {
- var code;
-
- code = format.replace(/%([A-Za-z])/g, function(s, c) {
- if (c in Time.formatters) {
- return "' + Time.formatters." + c + ".call(date) + '";
- } else {
- return s;
- }
- });
- return Function('Time', 'date', "return '" + code + "'");
- },
- day: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
- month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
- zeroPad: function(n) {
- if (n < 10) {
- return "0" + n;
- } else {
- return n;
- }
- },
- formatters: {
- a: function() {
- return Time.day[this.getDay()].slice(0, 3);
- },
- A: function() {
- return Time.day[this.getDay()];
- },
- b: function() {
- return Time.month[this.getMonth()].slice(0, 3);
- },
- B: function() {
- return Time.month[this.getMonth()];
- },
- d: function() {
- return Time.zeroPad(this.getDate());
- },
- e: function() {
- return this.getDate();
- },
- H: function() {
- return Time.zeroPad(this.getHours());
- },
- I: function() {
- return Time.zeroPad(this.getHours() % 12 || 12);
- },
- k: function() {
- return this.getHours();
- },
- l: function() {
- return this.getHours() % 12 || 12;
- },
- m: function() {
- return Time.zeroPad(this.getMonth() + 1);
- },
- M: function() {
- return Time.zeroPad(this.getMinutes());
- },
- p: function() {
- if (this.getHours() < 12) {
- return 'AM';
- } else {
- return 'PM';
- }
- },
- P: function() {
- if (this.getHours() < 12) {
- return 'am';
- } else {
- return 'pm';
- }
- },
- S: function() {
- return Time.zeroPad(this.getSeconds());
- },
- y: function() {
- return this.getFullYear() - 2000;
- }
- }
- };
-
- Favicon = {
- init: function() {
- return $.ready(function() {
- var href;
-
- Favicon.el = $('link[rel="shortcut icon"]', d.head);
- Favicon.el.type = 'image/x-icon';
- href = Favicon.el.href;
- Favicon.SFW = /ws\.ico$/.test(href);
- Favicon["default"] = href;
- return Favicon["switch"]();
- });
- },
- "switch": function() {
- switch (Conf['favicon']) {
- case 'ferongr':
- Favicon.unreadDead = 'data:image/gif;base64,R0lGODlhEAAQAOMHAOgLAnMFAL8AAOgLAukMA/+AgP+rq////////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
- Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAS1BMVEUAAAAAAAAAAAAJAAASAAAZAQAaAQAiAQAkAQAoFBQyAgAzAgA1AgA4AABBAgBXAwBzBQCEBgGvCAG/AADoCwLpDAP/gID/q6v///9zILr8AAAAA3RSTlMAx9dmesIgAAAAc0lEQVQY02WPgQ6DIBBDmTqnbE70Cvb/v3TAnW5OSKB9ybXg3HUBOAmEEH4FQtrSn4gxi+xjVC9SVOEiSvbZI8zSV+/Xo7icnryZ15GObMxvtWUkB/VJW57kHU7fUcHStm8FkncGE/mwP6CGzq/eauHwvT7sWQt3gZLW+AAAAABJRU5ErkJggg==';
- Favicon.unreadSFW = 'data:image/gif;base64,R0lGODlhEAAQAOMHAADX8QBwfgC2zADX8QDY8nnl8qLp8v///////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
- Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAASFBMVEUAAAAAAAAAAAAACAkAERMAGBsAGR0AISUALzQALzUAMTcANjwAP0cAVF8AcH4AeokAorYAtswA1/EA2PISIyV55fKi6fL////l+pZqAAAAA3RSTlMAx9dmesIgAAAAcklEQVQY02VPARLCIAxjsjnUWdcg6/9/ukIr00nvIMldEhrC/wHwA0BE3wBUtnICOStQnrNx5oqqzmzKx9vDPH1Nae3F9U4ig3OzjCIX51treYvMxou13EQmBPtHE14xLiawjgoPtfgOaKHP+9VrEXA8O1v7CmSPE3u0AAAAAElFTkSuQmCC';
- Favicon.unreadNSFW = 'data:image/gif;base64,R0lGODlhEAAQAOMHAFT+ACh5AEncAFT+AFX/Acz/su7/5v///////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
- Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAS1BMVEUAAAAAAAAAAAADCgAGEgAIGgAJGwALJAANJwASNwASOAATOgAVQQAWRAAeWwAgKBsoeQAwkQA/wABJ3ABU/gBV/wHM/7Lu/+b////r+K2AAAAAA3RSTlMAx9dmesIgAAAAc0lEQVQY02WPgQ6DIBBDmTonbk70Cvb/v3TAnW5OSKB9ybXg3HUBOAmEEH4FQtrSn4gxi+xjVC9SVOEiSvbZI8zSV+/Xo7icnryZ15GObMxvtWUmB/VJW0byDqfvqGBp20mB5J3Bi3zYH1BD38/eauHwvT7sEAt1Fb320QAAAABJRU5ErkJggg==';
- break;
- case 'xat-':
- Favicon.unreadDead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA2ElEQVQ4y61TQQrCMBDMQ8WDIEV6LbT2A4og2Hq0veo7fIAH04dY9N4xmyYlpGmI2MCQTWYy3Wy2DAD7B2wWAzWgcTgVeZKlZRxHNYFi2jM18oBh0IcKtC6ixf22WT4IFLs0owxswXu9egm0Ls6bwfCFfNsJYJKfqoEkd3vgUgFVLWObtzNgVKyruC+ljSzr5OEnBzjvjcQecaQhbZgBb4CmGQw+PoMkTUtdbd8VSEPakcGxPOcsoIgUKy0LecY29BmdBrqRfjIwZ93KLs5loHvBnL3cLH/jF+C/+z5dgUysAAAAAElFTkSuQmCC';
- Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACKkJGNkpN0d3d0eHdra2dGRkORZ1wAAACmaV6naV4PDw8LCwsLCwvyZWLyZWIeExEyFBTAWlr/eHj/enkAAAAKAAAoAAA4AAA4GhpMAACRAAD/AAD/enn/h4j/m5z/nJ3/0dL/0tL/0tP/09P///9VK8WFAAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uZfI0YOdiiMiJw+2CKIPkZzGtcbgKYIJaI26LAfQOzOqoYNA4Z49Nguv/gEEhw2/C5BUZgAAAABJRU5ErkJggg==';
- Favicon.unreadSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA30lEQVQ4y2P4//8/AyWYgSoGQMF/GJ7Y11VVUVoyKTM9ey4Ig9ggMWQ1YA1IBvzXm34YjkH8mPyJB+Nqlp8FYRAbmxoMF6ArSNrw6T0Qf8Amh9cFMEWVR/7/A+L/uORxhgEIt5/+/3/2lf//5wAxiI0uj+4CBlBgxVUvOwtydgXQZpDmi2/+/7/0GmIQSAwkB1IDUkuUAZeABlx+g2zAZ9wGlAOjChba+LwAUgNSi2HA5Am9VciBhSsQQWyoWgZiovEDsdGI1QBYQiLJAGQalpSxyWEzAJYWkGm8clTJjQCZ1hkoVG0CygAAAABJRU5ErkJggg==';
- Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACRjoqTkI13dXR4dXRpZ2tFQ0Zcb5EAAABee6ZefKcPDw8LCwsLCwtisPJisPIRFh4UJDJalMB4xP95xP8AAAABBQcHFx4KISoNLToaKzgaVW4ul8N5xP+Hy/+b1P+c1P/R7P/S6//S7P/T7P////9P0rk0AAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uUrk6MFOxRGRkwdbBNGHSE7jWmPwFMEEtEZdlgPonRmvoYNA4Z49Nguv/gEE3A2/sQ7iRgAAAABJRU5ErkJggg==';
- Favicon.unreadNSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA4ElEQVQ4y2P4//8/AyWYgSoGQMF/GJ7YNbGqrKRiUnp21lwQBrFBYshqwBqQDPifdsYYjkH8mInxB+OWx58FYRAbmxoMF6ArKPmU9B6IP2CTw+sCmKKe/5X/gPg/LnmcYQDCs/63/1/9fzYQzwGz0eXRXcAACqy4ZfFnQc7u+V/xD6T55v+LQHwJbBBIDCQHUgNSS5QBt4Cab/2/jDDgMx4DykrKJ8FCG58XQGpAajEMmNw7uQo5sHAFIogNVctATDR+IDYasRoAS0gkGYBMw5IyNjlsBsDSAjKNV44quREAx58Mr9vt5wQAAAAASUVORK5CYII=';
- Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACRipGTjZN2dHd2dHhna2pDRkVckV8AAABepl9ep18PDw8LCwsLCwt08mJ08mIRHhEYMhRpwFqM/3iM/3kAAAAECAIQIAgWLAseOBoePA86dB1mzDOM/3ma/4er/5ur/5zZ/9HZ/9La/9La/9P///85Jx7jAAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uZfI0YOdiiMiJw+2CKIPkZzGtcbgKYIJaI26LAfQOzOqoYNA4Z49Nguv/gEEhw2/C5BUZgAAAABJRU5ErkJggg==';
- break;
- case 'Mayhem':
- Favicon.unreadDead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABIUlEQVQ4jZ2ScWuDMBDFgw4pIkU0WsoQkWAYIkXZH4N9/+/V3dmfXSrKYIFHwt17j8vdGWNMIkgFuaDgzgQnwRs4EQs5KdolUQtagRN0givEDBTEOjgtGs0Zq8F7cKqqusVxrMQLaDUWcjBSrXkn8gs51tpJSWLk9b3HUa0aNIL5gPBR1/V4kJvR7lTwl8GmAm1Gf9+c3S+89qBHa8502AsmSrtBaEBPbIbj0ah2madlNAPEccdgJDfAtWifBjqWKShRBT6KoiH8QlEUn/qt0CCjnNdmPUwmFWzj9Oe6LpKuZXcwqq88z78Pch3aZU3dPwwc2sWlfZKCW5tWluV8kGvXClLm6dYN4/aUqfCbnEOzNDGhGZbNargvxCzvMGfRJD8UaDVvgkzo6QAAAABJRU5ErkJggg==';
- Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABj0lEQVQ4y42TQUorQRCGv+oekpj43pOhOyIiKoHBxTMkuAnEtWcwx/AY3sUbBIRcwCw8gCfIMkaTOOUiNdgGRRuKoav+v2qq/i4BakBmXweUwDoxLF5ZhVkC64rYBHYMUAIvwKuBMEwdaFiCNbAAngEC0NHkxBi73vsOsG92HGPsphigY1wOzfNhqhpC6AEd730RQuh9hQEOAY6A/jeAs3a7/f+bWB84ckCpqg+I8Osjgqo+AKUDViJS8LkGMcY+sJrNZssYY387LiIFsBLgL9AC/pgaArzZlF+sZgO4BG7sfgvcA3MxUtOStBIpX7cS3Klqd9OBTIEr4DlLOsuAmqpODXQOiHMuy/O8FkLoJth/6Uh2gQPg87Q3k+7leX6hqnpmPvM/GWfXWeWGqj5+oUS9LMs6wF7iHAwGJ9ZW5uxpup+UGwEtEVoijEYjKl66PJujmvIW3vsFwBiYqzJXZTweY5wSU6Bd7UP1KoECODUrJpOJAtPhcKjAtXGaYptWs57qWyv9Zn/it1a5knj5Dm3v4q8APeACAAAAAElFTkSuQmCC';
- Favicon.unreadSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABCElEQVQ4jZ2S4crCMAxF+0OGDJEPKYrIGKOsiJSx/fJRfSAfTJNyKqXfiuDg0C25N2RJjTGmEVrhTzhw7oStsIEtsVzT4o2Jo9ALThiEM8IdHIgNaHo8mjNWg6/ske8bohPo+63QOLzmooHp8fyAICBSQkVz0QKdsFQEV6WSW/D+7+BbgbIDHcb4Kp61XyjyI16zZ8JemGltQtDBSGxB4/GoN+7TpkkjDCsFArm0IYv3U0BbnYtf8BCy+JytsE0X6VyuKhPPK/GAJ14kvZZDZVV3pZIb8MZr6n4o4PDGKn0S5SdDmyq5PnXQsk+Xbhinp03FFzmHJw6xYRiWm9VxnohZ3vOcxdO8ARmXRvbWdtzQAAAAAElFTkSuQmCC';
- Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAkFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OztMTEyRkZHBwcH///9dzWZ0AAAAI3RSTlMEBggKDA4QEhQWFxkbHR8hIyUmKCosLjAxN1hbYc7P0dLc3mzWzBUAAAC+SURBVBjTNY3pcsIwEIM3ePERx/bG5IIe0NIrhVbv/3Y4Ydj9Ic030ogqpY3mDdGGi1EVsYuSvGE2Pkl0TFYAdLGuY1eMWGowzzN6kX41DYVpNbvdKlO4Jx5gSbi2VO+Vcq2jrc/jNLQhtM+n05PfkrKxG/oFHIEXqwqQsVRy7n+AtwLYL3sYR3wA755Jp3Vvv8cn8Js0GXmA7/P5TwzpiLn8MOALuEZNygkm5JTy/+vl4BRVbJvQ1NbWRSxXN64PGOBlhG0qAAAAAElFTkSuQmCC';
- Favicon.unreadNSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABCklEQVQ4jZ2S0WrDMAxF/TBCCKWMYhZKCSGYmFJMSNjD/mhf239qJXNcjBdTWODgRLpXKJKNMaYROuFTOHEehFb4gJZYrunwxsSXMApOmIQzwgOciE1oRjyaM1aDj+yR7xuiHvT9VmgcXnPRwO/9+wWCgEgJFc1FCwzCVhFclUpuw/u3g3cFyg50GPOjePZ+ocjPeM2RCXthpbUFwQAzsQ2Nx6PeuE+bJo0w7BQI5NKGLN5XAW11LX7BQ8jia7bCLl2kc7mqTLzuxAOeeJH0Wk6VVf0oldyEN15T948CDm+sMiZRfjK0pZIbUwcd+3TphnF62lR8kXN44hAbhmG5WQNnT8zynucsnuYJhFpBfkMzqD4AAAAASUVORK5CYII=';
- Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAkFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztMTExmzDORkZHBwcH///92I3mvAAAAI3RSTlMEBggKDA4QEhQWFxkbHR8hIyUmKCosLjAxN1hbYc7P0dLc3mzWzBUAAAC+SURBVBjTNY3pcsIwEIM3ePERx/bG5IIe0NIT0ur93w4nDLs/pPlGGlGltNG8IdpwMaoidlGSN8zGJ4mOyQqALtZ17IoRSw3meUYv0q+moTCtZrdbZQr3xAMsCdeW6r1SrnW09XmchjaE9vl0evJbUjZ2Q7+AI/BiVQEylkrO/TfwVgD7ZQ/jiA/g3TPptO7t9/gEfpImIw/wez7/iSEdMZcfBnwB16hJOcGEnFL+f70cnKKKbROa2tq6iOXqBuMXGTe4CAUbAAAAAElFTkSuQmCC';
- break;
- case 'Original':
- Favicon.unreadDead = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
- Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAAKAAAoAAAoKCg4AAA4ODg7OztMAACRAADBwcH/AAD///+WCcPSAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQmAUAxEb4Isk0rwp3EPR3ECcRQrh7C3/nAasPwzmCgYuPBy5AH/NALSImqAK+H1oJRqyJVHNAnZqDITVhj7/PrAciJ9il0BHs/jjU+fnB9sQ0IxX6OBO6Xr0xKAxANLZzUanCWzZQAAAABJRU5ErkJggg==';
- Favicon.unreadSFW = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAC6Xw////////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
- Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OzvBwcH///8uS/CdAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQ2AUAhEbwKWoftRGvdwBEewchM7d9BFbE6pbP4Mgj+R5MjjwgP+qQSkRtQAV8K3lVI2Q648oknIRpWZsMI4988HjgvpU+wO8HgeHzR9cjZYhoRiPkcDd0rXpyUAiRd5YjKC7MvNRgAAAABJRU5ErkJggg==';
- Favicon.unreadNSFW = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAGbMM////////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
- Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztmzDPBwcH///+rsf3XAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQ2AUAhEbwKWofRL4x6O4AhuopWb2P4F7E5prP4MgiaSHHlceMA/jYC0iBrgSnjdKaUacuURTUI2qsyEFcaxvD6wnkifYleAx/N449Mn5wfbkFDM52jgTun6tAQg8QAEvjQg42KY2AAAAABJRU5ErkJggg==';
- }
- if (Favicon.SFW) {
- Favicon.unread = Favicon.unreadSFW;
- return Favicon.unreadY = Favicon.unreadSFWY;
- } else {
- Favicon.unread = Favicon.unreadNSFW;
- return Favicon.unreadY = Favicon.unreadNSFWY;
- }
- },
- empty: 'data:image/gif;base64,R0lGODlhEAAQAJEAAAAAAP///9vb2////yH5BAEAAAMALAAAAAAQABAAAAIvnI+pq+D9DBAUoFkPFnbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw==',
- dead: 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAIALAAAAAAQABAAAAIvlI+pq+D9DAgUoFkPDlbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw=='
- };
-
- ThreadExcerpt = {
- init: function() {
- if (g.VIEW !== 'thread' || !Conf['Thread Excerpt']) {
- return;
- }
- return Thread.prototype.callbacks.push({
- name: 'Thread Excerpt',
- cb: this.node
- });
- },
- node: function() {
- return d.title = Get.threadExcerpt(this);
- }
- };
-
- ThreadStats = {
- init: function() {
- var sc;
-
- if (g.VIEW !== 'thread' || !Conf['Thread Stats']) {
- return;
- }
- this.dialog = sc = $.el('span', {
- innerHTML: "0 / 0",
- id: 'thread-stats'
- });
- this.postCountEl = $('#post-count', sc);
- this.fileCountEl = $('#file-count', sc);
- Header.addShortcut(sc);
- return Thread.prototype.callbacks.push({
- name: 'Thread Stats',
- cb: this.node
- });
- },
- node: function() {
- var ID, fileCount, post, postCount, _ref;
-
- postCount = 0;
- fileCount = 0;
- _ref = this.posts;
- for (ID in _ref) {
- post = _ref[ID];
- postCount++;
- if (post.file) {
- fileCount++;
- }
- }
- ThreadStats.thread = this;
- ThreadStats.update(postCount, fileCount);
- return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate);
- },
- onUpdate: function(e) {
- var fileCount, postCount, _ref;
-
- if (e.detail[404]) {
- return;
- }
- _ref = e.detail, postCount = _ref.postCount, fileCount = _ref.fileCount;
- return ThreadStats.update(postCount, fileCount);
- },
- update: function(postCount, fileCount) {
- var fileCountEl, postCountEl, thread;
-
- thread = ThreadStats.thread, postCountEl = ThreadStats.postCountEl, fileCountEl = ThreadStats.fileCountEl;
- postCountEl.textContent = postCount;
- fileCountEl.textContent = fileCount;
- (thread.postLimit && !thread.isSticky ? $.addClass : $.rmClass)(postCountEl, 'warning');
- return (thread.fileLimit && !thread.isSticky ? $.addClass : $.rmClass)(fileCountEl, 'warning');
- }
- };
-
- ThreadUpdater = {
- init: function() {
- var checked, conf, el, input, name, sc, settings, subEntries, _ref;
-
- if (g.VIEW !== 'thread' || !Conf['Thread Updater']) {
- return;
- }
- checked = Conf['Auto Update'] ? 'checked' : '';
- this.dialog = sc = $.el('span', {
- innerHTML: "",
- id: 'updater'
- });
- this.timer = $('#update-timer', sc);
- this.status = $('#update-status', sc);
- $.on(this.timer, 'click', ThreadUpdater.update);
- $.on(this.status, 'click', ThreadUpdater.update);
- this.checkPostCount = 0;
- Header.addShortcut(sc);
- subEntries = [];
- _ref = Config.updater.checkbox;
- for (name in _ref) {
- conf = _ref[name];
- checked = Conf[name] ? 'checked' : '';
- el = $.el('label', {
- title: "" + conf[1],
- innerHTML: " " + name
- });
- input = el.firstElementChild;
- $.on(input, 'change', $.cb.checked);
- if (input.name === 'Scroll BG') {
- $.on(input, 'change', ThreadUpdater.cb.scrollBG);
- ThreadUpdater.cb.scrollBG();
- }
- subEntries.push({
- el: el
- });
- }
- settings = $.el('span', {
- innerHTML: 'Interval'
- });
- $.on(settings, 'click', this.intervalShortcut);
- subEntries.push({
- el: settings
- });
- $.event('AddMenuEntry', {
- type: 'header',
- el: $.el('span', {
- textContent: 'Updater'
- }),
- order: 110,
- subEntries: subEntries
- });
- return Thread.prototype.callbacks.push({
- name: 'Thread Updater',
- cb: this.node
- });
- },
- node: function() {
- ThreadUpdater.thread = this;
- ThreadUpdater.root = this.OP.nodes.root.parentNode;
- ThreadUpdater.lastPost = +ThreadUpdater.root.lastElementChild.id.match(/\d+/)[0];
- ThreadUpdater.outdateCount = 0;
- ThreadUpdater.lastModified = '0';
- ThreadUpdater.cb.interval.call($.el('input', {
- value: Conf['Interval']
- }));
- $.on(window, 'online offline', ThreadUpdater.cb.online);
- $.on(d, 'QRPostSuccessful', ThreadUpdater.cb.post);
- $.on(d, 'visibilitychange', ThreadUpdater.cb.visibility);
- return ThreadUpdater.cb.online();
- },
- /*
- http://freesound.org/people/pierrecartoons1979/sounds/90112/
- cc-by-nc-3.0
- */
-
- beep: 'data:audio/wav;base64,UklGRjQDAABXQVZFZm10IBAAAAABAAEAgD4AAIA+AAABAAgAc21wbDwAAABBAAADAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkYXRhzAIAAGMms8em0tleMV4zIpLVo8nhfSlcPR102Ki+5JspVEkdVtKzs+K1NEhUIT7DwKrcy0g6WygsrM2k1NpiLl0zIY/WpMrjgCdbPhxw2Kq+5Z4qUkkdU9K1s+K5NkVTITzBwqnczko3WikrqM+l1NxlLF0zIIvXpsnjgydZPhxs2ay95aIrUEkdUdC3suK8N0NUIjq+xKrcz002WioppdGm091pK1w0IIjYp8jkhydXPxxq2K295aUrTkoeTs65suK+OUFUIzi7xqrb0VA0WSoootKm0t5tKlo1H4TYqMfkiydWQBxm16+85actTEseS8y7seHAPD9TIza5yKra01QyWSson9On0d5wKVk2H4DYqcfkjidUQB1j1rG75KsvSkseScu8seDCPz1TJDW2yara1FYxWSwnm9Sn0N9zKVg2H33ZqsXkkihSQR1g1bK65K0wSEsfR8i+seDEQTxUJTOzy6rY1VowWC0mmNWoz993KVc3H3rYq8TklSlRQh1d1LS647AyR0wgRMbAsN/GRDpTJTKwzKrX1l4vVy4lldWpzt97KVY4IXbUr8LZljVPRCxhw7W3z6ZISkw1VK+4sMWvXEhSPk6buay9sm5JVkZNiLWqtrJ+TldNTnquqbCwilZXU1BwpKirrpNgWFhTaZmnpquZbFlbVmWOpaOonHZcXlljhaGhpZ1+YWBdYn2cn6GdhmdhYGN3lp2enIttY2Jjco+bnJuOdGZlZXCImJqakHpoZ2Zug5WYmZJ/bGlobX6RlpeSg3BqaW16jZSVkoZ0bGtteImSk5KIeG5tbnaFkJKRinxxbm91gY2QkIt/c3BwdH6Kj4+LgnZxcXR8iI2OjIR5c3J0e4WLjYuFe3VzdHmCioyLhn52dHR5gIiKioeAeHV1eH+GiYqHgXp2dnh9hIiJh4J8eHd4fIKHiIeDfXl4eHyBhoeHhH96eHmA',
- cb: {
- online: function() {
- if (ThreadUpdater.online = navigator.onLine) {
- ThreadUpdater.outdateCount = 0;
- ThreadUpdater.set('timer', ThreadUpdater.getInterval());
- ThreadUpdater.update();
- ThreadUpdater.set('status', null, null);
- } else {
- ThreadUpdater.set('timer', null);
- ThreadUpdater.set('status', 'Offline', 'warning');
- }
- return ThreadUpdater.cb.autoUpdate();
- },
- post: function(e) {
- if (e.detail.threadID !== ThreadUpdater.thread.ID) {
- return;
- }
- ThreadUpdater.outdateCount = 0;
- if (ThreadUpdater.seconds > 2) {
- return setTimeout(ThreadUpdater.update, 1000);
- }
- },
- checkpost: function() {
- if (!(g.DEAD || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 10)) {
- return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * 500);
- }
- ThreadUpdater.checkPostCount = 0;
- delete ThreadUpdater.foundPost;
- return delete ThreadUpdater.postID;
- },
- visibility: function() {
- if (d.hidden) {
- return;
- }
- ThreadUpdater.outdateCount = 0;
- if (ThreadUpdater.seconds > ThreadUpdater.interval) {
- return ThreadUpdater.set('timer', ThreadUpdater.getInterval());
- }
- },
- scrollBG: function() {
- return ThreadUpdater.scrollBG = Conf['Scroll BG'] ? function() {
- return true;
- } : function() {
- return !d.hidden;
- };
- },
- autoUpdate: function() {
- if (ThreadUpdater.online) {
- return ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
- } else {
- return clearTimeout(ThreadUpdater.timeoutID);
- }
- },
- interval: function() {
- var val;
-
- val = +this.value;
- if (val < 1) {
- val = 1;
- }
- ThreadUpdater.interval = this.value = val;
- return $.cb.value.call(this);
- },
- load: function() {
- var klass, req, text, _ref;
-
- req = ThreadUpdater.req;
- switch (req.status) {
- case 200:
- g.DEAD = false;
- ThreadUpdater.parse(JSON.parse(req.response).posts);
- ThreadUpdater.lastModified = req.getResponseHeader('Last-Modified');
- ThreadUpdater.set('timer', ThreadUpdater.getInterval());
- break;
- case 404:
- g.DEAD = true;
- ThreadUpdater.set('timer', null);
- ThreadUpdater.set('status', '404', 'warning');
- clearTimeout(ThreadUpdater.timeoutID);
- ThreadUpdater.thread.kill();
- $.event('ThreadUpdate', {
- 404: true,
- thread: ThreadUpdater.thread
- });
- break;
- default:
- ThreadUpdater.outdateCount++;
- ThreadUpdater.set('timer', ThreadUpdater.getInterval());
- /*
- Status Code 304: Not modified
- By sending the `If-Modified-Since` header we get a proper status code, and no response.
- This saves bandwidth for both the user and the servers and avoid unnecessary computation.
- */
-
- _ref = [0, 304].contains(req.status) ? [null, null] : ["" + req.statusText + " (" + req.status + ")", 'warning'], text = _ref[0], klass = _ref[1];
- ThreadUpdater.set('status', text, klass);
- }
- if (ThreadUpdater.postID) {
- ThreadUpdater.cb.checkpost(this.status);
- }
- return delete ThreadUpdater.req;
- }
- },
- getInterval: function() {
- var i, j;
-
- i = ThreadUpdater.interval;
- j = Math.min(ThreadUpdater.outdateCount, 10);
- if (!d.hidden) {
- j = Math.min(j, 7);
- }
- return ThreadUpdater.seconds = Conf['Optional Increase'] ? Math.max(i, [0, 5, 10, 15, 20, 30, 60, 90, 120, 240, 300][j]) : i;
- },
- intervalShortcut: function() {
- var settings;
-
- Settings.open('Advanced');
- settings = $.id('fourchanx-settings');
- return $('input[name=Interval]', settings).focus();
- },
- set: function(name, text, klass) {
- var el, node;
-
- el = ThreadUpdater[name];
- if (node = el.firstChild) {
- node.data = text;
- } else {
- el.textContent = text;
- }
- if (klass !== void 0) {
- return el.className = klass;
- }
- },
- timeout: function() {
- var n;
-
- ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
- if (!(n = --ThreadUpdater.seconds)) {
- return ThreadUpdater.update();
- } else if (n <= -60) {
- ThreadUpdater.set('status', 'Retrying', null);
- return ThreadUpdater.update();
- } else if (n > 0) {
- return ThreadUpdater.set('timer', n);
- }
- },
- update: function() {
- var url;
-
- if (!ThreadUpdater.online) {
- return;
- }
- ThreadUpdater.seconds = 0;
- ThreadUpdater.set('timer', '...');
- if (ThreadUpdater.req) {
- ThreadUpdater.req.onloadend = null;
- ThreadUpdater.req.abort();
- }
- url = "//api.4chan.org/" + ThreadUpdater.thread.board + "/res/" + ThreadUpdater.thread + ".json";
- return ThreadUpdater.req = $.ajax(url, {
- onloadend: ThreadUpdater.cb.load
- }, {
- headers: {
- 'If-Modified-Since': ThreadUpdater.lastModified
- }
- });
- },
- updateThreadStatus: function(title, OP) {
- var icon, message, root, titleLC;
-
- titleLC = title.toLowerCase();
- if (ThreadUpdater.thread["is" + title] === !!OP[titleLC]) {
- return;
- }
- if (!(ThreadUpdater.thread["is" + title] = !!OP[titleLC])) {
- message = title === 'Sticky' ? 'The thread is not a sticky anymore.' : 'The thread is not closed anymore.';
- new Notification('info', message, 30);
- $.rm($("." + titleLC + "Icon", ThreadUpdater.thread.OP.nodes.info));
- return;
- }
- message = title === 'Sticky' ? 'The thread is now a sticky.' : 'The thread is now closed.';
- new Notification('info', message, 30);
- icon = $.el('img', {
- src: "//static.4chan.org/image/" + titleLC + ".gif",
- alt: title,
- title: title,
- className: "" + titleLC + "Icon"
- });
- root = $('[title="Quote this post"]', ThreadUpdater.thread.OP.nodes.info);
- if (title === 'Closed') {
- root = $('.stickyIcon', ThreadUpdater.thread.OP.nodes.info) || root;
- }
- return $.after(root, [$.tn(' '), icon]);
- },
- parse: function(postObjects) {
- var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, scroll, _i, _len, _ref;
-
- OP = postObjects[0];
- Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
- ThreadUpdater.updateThreadStatus('Sticky', OP);
- ThreadUpdater.updateThreadStatus('Closed', OP);
- ThreadUpdater.thread.postLimit = !!OP.bumplimit;
- ThreadUpdater.thread.fileLimit = !!OP.imagelimit;
- posts = [];
- index = [];
- files = [];
- count = 0;
- for (_i = 0, _len = postObjects.length; _i < _len; _i++) {
- postObject = postObjects[_i];
- num = postObject.no;
- index.push(num);
- if (postObject.fsize) {
- files.push(num);
- }
- if (num <= ThreadUpdater.lastPost) {
- continue;
- }
- count++;
- node = Build.postFromObject(postObject, ThreadUpdater.thread.board);
- posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
- }
- deletedPosts = [];
- deletedFiles = [];
- _ref = ThreadUpdater.thread.posts;
- for (ID in _ref) {
- post = _ref[ID];
- ID = +ID;
- if (post.isDead && index.contains(ID)) {
- post.resurrect();
- } else if (!index.contains(ID)) {
- post.kill();
- deletedPosts.push(post);
- } else if (post.file && !post.file.isDead && !files.contains(ID)) {
- post.kill(true);
- deletedFiles.push(post);
- }
- if (ThreadUpdater.postID) {
- if (ID === ThreadUpdater.postID) {
- ThreadUpdater.foundPost = true;
- }
- }
- }
- if (!count) {
- ThreadUpdater.set('status', null, null);
- ThreadUpdater.outdateCount++;
- } else {
- ThreadUpdater.set('status', "+" + count, 'new');
- ThreadUpdater.outdateCount = 0;
- if (Conf['Beep'] && d.hidden && Unread.posts && !Unread.posts.length) {
- if (!ThreadUpdater.audio) {
- ThreadUpdater.audio = $.el('audio', {
- src: ThreadUpdater.beep
- });
- }
- ThreadUpdater.audio.play();
- }
- ThreadUpdater.lastPost = posts[count - 1].ID;
- Main.callbackNodes(Post, posts);
- scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25;
- for (key in posts) {
- post = posts[key];
- if (!posts.hasOwnProperty(key)) {
- continue;
- }
- if (post.cb) {
- if (!post.cb.call(post)) {
- $.add(ThreadUpdater.root, post.nodes.root);
- }
- } else {
- $.add(ThreadUpdater.root, post.nodes.root);
- }
- }
- if (scroll) {
- if (Conf['Bottom Scroll']) {
- d.body.scrollTop = d.body.clientHeight;
- } else {
- Header.scrollToPost(nodes[0]);
- }
- }
- $.queueTask(function() {
- var length, threadID;
-
- threadID = ThreadUpdater.thread.ID;
- length = $$('.thread > .postContainer', ThreadUpdater.root).length;
- return Fourchan.parseThread(threadID, length - count, length);
- });
- }
- return $.event('ThreadUpdate', {
- 404: false,
- thread: ThreadUpdater.thread,
- newPosts: posts,
- deletedPosts: deletedPosts,
- deletedFiles: deletedFiles,
- postCount: OP.replies + 1,
- fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead)
- });
- }
- };
-
- ThreadWatcher = {
- init: function() {
- if (!Conf['Thread Watcher']) {
- return;
- }
- this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', 'Thread Watcher
');
- $.on(d, 'QRPostSuccessful', this.cb.post);
- $.on(d, '4chanXInitFinished', this.ready);
- $.sync('WatchedThreads', this.refresh);
- return Thread.prototype.callbacks.push({
- name: 'Thread Watcher',
- cb: this.node
- });
- },
- node: function() {
- var favicon,
- _this = this;
-
- favicon = $.el('img', {
- className: 'favicon'
- });
- $.on(favicon, 'click', ThreadWatcher.cb.toggle);
- $.before($('input', this.OP.nodes.post), favicon);
- if (g.VIEW !== 'thread') {
- return;
- }
- return $.get('AutoWatch', 0, function(item) {
- if (item['AutoWatch'] !== _this.ID) {
- return;
- }
- ThreadWatcher.watch(_this);
- return $["delete"]('AutoWatch');
- });
- },
- ready: function() {
- $.off(d, '4chanXInitFinished', ThreadWatcher.ready);
- if (!Main.isThisPageLegit()) {
- return;
- }
- ThreadWatcher.refresh();
- return $.add(d.body, ThreadWatcher.dialog);
- },
- refresh: function(watched) {
- var ID, board, div, favicon, id, link, nodes, props, thread, x, _ref, _ref1;
-
- if (!watched) {
- $.get('WatchedThreads', {}, function(item) {
- return ThreadWatcher.refresh(item['WatchedThreads']);
- });
- return;
- }
- nodes = [$('.move', ThreadWatcher.dialog)];
- for (board in watched) {
- _ref = watched[board];
- for (id in _ref) {
- props = _ref[id];
- x = $.el('a', {
- textContent: '×',
- href: 'javascript:;'
- });
- $.on(x, 'click', ThreadWatcher.cb.x);
- link = $.el('a', props);
- link.title = link.textContent;
- div = $.el('div');
- $.add(div, [x, $.tn(' '), link]);
- nodes.push(div);
- }
- }
- $.rmAll(ThreadWatcher.dialog);
- $.add(ThreadWatcher.dialog, nodes);
- watched = watched[g.BOARD] || {};
- _ref1 = g.BOARD.threads;
- for (ID in _ref1) {
- thread = _ref1[ID];
- favicon = $('.favicon', thread.OP.nodes.post);
- favicon.src = ID in watched ? Favicon["default"] : Favicon.empty;
- }
- },
- cb: {
- toggle: function() {
- return ThreadWatcher.toggle(Get.postFromNode(this).thread);
- },
- x: function() {
- var thread;
-
- thread = this.nextElementSibling.pathname.split('/');
- return ThreadWatcher.unwatch(thread[1], thread[3]);
- },
- post: function(e) {
- var board, postID, threadID, _ref;
-
- _ref = e.detail, board = _ref.board, postID = _ref.postID, threadID = _ref.threadID;
- if (postID === threadID) {
- if (Conf['Auto Watch']) {
- return $.set('AutoWatch', threadID);
- }
- } else if (Conf['Auto Watch Reply']) {
- return ThreadWatcher.watch(board.threads[threadID]);
- }
- }
- },
- toggle: function(thread) {
- if ($('.favicon', thread.OP.nodes.post).src === Favicon.empty) {
- return ThreadWatcher.watch(thread);
- } else {
- return ThreadWatcher.unwatch(thread.board, thread.ID);
- }
- },
- unwatch: function(board, threadID) {
- return $.get('WatchedThreads', {}, function(item) {
- var watched;
-
- watched = item['WatchedThreads'];
- delete watched[board][threadID];
- if (!Object.keys(watched[board]).length) {
- delete watched[board];
- }
- ThreadWatcher.refresh(watched);
- return $.set('WatchedThreads', watched);
- });
- },
- watch: function(thread) {
- return $.get('WatchedThreads', {}, function(item) {
- var watched, _name;
-
- watched = item['WatchedThreads'];
- watched[_name = thread.board] || (watched[_name] = {});
- watched[thread.board][thread] = {
- href: "/" + thread.board + "/res/" + thread,
- textContent: Get.threadExcerpt(thread)
- };
- ThreadWatcher.refresh(watched);
- return $.set('WatchedThreads', watched);
- });
- }
- };
-
- Unread = {
- init: function() {
- if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon']) {
- return;
- }
- this.db = new DataBoard('lastReadPosts', this.sync);
- this.hr = $.el('hr', {
- id: 'unread-line'
- });
- this.posts = [];
- this.postsQuotingYou = [];
- return Thread.prototype.callbacks.push({
- name: 'Unread',
- cb: this.node
- });
- },
- node: function() {
- Unread.thread = this;
- Unread.title = d.title;
- Unread.lastReadPost = Unread.db.get({
- boardID: this.board.ID,
- threadID: this.ID,
- defaultValue: 0
- });
- $.on(d, '4chanXInitFinished', Unread.ready);
- $.on(d, 'ThreadUpdate', Unread.onUpdate);
- $.on(d, 'scroll visibilitychange', Unread.read);
- if (Conf['Unread Line']) {
- $.on(d, 'visibilitychange', Unread.setLine);
- }
- if (Conf['Scroll to Last Read Post']) {
- return $.on(window, 'load', Unread.scroll);
- }
- },
- ready: function() {
- var ID, post, posts, _ref;
-
- $.off(d, '4chanXInitFinished', Unread.ready);
- posts = [];
- _ref = Unread.thread.posts;
- for (ID in _ref) {
- post = _ref[ID];
- if (post.isReply) {
- posts.push(post);
- }
- }
- return Unread.addPosts(posts);
- },
- scroll: function() {
- var hash, post, posts, prevID, root;
-
- if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
- return;
- }
- if (Unread.posts.length) {
- prevID = 0;
- while (root = $.x('preceding-sibling::div[contains(@class,"postContainer")][1]', Unread.posts[0].nodes.root)) {
- post = Get.postFromRoot(root);
- if (prevID === post.ID) {
- break;
- }
- prevID = post.ID;
- if (!post.isHidden) {
- break;
- }
- }
- root.scrollIntoView(false);
- return;
- }
- posts = Object.keys(Unread.thread.posts);
- return Header.scrollToPost(Unread.thread.posts[posts[posts.length - 1]].nodes.root);
- },
- sync: function() {
- var lastReadPost;
-
- lastReadPost = Unread.db.get({
- boardID: Unread.thread.board.ID,
- threadID: Unread.thread.ID,
- defaultValue: 0
- });
- if (!(Unread.lastReadPost < lastReadPost)) {
- return;
- }
- Unread.lastReadPost = lastReadPost;
- Unread.readArray(Unread.posts);
- Unread.readArray(Unread.postsQuotingYou);
- Unread.setLine();
- return Unread.update();
- },
- addPosts: function(newPosts) {
- var ID, data, post, _i, _len;
-
- for (_i = 0, _len = newPosts.length; _i < _len; _i++) {
- post = newPosts[_i];
- ID = post.ID;
- if (ID <= Unread.lastReadPost || post.isHidden) {
- continue;
- }
- if (QR.db) {
- data = {
- boardID: post.board.ID,
- threadID: post.thread.ID,
- postID: post.ID
- };
- if (QR.db.get(data)) {
- continue;
- }
- }
- Unread.posts.push(post);
- Unread.addPostQuotingYou(post);
- }
- if (Conf['Unread Line']) {
- Unread.setLine(newPosts.contains(Unread.posts[0]));
- }
- Unread.read();
- return Unread.update();
- },
- addPostQuotingYou: function(post) {
- var quotelink, _i, _len, _ref;
-
- if (!QR.db) {
- return;
- }
- _ref = post.nodes.quotelinks;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quotelink = _ref[_i];
- if (QR.db.get(Get.postDataFromLink(quotelink))) {
- Unread.postsQuotingYou.push(post);
- }
- }
- },
- onUpdate: function(e) {
- if (e.detail[404]) {
- return Unread.update();
- } else {
- return Unread.addPosts(e.detail.newPosts);
- }
- },
- readSinglePost: function(post) {
- var i;
-
- if ((i = Unread.posts.indexOf(post)) === -1) {
- return;
- }
- Unread.posts.splice(i, 1);
- if (i === 0) {
- Unread.lastReadPost = post.ID;
- Unread.saveLastReadPost();
- }
- if ((i = Unread.postsQuotingYou.indexOf(post)) !== -1) {
- Unread.postsQuotingYou.splice(i, 1);
- }
- return Unread.update();
- },
- readArray: function(arr) {
- var i, post, _i, _len;
-
- for (i = _i = 0, _len = arr.length; _i < _len; i = ++_i) {
- post = arr[i];
- if (post.ID > Unread.lastReadPost) {
- break;
- }
- }
- return arr.splice(0, i);
- },
- read: $.debounce(50, function(e) {
- var ID, bottom, height, i, post, posts, read;
-
- if (d.hidden || !Unread.posts.length) {
- return;
- }
- height = doc.clientHeight;
- posts = Unread.posts;
- read = [];
- i = posts.length;
- while (post = posts[--i]) {
- bottom = post.nodes.root.getBoundingClientRect().bottom;
- if (bottom < height) {
- ID = post.ID;
- posts.remove(post);
- }
- }
- if (!ID) {
- return;
- }
- Unread.lastReadPost = ID;
- Unread.saveLastReadPost();
- Unread.readArray(Unread.postsQuotingYou);
- if (e) {
- return Unread.update();
- }
- }),
- saveLastReadPost: $.debounce(2 * $.SECOND, function() {
- return Unread.db.set({
- boardID: Unread.thread.board.ID,
- threadID: Unread.thread.ID,
- val: Unread.lastReadPost
- });
- }),
- setLine: function(force) {
- var post, root;
-
- if (!(d.hidden || force === true)) {
- return;
- }
- if (post = Unread.posts[0]) {
- root = post.nodes.root;
- if (root !== $('.thread > .replyContainer', root.parentNode)) {
- return $.before(root, Unread.hr);
- }
- } else {
- return $.rm(Unread.hr);
- }
- },
- update: function(dontrepeat) {
- var count;
-
- count = Unread.posts.length;
- if (Conf['Unread Count']) {
- d.title = "" + (count || !Conf['Hide Unread Count at (0)'] ? "(" + count + ") " : '') + (g.DEAD ? "/" + g.BOARD + "/ - 404" : "" + Unread.title);
- if (!dontrepeat) {
- setTimeout(function() {
- d.title = '';
- return Unread.update(true);
- }, $.SECOND);
- }
- }
- if (!Conf['Unread Favicon']) {
- return;
- }
- return Favicon.el.href = g.DEAD ? Unread.postsQuotingYou.length ? Favicon.unreadDeadY : count ? Favicon.unreadDead : Favicon.dead : count ? Unread.postsQuotingYou.length ? Favicon.unreadY : Favicon.unread : Favicon["default"];
- }
- };
-
QR = {
init: function() {
var sc;
@@ -8213,619 +5722,2033 @@
}
};
- QuoteBacklink = {
+ FappeTyme = {
init: function() {
- var format;
+ var el, input;
- if (g.VIEW === 'catalog' || !Conf['Quote Backlinks']) {
+ if (!Conf['Fappe Tyme'] || g.VIEW === 'catalog' || g.BOARD === 'f') {
return;
}
- format = Conf['backlink'].replace(/%id/g, "' + id + '");
- this.funk = Function('id', "return '" + format + "'");
- this.containers = {};
- Post.prototype.callbacks.push({
- name: 'Quote Backlinking Part 1',
- cb: this.firstNode
+ el = $.el('label', {
+ innerHTML: " Fappe Tyme",
+ title: 'Fappe Tyme'
+ });
+ FappeTyme.input = input = el.firstElementChild;
+ $.on(input, 'change', FappeTyme.toggle);
+ $.event('AddMenuEntry', {
+ type: 'header',
+ el: el,
+ order: 97
});
return Post.prototype.callbacks.push({
- name: 'Quote Backlinking Part 2',
- cb: this.secondNode
+ name: 'Fappe Tyme',
+ cb: this.node
});
},
- firstNode: function() {
- var a, clone, container, containers, link, post, quote, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
+ node: function() {
+ if (this.file) {
+ return;
+ }
+ return $.addClass(this.nodes.root, "noFile");
+ },
+ toggle: function() {
+ $.event('CloseMenu');
+ return (this.checked ? $.addClass : $.rmClass)(doc, 'fappeTyme');
+ }
+ };
- if (this.isClone || !this.quotes.length) {
+ ImageExpand = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
+ return;
+ }
+ this.EAI = $.el('a', {
+ className: 'expand-all-shortcut',
+ textContent: 'EAI',
+ title: 'Expand All Images',
+ href: 'javascript:;'
+ });
+ $.on(this.EAI, 'click', ImageExpand.cb.toggleAll);
+ Header.addShortcut(this.EAI);
+ return Post.prototype.callbacks.push({
+ name: 'Image Expansion',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var thumb, _ref;
+
+ if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ return;
+ }
+ thumb = this.file.thumb;
+ $.on(thumb.parentNode, 'click', ImageExpand.cb.toggle);
+ if (this.isClone && $.hasClass(thumb, 'expanding')) {
+ ImageExpand.contract(this);
+ ImageExpand.expand(this);
+ return;
+ }
+ if (ImageExpand.on && !this.isHidden) {
+ return ImageExpand.expand(this);
+ }
+ },
+ cb: {
+ toggle: function(e) {
+ if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
+ return;
+ }
+ e.preventDefault();
+ return ImageExpand.toggle(Get.postFromNode(this));
+ },
+ toggleAll: function() {
+ var ID, file, func, post, _i, _len, _ref, _ref1;
+
+ $.event('CloseMenu');
+ if (ImageExpand.on = $.hasClass(ImageExpand.EAI, 'expand-all-shortcut')) {
+ ImageExpand.EAI.className = 'contract-all-shortcut';
+ ImageExpand.EAI.title = 'Contract All Images';
+ func = ImageExpand.expand;
+ } else {
+ ImageExpand.EAI.className = 'expand-all-shortcut';
+ ImageExpand.EAI.title = 'Expand All Images';
+ func = ImageExpand.contract;
+ }
+ _ref = g.posts;
+ for (ID in _ref) {
+ post = _ref[ID];
+ _ref1 = [post].concat(post.clones);
+ for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
+ post = _ref1[_i];
+ file = post.file;
+ if (!(file && file.isImage && doc.contains(post.nodes.root))) {
+ continue;
+ }
+ if (ImageExpand.on && (!Conf['Expand spoilers'] && file.isSpoiler || Conf['Expand from here'] && file.thumb.getBoundingClientRect().top < 0)) {
+ continue;
+ }
+ $.queueTask(func, post);
+ }
+ }
+ },
+ setFitness: function() {
+ var checked;
+
+ checked = this.checked;
+ (checked ? $.addClass : $.rmClass)(doc, this.name.toLowerCase().replace(/\s+/g, '-'));
+ if (this.name !== 'Fit height') {
+ return;
+ }
+ if (checked) {
+ $.on(window, 'resize', ImageExpand.resize);
+ if (!ImageExpand.style) {
+ ImageExpand.style = $.addStyle(null);
+ }
+ return ImageExpand.resize();
+ } else {
+ return $.off(window, 'resize', ImageExpand.resize);
+ }
+ }
+ },
+ toggle: function(post) {
+ var headRect, rect, root, thumb, top;
+
+ thumb = post.file.thumb;
+ if (!(post.file.isExpanded || $.hasClass(thumb, 'expanding'))) {
+ ImageExpand.expand(post);
+ return;
+ }
+ ImageExpand.contract(post);
+ rect = post.nodes.root.getBoundingClientRect();
+ if (!(rect.top <= 0 || rect.left <= 0)) {
+ return;
+ }
+ top = rect.top;
+ if (Conf['Fixed Header'] && !Conf['Bottom Header']) {
+ headRect = Header.bar.getBoundingClientRect();
+ top += -headRect.top - headRect.height;
+ }
+ root = d.body;
+ if (rect.top < 0) {
+ root.scrollTop += top;
+ }
+ if (rect.left < 0) {
+ return root.scrollLeft = 0;
+ }
+ },
+ contract: function(post) {
+ $.rmClass(post.nodes.root, 'expanded-image');
+ $.rmClass(post.file.thumb, 'expanding');
+ return post.file.isExpanded = false;
+ },
+ expand: function(post, src) {
+ var img, thumb;
+
+ thumb = post.file.thumb;
+ if (post.isHidden || post.file.isExpanded || $.hasClass(thumb, 'expanding')) {
+ return;
+ }
+ $.addClass(thumb, 'expanding');
+ if (post.file.fullImage) {
+ $.asap((function() {
+ return post.file.fullImage.naturalHeight;
+ }), function() {
+ return ImageExpand.completeExpand(post);
+ });
+ return;
+ }
+ post.file.fullImage = img = $.el('img', {
+ className: 'full-image',
+ src: src || post.file.URL
+ });
+ $.on(img, 'error', ImageExpand.error);
+ $.asap((function() {
+ return post.file.fullImage.naturalHeight;
+ }), function() {
+ return ImageExpand.completeExpand(post);
+ });
+ return $.after(thumb, img);
+ },
+ completeExpand: function(post) {
+ var prev, thumb;
+
+ thumb = post.file.thumb;
+ if (!$.hasClass(thumb, 'expanding')) {
+ return;
+ }
+ post.file.isExpanded = true;
+ if (!post.nodes.root.parentNode) {
+ $.addClass(post.nodes.root, 'expanded-image');
+ $.rmClass(post.file.thumb, 'expanding');
+ return;
+ }
+ prev = post.nodes.root.getBoundingClientRect();
+ return $.queueTask(function() {
+ var curr, root;
+
+ $.addClass(post.nodes.root, 'expanded-image');
+ $.rmClass(post.file.thumb, 'expanding');
+ if (!(prev.top + prev.height <= 0)) {
+ return;
+ }
+ root = d.body;
+ curr = post.nodes.root.getBoundingClientRect();
+ return root.scrollTop += curr.height - prev.height + curr.top - prev.top;
+ });
+ },
+ error: function() {
+ var URL, post, src, timeoutID;
+
+ post = Get.postFromNode(this);
+ $.rm(this);
+ delete post.file.fullImage;
+ if (!($.hasClass(post.file.thumb, 'expanding') || $.hasClass(post.nodes.root, 'expanded-image'))) {
+ return;
+ }
+ ImageExpand.contract(post);
+ src = this.src.split('/');
+ if (src[2] === 'images.4chan.org') {
+ if (URL = Redirect.image(src[3], src[5])) {
+ setTimeout(ImageExpand.expand, 10000, post, URL);
+ return;
+ }
+ if (g.DEAD || post.isDead || post.file.isDead) {
+ return;
+ }
+ }
+ timeoutID = setTimeout(ImageExpand.expand, 10000, post);
+ return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", {
+ onload: function() {
+ var postObj, _i, _len, _ref;
+
+ if (this.status !== 200) {
+ return;
+ }
+ _ref = JSON.parse(this.response).posts;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ postObj = _ref[_i];
+ if (postObj.no === post.ID) {
+ break;
+ }
+ }
+ if (postObj.no !== post.ID) {
+ clearTimeout(timeoutID);
+ return post.kill();
+ } else if (postObj.filedeleted) {
+ clearTimeout(timeoutID);
+ return post.kill(true);
+ }
+ }
+ });
+ },
+ menu: {
+ init: function() {
+ var conf, createSubEntry, el, key, subEntries, _ref;
+
+ if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
+ return;
+ }
+ el = $.el('span', {
+ textContent: 'Image Expansion',
+ className: 'image-expansion-link'
+ });
+ createSubEntry = ImageExpand.menu.createSubEntry;
+ subEntries = [];
+ _ref = Config.imageExpansion;
+ for (key in _ref) {
+ conf = _ref[key];
+ subEntries.push(createSubEntry(key, conf));
+ }
+ return $.event('AddMenuEntry', {
+ type: 'header',
+ el: el,
+ order: 105,
+ subEntries: subEntries
+ });
+ },
+ createSubEntry: function(type, config) {
+ var input, label;
+
+ label = $.el('label', {
+ innerHTML: " " + type
+ });
+ input = label.firstElementChild;
+ if (type === 'Fit width' || type === 'Fit height') {
+ $.on(input, 'change', ImageExpand.cb.setFitness);
+ }
+ if (config) {
+ label.title = config[1];
+ input.checked = Conf[type];
+ $.event('change', null, input);
+ $.on(input, 'change', $.cb.checked);
+ }
+ return {
+ el: label
+ };
+ }
+ },
+ resize: function() {
+ return ImageExpand.style.textContent = ":root.fit-height .full-image {max-height:" + doc.clientHeight + "px}";
+ },
+ menuToggle: function(e) {
+ return ImageExpand.opmenu.toggle(e, this, g);
+ }
+ };
+
+ ImageHover = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Image Hover']) {
+ return;
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Image Hover',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var _ref;
+
+ if (!((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ return;
+ }
+ return $.on(this.file.thumb, 'mouseover', ImageHover.mouseover);
+ },
+ mouseover: function(e) {
+ var el, post;
+
+ post = Get.postFromNode(this);
+ el = $.el('img', {
+ id: 'ihover',
+ src: post.file.URL
+ });
+ el.setAttribute('data-fullid', post.fullID);
+ $.add(Header.hover, el);
+ UI.hover({
+ root: this,
+ el: el,
+ latestEvent: e,
+ endEvents: 'mouseout click',
+ asapTest: function() {
+ return el.naturalHeight;
+ }
+ });
+ return $.on(el, 'error', ImageHover.error);
+ },
+ error: function() {
+ var URL, post, src, timeoutID,
+ _this = this;
+
+ if (!doc.contains(this)) {
+ return;
+ }
+ post = g.posts[this.dataset.fullid];
+ src = this.src.split('/');
+ if (src[2] === 'images.4chan.org') {
+ if (URL = Redirect.image(src[3], src[5].replace(/\?.+$/, ''))) {
+ this.src = URL;
+ return;
+ }
+ if (g.DEAD || post.isDead || post.file.isDead) {
+ return;
+ }
+ }
+ timeoutID = setTimeout((function() {
+ return _this.src = post.file.URL + '?' + Date.now();
+ }), 3000);
+ return $.ajax("//api.4chan.org/" + post.board + "/res/" + post.thread + ".json", {
+ onload: function() {
+ var postObj, _i, _len, _ref;
+
+ if (this.status !== 200) {
+ return;
+ }
+ _ref = JSON.parse(this.response).posts;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ postObj = _ref[_i];
+ if (postObj.no === post.ID) {
+ break;
+ }
+ }
+ if (postObj.no !== post.ID) {
+ clearTimeout(timeoutID);
+ return post.kill();
+ } else if (postObj.filedeleted) {
+ clearTimeout(timeoutID);
+ return post.kill(true);
+ }
+ }
+ });
+ }
+ };
+
+ ImageReplace = {
+ init: function() {
+ if (g.VIEW === 'catalog') {
+ return;
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Image Replace',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var URL, img, style, thumb, type, _ref, _ref1;
+
+ if (this.isClone || this.isHidden || this.thread.isHidden || !((_ref = this.file) != null ? _ref.isImage : void 0)) {
+ return;
+ }
+ _ref1 = this.file, thumb = _ref1.thumb, URL = _ref1.URL;
+ if (!(Conf["Replace " + ((type = (URL.match(/\w{3}$/))[0].toUpperCase()) === 'PEG' ? 'JPG' : type)] && !/spoiler/.test(thumb.src))) {
+ return;
+ }
+ if (this.file.isSpoiler) {
+ style = thumb.style;
+ style.maxHeight = style.maxWidth = this.isReply ? '125px' : '250px';
+ }
+ img = $.el('img');
+ $.on(img, 'load', function() {
+ return thumb.src = URL;
+ });
+ return img.src = URL;
+ }
+ };
+
+ RevealSpoilers = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Reveal Spoilers']) {
+ return;
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Reveal Spoilers',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var thumb, _ref;
+
+ if (this.isClone || !((_ref = this.file) != null ? _ref.isSpoiler : void 0)) {
+ return;
+ }
+ thumb = this.file.thumb;
+ thumb.removeAttribute('style');
+ return thumb.src = this.file.thumbURL;
+ }
+ };
+
+ ArchiveLink = {
+ init: function() {
+ var div, entry, type, _i, _len, _ref;
+
+ if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Archive Link']) {
+ return;
+ }
+ div = $.el('div', {
+ textContent: 'Archive'
+ });
+ entry = {
+ type: 'post',
+ el: div,
+ order: 90,
+ open: function(_arg) {
+ var ID, board, redirect, thread;
+
+ ID = _arg.ID, thread = _arg.thread, board = _arg.board;
+ redirect = Redirect.to({
+ postID: ID,
+ threadID: thread.ID,
+ boardID: board.ID
+ });
+ return redirect !== ("//boards.4chan.org/" + board + "/");
+ },
+ subEntries: []
+ };
+ _ref = [['Post', 'post'], ['Name', 'name'], ['Tripcode', 'tripcode'], ['E-mail', 'email'], ['Subject', 'subject'], ['Filename', 'filename'], ['Image MD5', 'MD5']];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ type = _ref[_i];
+ entry.subEntries.push(this.createSubEntry(type[0], type[1]));
+ }
+ return $.event('AddMenuEntry', entry);
+ },
+ createSubEntry: function(text, type) {
+ var el, open;
+
+ el = $.el('a', {
+ textContent: text,
+ target: '_blank'
+ });
+ open = type === 'post' ? function(_arg) {
+ var ID, board, thread;
+
+ ID = _arg.ID, thread = _arg.thread, board = _arg.board;
+ el.href = Redirect.to({
+ postID: ID,
+ threadID: thread.ID,
+ boardID: board.ID
+ });
+ return true;
+ } : function(post) {
+ var value;
+
+ value = Filter[type](post);
+ if (!value) {
+ return false;
+ }
+ el.href = Redirect.to({
+ boardID: post.board.ID,
+ type: type,
+ value: value,
+ isSearch: true
+ });
+ return true;
+ };
+ return {
+ el: el,
+ open: open
+ };
+ }
+ };
+
+ DeleteLink = {
+ init: function() {
+ var div, fileEl, fileEntry, postEl, postEntry;
+
+ if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Delete Link']) {
+ return;
+ }
+ div = $.el('div', {
+ className: 'delete-link',
+ textContent: 'Delete'
+ });
+ postEl = $.el('a', {
+ className: 'delete-post',
+ href: 'javascript:;'
+ });
+ fileEl = $.el('a', {
+ className: 'delete-file',
+ href: 'javascript:;'
+ });
+ postEntry = {
+ el: postEl,
+ open: function() {
+ postEl.textContent = 'Post';
+ $.on(postEl, 'click', DeleteLink["delete"]);
+ return true;
+ }
+ };
+ fileEntry = {
+ el: fileEl,
+ open: function(_arg) {
+ var file;
+
+ file = _arg.file;
+ if (!file || file.isDead) {
+ return false;
+ }
+ fileEl.textContent = 'File';
+ $.on(fileEl, 'click', DeleteLink["delete"]);
+ return true;
+ }
+ };
+ return $.event('AddMenuEntry', {
+ type: 'post',
+ el: div,
+ order: 40,
+ open: function(post) {
+ var node;
+
+ if (post.isDead) {
+ return false;
+ }
+ DeleteLink.post = post;
+ node = div.firstChild;
+ node.textContent = 'Delete';
+ DeleteLink.cooldown.start(post, node);
+ return true;
+ },
+ subEntries: [postEntry, fileEntry]
+ });
+ },
+ "delete": function() {
+ var fileOnly, form, link, m, post, pwd;
+
+ post = DeleteLink.post;
+ if (DeleteLink.cooldown.counting === post) {
+ return;
+ }
+ $.off(this, 'click', DeleteLink["delete"]);
+ this.textContent = "Deleting " + this.textContent + "...";
+ pwd = (m = d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : $.id('delPassword').value;
+ fileOnly = $.hasClass(this, 'delete-file');
+ form = {
+ mode: 'usrdel',
+ onlyimgdel: fileOnly,
+ pwd: pwd
+ };
+ form[post.ID] = 'delete';
+ link = this;
+ return $.ajax($.id('delform').action.replace("/" + g.BOARD + "/", "/" + post.board + "/"), {
+ onload: function() {
+ return DeleteLink.load(link, post, fileOnly, this.response);
+ },
+ onerror: function() {
+ return DeleteLink.error(link);
+ }
+ }, {
+ cred: true,
+ form: $.formData(form)
+ });
+ },
+ load: function(link, post, fileOnly, html) {
+ var msg, s, tmpDoc;
+
+ tmpDoc = d.implementation.createHTMLDocument('');
+ tmpDoc.documentElement.innerHTML = html;
+ if (tmpDoc.title === '4chan - Banned') {
+ s = 'Banned!';
+ } else if (msg = tmpDoc.getElementById('errmsg')) {
+ s = msg.textContent;
+ $.on(link, 'click', DeleteLink["delete"]);
+ } else {
+ if (tmpDoc.title === 'Updating index...') {
+ (post.origin || post).kill(fileOnly);
+ }
+ s = 'Deleted';
+ }
+ return link.textContent = s;
+ },
+ error: function(link) {
+ link.textContent = 'Connection error, please retry.';
+ return $.on(link, 'click', DeleteLink["delete"]);
+ },
+ cooldown: {
+ start: function(post, node) {
+ var length, seconds, _ref;
+
+ if (!((_ref = QR.db) != null ? _ref.get({
+ boardID: post.board.ID,
+ threadID: post.thread.ID,
+ postID: post.ID
+ }) : void 0)) {
+ delete DeleteLink.cooldown.counting;
+ return;
+ }
+ DeleteLink.cooldown.counting = post;
+ length = post.board.ID === 'q' ? 600 : 30;
+ seconds = Math.ceil((length * $.SECOND - (Date.now() - post.info.date)) / $.SECOND);
+ return DeleteLink.cooldown.count(post, seconds, length, node);
+ },
+ count: function(post, seconds, length, node) {
+ if (DeleteLink.cooldown.counting !== post) {
+ return;
+ }
+ if (!((0 <= seconds && seconds <= length))) {
+ if (DeleteLink.cooldown.counting === post) {
+ node.textContent = 'Delete';
+ delete DeleteLink.cooldown.counting;
+ }
+ return;
+ }
+ setTimeout(DeleteLink.cooldown.count, 1000, post, seconds - 1, length, node);
+ return node.textContent = "Delete (" + seconds + ")";
+ }
+ }
+ };
+
+ DownloadLink = {
+ init: function() {
+ var a;
+
+ if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Download Link']) {
return;
}
a = $.el('a', {
- href: "/" + this.board + "/res/" + this.thread + "#p" + this,
- className: this.isHidden ? 'filtered backlink' : 'backlink',
- textContent: (QuoteBacklink.funk(this.ID)) + (Conf['Mark Quotes of You'] && this.info.yours ? QuoteYou.text : '')
+ className: 'download-link',
+ textContent: 'Download file'
});
- _ref = this.quotes;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quote = _ref[_i];
- containers = [QuoteBacklink.getContainer(quote)];
- if ((post = g.posts[quote]) && post.nodes.backlinkContainer) {
- _ref1 = post.clones;
- for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
- clone = _ref1[_j];
- containers.push(clone.nodes.backlinkContainer);
- }
- }
- for (_k = 0, _len2 = containers.length; _k < _len2; _k++) {
- container = containers[_k];
- link = a.cloneNode(true);
- if (Conf['Quote Previewing']) {
- $.on(link, 'mouseover', QuotePreview.mouseover);
- }
- if (Conf['Quote Inlining']) {
- $.on(link, 'click', QuoteInline.toggle);
- }
- $.add(container, [$.tn(' '), link]);
- }
- }
- },
- secondNode: function() {
- var container;
+ return $.event('AddMenuEntry', {
+ type: 'post',
+ el: a,
+ order: 70,
+ open: function(_arg) {
+ var file;
- if (this.isClone && (this.origin.isReply || Conf['OP Backlinks'])) {
- this.nodes.backlinkContainer = $('.container', this.nodes.info);
- return;
- }
- if (!(this.isReply || Conf['OP Backlinks'])) {
- return;
- }
- container = QuoteBacklink.getContainer(this.fullID);
- this.nodes.backlinkContainer = container;
- return $.add(this.nodes.info, container);
- },
- getContainer: function(id) {
- var _base;
-
- return (_base = this.containers)[id] || (_base[id] = $.el('span', {
- className: 'container'
- }));
+ file = _arg.file;
+ if (!file) {
+ return false;
+ }
+ a.href = file.URL;
+ a.download = file.name;
+ return true;
+ }
+ });
}
};
- QuoteCT = {
+ Menu = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Mark Cross-thread Quotes']) {
+ if (g.VIEW === 'catalog' || !Conf['Menu']) {
return;
}
- if (Conf['Comment Expansion']) {
- ExpandComment.callbacks.push(this.node);
- }
- this.text = '\u00A0(Cross-thread)';
+ this.menu = new UI.Menu('post');
return Post.prototype.callbacks.push({
- name: 'Mark Cross-thread Quotes',
+ name: 'Menu',
cb: this.node
});
},
node: function() {
- var board, boardID, quotelink, quotelinks, quotes, thread, threadID, _i, _len, _ref, _ref1;
+ var button;
- if (this.isClone && this.thread === this.context.thread) {
+ button = Menu.makeButton(this);
+ if (this.isClone) {
+ $.replace($('.menu-button', this.nodes.info), button);
return;
}
- if (!(quotes = this.quotes).length) {
- return;
- }
- quotelinks = this.nodes.quotelinks;
- _ref = this.isClone ? this.context : this, board = _ref.board, thread = _ref.thread;
- for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
- quotelink = quotelinks[_i];
- _ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, threadID = _ref1.threadID;
- if (!threadID) {
- continue;
- }
- if (this.isClone) {
- quotelink.textContent = quotelink.textContent.replace(QuoteCT.text, '');
- }
- if (boardID === this.board.ID && threadID !== thread.ID) {
- $.add(quotelink, $.tn(QuoteCT.text));
- }
- }
- }
- };
-
- QuoteInline = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Quote Inlining']) {
- return;
- }
- if (Conf['Comment Expansion']) {
- ExpandComment.callbacks.push(this.node);
- }
- return Post.prototype.callbacks.push({
- name: 'Quote Inlining',
- cb: this.node
- });
+ return $.add(this.nodes.info, [$.tn('\u00A0'), button]);
},
- node: function() {
- var link, _i, _len, _ref;
+ makeButton: (function() {
+ var a;
- _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- link = _ref[_i];
- $.on(link, 'click', QuoteInline.toggle);
- }
- },
+ a = null;
+ return function(post) {
+ var clone;
+
+ a || (a = $.el('a', {
+ className: 'menu-button',
+ innerHTML: '[]',
+ href: 'javascript:;'
+ }));
+ clone = a.cloneNode(true);
+ clone.setAttribute('data-postid', post.fullID);
+ if (post.isClone) {
+ clone.setAttribute('data-clone', true);
+ }
+ $.on(clone, 'click', Menu.toggle);
+ return clone;
+ };
+ })(),
toggle: function(e) {
- var boardID, context, postID, threadID, _ref;
+ var post;
- if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
- return;
- }
- e.preventDefault();
- _ref = Get.postDataFromLink(this), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
- context = Get.contextFromLink(this);
- if ($.hasClass(this, 'inlined')) {
- QuoteInline.rm(this, boardID, threadID, postID, context);
- } else {
- if ($.x("ancestor::div[@id='p" + postID + "']", this)) {
- return;
- }
- QuoteInline.add(this, boardID, threadID, postID, context);
- }
- return this.classList.toggle('inlined');
- },
- findRoot: function(quotelink, isBacklink) {
- if (isBacklink) {
- return quotelink.parentNode.parentNode;
- } else {
- return $.x('ancestor-or-self::*[parent::blockquote][1]', quotelink);
- }
- },
- add: function(quotelink, boardID, threadID, postID, context) {
- var inline, isBacklink, post;
-
- isBacklink = $.hasClass(quotelink, 'backlink');
- inline = $.el('div', {
- id: "i" + postID,
- className: 'inline'
- });
- $.after(QuoteInline.findRoot(quotelink, isBacklink), inline);
- Get.postClone(boardID, threadID, postID, inline, context);
- if (!((post = g.posts["" + boardID + "." + postID]) && context.thread === post.thread)) {
- return;
- }
- if (isBacklink && Conf['Forward Hiding']) {
- $.addClass(post.nodes.root, 'forwarded');
- post.forwarded++ || (post.forwarded = 1);
- }
- if (!Unread.posts) {
- return;
- }
- return Unread.readSinglePost(post);
- },
- rm: function(quotelink, boardID, threadID, postID, context) {
- var el, inlined, isBacklink, post, root, _ref;
-
- isBacklink = $.hasClass(quotelink, 'backlink');
- root = QuoteInline.findRoot(quotelink, isBacklink);
- root = $.x("following-sibling::div[@id='i" + postID + "'][1]", root);
- $.rm(root);
- if (!(el = root.firstElementChild)) {
- return;
- }
- post = g.posts["" + boardID + "." + postID];
- post.rmClone(el.dataset.clone);
- if (Conf['Forward Hiding'] && isBacklink && context.thread === g.threads["" + boardID + "." + threadID] && !--post.forwarded) {
- delete post.forwarded;
- $.rmClass(post.nodes.root, 'forwarded');
- }
- while (inlined = $('.inlined', el)) {
- _ref = Get.postDataFromLink(inlined), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
- QuoteInline.rm(inlined, boardID, threadID, postID, context);
- $.rmClass(inlined, 'inlined');
- }
+ post = this.dataset.clone ? Get.postFromNode(this) : g.posts[this.dataset.postid];
+ return Menu.menu.toggle(e, this, post);
}
};
- QuoteOP = {
+ ReportLink = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Mark OP Quotes']) {
+ var a;
+
+ if (g.VIEW === 'catalog' || !Conf['Menu'] || !Conf['Report Link']) {
return;
}
- if (Conf['Comment Expansion']) {
- ExpandComment.callbacks.push(this.node);
+ a = $.el('a', {
+ className: 'report-link',
+ href: 'javascript:;',
+ textContent: 'Report this post'
+ });
+ $.on(a, 'click', ReportLink.report);
+ return $.event('AddMenuEntry', {
+ type: 'post',
+ el: a,
+ order: 10,
+ open: function(post) {
+ ReportLink.post = post;
+ return !post.isDead;
+ }
+ });
+ },
+ report: function() {
+ var id, post, set, url;
+
+ post = ReportLink.post;
+ url = "//sys.4chan.org/" + post.board + "/imgboard.php?mode=report&no=" + post;
+ id = Date.now();
+ set = "toolbar=0,scrollbars=0,location=0,status=1,menubar=0,resizable=1,width=685,height=200";
+ return window.open(url, id, set);
+ }
+ };
+
+ Favicon = {
+ init: function() {
+ return $.ready(function() {
+ var href;
+
+ Favicon.el = $('link[rel="shortcut icon"]', d.head);
+ Favicon.el.type = 'image/x-icon';
+ href = Favicon.el.href;
+ Favicon.SFW = /ws\.ico$/.test(href);
+ Favicon["default"] = href;
+ return Favicon["switch"]();
+ });
+ },
+ "switch": function() {
+ switch (Conf['favicon']) {
+ case 'ferongr':
+ Favicon.unreadDead = 'data:image/gif;base64,R0lGODlhEAAQAOMHAOgLAnMFAL8AAOgLAukMA/+AgP+rq////////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
+ Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAS1BMVEUAAAAAAAAAAAAJAAASAAAZAQAaAQAiAQAkAQAoFBQyAgAzAgA1AgA4AABBAgBXAwBzBQCEBgGvCAG/AADoCwLpDAP/gID/q6v///9zILr8AAAAA3RSTlMAx9dmesIgAAAAc0lEQVQY02WPgQ6DIBBDmTqnbE70Cvb/v3TAnW5OSKB9ybXg3HUBOAmEEH4FQtrSn4gxi+xjVC9SVOEiSvbZI8zSV+/Xo7icnryZ15GObMxvtWUkB/VJW57kHU7fUcHStm8FkncGE/mwP6CGzq/eauHwvT7sWQt3gZLW+AAAAABJRU5ErkJggg==';
+ Favicon.unreadSFW = 'data:image/gif;base64,R0lGODlhEAAQAOMHAADX8QBwfgC2zADX8QDY8nnl8qLp8v///////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
+ Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAASFBMVEUAAAAAAAAAAAAACAkAERMAGBsAGR0AISUALzQALzUAMTcANjwAP0cAVF8AcH4AeokAorYAtswA1/EA2PISIyV55fKi6fL////l+pZqAAAAA3RSTlMAx9dmesIgAAAAcklEQVQY02VPARLCIAxjsjnUWdcg6/9/ukIr00nvIMldEhrC/wHwA0BE3wBUtnICOStQnrNx5oqqzmzKx9vDPH1Nae3F9U4ig3OzjCIX51treYvMxou13EQmBPtHE14xLiawjgoPtfgOaKHP+9VrEXA8O1v7CmSPE3u0AAAAAElFTkSuQmCC';
+ Favicon.unreadNSFW = 'data:image/gif;base64,R0lGODlhEAAQAOMHAFT+ACh5AEncAFT+AFX/Acz/su7/5v///////////////////////////////////yH5BAEKAAcALAAAAAAQABAAAARZ8MhJ6xwDWIBv+AM1fEEIBIVRlNKYrtpIECuGzuwpCLg974EYiXUYkUItjGbC6VQ4omXFiKROA6qSy0A8nAo9GS3YCswIWnOvLAi0be23Z1QtdSUaqXcviQAAOw==';
+ Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAS1BMVEUAAAAAAAAAAAADCgAGEgAIGgAJGwALJAANJwASNwASOAATOgAVQQAWRAAeWwAgKBsoeQAwkQA/wABJ3ABU/gBV/wHM/7Lu/+b////r+K2AAAAAA3RSTlMAx9dmesIgAAAAc0lEQVQY02WPgQ6DIBBDmTonbk70Cvb/v3TAnW5OSKB9ybXg3HUBOAmEEH4FQtrSn4gxi+xjVC9SVOEiSvbZI8zSV+/Xo7icnryZ15GObMxvtWUmB/VJW0byDqfvqGBp20mB5J3Bi3zYH1BD38/eauHwvT7sEAt1Fb320QAAAABJRU5ErkJggg==';
+ break;
+ case 'xat-':
+ Favicon.unreadDead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA2ElEQVQ4y61TQQrCMBDMQ8WDIEV6LbT2A4og2Hq0veo7fIAH04dY9N4xmyYlpGmI2MCQTWYy3Wy2DAD7B2wWAzWgcTgVeZKlZRxHNYFi2jM18oBh0IcKtC6ixf22WT4IFLs0owxswXu9egm0Ls6bwfCFfNsJYJKfqoEkd3vgUgFVLWObtzNgVKyruC+ljSzr5OEnBzjvjcQecaQhbZgBb4CmGQw+PoMkTUtdbd8VSEPakcGxPOcsoIgUKy0LecY29BmdBrqRfjIwZ93KLs5loHvBnL3cLH/jF+C/+z5dgUysAAAAAElFTkSuQmCC';
+ Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACKkJGNkpN0d3d0eHdra2dGRkORZ1wAAACmaV6naV4PDw8LCwsLCwvyZWLyZWIeExEyFBTAWlr/eHj/enkAAAAKAAAoAAA4AAA4GhpMAACRAAD/AAD/enn/h4j/m5z/nJ3/0dL/0tL/0tP/09P///9VK8WFAAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uZfI0YOdiiMiJw+2CKIPkZzGtcbgKYIJaI26LAfQOzOqoYNA4Z49Nguv/gEEhw2/C5BUZgAAAABJRU5ErkJggg==';
+ Favicon.unreadSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA30lEQVQ4y2P4//8/AyWYgSoGQMF/GJ7Y11VVUVoyKTM9ey4Ig9ggMWQ1YA1IBvzXm34YjkH8mPyJB+Nqlp8FYRAbmxoMF6ArSNrw6T0Qf8Amh9cFMEWVR/7/A+L/uORxhgEIt5/+/3/2lf//5wAxiI0uj+4CBlBgxVUvOwtydgXQZpDmi2/+/7/0GmIQSAwkB1IDUkuUAZeABlx+g2zAZ9wGlAOjChba+LwAUgNSi2HA5Am9VciBhSsQQWyoWgZiovEDsdGI1QBYQiLJAGQalpSxyWEzAJYWkGm8clTJjQCZ1hkoVG0CygAAAABJRU5ErkJggg==';
+ Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACRjoqTkI13dXR4dXRpZ2tFQ0Zcb5EAAABee6ZefKcPDw8LCwsLCwtisPJisPIRFh4UJDJalMB4xP95xP8AAAABBQcHFx4KISoNLToaKzgaVW4ul8N5xP+Hy/+b1P+c1P/R7P/S6//S7P/T7P////9P0rk0AAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uUrk6MFOxRGRkwdbBNGHSE7jWmPwFMEEtEZdlgPonRmvoYNA4Z49Nguv/gEE3A2/sQ7iRgAAAABJRU5ErkJggg==';
+ Favicon.unreadNSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA4ElEQVQ4y2P4//8/AyWYgSoGQMF/GJ7YNbGqrKRiUnp21lwQBrFBYshqwBqQDPifdsYYjkH8mInxB+OWx58FYRAbmxoMF6ArKPmU9B6IP2CTw+sCmKKe/5X/gPg/LnmcYQDCs/63/1/9fzYQzwGz0eXRXcAACqy4ZfFnQc7u+V/xD6T55v+LQHwJbBBIDCQHUgNSS5QBt4Cab/2/jDDgMx4DykrKJ8FCG58XQGpAajEMmNw7uQo5sHAFIogNVctATDR+IDYasRoAS0gkGYBMw5IyNjlsBsDSAjKNV44quREAx58Mr9vt5wQAAAAASUVORK5CYII=';
+ Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAdVBMVEUAAAAAAACRipGTjZN2dHd2dHhna2pDRkVckV8AAABepl9ep18PDw8LCwsLCwt08mJ08mIRHhEYMhRpwFqM/3iM/3kAAAAECAIQIAgWLAseOBoePA86dB1mzDOM/3ma/4er/5ur/5zZ/9HZ/9La/9La/9P///85Jx7jAAAAFnRSTlMAPnp6kpKdtcHEzc3p6u7v8PT7/v7++jx7+QAAAIFJREFUGNONj90OgjAMhStKmU5k/h1UmAzUvv8jSrYBIeGC9qLtl/a0JVphAJKUOU36xNfWWiitlU9GUphZbXF/hxg10Li2QdQgPhQ3133c9XLOJvD9uZfI0YOdiiMiJw+2CKIPkZzGtcbgKYIJaI26LAfQOzOqoYNA4Z49Nguv/gEEhw2/C5BUZgAAAABJRU5ErkJggg==';
+ break;
+ case 'Mayhem':
+ Favicon.unreadDead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABIUlEQVQ4jZ2ScWuDMBDFgw4pIkU0WsoQkWAYIkXZH4N9/+/V3dmfXSrKYIFHwt17j8vdGWNMIkgFuaDgzgQnwRs4EQs5KdolUQtagRN0givEDBTEOjgtGs0Zq8F7cKqqusVxrMQLaDUWcjBSrXkn8gs51tpJSWLk9b3HUa0aNIL5gPBR1/V4kJvR7lTwl8GmAm1Gf9+c3S+89qBHa8502AsmSrtBaEBPbIbj0ah2madlNAPEccdgJDfAtWifBjqWKShRBT6KoiH8QlEUn/qt0CCjnNdmPUwmFWzj9Oe6LpKuZXcwqq88z78Pch3aZU3dPwwc2sWlfZKCW5tWluV8kGvXClLm6dYN4/aUqfCbnEOzNDGhGZbNargvxCzvMGfRJD8UaDVvgkzo6QAAAABJRU5ErkJggg==';
+ Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABj0lEQVQ4y42TQUorQRCGv+oekpj43pOhOyIiKoHBxTMkuAnEtWcwx/AY3sUbBIRcwCw8gCfIMkaTOOUiNdgGRRuKoav+v2qq/i4BakBmXweUwDoxLF5ZhVkC64rYBHYMUAIvwKuBMEwdaFiCNbAAngEC0NHkxBi73vsOsG92HGPsphigY1wOzfNhqhpC6AEd730RQuh9hQEOAY6A/jeAs3a7/f+bWB84ckCpqg+I8Osjgqo+AKUDViJS8LkGMcY+sJrNZssYY387LiIFsBLgL9AC/pgaArzZlF+sZgO4BG7sfgvcA3MxUtOStBIpX7cS3Klqd9OBTIEr4DlLOsuAmqpODXQOiHMuy/O8FkLoJth/6Uh2gQPg87Q3k+7leX6hqnpmPvM/GWfXWeWGqj5+oUS9LMs6wF7iHAwGJ9ZW5uxpup+UGwEtEVoijEYjKl66PJujmvIW3vsFwBiYqzJXZTweY5wSU6Bd7UP1KoECODUrJpOJAtPhcKjAtXGaYptWs57qWyv9Zn/it1a5knj5Dm3v4q8APeACAAAAAElFTkSuQmCC';
+ Favicon.unreadSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABCElEQVQ4jZ2S4crCMAxF+0OGDJEPKYrIGKOsiJSx/fJRfSAfTJNyKqXfiuDg0C25N2RJjTGmEVrhTzhw7oStsIEtsVzT4o2Jo9ALThiEM8IdHIgNaHo8mjNWg6/ske8bohPo+63QOLzmooHp8fyAICBSQkVz0QKdsFQEV6WSW/D+7+BbgbIDHcb4Kp61XyjyI16zZ8JemGltQtDBSGxB4/GoN+7TpkkjDCsFArm0IYv3U0BbnYtf8BCy+JytsE0X6VyuKhPPK/GAJ14kvZZDZVV3pZIb8MZr6n4o4PDGKn0S5SdDmyq5PnXQsk+Xbhinp03FFzmHJw6xYRiWm9VxnohZ3vOcxdO8ARmXRvbWdtzQAAAAAElFTkSuQmCC';
+ Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAkFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OztMTEyRkZHBwcH///9dzWZ0AAAAI3RSTlMEBggKDA4QEhQWFxkbHR8hIyUmKCosLjAxN1hbYc7P0dLc3mzWzBUAAAC+SURBVBjTNY3pcsIwEIM3ePERx/bG5IIe0NIrhVbv/3Y4Ydj9Ic030ogqpY3mDdGGi1EVsYuSvGE2Pkl0TFYAdLGuY1eMWGowzzN6kX41DYVpNbvdKlO4Jx5gSbi2VO+Vcq2jrc/jNLQhtM+n05PfkrKxG/oFHIEXqwqQsVRy7n+AtwLYL3sYR3wA755Jp3Vvv8cn8Js0GXmA7/P5TwzpiLn8MOALuEZNygkm5JTy/+vl4BRVbJvQ1NbWRSxXN64PGOBlhG0qAAAAAElFTkSuQmCC';
+ Favicon.unreadNSFW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABCklEQVQ4jZ2S0WrDMAxF/TBCCKWMYhZKCSGYmFJMSNjD/mhf239qJXNcjBdTWODgRLpXKJKNMaYROuFTOHEehFb4gJZYrunwxsSXMApOmIQzwgOciE1oRjyaM1aDj+yR7xuiHvT9VmgcXnPRwO/9+wWCgEgJFc1FCwzCVhFclUpuw/u3g3cFyg50GPOjePZ+ocjPeM2RCXthpbUFwQAzsQ2Nx6PeuE+bJo0w7BQI5NKGLN5XAW11LX7BQ8jia7bCLl2kc7mqTLzuxAOeeJH0Wk6VVf0oldyEN15T948CDm+sMiZRfjK0pZIbUwcd+3TphnF62lR8kXN44hAbhmG5WQNnT8zynucsnuYJhFpBfkMzqD4AAAAASUVORK5CYII=';
+ Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAkFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztMTExmzDORkZHBwcH///92I3mvAAAAI3RSTlMEBggKDA4QEhQWFxkbHR8hIyUmKCosLjAxN1hbYc7P0dLc3mzWzBUAAAC+SURBVBjTNY3pcsIwEIM3ePERx/bG5IIe0NIT0ur93w4nDLs/pPlGGlGltNG8IdpwMaoidlGSN8zGJ4mOyQqALtZ17IoRSw3meUYv0q+moTCtZrdbZQr3xAMsCdeW6r1SrnW09XmchjaE9vl0evJbUjZ2Q7+AI/BiVQEylkrO/TfwVgD7ZQ/jiA/g3TPptO7t9/gEfpImIw/wez7/iSEdMZcfBnwB16hJOcGEnFL+f70cnKKKbROa2tq6iOXqBuMXGTe4CAUbAAAAAElFTkSuQmCC';
+ break;
+ case 'Original':
+ Favicon.unreadDead = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
+ Favicon.unreadDeadY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAAKAAAoAAAoKCg4AAA4ODg7OztMAACRAADBwcH/AAD///+WCcPSAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQmAUAxEb4Isk0rwp3EPR3ECcRQrh7C3/nAasPwzmCgYuPBy5AH/NALSImqAK+H1oJRqyJVHNAnZqDITVhj7/PrAciJ9il0BHs/jjU+fnB9sQ0IxX6OBO6Xr0xKAxANLZzUanCWzZQAAAABJRU5ErkJggg==';
+ Favicon.unreadSFW = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAC6Xw////////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
+ Favicon.unreadSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OzvBwcH///8uS/CdAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQ2AUAhEbwKWoftRGvdwBEewchM7d9BFbE6pbP4Mgj+R5MjjwgP+qQSkRtQAV8K3lVI2Q648oknIRpWZsMI4988HjgvpU+wO8HgeHzR9cjZYhoRiPkcDd0rXpyUAiRd5YjKC7MvNRgAAAABJRU5ErkJggg==';
+ Favicon.unreadNSFW = 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAGbMM////////yH5BAEKAAMALAAAAAAQABAAAAI/nI95wsqygIRxDgGCBhTrwF3Zxowg5H1cSopS6FrGQ82PU1951ckRmYKJVCXizLRC9kAnT0aIiR6lCFT1cigAADs=';
+ Favicon.unreadNSFWY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAALVBMVEUAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztmzDPBwcH///+rsf3XAAAAA3RSTlMAx9dmesIgAAAAZ0lEQVQI1z2LsQ2AUAhEbwKWofRL4x6O4AhuopWb2P4F7E5prP4MgiaSHHlceMA/jYC0iBrgSnjdKaUacuURTUI2qsyEFcaxvD6wnkifYleAx/N449Mn5wfbkFDM52jgTun6tAQg8QAEvjQg42KY2AAAAABJRU5ErkJggg==';
}
- this.text = '\u00A0(OP)';
- return Post.prototype.callbacks.push({
- name: 'Mark OP Quotes',
+ if (Favicon.SFW) {
+ Favicon.unread = Favicon.unreadSFW;
+ return Favicon.unreadY = Favicon.unreadSFWY;
+ } else {
+ Favicon.unread = Favicon.unreadNSFW;
+ return Favicon.unreadY = Favicon.unreadNSFWY;
+ }
+ },
+ empty: 'data:image/gif;base64,R0lGODlhEAAQAJEAAAAAAP///9vb2////yH5BAEAAAMALAAAAAAQABAAAAIvnI+pq+D9DBAUoFkPFnbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw==',
+ dead: 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAIALAAAAAAQABAAAAIvlI+pq+D9DAgUoFkPDlbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw=='
+ };
+
+ ThreadExcerpt = {
+ init: function() {
+ if (g.VIEW !== 'thread' || !Conf['Thread Excerpt']) {
+ return;
+ }
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Excerpt',
cb: this.node
});
},
node: function() {
- var boardID, op, postID, quotelink, quotelinks, quotes, _i, _j, _len, _len1, _ref;
-
- if (this.isClone && this.thread === this.context.thread) {
- return;
- }
- if (!(quotes = this.quotes).length) {
- return;
- }
- quotelinks = this.nodes.quotelinks;
- if (this.isClone && quotes.contains(this.thread.fullID)) {
- for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
- quotelink = quotelinks[_i];
- quotelink.textContent = quotelink.textContent.replace(QuoteOP.text, '');
- }
- }
- op = (this.isClone ? this.context : this).thread.fullID;
- if (!quotes.contains(op)) {
- return;
- }
- for (_j = 0, _len1 = quotelinks.length; _j < _len1; _j++) {
- quotelink = quotelinks[_j];
- _ref = Get.postDataFromLink(quotelink), boardID = _ref.boardID, postID = _ref.postID;
- if (("" + boardID + "." + postID) === op) {
- $.add(quotelink, $.tn(QuoteOP.text));
- }
- }
+ return d.title = Get.threadExcerpt(this);
}
};
- QuotePreview = {
+ ThreadStats = {
init: function() {
- if (g.VIEW === 'catalog' || !Conf['Quote Previewing']) {
+ var sc;
+
+ if (g.VIEW !== 'thread' || !Conf['Thread Stats']) {
return;
}
- if (Conf['Comment Expansion']) {
- ExpandComment.callbacks.push(this.node);
- }
- return Post.prototype.callbacks.push({
- name: 'Quote Previewing',
+ this.dialog = sc = $.el('span', {
+ innerHTML: "0 / 0",
+ id: 'thread-stats'
+ });
+ this.postCountEl = $('#post-count', sc);
+ this.fileCountEl = $('#file-count', sc);
+ Header.addShortcut(sc);
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Stats',
cb: this.node
});
},
node: function() {
- var link, _i, _len, _ref;
+ var ID, fileCount, post, postCount, _ref;
- _ref = this.nodes.quotelinks.concat(__slice.call(this.nodes.backlinks));
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- link = _ref[_i];
- $.on(link, 'mouseover', QuotePreview.mouseover);
+ postCount = 0;
+ fileCount = 0;
+ _ref = this.posts;
+ for (ID in _ref) {
+ post = _ref[ID];
+ postCount++;
+ if (post.file) {
+ fileCount++;
+ }
}
+ ThreadStats.thread = this;
+ ThreadStats.update(postCount, fileCount);
+ return $.on(d, 'ThreadUpdate', ThreadStats.onUpdate);
},
- mouseover: function(e) {
- var boardID, clone, origin, post, postID, posts, qp, quote, quoterID, threadID, _i, _j, _len, _len1, _ref, _ref1;
+ onUpdate: function(e) {
+ var fileCount, postCount, _ref;
- if ($.hasClass(this, 'inlined')) {
+ if (e.detail[404]) {
return;
}
- _ref = Get.postDataFromLink(this), boardID = _ref.boardID, threadID = _ref.threadID, postID = _ref.postID;
- qp = $.el('div', {
- id: 'qp',
- className: 'dialog'
- });
- $.add(Header.hover, qp);
- Get.postClone(boardID, threadID, postID, qp, Get.contextFromLink(this));
- UI.hover({
- root: this,
- el: qp,
- latestEvent: e,
- endEvents: 'mouseout click',
- cb: QuotePreview.mouseout,
- asapTest: function() {
- return qp.firstElementChild;
- }
- });
- if (!(origin = g.posts["" + boardID + "." + postID])) {
- return;
- }
- if (Conf['Quote Highlighting']) {
- posts = [origin].concat(origin.clones);
- posts.pop();
- for (_i = 0, _len = posts.length; _i < _len; _i++) {
- post = posts[_i];
- $.addClass(post.nodes.post, 'qphl');
- }
- }
- quoterID = $.x('ancestor::*[@id][1]', this).id.match(/\d+$/)[0];
- clone = Get.postFromRoot(qp.firstChild);
- _ref1 = clone.nodes.quotelinks.concat(__slice.call(clone.nodes.backlinks));
- for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
- quote = _ref1[_j];
- if (quote.hash.slice(2) === quoterID) {
- $.addClass(quote, 'forwardlink');
- }
- }
+ _ref = e.detail, postCount = _ref.postCount, fileCount = _ref.fileCount;
+ return ThreadStats.update(postCount, fileCount);
},
- mouseout: function() {
- var clone, post, root, _i, _len, _ref;
+ update: function(postCount, fileCount) {
+ var fileCountEl, postCountEl, thread;
- if (!(root = this.el.firstElementChild)) {
- return;
- }
- clone = Get.postFromRoot(root);
- post = clone.origin;
- post.rmClone(root.dataset.clone);
- if (!Conf['Quote Highlighting']) {
- return;
- }
- _ref = [post].concat(post.clones);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- post = _ref[_i];
- $.rmClass(post.nodes.post, 'qphl');
- }
+ thread = ThreadStats.thread, postCountEl = ThreadStats.postCountEl, fileCountEl = ThreadStats.fileCountEl;
+ postCountEl.textContent = postCount;
+ fileCountEl.textContent = fileCount;
+ (thread.postLimit && !thread.isSticky ? $.addClass : $.rmClass)(postCountEl, 'warning');
+ return (thread.fileLimit && !thread.isSticky ? $.addClass : $.rmClass)(fileCountEl, 'warning');
}
};
- /*
- <3 aeosynth
- */
-
-
- QuoteThreading = {
+ ThreadUpdater = {
init: function() {
- var input;
+ var checked, conf, el, input, name, sc, settings, subEntries, _ref;
- if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
+ if (g.VIEW !== 'thread' || !Conf['Thread Updater']) {
return;
}
- this.enabled = true;
- this.controls = $.el('span', {
- innerHTML: ''
+ checked = Conf['Auto Update'] ? 'checked' : '';
+ this.dialog = sc = $.el('span', {
+ innerHTML: "",
+ id: 'updater'
+ });
+ this.timer = $('#update-timer', sc);
+ this.status = $('#update-status', sc);
+ $.on(this.timer, 'click', ThreadUpdater.update);
+ $.on(this.status, 'click', ThreadUpdater.update);
+ this.checkPostCount = 0;
+ Header.addShortcut(sc);
+ subEntries = [];
+ _ref = Config.updater.checkbox;
+ for (name in _ref) {
+ conf = _ref[name];
+ checked = Conf[name] ? 'checked' : '';
+ el = $.el('label', {
+ title: "" + conf[1],
+ innerHTML: " " + name
+ });
+ input = el.firstElementChild;
+ $.on(input, 'change', $.cb.checked);
+ if (input.name === 'Scroll BG') {
+ $.on(input, 'change', ThreadUpdater.cb.scrollBG);
+ ThreadUpdater.cb.scrollBG();
+ }
+ subEntries.push({
+ el: el
+ });
+ }
+ settings = $.el('span', {
+ innerHTML: 'Interval'
+ });
+ $.on(settings, 'click', this.intervalShortcut);
+ subEntries.push({
+ el: settings
});
- input = $('input', this.controls);
- $.on(input, 'change', QuoteThreading.toggle);
$.event('AddMenuEntry', {
type: 'header',
- el: this.controls,
- order: 98
+ el: $.el('span', {
+ textContent: 'Updater'
+ }),
+ order: 110,
+ subEntries: subEntries
});
- $.on(d, '4chanXInitFinished', this.setup);
- return Post.prototype.callbacks.push({
- name: 'Quote Threading',
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Updater',
cb: this.node
});
},
- setup: function() {
- var ID, post, posts;
-
- $.off(d, '4chanXInitFinished', QuoteThreading.setup);
- posts = g.posts;
- for (ID in posts) {
- post = posts[ID];
- if (post.cb) {
- post.cb.call(post);
- }
- }
- return QuoteThreading.hasRun = true;
- },
node: function() {
- var ID, fullID, keys, len, post, posts, qid, quote, quotes, uniq, _i, _len;
+ ThreadUpdater.thread = this;
+ ThreadUpdater.root = this.OP.nodes.root.parentNode;
+ ThreadUpdater.lastPost = +ThreadUpdater.root.lastElementChild.id.match(/\d+/)[0];
+ ThreadUpdater.outdateCount = 0;
+ ThreadUpdater.lastModified = '0';
+ ThreadUpdater.cb.interval.call($.el('input', {
+ value: Conf['Interval']
+ }));
+ $.on(window, 'online offline', ThreadUpdater.cb.online);
+ $.on(d, 'QRPostSuccessful', ThreadUpdater.cb.post);
+ $.on(d, 'visibilitychange', ThreadUpdater.cb.visibility);
+ return ThreadUpdater.cb.online();
+ },
+ /*
+ http://freesound.org/people/pierrecartoons1979/sounds/90112/
+ cc-by-nc-3.0
+ */
- if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) {
+ beep: 'data:audio/wav;base64,UklGRjQDAABXQVZFZm10IBAAAAABAAEAgD4AAIA+AAABAAgAc21wbDwAAABBAAADAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkYXRhzAIAAGMms8em0tleMV4zIpLVo8nhfSlcPR102Ki+5JspVEkdVtKzs+K1NEhUIT7DwKrcy0g6WygsrM2k1NpiLl0zIY/WpMrjgCdbPhxw2Kq+5Z4qUkkdU9K1s+K5NkVTITzBwqnczko3WikrqM+l1NxlLF0zIIvXpsnjgydZPhxs2ay95aIrUEkdUdC3suK8N0NUIjq+xKrcz002WioppdGm091pK1w0IIjYp8jkhydXPxxq2K295aUrTkoeTs65suK+OUFUIzi7xqrb0VA0WSoootKm0t5tKlo1H4TYqMfkiydWQBxm16+85actTEseS8y7seHAPD9TIza5yKra01QyWSson9On0d5wKVk2H4DYqcfkjidUQB1j1rG75KsvSkseScu8seDCPz1TJDW2yara1FYxWSwnm9Sn0N9zKVg2H33ZqsXkkihSQR1g1bK65K0wSEsfR8i+seDEQTxUJTOzy6rY1VowWC0mmNWoz993KVc3H3rYq8TklSlRQh1d1LS647AyR0wgRMbAsN/GRDpTJTKwzKrX1l4vVy4lldWpzt97KVY4IXbUr8LZljVPRCxhw7W3z6ZISkw1VK+4sMWvXEhSPk6buay9sm5JVkZNiLWqtrJ+TldNTnquqbCwilZXU1BwpKirrpNgWFhTaZmnpquZbFlbVmWOpaOonHZcXlljhaGhpZ1+YWBdYn2cn6GdhmdhYGN3lp2enIttY2Jjco+bnJuOdGZlZXCImJqakHpoZ2Zug5WYmZJ/bGlobX6RlpeSg3BqaW16jZSVkoZ0bGtteImSk5KIeG5tbnaFkJKRinxxbm91gY2QkIt/c3BwdH6Kj4+LgnZxcXR8iI2OjIR5c3J0e4WLjYuFe3VzdHmCioyLhn52dHR5gIiKioeAeHV1eH+GiYqHgXp2dnh9hIiJh4J8eHd4fIKHiIeDfXl4eHyBhoeHhH96eHmA',
+ cb: {
+ online: function() {
+ if (ThreadUpdater.online = navigator.onLine) {
+ ThreadUpdater.outdateCount = 0;
+ ThreadUpdater.set('timer', ThreadUpdater.getInterval());
+ ThreadUpdater.update();
+ ThreadUpdater.set('status', null, null);
+ } else {
+ ThreadUpdater.set('timer', null);
+ ThreadUpdater.set('status', 'Offline', 'warning');
+ }
+ return ThreadUpdater.cb.autoUpdate();
+ },
+ post: function(e) {
+ if (e.detail.threadID !== ThreadUpdater.thread.ID) {
+ return;
+ }
+ ThreadUpdater.outdateCount = 0;
+ if (ThreadUpdater.seconds > 2) {
+ return setTimeout(ThreadUpdater.update, 1000);
+ }
+ },
+ checkpost: function() {
+ if (!(g.DEAD || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 10)) {
+ return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * 500);
+ }
+ ThreadUpdater.checkPostCount = 0;
+ delete ThreadUpdater.foundPost;
+ return delete ThreadUpdater.postID;
+ },
+ visibility: function() {
+ if (d.hidden) {
+ return;
+ }
+ ThreadUpdater.outdateCount = 0;
+ if (ThreadUpdater.seconds > ThreadUpdater.interval) {
+ return ThreadUpdater.set('timer', ThreadUpdater.getInterval());
+ }
+ },
+ scrollBG: function() {
+ return ThreadUpdater.scrollBG = Conf['Scroll BG'] ? function() {
+ return true;
+ } : function() {
+ return !d.hidden;
+ };
+ },
+ autoUpdate: function() {
+ if (ThreadUpdater.online) {
+ return ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
+ } else {
+ return clearTimeout(ThreadUpdater.timeoutID);
+ }
+ },
+ interval: function() {
+ var val;
+
+ val = +this.value;
+ if (val < 1) {
+ val = 1;
+ }
+ ThreadUpdater.interval = this.value = val;
+ return $.cb.value.call(this);
+ },
+ load: function() {
+ var klass, req, text, _ref;
+
+ req = ThreadUpdater.req;
+ switch (req.status) {
+ case 200:
+ g.DEAD = false;
+ ThreadUpdater.parse(JSON.parse(req.response).posts);
+ ThreadUpdater.lastModified = req.getResponseHeader('Last-Modified');
+ ThreadUpdater.set('timer', ThreadUpdater.getInterval());
+ break;
+ case 404:
+ g.DEAD = true;
+ ThreadUpdater.set('timer', null);
+ ThreadUpdater.set('status', '404', 'warning');
+ clearTimeout(ThreadUpdater.timeoutID);
+ ThreadUpdater.thread.kill();
+ $.event('ThreadUpdate', {
+ 404: true,
+ thread: ThreadUpdater.thread
+ });
+ break;
+ default:
+ ThreadUpdater.outdateCount++;
+ ThreadUpdater.set('timer', ThreadUpdater.getInterval());
+ /*
+ Status Code 304: Not modified
+ By sending the `If-Modified-Since` header we get a proper status code, and no response.
+ This saves bandwidth for both the user and the servers and avoid unnecessary computation.
+ */
+
+ _ref = [0, 304].contains(req.status) ? [null, null] : ["" + req.statusText + " (" + req.status + ")", 'warning'], text = _ref[0], klass = _ref[1];
+ ThreadUpdater.set('status', text, klass);
+ }
+ if (ThreadUpdater.postID) {
+ ThreadUpdater.cb.checkpost(this.status);
+ }
+ return delete ThreadUpdater.req;
+ }
+ },
+ getInterval: function() {
+ var i, j;
+
+ i = ThreadUpdater.interval;
+ j = Math.min(ThreadUpdater.outdateCount, 10);
+ if (!d.hidden) {
+ j = Math.min(j, 7);
+ }
+ return ThreadUpdater.seconds = Conf['Optional Increase'] ? Math.max(i, [0, 5, 10, 15, 20, 30, 60, 90, 120, 240, 300][j]) : i;
+ },
+ intervalShortcut: function() {
+ var settings;
+
+ Settings.open('Advanced');
+ settings = $.id('fourchanx-settings');
+ return $('input[name=Interval]', settings).focus();
+ },
+ set: function(name, text, klass) {
+ var el, node;
+
+ el = ThreadUpdater[name];
+ if (node = el.firstChild) {
+ node.data = text;
+ } else {
+ el.textContent = text;
+ }
+ if (klass !== void 0) {
+ return el.className = klass;
+ }
+ },
+ timeout: function() {
+ var n;
+
+ ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
+ if (!(n = --ThreadUpdater.seconds)) {
+ return ThreadUpdater.update();
+ } else if (n <= -60) {
+ ThreadUpdater.set('status', 'Retrying', null);
+ return ThreadUpdater.update();
+ } else if (n > 0) {
+ return ThreadUpdater.set('timer', n);
+ }
+ },
+ update: function() {
+ var url;
+
+ if (!ThreadUpdater.online) {
return;
}
- quotes = this.quotes, ID = this.ID, fullID = this.fullID;
- posts = g.posts;
- if (!(post = posts[fullID]) || post.isHidden) {
+ ThreadUpdater.seconds = 0;
+ ThreadUpdater.set('timer', '...');
+ if (ThreadUpdater.req) {
+ ThreadUpdater.req.onloadend = null;
+ ThreadUpdater.req.abort();
+ }
+ url = "//api.4chan.org/" + ThreadUpdater.thread.board + "/res/" + ThreadUpdater.thread + ".json";
+ return ThreadUpdater.req = $.ajax(url, {
+ onloadend: ThreadUpdater.cb.load
+ }, {
+ headers: {
+ 'If-Modified-Since': ThreadUpdater.lastModified
+ }
+ });
+ },
+ updateThreadStatus: function(title, OP) {
+ var icon, message, root, titleLC;
+
+ titleLC = title.toLowerCase();
+ if (ThreadUpdater.thread["is" + title] === !!OP[titleLC]) {
return;
}
- uniq = {};
- len = ("" + g.BOARD).length + 1;
- for (_i = 0, _len = quotes.length; _i < _len; _i++) {
- quote = quotes[_i];
- qid = quote;
- if (!(qid.slice(len) < ID)) {
+ if (!(ThreadUpdater.thread["is" + title] = !!OP[titleLC])) {
+ message = title === 'Sticky' ? 'The thread is not a sticky anymore.' : 'The thread is not closed anymore.';
+ new Notification('info', message, 30);
+ $.rm($("." + titleLC + "Icon", ThreadUpdater.thread.OP.nodes.info));
+ return;
+ }
+ message = title === 'Sticky' ? 'The thread is now a sticky.' : 'The thread is now closed.';
+ new Notification('info', message, 30);
+ icon = $.el('img', {
+ src: "//static.4chan.org/image/" + titleLC + ".gif",
+ alt: title,
+ title: title,
+ className: "" + titleLC + "Icon"
+ });
+ root = $('[title="Quote this post"]', ThreadUpdater.thread.OP.nodes.info);
+ if (title === 'Closed') {
+ root = $('.stickyIcon', ThreadUpdater.thread.OP.nodes.info) || root;
+ }
+ return $.after(root, [$.tn(' '), icon]);
+ },
+ parse: function(postObjects) {
+ var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, scroll, _i, _len, _ref;
+
+ OP = postObjects[0];
+ Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
+ ThreadUpdater.updateThreadStatus('Sticky', OP);
+ ThreadUpdater.updateThreadStatus('Closed', OP);
+ ThreadUpdater.thread.postLimit = !!OP.bumplimit;
+ ThreadUpdater.thread.fileLimit = !!OP.imagelimit;
+ posts = [];
+ index = [];
+ files = [];
+ count = 0;
+ for (_i = 0, _len = postObjects.length; _i < _len; _i++) {
+ postObject = postObjects[_i];
+ num = postObject.no;
+ index.push(num);
+ if (postObject.fsize) {
+ files.push(num);
+ }
+ if (num <= ThreadUpdater.lastPost) {
continue;
}
- if (qid in posts) {
- uniq[qid.slice(len)] = true;
+ count++;
+ node = Build.postFromObject(postObject, ThreadUpdater.thread.board);
+ posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
+ }
+ deletedPosts = [];
+ deletedFiles = [];
+ _ref = ThreadUpdater.thread.posts;
+ for (ID in _ref) {
+ post = _ref[ID];
+ ID = +ID;
+ if (post.isDead && index.contains(ID)) {
+ post.resurrect();
+ } else if (!index.contains(ID)) {
+ post.kill();
+ deletedPosts.push(post);
+ } else if (post.file && !post.file.isDead && !files.contains(ID)) {
+ post.kill(true);
+ deletedFiles.push(post);
+ }
+ if (ThreadUpdater.postID) {
+ if (ID === ThreadUpdater.postID) {
+ ThreadUpdater.foundPost = true;
+ }
}
}
- keys = Object.keys(uniq);
- if (keys.length !== 1) {
+ if (!count) {
+ ThreadUpdater.set('status', null, null);
+ ThreadUpdater.outdateCount++;
+ } else {
+ ThreadUpdater.set('status', "+" + count, 'new');
+ ThreadUpdater.outdateCount = 0;
+ if (Conf['Beep'] && d.hidden && Unread.posts && !Unread.posts.length) {
+ if (!ThreadUpdater.audio) {
+ ThreadUpdater.audio = $.el('audio', {
+ src: ThreadUpdater.beep
+ });
+ }
+ ThreadUpdater.audio.play();
+ }
+ ThreadUpdater.lastPost = posts[count - 1].ID;
+ Main.callbackNodes(Post, posts);
+ scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25;
+ for (key in posts) {
+ post = posts[key];
+ if (!posts.hasOwnProperty(key)) {
+ continue;
+ }
+ if (post.cb) {
+ if (!post.cb.call(post)) {
+ $.add(ThreadUpdater.root, post.nodes.root);
+ }
+ } else {
+ $.add(ThreadUpdater.root, post.nodes.root);
+ }
+ }
+ if (scroll) {
+ if (Conf['Bottom Scroll']) {
+ d.body.scrollTop = d.body.clientHeight;
+ } else {
+ Header.scrollToPost(nodes[0]);
+ }
+ }
+ $.queueTask(function() {
+ var length, threadID;
+
+ threadID = ThreadUpdater.thread.ID;
+ length = $$('.thread > .postContainer', ThreadUpdater.root).length;
+ return Fourchan.parseThread(threadID, length - count, length);
+ });
+ }
+ return $.event('ThreadUpdate', {
+ 404: false,
+ thread: ThreadUpdater.thread,
+ newPosts: posts,
+ deletedPosts: deletedPosts,
+ deletedFiles: deletedFiles,
+ postCount: OP.replies + 1,
+ fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead)
+ });
+ }
+ };
+
+ ThreadWatcher = {
+ init: function() {
+ if (!Conf['Thread Watcher']) {
return;
}
- this.threaded = "" + g.BOARD + "." + keys[0];
- return this.cb = QuoteThreading.nodeinsert;
+ this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', 'Thread Watcher
');
+ $.on(d, 'QRPostSuccessful', this.cb.post);
+ $.on(d, '4chanXInitFinished', this.ready);
+ $.sync('WatchedThreads', this.refresh);
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Watcher',
+ cb: this.node
+ });
},
- nodeinsert: function() {
- var bottom, height, posts, qpost, qroot, threadContainer, top, _ref;
+ node: function() {
+ var favicon,
+ _this = this;
- posts = g.posts;
- qpost = posts[this.threaded];
- delete this.threaded;
- delete this.cb;
- if (this.thread.OP === qpost) {
- return false;
+ favicon = $.el('img', {
+ className: 'favicon'
+ });
+ $.on(favicon, 'click', ThreadWatcher.cb.toggle);
+ $.before($('input', this.OP.nodes.post), favicon);
+ if (g.VIEW !== 'thread') {
+ return;
}
- if (QuoteThreading.hasRun) {
- height = doc.clientHeight;
- _ref = qpost.nodes.root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top;
- if (!(Unread.posts.contains(qpost) || ((bottom < height) && (top > 0)))) {
+ return $.get('AutoWatch', 0, function(item) {
+ if (item['AutoWatch'] !== _this.ID) {
+ return;
+ }
+ ThreadWatcher.watch(_this);
+ return $["delete"]('AutoWatch');
+ });
+ },
+ ready: function() {
+ $.off(d, '4chanXInitFinished', ThreadWatcher.ready);
+ if (!Main.isThisPageLegit()) {
+ return;
+ }
+ ThreadWatcher.refresh();
+ return $.add(d.body, ThreadWatcher.dialog);
+ },
+ refresh: function(watched) {
+ var ID, board, div, favicon, id, link, nodes, props, thread, x, _ref, _ref1;
+
+ if (!watched) {
+ $.get('WatchedThreads', {}, function(item) {
+ return ThreadWatcher.refresh(item['WatchedThreads']);
+ });
+ return;
+ }
+ nodes = [$('.move', ThreadWatcher.dialog)];
+ for (board in watched) {
+ _ref = watched[board];
+ for (id in _ref) {
+ props = _ref[id];
+ x = $.el('a', {
+ textContent: '×',
+ href: 'javascript:;'
+ });
+ $.on(x, 'click', ThreadWatcher.cb.x);
+ link = $.el('a', props);
+ link.title = link.textContent;
+ div = $.el('div');
+ $.add(div, [x, $.tn(' '), link]);
+ nodes.push(div);
+ }
+ }
+ $.rmAll(ThreadWatcher.dialog);
+ $.add(ThreadWatcher.dialog, nodes);
+ watched = watched[g.BOARD] || {};
+ _ref1 = g.BOARD.threads;
+ for (ID in _ref1) {
+ thread = _ref1[ID];
+ favicon = $('.favicon', thread.OP.nodes.post);
+ favicon.src = ID in watched ? Favicon["default"] : Favicon.empty;
+ }
+ },
+ cb: {
+ toggle: function() {
+ return ThreadWatcher.toggle(Get.postFromNode(this).thread);
+ },
+ x: function() {
+ var thread;
+
+ thread = this.nextElementSibling.pathname.split('/');
+ return ThreadWatcher.unwatch(thread[1], thread[3]);
+ },
+ post: function(e) {
+ var board, postID, threadID, _ref;
+
+ _ref = e.detail, board = _ref.board, postID = _ref.postID, threadID = _ref.threadID;
+ if (postID === threadID) {
+ if (Conf['Auto Watch']) {
+ return $.set('AutoWatch', threadID);
+ }
+ } else if (Conf['Auto Watch Reply']) {
+ return ThreadWatcher.watch(board.threads[threadID]);
+ }
+ }
+ },
+ toggle: function(thread) {
+ if ($('.favicon', thread.OP.nodes.post).src === Favicon.empty) {
+ return ThreadWatcher.watch(thread);
+ } else {
+ return ThreadWatcher.unwatch(thread.board, thread.ID);
+ }
+ },
+ unwatch: function(board, threadID) {
+ return $.get('WatchedThreads', {}, function(item) {
+ var watched;
+
+ watched = item['WatchedThreads'];
+ delete watched[board][threadID];
+ if (!Object.keys(watched[board]).length) {
+ delete watched[board];
+ }
+ ThreadWatcher.refresh(watched);
+ return $.set('WatchedThreads', watched);
+ });
+ },
+ watch: function(thread) {
+ return $.get('WatchedThreads', {}, function(item) {
+ var watched, _name;
+
+ watched = item['WatchedThreads'];
+ watched[_name = thread.board] || (watched[_name] = {});
+ watched[thread.board][thread] = {
+ href: "/" + thread.board + "/res/" + thread,
+ textContent: Get.threadExcerpt(thread)
+ };
+ ThreadWatcher.refresh(watched);
+ return $.set('WatchedThreads', watched);
+ });
+ }
+ };
+
+ Unread = {
+ init: function() {
+ if (g.VIEW !== 'thread' || !Conf['Unread Count'] && !Conf['Unread Favicon']) {
+ return;
+ }
+ this.db = new DataBoard('lastReadPosts', this.sync);
+ this.hr = $.el('hr', {
+ id: 'unread-line'
+ });
+ this.posts = [];
+ this.postsQuotingYou = [];
+ return Thread.prototype.callbacks.push({
+ name: 'Unread',
+ cb: this.node
+ });
+ },
+ node: function() {
+ Unread.thread = this;
+ Unread.title = d.title;
+ Unread.lastReadPost = Unread.db.get({
+ boardID: this.board.ID,
+ threadID: this.ID,
+ defaultValue: 0
+ });
+ $.on(d, '4chanXInitFinished', Unread.ready);
+ $.on(d, 'ThreadUpdate', Unread.onUpdate);
+ $.on(d, 'scroll visibilitychange', Unread.read);
+ if (Conf['Unread Line']) {
+ $.on(d, 'visibilitychange', Unread.setLine);
+ }
+ if (Conf['Scroll to Last Read Post']) {
+ return $.on(window, 'load', Unread.scroll);
+ }
+ },
+ ready: function() {
+ var ID, post, posts, _ref;
+
+ $.off(d, '4chanXInitFinished', Unread.ready);
+ posts = [];
+ _ref = Unread.thread.posts;
+ for (ID in _ref) {
+ post = _ref[ID];
+ if (post.isReply) {
+ posts.push(post);
+ }
+ }
+ return Unread.addPosts(posts);
+ },
+ scroll: function() {
+ var hash, post, posts, prevID, root;
+
+ if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
+ return;
+ }
+ if (Unread.posts.length) {
+ prevID = 0;
+ while (root = $.x('preceding-sibling::div[contains(@class,"postContainer")][1]', Unread.posts[0].nodes.root)) {
+ post = Get.postFromRoot(root);
+ if (prevID === post.ID) {
+ break;
+ }
+ prevID = post.ID;
+ if (!post.isHidden) {
+ break;
+ }
+ }
+ root.scrollIntoView(false);
+ return;
+ }
+ posts = Object.keys(Unread.thread.posts);
+ return Header.scrollToPost(Unread.thread.posts[posts[posts.length - 1]].nodes.root);
+ },
+ sync: function() {
+ var lastReadPost;
+
+ lastReadPost = Unread.db.get({
+ boardID: Unread.thread.board.ID,
+ threadID: Unread.thread.ID,
+ defaultValue: 0
+ });
+ if (!(Unread.lastReadPost < lastReadPost)) {
+ return;
+ }
+ Unread.lastReadPost = lastReadPost;
+ Unread.readArray(Unread.posts);
+ Unread.readArray(Unread.postsQuotingYou);
+ Unread.setLine();
+ return Unread.update();
+ },
+ addPosts: function(newPosts) {
+ var ID, data, post, _i, _len;
+
+ for (_i = 0, _len = newPosts.length; _i < _len; _i++) {
+ post = newPosts[_i];
+ ID = post.ID;
+ if (ID <= Unread.lastReadPost || post.isHidden) {
+ continue;
+ }
+ if (QR.db) {
+ data = {
+ boardID: post.board.ID,
+ threadID: post.thread.ID,
+ postID: post.ID
+ };
+ if (QR.db.get(data)) {
+ continue;
+ }
+ }
+ Unread.posts.push(post);
+ Unread.addPostQuotingYou(post);
+ }
+ if (Conf['Unread Line']) {
+ Unread.setLine(newPosts.contains(Unread.posts[0]));
+ }
+ Unread.read();
+ return Unread.update();
+ },
+ addPostQuotingYou: function(post) {
+ var quotelink, _i, _len, _ref;
+
+ if (!QR.db) {
+ return;
+ }
+ _ref = post.nodes.quotelinks;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ quotelink = _ref[_i];
+ if (QR.db.get(Get.postDataFromLink(quotelink))) {
+ Unread.postsQuotingYou.push(post);
+ }
+ }
+ },
+ onUpdate: function(e) {
+ if (e.detail[404]) {
+ return Unread.update();
+ } else {
+ return Unread.addPosts(e.detail.newPosts);
+ }
+ },
+ readSinglePost: function(post) {
+ var i;
+
+ if ((i = Unread.posts.indexOf(post)) === -1) {
+ return;
+ }
+ Unread.posts.splice(i, 1);
+ if (i === 0) {
+ Unread.lastReadPost = post.ID;
+ Unread.saveLastReadPost();
+ }
+ if ((i = Unread.postsQuotingYou.indexOf(post)) !== -1) {
+ Unread.postsQuotingYou.splice(i, 1);
+ }
+ return Unread.update();
+ },
+ readArray: function(arr) {
+ var i, post, _i, _len;
+
+ for (i = _i = 0, _len = arr.length; _i < _len; i = ++_i) {
+ post = arr[i];
+ if (post.ID > Unread.lastReadPost) {
+ break;
+ }
+ }
+ return arr.splice(0, i);
+ },
+ read: $.debounce(50, function(e) {
+ var ID, bottom, height, i, post, posts, read;
+
+ if (d.hidden || !Unread.posts.length) {
+ return;
+ }
+ height = doc.clientHeight;
+ posts = Unread.posts;
+ read = [];
+ i = posts.length;
+ while (post = posts[--i]) {
+ bottom = post.nodes.root.getBoundingClientRect().bottom;
+ if (bottom < height) {
+ ID = post.ID;
+ posts.remove(post);
+ }
+ }
+ if (!ID) {
+ return;
+ }
+ Unread.lastReadPost = ID;
+ Unread.saveLastReadPost();
+ Unread.readArray(Unread.postsQuotingYou);
+ if (e) {
+ return Unread.update();
+ }
+ }),
+ saveLastReadPost: $.debounce(2 * $.SECOND, function() {
+ return Unread.db.set({
+ boardID: Unread.thread.board.ID,
+ threadID: Unread.thread.ID,
+ val: Unread.lastReadPost
+ });
+ }),
+ setLine: function(force) {
+ var post, root;
+
+ if (!(d.hidden || force === true)) {
+ return;
+ }
+ if (post = Unread.posts[0]) {
+ root = post.nodes.root;
+ if (root !== $('.thread > .replyContainer', root.parentNode)) {
+ return $.before(root, Unread.hr);
+ }
+ } else {
+ return $.rm(Unread.hr);
+ }
+ },
+ update: function(dontrepeat) {
+ var count;
+
+ count = Unread.posts.length;
+ if (Conf['Unread Count']) {
+ d.title = "" + (count || !Conf['Hide Unread Count at (0)'] ? "(" + count + ") " : '') + (g.DEAD ? "/" + g.BOARD + "/ - 404" : "" + Unread.title);
+ if (!dontrepeat) {
+ setTimeout(function() {
+ d.title = '';
+ return Unread.update(true);
+ }, $.SECOND);
+ }
+ }
+ if (!Conf['Unread Favicon']) {
+ return;
+ }
+ return Favicon.el.href = g.DEAD ? Unread.postsQuotingYou.length ? Favicon.unreadDeadY : count ? Favicon.unreadDead : Favicon.dead : count ? Unread.postsQuotingYou.length ? Favicon.unreadY : Favicon.unread : Favicon["default"];
+ }
+ };
+
+ Redirect = {
+ init: function() {
+ return $.sync('archs', this.updateArchives);
+ },
+ updateArchives: function() {
+ return $.get('archivers', {}, function(_arg) {
+ var archivers;
+
+ archivers = _arg.archivers;
+ return Conf['archivers'] = archivers;
+ });
+ },
+ image: function(boardID, filename) {
+ switch (boardID) {
+ case 'a':
+ case 'gd':
+ case 'jp':
+ case 'm':
+ case 'q':
+ case 'tg':
+ case 'vg':
+ case 'vp':
+ case 'vr':
+ case 'wsg':
+ return "//archive.foolz.us/" + boardID + "/full_image/" + filename;
+ case 'u':
+ return "//nsfw.foolz.us/" + boardID + "/full_image/" + filename;
+ case 'po':
+ return "//archive.thedarkcave.org/" + boardID + "/full_image/" + filename;
+ case 'hr':
+ case 'tv':
+ return "http://archive.4plebs.org/" + boardID + "/full_image/" + filename;
+ case 'ck':
+ case 'fa':
+ case 'lit':
+ case 's4s':
+ return "//fuuka.warosu.org/" + boardID + "/full_image/" + filename;
+ case 'cgl':
+ case 'g':
+ case 'mu':
+ case 'w':
+ return "//rbt.asia/" + boardID + "/full_image/" + filename;
+ case 'an':
+ case 'k':
+ case 'toy':
+ case 'x':
+ return "http://archive.heinessen.com/" + boardID + "/full_image/" + filename;
+ case 'c':
+ return "//archive.nyafuu.org/" + boardID + "/full_image/" + filename;
+ }
+ },
+ post: function(boardID, postID) {
+ var archive, name, _base, _ref;
+
+ if (Redirect.post[boardID] == null) {
+ _ref = this.archiver;
+ for (name in _ref) {
+ archive = _ref[name];
+ if (archive.type === 'foolfuuka' && archive.boards.contains(boardID)) {
+ Redirect.post[boardID] = archive.base;
+ break;
+ }
+ }
+ (_base = Redirect.post)[boardID] || (_base[boardID] = false);
+ }
+ if (Redirect.post[boardID]) {
+ return "" + Redirect.post[boardID] + "/_/api/chan/post/?board=" + boardID + "&num=" + postID;
+ } else {
+ return null;
+ }
+ },
+ select: function(board) {
+ var archive, name, _ref, _results;
+
+ _ref = this.archiver;
+ _results = [];
+ for (name in _ref) {
+ archive = _ref[name];
+ if (!archive.boards.contains(board)) {
+ continue;
+ }
+ _results.push(name);
+ }
+ return _results;
+ },
+ to: function(data) {
+ var arch, archive, boardID;
+
+ boardID = data.boardID;
+ if ((arch = Conf.archivers[boardID]) == null) {
+ Conf.archivers[boardID] = arch = this.select(boardID)[0];
+ $.set('archivers', Conf.archivers);
+ }
+ return (arch && (archive = this.archiver[arch]) ? Redirect.path(archive.base, archive.type, data) : data.threadID ? "//boards.4chan.org/" + boardID + "/" : null);
+ },
+ archiver: {
+ 'Foolz': {
+ base: 'https://archive.foolz.us',
+ boards: ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'v', 'vg', 'vp', 'vr', 'wsg'],
+ type: 'foolfuuka'
+ },
+ 'NSFWFoolz': {
+ base: 'https://nsfw.foolz.us',
+ boards: ['u'],
+ type: 'foolfuuka'
+ },
+ 'TheDarkCave': {
+ base: 'http://archive.thedarkcave.org',
+ boards: ['c', 'int', 'out', 'po'],
+ type: 'foolfuuka'
+ },
+ '4plebs': {
+ base: 'http://archive.4plebs.org',
+ boards: ['hr', 'tg', 'tv', 'x'],
+ base: 'foolfuuka'
+ },
+ 'Warosu': {
+ base: '//fuuka.warosu.org',
+ boards: ['cgl', 'ck', 'fa', 'jp', 'lit', 's4s', 'q', 'tg'],
+ type: 'fuuka'
+ },
+ 'InstallGentoo': {
+ base: '//archive.installgentoo.net',
+ boards: ['diy', 'g', 'sci'],
+ type: 'fuuka'
+ },
+ 'RebeccaBlackTech': {
+ base: '//rbt.asia',
+ boards: ['an', 'cgl', 'g', 'mu', 'w'],
+ type: 'fuuka_mail'
+ },
+ 'Heinessen': {
+ base: 'http://archive.heinessen.com',
+ boards: ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x'],
+ type: 'fuuka'
+ },
+ 'Cliche': {
+ base: '//www.cliché.net/4chan/cgi-board.pl',
+ boards: ['e'],
+ type: 'fuuka'
+ },
+ 'NyaFuu': {
+ base: '//archive.nyafuu.org',
+ boards: ['c', 'w'],
+ type: 'fuuka'
+ }
+ },
+ path: function(base, archiver, data) {
+ var boardID, path, postID, threadID, type, value;
+
+ if (data.isSearch) {
+ boardID = data.boardID, type = data.type, value = data.value;
+ type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type;
+ value = encodeURIComponent(value);
+ if (archiver === 'foolfuuka') {
+ return "" + base + "/" + boardID + "/search/" + type + "/" + value;
+ } else if (type === 'image') {
+ return "" + base + "/" + boardID + "/?task=search2&search_media_hash=" + value;
+ } else {
+ return "" + base + "/" + boardID + "/?task=search2&search_" + type + "=" + value;
+ }
+ }
+ boardID = data.boardID, threadID = data.threadID, postID = data.postID;
+ path = threadID ? "" + boardID + "/thread/" + threadID : "" + boardID + "/post/" + postID;
+ if (archiver === 'foolfuuka') {
+ path += '/';
+ }
+ if (threadID && postID) {
+ path += archiver === 'foolfuuka' ? "#" + postID : "#p" + postID;
+ }
+ return "" + base + "/" + path;
+ }
+ };
+
+ PSAHiding = {
+ init: function() {
+ var entry;
+
+ if (!Conf['Announcement Hiding']) {
+ return;
+ }
+ entry = {
+ type: 'header',
+ el: $.el('a', {
+ textContent: 'Show announcement',
+ className: 'show-announcement',
+ href: 'javascript:;'
+ }),
+ order: 50,
+ open: function() {
+ var _ref;
+
+ if ((_ref = $.id('globalMessage')) != null ? _ref.hidden : void 0) {
+ return true;
+ }
return false;
}
+ };
+ $.event('AddMenuEntry', entry);
+ $.on(entry.el, 'click', PSAHiding.toggle);
+ $.addClass(doc, 'hide-announcement');
+ return $.on(d, '4chanXInitFinished', this.setup);
+ },
+ setup: function() {
+ var btn, psa;
+
+ $.off(d, '4chanXInitFinished', PSAHiding.setup);
+ if (!(psa = $.id('globalMessage'))) {
+ $.rmClass(doc, 'hide-announcement');
+ return;
}
- qroot = qpost.nodes.root;
- if (!$.hasClass(qroot, 'threadOP')) {
- $.addClass(qroot, 'threadOP');
- threadContainer = $.el('div', {
- className: 'threadContainer'
- });
- $.after(qroot, threadContainer);
- } else {
- threadContainer = qroot.nextSibling;
+ PSAHiding.btn = btn = $.el('a', {
+ innerHTML: '[ - ]',
+ title: 'Hide announcement.',
+ className: 'hide-announcement',
+ href: 'javascript:;'
+ });
+ $.on(btn, 'click', PSAHiding.toggle);
+ $.get('hiddenPSAs', [], function(item) {
+ PSAHiding.sync(item['hiddenPSAs']);
+ $.before(psa, btn);
+ return $.rmClass(doc, 'hide-announcement');
+ });
+ return $.sync('hiddenPSAs', PSAHiding.sync);
+ },
+ toggle: function(e) {
+ var hide, text;
+
+ hide = $.hasClass(this, 'hide-announcement');
+ text = PSAHiding.trim($.id('globalMessage'));
+ return $.get('hiddenPSAs', [], function(_arg) {
+ var hiddenPSAs, i;
+
+ hiddenPSAs = _arg.hiddenPSAs;
+ if (hide) {
+ hiddenPSAs.push(text);
+ hiddenPSAs = hiddenPSAs.slice(-5);
+ } else {
+ $.event('CloseMenu');
+ i = hiddenPSAs.indexOf(text);
+ hiddenPSAs.splice(i, 1);
+ }
+ PSAHiding.sync(hiddenPSAs);
+ return $.set('hiddenPSAs', hiddenPSAs);
+ });
+ },
+ sync: function(hiddenPSAs) {
+ var hr, psa, _ref;
+
+ psa = $.id('globalMessage');
+ psa.hidden = PSAHiding.btn.hidden = (_ref = PSAHiding.trim(psa), __indexOf.call(hiddenPSAs, _ref) >= 0) ? true : false;
+ if ((hr = psa.nextElementSibling) && hr.nodeName === 'HR') {
+ return hr.hidden = psa.hidden;
}
- $.add(threadContainer, this.nodes.root);
- return true;
+ },
+ trim: function(psa) {
+ return psa.textContent.replace(/\W+/g, '').toLowerCase();
+ }
+ };
+
+ CatalogLinks = {
+ init: function() {
+ var el, input;
+
+ if (!Conf['Catalog Links']) {
+ return;
+ }
+ el = $.el('label', {
+ id: 'toggleCatalog',
+ href: 'javascript:;',
+ innerHTML: "Catalog Links",
+ title: "Turn catalog links " + (Conf['Header catalog links'] ? 'off' : 'on') + "."
+ });
+ input = $('input', el);
+ $.on(input, 'change', this.toggle);
+ $.sync('Header catalog links', CatalogLinks.set);
+ $.event('AddMenuEntry', {
+ type: 'header',
+ el: el,
+ order: 95
+ });
+ return $.on(d, '4chanXInitFinished', function() {
+ return CatalogLinks.set(Conf['Header catalog links']);
+ });
},
toggle: function() {
- var container, containers, node, nodes, replies, reply, thread, _i, _j, _len, _len1;
+ var useCatalog;
- thread = $('.thread');
- replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread);
- QuoteThreading.enabled = this.checked;
- if (this.checked) {
- nodes = (function() {
- var _i, _len, _results;
-
- _results = [];
- for (_i = 0, _len = replies.length; _i < _len; _i++) {
- reply = replies[_i];
- _results.push(Get.postFromNode(reply));
- }
- return _results;
- })();
- for (_i = 0, _len = nodes.length; _i < _len; _i++) {
- node = nodes[_i];
- QuoteThreading.node(node);
- }
- } else {
- replies.sort(function(a, b) {
- var aID, bID;
-
- aID = Number(a.id.slice(2));
- bID = Number(b.id.slice(2));
- return aID - bID;
- });
- $.add(thread, replies);
- containers = $$('.threadContainer', thread);
- for (_j = 0, _len1 = containers.length; _j < _len1; _j++) {
- container = containers[_j];
- $.rm(container);
- }
- Unread.update(true);
- }
+ $.event('CloseMenu');
+ $.set('Header catalog links', useCatalog = this.checked);
+ return CatalogLinks.set(useCatalog);
},
- kb: function() {
- var control;
+ set: function(useCatalog) {
+ var a, board, path, _i, _len, _ref;
- control = $.id('threadingControl');
- return control.click();
- }
- };
-
- QuoteYou = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Mark Quotes of You'] || !Conf['Quick Reply']) {
- return;
- }
- this.text = '\u00A0(You)';
- return Post.prototype.callbacks.push({
- name: 'Mark Quotes of You',
- cb: this.node
- });
- },
- node: function() {
- var quotelink, quotelinks, quotes, _i, _len;
-
- if (this.isClone) {
- return;
- }
- if (this.info.yours) {
- $.addClass(this.nodes.root, 'yourPost');
- }
- if (Conf['Highlight Own Posts']) {
- $.addClass(doc, 'highlight-own');
- }
- if (!(quotes = this.quotes).length) {
- return;
- }
- quotelinks = this.nodes.quotelinks;
- for (_i = 0, _len = quotelinks.length; _i < _len; _i++) {
- quotelink = quotelinks[_i];
- if (QR.db.get(Get.postDataFromLink(quotelink))) {
- $.add(quotelink, $.tn(QuoteYou.text));
- }
- }
- }
- };
-
- Quotify = {
- init: function() {
- if (g.VIEW === 'catalog' || !Conf['Resurrect Quotes']) {
- return;
- }
- if (Conf['Comment Expansion']) {
- ExpandComment.callbacks.push(this.node);
- }
- return Post.prototype.callbacks.push({
- name: 'Resurrect Quotes',
- cb: this.node
- });
- },
- node: function() {
- var deadlink, _i, _len, _ref;
-
- _ref = $$('.deadlink', this.nodes.comment);
+ path = useCatalog ? 'catalog' : '';
+ _ref = $$("#board-list a[href*=\"boards.4chan.org\"],\n#boardNavDesktop a[href*=\"boards.4chan.org\"],\n#boardNavDesktopFoot a[href*=\"boards.4chan.org\"]");
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- deadlink = _ref[_i];
- if (this.isClone) {
- if ($.hasClass(deadlink, 'quotelink')) {
- this.nodes.quotelinks.push(deadlink);
- }
- } else {
- Quotify.parseDeadlink.call(this, deadlink);
+ a = _ref[_i];
+ board = a.pathname.split('/')[1];
+ if (['f', 'status', '4chan'].contains(board) || !board) {
+ continue;
}
+ if (Conf['External Catalog']) {
+ a.href = useCatalog ? CatalogLinks.external(board) : "//boards.4chan.org/" + board + "/";
+ } else {
+ a.pathname = "/" + board + "/" + path;
+ }
+ a.title = useCatalog ? "" + a.title + " - Catalog" : a.title.replace(/\ -\ Catalog$/, '');
+ }
+ return this.title = "Turn catalog links " + (useCatalog ? 'off' : 'on') + ".";
+ },
+ external: function(board) {
+ return (['a', 'c', 'g', 'co', 'k', 'm', 'o', 'p', 'v', 'vg', 'w', 'cm', '3', 'adv', 'an', 'cgl', 'ck', 'diy', 'fa', 'fit', 'int', 'jp', 'mlp', 'lit', 'mu', 'n', 'po', 'sci', 'toy', 'trv', 'tv', 'vp', 'x', 'q'].contains(board) ? "http://catalog.neet.tv/" + board : ['d', 'e', 'gif', 'h', 'hr', 'hc', 'r9k', 's', 'pol', 'soc', 'u', 'i', 'ic', 'hm', 'r', 'w', 'wg', 'wsg', 't', 'y'].contains(board) ? "http://4index.gropes.us/" + board : "//boards.4chan.org/" + board + "/catalog");
+ }
+ };
+
+ IDColor = {
+ init: function() {
+ if (!Conf['Color User IDs']) {
+ return;
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Reveal Spoilers',
+ cb: this.node
+ });
+ },
+ node: function(post) {
+ var str, uid;
+
+ if (!(uid = $('.hand', this.nodes.uniqueID))) {
+ return;
+ }
+ str = this.info.uniqueID;
+ if (uid.nodeName === 'SPAN') {
+ return uid.style.cssText = IDColor.apply.call(str);
}
},
- parseDeadlink: function(deadlink) {
- var a, boardID, m, post, postID, quote, quoteID, redirect, _ref;
+ ids: {},
+ compute: function(str) {
+ var hash, rgb;
- if (deadlink.parentNode.className === 'prettyprint') {
- $.replace(deadlink, __slice.call(deadlink.childNodes));
- return;
- }
- quote = deadlink.textContent;
- if (!(postID = (_ref = quote.match(/\d+$/)) != null ? _ref[0] : void 0)) {
- return;
- }
- boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID;
- quoteID = "" + boardID + "." + postID;
- if (post = g.posts[quoteID]) {
- if (!post.isDead) {
- a = $.el('a', {
- href: "/" + boardID + "/" + post.thread + "/res/#p" + postID,
- className: 'quotelink',
- textContent: quote
- });
- } else {
- a = $.el('a', {
- href: "/" + boardID + "/" + post.thread + "/res/#p" + postID,
- className: 'quotelink deadlink',
- target: '_blank',
- textContent: "" + quote + "\u00A0(Dead)"
- });
- a.setAttribute('data-boardid', boardID);
- a.setAttribute('data-threadid', post.thread.ID);
- a.setAttribute('data-postid', postID);
- }
- } else if (redirect = Redirect.to({
- boardID: boardID,
- threadID: 0,
- postID: postID
- })) {
- a = $.el('a', {
- href: redirect,
- className: 'deadlink',
- target: '_blank',
- textContent: "" + quote + "\u00A0(Dead)"
- });
- if (Redirect.post(boardID, postID)) {
- $.addClass(a, 'quotelink');
- a.setAttribute('data-boardid', boardID);
- a.setAttribute('data-postid', postID);
- }
- }
- if (__indexOf.call(this.quotes, quoteID) < 0) {
- this.quotes.push(quoteID);
- }
- if (!a) {
- deadlink.textContent = "" + quote + "\u00A0(Dead)";
- return;
- }
- $.replace(deadlink, a);
- if ($.hasClass(a, 'quotelink')) {
- return this.nodes.quotelinks.push(a);
+ hash = this.hash(str);
+ rgb = [(hash >> 24) & 0xFF, (hash >> 16) & 0xFF, (hash >> 8) & 0xFF];
+ rgb[3] = ((rgb[0] * 0.299) + (rgb[1] * 0.587) + (rgb[2] * 0.114)) > 125;
+ this.ids[str] = rgb;
+ return rgb;
+ },
+ apply: function() {
+ var rgb;
+
+ rgb = IDColor.ids[this] || IDColor.compute(this);
+ return ("background-color: rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "); color: ") + (rgb[3] ? "black;" : "white; border-radius: 3px; padding: 0px 2px;");
+ },
+ hash: function(str) {
+ var i, j, msg;
+
+ msg = 0;
+ i = 0;
+ j = str.length;
+ while (i < j) {
+ msg = ((msg << 5) - msg) + str.charCodeAt(i);
+ ++i;
}
+ return msg;
}
};
@@ -8853,6 +7776,1172 @@
}
};
+ Emoji = {
+ init: function() {
+ var css, icon, name, pos, _ref;
+
+ if (!Conf['Emoji']) {
+ return;
+ }
+ pos = Conf['emojiPos'];
+ css = ["a.useremail[href]:last-of-type::" + pos + " {\n vertical-align: top;\n margin-" + (pos === "before" ? "right" : "left") + ": 5px;\n}\n"];
+ this.icons["PlanNine"] = Emoji.icons["Plan9"];
+ this.icons['Sage'] = Emoji.sage[Conf['sageEmoji']];
+ _ref = this.icons;
+ for (name in _ref) {
+ icon = _ref[name];
+ if (!this.icons.hasOwnProperty(name)) {
+ continue;
+ }
+ css.push("a.useremail[href*='" + name + "']:last-of-type::" + pos + ",\na.useremail[href*='" + (name.toLowerCase()) + "']:last-of-type::" + pos + ",\na.useremail[href*='" + (name.toUpperCase()) + "']:last-of-type::" + pos + " {\n content: url('data:image/png;base64," + icon + "');\n}\n");
+ }
+ return $.addStyle(css.join(""), 'emoji');
+ },
+ sage: {
+ '4chan SS': 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAYAAACZ3F9/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAa9JREFUKFOdkt0rg2EUwM95b2zlL0CRRLngksznXrJsNtYW1tjYhM3mY6+IXZAbikhTKJp8XZAp81UmWYhIRHHhUi60e7s6ntdCa2449es8PfU7z+k5B6AbyuE/wQlc4BcO2d06unAUBCgFE0hianOd3NHIcy8NPwrUf9NBPZcOEi7ayXZiea/1V7+ljaXeYAfOgg2So2TOwQWGnwQafOgi962TnMFmatozUeNu4yetASspVvgXiUvii5K5Nm6z56ol3Hdtpy+cwSYy+HRUt1nLsoEato0kXyh6wTac+24brThWv6MNOYNW9prlG/uxmbRrFaT0VrCspZoNPSUNJNyCBcoiLZuhLH0o9U6UrAfGKCz7RlLM81Q8XUwqr4oKPLIQmnA8IupBigacVy7yrya/2JouhryJHJJNykg+UxLGOtz6+SQNpEiMcduls4Wvoli9WklVKz+ol5SU4U6ngql8Qj2eRI+GyajBhSRH4r3cUxhSeRVhsYBmWUWiyM+UMDmDUI2nsfuSC1I27nLgYZJlP8jhjJ3PY8iE+L8tWx4kQC6MQA5b1D9HNiRCFhx8AF/e2qh92VnKAAAAAElFTkSuQmCC',
+ 'appchan': 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAABa1BMVEUAAACqrKiCgYIAAAAAAAAAAACHmX5pgl5NUEx/hnx4hXRSUVMiIyKwrbFzn19SbkZ1d3OvtqtpaWhcX1ooMyRsd2aWkZddkEV8vWGcpZl+kHd7jHNdYFuRmI4bHRthaV5WhUFsfGZReUBFZjdJazpGVUBnamYfHB9TeUMzSSpHgS1cY1k1NDUyOC8yWiFywVBoh1lDSEAZHBpucW0ICQgUHhBjfFhCRUA+QTtEQUUBAQFyo1praWspKigWFRZHU0F6j3E9Oz5VWFN0j2hncWONk4sAAABASDxJWkJKTUgAAAAvNC0fJR0DAwMAAAA9QzoWGhQAAAA8YytvrFOJsnlqyT9oqExqtkdrsExpsUsqQx9rpVJDbzBBbi5utk9jiFRuk11iqUR64k5Wf0JIZTpadk5om1BkyjmF1GRNY0FheFdXpjVXhz86XSp2yFJwslR3w1NbxitbtDWW5nNnilhFXTtYqDRwp1dSijiJ7H99AAAAUnRSTlMAJTgNGQml71ypu3cPEN/RDh8HBbOwQN7wVg4CAQZ28vs9EDluXjo58Ge8xwMy0P3+rV8cT73sawEdTv63NAa3rQwo4cUdAl3hWQSWvS8qqYsjEDiCzAAAAIVJREFUeNpFx7GKAQAYAOD/A7GbZVAWZTBZFGQw6LyCF/MIkiTdcOmWSzYbJVE2u1KX0J1v+8QDv/EkyS0yXF/NgeEILiHfyc74mICTQltqYXBeAWU9HGxU09YqqEvAElGjyZYjPyLqitjzHSEiGkrsfMWr0VLe+oy/djGP//YwfbeP8bN3Or0bkqEVblAAAAAASUVORK5CYII='
+ },
+ icons: {
+ 'Plan9': 'iVBORw0KGgoAAAANSUhEUgAAAAwAAAAPCAYAAAGn5h7fAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAzE15J1s7QAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAACAElEQVQoz3WSz4sSARTHvzMjygpqYg3+KIhkE83DKtKlf0C9SrTRuZNEx0VowU6CuSeJNlwwpEO2kJ6SQBiIUAzFjRDF4wrjKosnGx3HmdehFDfpe/2+z/s++D5gU7IsEwRByICIiAEAIiIAYAFAXsjYVr/fLxMRNVvN+prJ5/OA3+/XERFNf02JyeVyDx0OxyvLNQsnimLKfcf9KRQKXQAAnE6nlf5qMpnQycnbP/kAoKoqsSwLAJhOp+AAwOv1otvtpqxWq73dbt/r9XqvEQ6HUalUEvF4XLd5IpvNZqlerzd5nlf6/f6tTCZjBACk0+nb+XxeW4UrikLJZPImAGA0Gq0NIqJyuSyyANDr9Q5Wu1utFvR6/SULAI1G4+vK8Pv90DTtGwsAJpPpaGUYDAZ0Op3PHAAEg8H3tVqtbrtu21sqyxuRSOQJk0ql9IvF4r7b7f7pcrlejkaj57IsH58Pzp8dvjhc/lsBk0gkbLFYrFqtVvd27+4qOk733ePxPDCbzVBVFfP5fCiK4rvhxfDN/qP9wSasGwwGMv1HiqJQsVg8ZlfTHMepkiR1t05gGJBGmM/nMBqNj9nN9kql0lNN064ARISzH2cQBAGz2ewLu2na7XYLwzBbvxYIBBCNRrFj3BmsAZ/PZ+J5/kOhUIAkSVeA8XiMZqt5efrx9OA3GfcgvyVno9cAAAAASUVORK5CYII=',
+ 'Neko': 'iVBORw0KGgoAAAANSUhEUgAAABMAAAARCAMAAAAIRmf1AAACoFBMVEUAAABnUFZoUVddU1T6+PvFwLzn4eFXVlT/+vZpZGCgm5dKU1Cfnpz//flbWljr5uLp5OCalpNZWFb//f3r6+n28ff9+PRaVVH59Pr//vr38vj57/Dp7eyjn5zq8O5aVVJbYV9nVFhjUFRiWFlZVlFgZGOboJzm5uZhamfz9/bt8fDw6+drb26bl5j/8/lkX1z06uldWFS5r61UT0tfWlbDwr3Ew76moqNRTU7Mx8P75OpeY19pWl1XW1qzr6x5eHaLiojv7+1UT0xIU0uzqadVS0nV0MxkZGT5+PPk497///ra29Xq5eFtY2H28e2hnJignJlUUE1dXV2vrqxkY2FkYF/m3d5vZmfDuruhl5aZlJHx8O75+PZWVVP29vT/9fTj3trv6ubh5eRdXFqTkpBOTUtqZmX88/RMQ0T78vPEvr7HwcHDwsDq6ef///3Gx8H++fXEv7tZWVedmZZXXVudnJp0c3FZU1f79fnb1dlXUVVjXWFrZmy8t7359/qLj455e3q4s69vamZjX1zy4+avpaReWFz/+f1NR0vu6Ozp4+f48/lnYmi8ur3Iw7/69fHz7+xbV1SZmJZVUk1ZV1zq5ez++f/c196uqbDn4uj9+P7z7vRVVVXt6ORiXl/OycXHw8CPi4ihoJ5aWF3/+v/k3+axrLOsp67LzMZYU1m2sq9dWF5WUU1WUk/Au7eYlJGqpqObmphYVV749f7p5Or38fPu6OpiXFz38fH79vLz7urv6+hhYF5cWWKal6D//f/Z09Xg29exraqbl5RqaW6kpKTq5uPv7Of/+PDj29D//vP18Ozs5+OloJymoZ1ZVVJZWVlkYF2hnpmblIyspJmVjYKQi4enop5STUlRTUpcWUhqY1BgWT9ZUjhcV1NiXVkkhke3AAAABHRSTlMA5vjapJ+a9wAAAP9JREFUGBk9wA1EAwEAhuHv3dTQAkLiUlJFJWF0QDLFYDRXIMkomBgxNIYxhOk4wwCqQhQjxgxSGIsALFA5BiYbMZHajz1oJlx51sBJpf6Gd3zONcrqm/r1W8ByK0r+XV1LXyOLLnjW6hMGpu0u1IzPSdO17DgrGC6AadrVodGcDQYbhguP6wAvAaC0BRZQalkUQ8UQDz5tAof0XbejOFcV5xiUoCfjj3O/nf0ZbqAMPYmzU18KSDaRQ08qnfw+B2JNdAEQt2O5vctUGjhoIBU4ygPsj2Vh5zYopDK73hsirdkPTwGCbSHpiYFwYVVC/17pCFSBeUmoqwYQuZtWxx+BVEz0LeVKIQAAAABJRU5ErkJggg==',
+ 'Madotsuki': 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAMAAADTRh9nAAAALVBMVEUAAAC3iopWLTtWPkHnvqUcBxx5GCZyAAARERGbdXJrRUyGRUyYbY23coZFGDRFGEYfAAAAAXRSTlMAQObYZgAAAGhJREFUeF5Vy1kOQyEMQ1Fshzd12P9y61AixLX4yJFo1cvVUfT23GaflF0HPLln6bhnZVKCcrIWGqpCUcKYSP3JSIRySKTtULPNwMaD8/NC8tsyqsd1hR+6qeqIDHc3LD0B3KdtV1f2A+LJBBIHSgcEAAAAAElFTkSuQmCC',
+ 'Sega': 'iVBORw0KGgoAAAANSUhEUgAAACwAAAALBAMAAAD2A3K8AAAAMFBMVEUAAACMjpOChImytLmdnqMrKzDIyM55dnkODQ94foQ7PkXm5Olsb3VUUVVhZmw8Sl6klHLxAAAAAXRSTlMAQObYZgAAANFJREFUGJVjYIACRiUlJUUGDHBk4syTkxQwhO3/rQ/4ZYsuymi3YEFUqAhC4LCJZJGIi1uimKKjk3KysbOxsaMnAwNLyqoopaXhttf2it1anrJqke1pr1DlBAZhicLnM5YXZ4RWlIYoezx0zrjYqG6czCDsYRzxIko6Q/qFaKy0690Ij0MxN8K2MIhJXF+hsfxJxuwdpYGVaUU3Mm5bqgKFOZOFit3Vp23J3pgsqLxFUXpLtlD5bgcGBs45794dn6mkOVFQUOjNmXPPz8ysOcAAANw6SHLtrqolAAAAAElFTkSuQmCC',
+ 'Sakamoto': 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAYAAADwMZRfAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAxVJREFUOE+Nk19IU1EYwK+GQQTVQ39egh6ibKlzw91z7rn3bvfOmddNszl1bjKXc5rJJGmBUr7Yg9qTD0IalFgRBEYg6EDQQB+GovQyQgiaUZsoLcgHMcr069w7MgcGXfi453zn+37fv3MYZt/n99e76tzVj4JN/hP79fvXnV3hnNabwUBjoOHcgTYOu/JQspgTzsqKgn9BfD4vkWTzur287PqLVy+zM+yePB7KsRXLywTjnSpnZctBkPCdW8ccDuU55vBO8RXbkC/oP5ph19V5+7LIky0OY1BKbZEbLcFSt7u6pN7jLmltCVrr3DV5jY3+KovFEsccB1KJNVpefe10BqS2tqqO4/AuphBB4L/LkrRqNgtJs1lMypLls1kU38mytMLz/E8VIlutqVqX6/weZG52OttRXjbE0cP/FYLRlpVjDXuQ/r77x2XZPKkCHA4HBAIBkCQpAygIAvh8Pu2MZgO0Lz+QSa/sQfwN9RfpVN66XC6Ynp6GhYUFGBwczAC1t7fD0tISxONx6O7upgHILmsqvLcHodOggfiV/v5+SCaT4HQ6IRaLgdfr1bIRRREmJyfBZrNBNBqF+fl5sNsdgE2GiAbp6bmbdbXC7qWQbxMTE7C2tgY6nQ5SqRSEw2ENopaoZpCXlwdTU1NaoECgCbgiU6y8QH+ECYWaTymK7TWdys7MzIwGaWtrg42NDejo6AB1WjU1NZo+FArB2NgYrK6uQrAlCASxn2z6wkuMp87VIAhkE2MEAwMDkEgkYHx8HBYXF0HtkQpRy1BLiEQisLy8rPVNKSsFjEzrXH4+z1hlS4xDhKadNu7t7YPR0VHweDzAEVWfHru6HxkZgeHhYVAURYNjkylVWKArZjjMzqmdVi+QCsLUkQiEjvDvncEkvU7/qQ0Vgukeo48Go87IiCJnZNmipxiz7wXEbVDnbUxQOgM12h9n6qTq6NvapRdtkwaP0XK8RmPuYSbxYfaQ/sJJhjfknuFRURUi7AMOozcCwl94hLZp5F+EioDQVwqYI6jomZU1NFtM+rOSxZjVazcyvwHr/p/Kws1jegAAAABJRU5ErkJggg==',
+ 'Baka': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA0pJREFUOE91k3tI01EUx39JOpA0H4jNx0pbD3XTalISWf8YFlEgldqDsBLLyqjEKBCiLLWiggh6/KEV1WZ7OaelLZvDdDafNW1JFraWe/32+01FrUZ9uy4ylLpw4Z5z7/nc77n3HIqaMRIjZJyEcNX+uFCFeGmI/GZciEIsCFJUTvoAzDz+1y7K76MSwhX5hXl6z+WSbrzU2KB8YEGDwgrTaxZ3b7xHcaHhR3xw7Z5/UviB1ReP5XSg3+TAqYJOxMzWISFIC0GQDomhTVA9skCnsaAwp/vnMq66dBokNuBR9uFd7T9Z1zCunjci0qcRJUVdoJ3DYOhRnC/qBZ+jQbfeCc+37yjY2UEg0iwvJE0k9l8Z+8xqHmTgot0QLdQgTaQFQ2AsOzlHvOu1S5pwOLsHHo8HjHMCq2MazNvTlByKHyrJLDvdR25jMWRxYx5HjeMH2r1BDOOeguRua4OI14jx8a8YH5tA+al3EHKlW6mYOapb2oZBOOwMbEMseAE12L+jjUh3w+VipyAZ65oxn1NP/GMYGR6Ftn4Qsf7qa9S82Y/l/X122G0uL2TbxmZEz1WhXW8mUol8moXu+SCi/OoQ6VsDh3UUwyQ1k9GOaI5MTkX4yWTGHutvgI1F28sviAlRgxeoRm62HvsyW8En9pZ1TYgi6TntoyQtFm86rVgUoJZRvDnKMmXVAGxWmkAYOBwudBqGcHCvHulrGpGT2Uy+z4yT+QYsCXtCUpp8GxbKhx8gDK0ro+KjJGvzdjfDZnN6VdisLD5/JjArQ2zW66PJOj2lEZtStaBphkwah7K6kMJ/GEulp1bMWhAmMbTozOQRaWRtfoZVgjo4iRra4SYgGi26TwjxVeDKhR7Y7U606ixICq9tr7hd7+OthRWL7yUnJ1WPmXotqLhpRICPHCePtuFV6xdUPTAhcWEtRHEqfHpPyto4hPXLXnzflSEJnFaN3OCKDcsFsrEntR9RUmxARLAUgT5iBPuJsXWDBj0dZjRU9yNV+PTbpjTp9OA/pOSk24nRkXf1J462oPxcJ65f6ULlHSMulepRerYDgvj7A0cKpNz/tyTZqbzXO4t0ZZGQJ34RH11lFHIlA8LIqreCCMUZRY3cd2bwL/5/RmjNSXqtAAAAAElFTkSuQmCC',
+ 'Ponyo': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAuNJREFUOE+Nk3tI01EUx39BTytConQTt1am07m5abi5KT5S8z2dj1yOEMUC7aUgIoimlmUEWX9kBZGWaamEmE6U1BI1XNPNGTrnHs33IwuSXrL4NgcJ0mNdOHDh3PPhnPP9XoKwcroJYvMQiRSicHCQKCgUyZC9/T5rNet5KUFs0zCZbZMsFmZ9fTEjEEBDp4/KSSSb/4JoGIyWaTYbiykpWEhOxhSHAzWD0aqkUGhWAcVkW58xlvuPhfh4zItEmOHxYDR3MhcdDaNAsKJydAz5IySKRNjEUmy88vjOVaU8F0iPCqCNjEBHkC/UYaGYFwqxmJoKLYOhkxPElg0QsbNtTlmox9yjRD9UCbnoOR+J/lwRWtOCcdXfDc2BPpg0d7CQlIQZPh9KKlVkAQjJ2x2zmOSsQu7hpzUJfBhLjsNQmADjxcT10Bcl4rE4EHc5LjBEhEPn7f1WTqXSLQB/s1Tp7vslsoIkyPPiMJAbi86McBguiaHKjoEqR4jJy2K0nAxApzMN5iUGrclrKVaz2fUvuF4tRbxDKA90w5VjTFyLZKHpTBSq4/1QnxGB2qxoVIZx0JopRCPHFSNOThfWZzfrXDcZEowH4iA05ATg68hDtBaL0HAuCm3lJ9Bfcx2fFNUoi/DCjRgfNHHd1wCZA2TyXjNkE6F0cBDpPFiojeNi8EkJdFoN3vXch0nbBJOhDd907dANv8JITxNqziag3ZsJbUDAwLin50Q9QWwl1qSYoNOVvUcOoqOqAAa9Fu9H2/F9+B5WZLcwOyxFX18flLI+VASyMGVeoJHD+Tzq5BS1PoaKRrNT8127P74swsq4FCa9FKvqBqwaOiz3hdEuLKueYSyECT2LNW0eIfo3E/WmEbvnG1MUJnWdpWhDGDvxQXZHo+RR0uW2tnv+auPX+TvtJm7zKpaen/4y2yjBUlcxlvtvmvT16ZWDpQeoVv3/60F/NrHjTf4ugazIXtJ8ivjnz/sJ+yGQRjcqUdIAAAAASUVORK5CYII=',
+ 'Rabite': 'iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAD/0lEQVR4Xl2MXUxbdQDFz/9+9Lb3tkBLCxTKhzgoOOZAsokbJmZxDFHnd+LL4hKVzBgfNCY++ODbjDEaZowvErOM6HRu6hKZY2rIAOkCY4OSDTpFaAsrlJa2t5+39+NvjT7tnJzknIfzI98Nf/C6TuXdguWBd1q9rcb8/CwsZiu2Ywm4nDVo3VWLZCKDaDwJq9mCg31PgjAMKKUwmcyYvTbek9iJRDm6M/XswEDjwNz6plWW6wdZhjUAintFCEEhn0N04zYskljaDLaj8ar49oUrsYR6mrFJNj322w46H8y+mitM/ZJKZmyE4XAvjJSsazpyuSzslVZIkgWKOvvRgQ6Xrdlhqmds7o7bFZoLkctreKxf7GtuCE7IyUQjBQcQ8j/lvxCGQJZz0IoCVpamTtzfIh9nwiaIrCQyjNg8mq11oDLUhNXRJfT1Ozr3tS/PqpnQ80qRgjAmKIqBfK4ItbSLKoOZqR/6neLkENlSUAIhlktvEf+sD2rkm8nWTHtvZCGMVON1ePuaoBER31/MXGly1wSqq9Uug6FluYyWXJiPqFXmjd4Dh9oF9ZKKimYXRtYCx8lmMIDIxlIPGz591av0mtanF7FcCEN6iMXeox2wOJ0QJAmUAoRQaIqCnWAQY1/ewKNGNeQuYXkm0d2NC2e+wvmRr/Hx+6+8PHayrbDyyQBNDb9As3PHKDWG6MTM23RoeJAWsqeoWvyUUv0UHf7pBB0fe4OeeXe3/vmHbx3+8dwIGJ4IsFpMMFe0fbtAn+nwZePr1u4MBK8XIALG/Rt479wYrs2vgeNNAMNgMbiNzybuoKVvn+Gs9kbr6qpBfJfGYHFIkJUCoGwfqcoMX/b27EGhwgOjoCADDlP+CA51ugFFRzoB8FYNaQ1oqKD44+eNL+wNj7zJGQSIhe8+jgQ9thk+27v/KRY6L4FSCkVOwtlQj6P73Qgt/o1ERoKt4iUkE7+jrZMHyzIoK9cOBFfT4LbWAk+0a7ZLnvqHcTNdACgFScfAcjxEdy00VQclHGo7dqGeYxHbvIo6hwhSghCehb3G5p6eW7VxXC5/xGWToMgrKKoaCnIalI9CIARasQAqloMI/x4BWrLLYwE1AEPTwCGHaGjz7pw/leZUNV8wNm9BLy6CxsvxZ1kMbaY4TKIIXlNBsynoVjvAC4CuAoYOVi+CMfLYCUfg95tPHuzZB0YtKzsb58RMucWE/fZmhCbdOP9rNnLnxko6GVoB8lFwyVVw8b/AyeulHoJyN4Rb19dTFyeqBlu6njvfsWcvOJvLs7DMmw/7bvpeE4pU2OIcgcqmp4fGAgt2Txwvqr7lTp5V7LquZxXC6+BqEvGcY5pyjaM1tffJbk89NE3FP5VQ6y7a+paZAAAAAElFTkSuQmCC',
+ 'Arch': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABCFBMVEUAAAAA//8rqtVAqtUQj88tpdIYks46otwVldUbktEaldMjldM2qNcXk9IWktQZkdIYlc8mnNUXlNEZktEZlNIYktIWlNMXktE7o9klmdMXktFHqdkXk9EWk9EYk9IlmtQXlNEXktAWk9AWlNEYlNFDptkZldMYk9E4otg/p9kXktEXk9AXlNA4otclmdQXk9IYktEXlNEwn9YXk9IXk9FFp9o3otgXk9FPrdwXk9E2otdCptkXk9E/ptkcldIXk9Edl9IXk9EjmdUXk9EXk9EXk9EbldIcldIjmdMmmtQsndUvntYyn9YyoNYzoNc0odc1odc2odc6pNg7pNg9pdlDp9pJqttOrdzlYlFbAAAARXRSTlMAAQYMEBEVFhgcHR0mLS8zNTY3PT4/RU1kdXp6e3+Cg4WIiYqMjZGXl5mbnqSnrbS3zMzV3OPk7Ozv8fT29vf4+fz8/f7SyXIjAAAAmUlEQVR4XlXI1WLCUBQF0YM3SHB3a1B3l7Bx1///E6ANkDtva0jKbCW2XIH1z2hiZEZ4uUgxo7JedTQye/KN/Sb5tbJ+7V9OXd1n+O+38257TL+tah3mADAwSMM7wzQWF4Hff6ubQIZIAIb6vxEF4CZyATXhZa4HwEnEA+2QgoiyQDnIEWkjVSBBZBqXbCRlKYo8+Rwkyx54AOYfFe7HhFa7AAAAAElFTkSuQmCC',
+ 'CentOS': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAB5lBMVEUAAADy8tng4Ovs9tnk5O3c7bX44LLduNO1tdDh7r/eutj43q2kocX23az07N+qqsvUqcmXl7331ZXJj7r40o/Pn8T42qP63KjNw9n21p3Y387Ml7732JzR55z05MSxtMLGn8TC4Hx8eqt8e62Af6/B4HnG4oPC4HzH44fBf7LCgbOkoMTcsrmtn8PWqcfFtKrj4Jvs2ZOz2FnMqLXT3KfY5p60Z6NUU5XRuqHzwWSywqDn3JaiiLWahrWhkry5zJjRmqm1Z6P1wmb1y319fK632mK5cKi5nH+73Gu73Gy73W283W+9eK17e6y1yZS3aqRZWJdcW5ldXJplXZppaKBwb6VwcKV5eKswL306OYNPTpGkfK+m0kGpUJWq1EnEqIuXK3+Xh7ahP4qhkryMfK6BgK+CdpGMaKKMa6O9ea2+eq6+oYW/eq+NbqWVlL2Wlr7AjanA4HnA4HrBkqbBlafB33rCgbLCmKjCxIzC1mSs1UytV5mtxIWt1lCuz2evWpuvXJywxYzHjrvH4oXIjrrN2HXO5pTO5pXUlYnUlYvVl5Hb0G7e0XTg03rhr5fpzHPpzXTp0Hvtz3/wrDHytknyt0zyuE3yuVHzvVr0wGP1x3T1yHf1yXe0ZaL2zYP30o730pD31ZeRIcF5AAAAQ3RSTlMAFBkbHEhJS0xMTk5UWWBsd4SEiIiPkJCVlZaam6CjpK29wMPDxMTFxcnK193e3+Dg4uTn5+fo6e/v8/P4+fn7/P7+J4XBAAAAAOBJREFUeF5Vj1OvAwEYBb/yGlu717atLW0b17Zt2/6nze42TTpvMw8nOZCAmwUpiIY6c5IiLi9tPX64GairqszHQ4X2VB64v1Cs6PxMPJSdHM777s6/jyaMRGiRLyyrb88OpjZ3CzAXrm1sqzSNNeN7kVBPNgB7cG51abE5l9cXDces7emQ1uadHhutFUg6gpPKkSIqQGavwz7r7O/+/3t/rSdjI9XDM3qz4fr3B/3iA0aJTG9x71+9oR/PLDwUe2wm19bly+fTIxHyEETatbPewGEw6Mk/tKZCEqSQQUlIHB/QNBEjjVN1AAAAAElFTkSuQmCC',
+ 'Debian': 'iVBORw0KGgoAAAANSUhEUgAAAA0AAAAQCAYAAADNo/U5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAZ5JREFUOE+Nkk0oBHEYxv8fu5GQj3JwcaDkIAc5IpR87M7MKnIVJVKclaIQ5Sy5OLkgR7n5OigcSNpmd2c2Vyfl4KT8/muWiVU79TTv+7zv837NCBF6PG1X+NpZyEYSD9mIc+tHnBPe23B9xKrCuTmbQA/JKfABrhBswa1hH4A38IwfOxPdX1qcjiCQxO5NyrjKV70TnSbeRPwJvGN3i4yyqnEucPY8ZZX9GSEgGK+RvFfyjk2VKZxzBNG8wJWWgh/xtDOeUXZ7Slr6TrSLYL9N4SMgYTTcwdc2ArvJcElhSVcM6mCNSV8n9hA59yTU5UWMG6HIbLhIWlglgWiC2L4Z79qTdo40D6ISuOWwKCWHyk9Fv8ldpUHOuGTuynwSBUynddPdlbEosVpP9Eu4FnOsRzUYNTsdmZN/d5LDiqM0w+2CMdAFFsFGWgfXxZnheqe/z+0puwEM0HHYV3Z9Sgz8TEz7GkQvpuJ/36ggj2AaHLrSlkULWV5x+h2E8xkZL16YVjGNaAUscfZ/f6c/k9ywLKI2MMcRWl0RLy007idmRbQJ7RIfDAAAAABJRU5ErkJggg==',
+ 'Fedora': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABPlBMVEUAAAApQXIpQXIpQXIqQ3UpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIpQXIqQ3QpQXIpQXIqRHYpQXIpQXIqQ3QqRHYpQXI8brT///8uTYMpQnM5Zqg5ZqnS1+I4ZaY4ZactSn8uRnYrQ3MrRXgsRHUsR3s8bbM8brMtSX4wUosxVI01XZw2X50vUIguToQvR3c6X5o6aKs6aq08Un8qQnM9VIFDWINJXohKcKlXapEqQ3UvUIc2X55bhcBdcJVgcpdhfapmd5tuk8dxgqJ1hKR5jbB6iah/m8Shudq3v9C4wNG/x9bFy9nFzNnFzNrIz9zK0NzK0t/O2+3P1eA2YaDU2eTb3+jb4Oje4urj6fHm6e/s7/Tz9fj3+fz7/P38/f3+/v83YaEa/NNxAAAAHnRSTlMABAoVGyY1SVlpeIuQsLfDzdHW4+3y8/b39/n6+vr4+ns8AAAAyklEQVR4XiWN5XrDMAxF75KOknYdZJS0klNmHjMzMzO9/wvMcH7I37mSJShsJ+5NjMT6umDoHyXDcI/2qJadh++P3cle1de+9yPe3/bTY92wzfzr7wGtP3JrAI72BZGVtcAdQlwHy+JS1pDbBE9qamZF3BYrjQxPEXwKc6dC8bXFm0QIpmt8kn0Rn093q82UCtK8oXZckwFJzuulV8bHkajPyXdbnJnARfDHs0trz+JQ+5AFvzp/L0+cL2qPAINUPrq5OC6p/64F/AMnrST+Dq/r7QAAAABJRU5ErkJggg==',
+ 'FreeBSD': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAABIAAAASABGyWs+AAAABmJLR0QA/wD/AP+gvaeTAAADXklEQVQYGQXBS2wUZQDA8f83j33M9rF9d7u4loaWklaDpkSo9KDGaIKUaGxshD2YSPRiuDVeTDyhBxosJCoa40ktpAkPDcUqAYVIpUSUPrAulEdD2bbb7e7ObGcfM/P5+4kwKDvq6yJ1FYYcvb+YAkqAHo/HQ7FYrFIoCiurq9ZXJ06YSOkA+kBzfX06bys3zHxS9EL0tXDVyZfefacqV+X/ZSJx5+qLbx98LhaL9RiGEZWlEsWC/Thd9q6Pf3vs2u6Orc83rFsvTwwfLf5obgywT1Vjh2Hh+rbNsnTssJdNLedK5aIrpSuldKVXKsnH4+Pyn6FDXn5tMef9O+3NvdkvP1V4+EYw2AoQ+KSx8dRYS6NXXnwovaItXduSrrkinWxGOmZWJi9OyOK9m1LmsjIz9IH8QUMOd3WfAQwNKCy2tJwbHB5+XasPaxIHmc4g7WWEZ1MquBiRFlJTf1E7+Tl/H/8asavPzTY1nWd2ZkMDRPeBeHPz5ojwsilEQCBvTSKunCF3M8FSNkBGVTHDYYrLj8jVNhDZ2SMa2zo3MTamaIC/u6Ojr3DtrOrvP0BpdATnyBeIhTxpR5ABUlKSUlXS1dWstbVxdz6hPL0l1quGqkLaKwNvVcjEXNRd/4mit4Z19DjefBEPyCKxgQJQcF28dBrHNDGTSZSezsjeff0hraa2Vs2vrvit81O4vj9xLJcC4ADrQA7YAGqBGsAql/EtLdFQE/L7dF1XZmdnSrbPMJfXoLDmolQK8gJyQBowgQhQDRQBD+hsraVhd4e5MH+/oExfvWLJ9q3/3S7qMpNH2hsS40kFS4EUUAMA2IANRIBXv4uzuO67c2PykqkA5YmZ6bN18YPi0Yoknxc4AsJPCMLVAk2BLKDosCWqs/PZaulkuxk9fekcUBAAQGDks5FT0W++3NuYuC0DVUL4DIEdlIQDAj0IRkigaMjArkFx0tf523sffrQHyKsAgHPhwoXLL+yP9/kePNhk5ExUTyKFkJVAUAiCFZrQup4Rv9ftuLV/6ONBYBVABQAArMvJ5MXW7duD6P62sD8UrPAFRU1TpeCpCnGvPZr7WW///v0jpw+VC9ZdAAABAAAAAMLo7drWrmQyPWG/r8tnaGIjaM05ujr16x/ZBFh5AACA/wGZnIuw4Z4A3AAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxMi0wNy0wNFQxMDowOTo0OS0wNDowMOPVpFwAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTItMDctMDRUMTA6MDk6NDktMDQ6MDCSiBzgAAAAAElFTkSuQmCC',
+ 'Gentoo': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAB9VBMVEUAAAD///+AgICqqv+AgIC/v9+Ojqqii9GAgKptYZKQkOmPj/ddUYBgW4eVjeCTgfiWjO5wbJaZkvPBvepkXomYkNldV4Bzbpl6dJ+Uj7ynoO6Vi+1qZI63se2mnudjXYjOy+GCfaqZjvWlm/Pc2e+Oh7NeWIOWjfeXjeW1sd+gl+diXIfp5/KHgKnn5/F2cZx6c6ZgWoXc2e6dltrAvNu0scrX1eTOyujCvup4c5qpovVpY43///+6uPPJyPXq6fvm5vrz8/z8/P7+/v/d3PixqvmxrPSyrfe0sPO0sfS3tMve2/3r6vy6ufPz8/3d3fi3tM63tPO4tsu5tsu5tvO6tfe6t/Vva5KRjKy7tvW7t/W9vPO/vM+/vvPCwfPEw/TFwvTFxOfGxfTGxvTHxvTIx/TJx/aTiOrNzPXNzfXQzfnRzuHS0fbS0vbT0uHU0e/U0uTU0/bW0+zW1ffX1vfY1/jZ2Pjb2/jc2uSTiemVkLSlnvbe3PTe3vng3fzg3f3g4Pnh4Pnh4fri4enj4/nk5Prl5Prm4/ymn/bn5vro5/rp6O/p6funoPWsqs3t7Pvt7fXv7vzv7v3w7/nx7/3y8f3y8v3z8vytqPWuqPX09P319P319P719f339v739/34+P35+f37+/+uqev9/f6vqvSwrPQAR0dcAAAAPHRSTlMAAQIDBAgJCwwVFyAsNUFHSVBneH+Bh4mVmZmanKCxsrK2tr3ExtDW19rb4ODl5u3t7u/w8/T6+/z9/f4MkNJ1AAAA8ElEQVR4XjXNw5aDURSE0YrRtm3b54+dtm3btm3bz9k3Wek9+2pSYFwT8ibzE93hwAtdJqK3nZo4J9hFXbP+vFHOthV6gnGzstZq94wdCs4UCCDymQ2v7X0LdYoSQ0MIENRYzJbRlPTTHu73ZNAL8vivmVui98PpzuqffX0mIPHJGtOQenukteJ+aS3b9htNpDnT9TeZH1bHAwBRMhGpd6e6uNrLoRgxBKmsX47nBlp678ojpEA40fejcmW4e/No0V8IIPfj6eKgbEJ3ZUnzgE1OqWp9Q3VeWRAsg51f1dZ8c31RmAsc+N5JGbG+zvj3BzDCPrzMDC9SAAAAAElFTkSuQmCC',
+ 'Mint': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAACVVBMVEUAAADh4eEAAAAAAAAAAAAAAAAAAAAsLCyXl5dgYGCnp6eTk5N3d3fBwcGqqqq8vLzNzc3Ozs7Ozs7Pz8/Pz9DQ0NHR0dLS0tLS0tPT09Pf3t/Pz8/i4eLb29vZ2drZ2tna2dra2trf3t/u7O/u7e/u7O/r6+vt7O/w7/Lw8PDy8fTz8fXz8fbx8fHz8/P19fb49/j49/n6+vuPxlmWyGOx437h9NDr9eD6/fj////+/v75/vTA5Jv6/fb7/fnL5bDL5q+AxjeDxUCEzTyGxUaGzjyHxkiHzz6J0D+Kxk6K0kCLyE2M00WNy06P00mSz1OUyF+W2FGX1FiY0F6Z02CZ21ac0Wiez2yfz2+f2mOh4GCi4GOi4WKi4mOk12+k3Wul32um1Hin0nun4G6n5Gin5Wmo23Op2Huq1n+q43Cr526s4Hit23+v6XSw34Cw34Gw6nWx4IKy4IOy44Cy63ez146z34az4IWz4YW03Y217nu38H2625e645G74pK83pu98Iq984W+4ZjA4px0tzDA5ZrB8ZDC5p7D55/E947F6KHF+JHH4qvH6qTI46/K5LLL5LN1tzLL5bN1uTDL57DM5bPM6qzM66/N5rTP6LbP6bTR6rfS573T67vT7LrV7r3X68XX7MHX773Y77/Y9rvZ8cHa7cjd88bi88/j8tTk8djk9tHm8trn89vo89zo9N3p9N3p9d7p9tvq9d/s+93s/dzy+erz+O73+vT4/PX5/fT5/fX5/vN1uzB3vTD6/ff6/fh5uTj8/fv9/vr9/vx8wjV/xDmrMRH0AAAAOXRSTlMAAAECAwQJDzk/RUlNU3F0kpSVlpeYmpucnaKjpKWqqqqtu8LExMTEzdTU1NXY4evy8vP+/v7+/v6LaR1mAAABD0lEQVR4XiXI03bEABAA0KltW9kaW3eSZW3btm3btm3b/q4mp/fxgqKOtpamhrqaqoqykrQYABh+PVMU9fjE5Xp8o54kgPHN0EBHU2N5YXZykiua0HHd2759VF2Sk5IYE5GGsmCEWLV1kVWwt5O+3x/qpgsy8k4ja+cJl2/v5C22tlgCAHtw9TQSa4s+AzfPSm0BRNl9SydhWJzLC567KrNhgrNwHIJ5qTz/2f9w7Jw/DNqIjVr04exW0AEOXcN3Ab7enr9eDW2VTJgehONyc2Z8XP5YdD0Tcuhcc4/r45OjGX51TEjYPbh8THRPvbz+CHusgSZlT7rP8PkCwfQKaQUi9Igr6JsRBMFiWZgb/AHKElRzKopZJQAAAABJRU5ErkJggg==',
+ 'Osx': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABrVBMVEUAAAD///////+qqqr///+ZmZn///+qqqqAgID///////+tra339/eAgICoqKjx8fGMjIzm5ubh4eGPj4/g4ODIyMiAgICSkpKLi4vS1tbPz8+Xl5eMjIypqanIyMjW1tZ2dnbR0dGamprFxcV3d3d+fn60tbV3d3dcXFx3d3epqal7fHxxcXF+foCnp6hYWFhyc3Ojo6SMjI5fX196enp+fn6Li4xERERqamqgoKFpaWmFhoeen6A/Pz9QUFCWlpeSk5SUlZWUlZaOjo+Tk5RHR0cuLi5YWFgwMDAeHh40NDQ3Nzc6OjpcXF1rbG0XFxdSU1NVVVVXV1dZWVlbW1tnZ2lwcHABAQEEBAQXFxchISI+P0BISUpaW1xHR0kNDg4qKyszNDU1NTY9Pj8NDQ1cXF4XFxhSU1QSEhIDAwMrKywtLS4uLi4wMDFHSElISEggISE0NDVJSktNTU1FRUVWVlhGRkYEBAVBQUE0NTZQUVJQUVMFBQUqKitWV1lXV1daWlpaWlw+Pj8bGxtcXV9dXV1fX19fYGFgYGBkZGRlZmhpaWlsbGxwcHB2dna844Y9AAAAV3RSTlMAAQIDAwUFBggMDhkeICMkKCgqMDIzPj9ERFBib4CCg4iMjZCcnp+jqamrw83W1tvb3ePl6Ojp6+vs7u7v8PHy9PT09PT3+vr7/f39/f39/v7+/v7+/v50ou7NAAAA30lEQVR4XkXIY3vDYABG4SepMdq2bRSz/capzdm2fvOuDO397Rw0Ly4tz2QAQPbcxuZ2E/STJwfxPhWgG355fRrVAIVb1zeP9UDLfiSwkAcADe8fn7tFxWuEXFRDoer/OgoMTRBCumj8yJwPBo8Zhpk14U856/HI8n0ZUtpZ1udrSzfVneA4roNKjdrwpcMRilb8d8G60+lKnrpWcn9bO+B23w2O8Tzfq4aiNSZJqzn5O4Kw16h06fPZ+VUlUHfo97+VAEb7rSh2UgDd4/U+TBlQY7FMj5gBIGvcarVVfQPVPTG94D0j9QAAAABJRU5ErkJggg==',
+ 'Rhel': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABj1BMVEUAAAD///////8AAAD///////8AAAD///8AAAD///////8AAAD///8AAAD+/v4AAAAAAAAAAAArKysAAAD///////8AAAAAAAAAAAAAAAD///8AAAAAAAAAAAD///8AAAD///8AAAAAAAAAAAAAAAB5eXn+/v5JSUnKysrS0tJ5eXmqqqqxsrL+/v4ZCgknJyeHh4eIiIjo6OgZCAdOTk7t7e3///8GCwwPAAArKyv19fX29vb9/f0EAAD////+/v4AAAAGBgYHAAAJAAAMAAANAQAPAQAVAQFyCQV9fX2pIRzmEQjn5+cBAAAFAAAAAADnEQjvEgn////uEQjyEgnsEQjzEgnxEgljBwPaEAj9EwnwEglHBQJHBQNNBQIBAAB3CQR5CQSHCgWLCgWRCgWTCwadDAWmDAapDAa/DgfKDwjWEAgGAADh4eHiEQjmEQjmEQkKAADoEQgLAQDtEQgMAQDuEQnvEQjvEQkPAQAfAgEuAwEvAwE8BAL1Egn3Egn4Egn6Egk+BAL+/v5CBQJrB0muAAAAT3RSTlMAAAMEBAkYGhsbMTRLUmpvcHeIjLe6vcHCxM3P0NbW3Ojp6u/w9ff5+fn6+vr6+/v7+/v8/Pz9/f39/f39/f7+/v7+/v7+/v7+/v7+/v7+Q8UoNAAAAO5JREFUeF4tiwVPA0EYRL9SXIsWl+LuxfcOd2Z3764quLu788NZNrxkksmbDP2R7vH6GioLs+iffEzNXd4+TqPErUUpVqMOvwgdzMPn1rv5vPsVeufBTaBK/bH2FPvkEUuIG5jIIc+sHYn/HJ3dC/Hxuo4y8s44dzwBbFkisHN8bVIdXs6jb+H97aCwbHEIqgcml64CD7YllNkAVQC940MLYe5YzvIeQAXNrd19Roc5MdzfdQLUUKaUYyuG9I8y1g4gj6hIak4X5cBIT2MquZJrJdOqpY11ZpAiqVwbY/C7KY1cRCrZxX4pWXVuiuq/hs49kg4OyP4AAAAASUVORK5CYII=',
+ 'Sabayon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABvFBMVEUAAAAcUaYdVKwAAAAAAAUABAwWRY4YSZYhZtIhaNYHDx0KCgoFDBcKCgoRMmYSNm0fXL0fXb8AAAAYS5gaTp8fXLwgXsEGBgYFBQUZSpgZTZ4JFSgODg4IEiIOJkwOKVIkW7EnXbQLGzUTExMKGC8LHjwMIkITExMiIiIPEBEPJ00QEhMXOXAaPncOJEgoXbApXbEcHBwwMDAEAgAfHRgQDgo3NC8AAAAHBwcKCgoLCwsJCQkaGhofHx8lJSUwMDA0NDQ4ODiRkZEICQocHBweHh4GBgYHCg8mJiYnJycpKSkrKystLS0uLi4ICAgODg43NzcRERF1dXUUFBSjo6O1tbUbGxsEBAMLGS8MDA0iIiIjIyMkJCQNDQ0NHTYKCQkoKCgPDw8QEBArMDkKCgkRERIREhMxMTEyMjISIz00Njk1NTU2NjYCAgIVFRU5OTo5P0c8PD0+Pj4/QURAQEBHR0dKSkpMTExSUlJiYmJlZWVnZ2cWFhZ2dnZ4eHh8fHx9fX2FhYUXFxeVlZWXl5eYmJiZmZmcnJwZGRmlpaWrq6usrKyvr68KFiq/v7/FxcXY2Nji4uLn5+ft7e0yif9uAAAAN3RSTlMAAAApKSkqKioqg4OEhISEhoa1tra3t7y9vr7S09PT09TU+Pj5+fn5+/v7+/v7+/v7/v7+/v7+70RY/wAAAPpJREFUeF4dyWNjw2AUBeC7dfYyorM6rx1exKltzLZt2/rDa/J8OgBVVlFDX39jcTZoUqCse251a2dvu6ccUtWlanLQ4Vpel+ThlWq1l3wEz58tx4dOt1dMlAJk9A5gMjG75LHwo46hzkwosGOMbejumoRvubC9EOrMviT0E0Us9fvN9dA6zxJCNv6+ECGsb6oNWsgmpZT9/UTUZo3Em6AW34guTL4jiAudiCM1kLcw8/SmHERfT1/eueBiDqR1GK1n9w+K8nglxYxd6QAML4ztXoQuj8YFgWcgqdJp8qzty26vaboCNIxBCshyQDKov0aXr29v1ufq1PwPx5Q7bCoh6eoAAAAASUVORK5CYII=',
+ 'Slackware': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AcEDi0qZWWDgAAAAx1JREFUOMt9kktoXHUchb/ffc1M7rySSdJMOknFPMRitLgoNKKI8ZHGKkgrjU8SitidimSh2UkXoQmoO1dGQSxJjdvOtqSaqlR0USEGSjVJGxuSmWR6M3fu4/93YX0g4rc9HA6cc4Q7DI+fpzz7PA8++2mxvZAeBZ4xhHtFcJRmXWsWvb36/OLcyxf5B/KHeYHy7DmGx1+YSDjmWTdlobTGMAStQGkNoLXS4tXDq7u7tUcWz49tA8jR8QUuzB5n5NTCV13F9JEo1JJwTLKuzU61QiOMcd0UDb+BncwQK3Rl15eNja3ui/Njq8aF2eMcO/XlBz0H8oO2ZUkum6A13WB99TtyzXlaCi24SaFa+ZFCzsG2DNnfkdbFjsI1APPhk+d6ujqznycdCxFozadYWvyMpx47wa+bPkGksKwUNnsk3TaCGASRXDZh5LpHXPPg4Rcni+3uYBxrtBbQghlscOVKmYHeEm0ZIZ9xyLffw41ND6VAa43SmjiMByzHYtjzwr9arfshxf5jOKlvKZfn8es77N2uks24PPfSFD/9Uvt7AtPKWmEU9d645eHYJo5tcKi/FX/zG+zmQxQH+rANk862DOW5N/hhaY64cJSa5xNFCgDDILZACMKYWAmh73HmzFsMlBQJ06LeiMinE1S3KzRCm5rXIIoUIoKIYCVM36urZFbEoiBLNMIhAE6/NsSB7h6SKZdL8xsUOnpx9j1KbTdARACIowArYe1ergfNT2i0mIbJys0GI6PT3N1/hJvrPxOFdRJNBQIy/FapI4Bpgohgcjuw+jq8jy8tV55MNBWI4ohS802CpizKv8q+FgALZAfYgSyAZtNro1oLaU1VvxCA029Oraxs7u/tKnXiNjn8HyKwur6lI++6vPK4V7IA7u+1Dyu1tr183ddNbkHuXP8/zEIYeFqiLRl6YO/p0bHJdflT/PD9qZa1W+ry99fcvlAlcZwUpuUAglIRYVgnDEIOlna4q0M/NPnuO1/PzMwg/045O/XeibUt5/Xangx6viSVFpK2jtMpvdyWCz+5ryf10clX3/amp6eZmJjgd441URWWJY8BAAAAAElFTkSuQmCC',
+ 'Trisquel': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABjFBMVEX///8AAAAAAAAAAAAAADMAAGYAAAAAHFUAGWYAF10AImYAIGAAHloAHGMAKGsAGmYAJmYAJGEAKnUAJ1gAMXYAJnEAJGQAI2EAK28AK3cAGTEAMHgALXEALXgALG0AFUAAI2oAK3EAMngANoYALXMANIAAM4IANIIAL3gANIcANokANoQANYQAOY0ANIYANooAN4kAN40AOY0APZMANIUAOY0AO5AAPZUAPJAAP5MAPpQAQJUAOYsAPpYANoUAPpoAPpUAM4AAQJkAPZIAPJEAQpgAN4cAPpQAPZUAPJEAO4oAOosAOo8AQJoAOYsAO44AQpsAO48AQp0AP5UAQpoARJwAQ58ARaAAQZgAQ54AQ50AQpgARaIARqMARaMARaIAR6QARaIARaEASakARKEAR6MASqsARKEASKcAR6MARqYAR6UATbEATa8ARqUARKAAR6oARqMASKgATK8AR6QATbIATbAASq0AR6cASKgASqwAR6UASKcATa8ASqoASqwAS6wASKoAS60ATbHn4CTpAAAAhHRSTlMAAQIFBQUGCQoLDxAREhMUFBUYGhobHB0eHh8gIiIjJCQkJCYoLC0xMTE0NDo6Oz1BQUNHSUxOVFVVVldaWl5iY2RkZWZoamtsb3FycnR1ent9f4KDhIiJioyNkJGYm5+foqOkpqamqKmqrKytsLKzs7e4uLy8v8TFxcXGx8rO0NXY2eZc4XYcAAAA00lEQVR4XkWN1VoCUQAG/3NWtwh7CTsQJOyk7BaDxuxA6bbrxf32gt25m7kZqDRYxziooDV7+1AalMUavQh2AsEZoWvzigLun+T17/c8QiJZ7qu2QKiNmyZthdcR1/as353jIeU1GxMHo5XHdqPFeX8IaDMdHPYN6dRN7LR4qQewdTa35HWkyh+fbxERAMjwlAWJv3CPSKDQ+H7XvHdkV4Pua3Gtm4sPKIF/WV8dop4VKBw/NU33B3x1JbTt+XwhkJQoqRfWvHOy28uqH8JIdomR/R+s9yR3Cso77AAAAABJRU5ErkJggg==',
+ 'Ubuntu': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABKVBMVEX////ojFzplGf1zbnqnHLvs5P10b3yuZv1xKrytZXvtJXys5LysI32waT0n3HxiVHwg0jxhk31kFn0h0zxf0P0hUrveTv2iU3yfkD1hEfyejv5eDLybSX0aR7zZxvyayH6ZxnxZBj4YhH7XAb5WALlUQLeTwHgUAHeTgHfTwD65NzdTQDdTQHdTgD31MfcTgLcTADcTQD////xt5/31Mf54dfmfE/dUAbeVQ/jcUDcTgHeWBnnflHohFvpjGbqkGztnX342Mz53dLgXiP65d399PHdUgrtoYLyu6Xzvaf76eLfXB/rkm/fWhvupojwrpTeVhTgYSfgYynzwa30xbL1ybnngFT31snngljhZS3539XhZzDiajbibDn77OX88Ovrl3X99vTjbz1fisGCAAAAMHRSTlMABgYGBwcHJiorMDA1NXGHjY2Nl5mZmZyfn6O5u8XHzc3X193j9fj4+vr6/f39/f08OUojAAAAx0lEQVR4Xi3HZVbDYBhGwQctWqzFPXiQ+36pu+LubvtfBKcN82/UEhld2vWXxyL6F92gbTPabse8hU/uHMx1SZoyyJWPTwq1Rs7GpYE9+Cg+OJcs1MHvU9y4fnrN31yUm18vMCIPjtw3QMndw4rs8ieVzAAcBlewpe1KM3uaBuD3Dda1BhWXAsi6AFY1a2SqifxZ+rnxWYcJDRkUS3fO1R5vwe+XZgw4D4L3RAJiknoXCVX3WeiUpJ5pIxTvVmg45pl5k4Ot/AGV2iqZBWgJJAAAAABJRU5ErkJggg==',
+ 'Windows': 'iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAA+pJREFUOE+F0n84FHYcB3CWSsL9ojo/6ik64c6PnTjmSS0limmrpBm2G002y++xzXRz6zE0R4nbw+RnTj/WD4sbanLkkAe55ccYlyNme4SrO9u9d13PI3/saZ+/vs/3831ez+f9eb5aWsuqy2mjRYeNUa7YmtjfTico7jNJ8z0eG24NB9vvnDrvufzpq89Npnr8VjMddNmuRh9rDfp36mFg91oM7qPIc5JdbDJq3An/JfCu7Hl53W2lpS220pP2OuniN299jAYbYizSENIoAgbCTdrTKtxOJVdvGo8psUwKy7Vxe4ez1YEVudGP8YEZzyveInFJ6mZRHHqYazDspw/pJwTIuERM5JIwmUdGdyo9K7/BszGzzg6fXzZHGJ8KvzQqXKOpoIeZLjofWR++BPWyCEnPY4xFGEKWQcLjMjKmr1MwfcMYwmz/Y4KOgNki0V5k1dkjUWCK93Kp2PMFFawos8cm1gZ2GqjLXktL4mbQPHLQ4B9ZDFE5+S356fQlyuJMqzH++HnTo6ui2OO1ko9Ul+4fxfd3d4F7k4YTReqpuFS88bGZUE2QNNDobuIq8Q5CduHb7lFJaTnvnym9ergjMWD/FG8zf+aKS3G9JO5C01Asah6wUXrvALKEDoitMMHhDKrKJdg8RU2s0EB2EWWur8dd7PDPFv6dUC0Gv3kAN36VPRGP/5k5NS6lljWxG0TDiSr1VKhoPwhevRMSqkwRxDObc/DavGtpP6zoi8XOyZfhnyNEvKANBU0P8VPfI/wyNCGXSn7wlEmyA9KrgmOKGth3eDVvPfyywq2dnUEv2R9qG2rLsH7xJXziKnWcI8tlTvEC7Mu8hROlImTU9aKqcwQ1vWOihWFu+sJknmph5CvxQh87c7bNh/NXo03hrMCosyvLmMNgMF7TQL6J1dsZIUVwjKqEO+cajp5vxPN439U/gKBt8PTcYHzL/BgHCyOf4unAISj6mFC2bYC82kB5Ls460NHRUVsDeYSXpGw7UgC7sAtwShDgzdM38W7BbURXtqpqhfmB8sEQuXwoCM/6faGQuGCxyxyKWhIm+PrSD495WL3cT0hhi8Whc3NbAs9KaOyCTvrJ8qkdX19XBeTUDU00+55USFzVU2yHstcaix0mUAjJkJeuRU868Ucmk0lcguiBnMAVxjbbdHV1yeq8+u4Hgo22huSG+iQXp83ftaxW3lsPZcs6KG5T8OwaAfJiPcxlrVRVRhvF02i0F/t5VbHZ7JWDfErKTLnhE3mFPuRFepg/uxqz6TqLv6euGj3ut87t/4ylvre3t3ZehOWWO1zjSFEqMVP4GfGb/DBykJcjmaZOoLsc+hcVY/LaAgcTQAAAAABJRU5ErkJggg==',
+ 'OpenBSD': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAykIPu64pQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADTklEQVQ4y32RXUxTdxjGn3N6eujoKT3SUkuk3VoBGfVjgFXAsZ7WkipyYXQbuu3CzUXZmGRbssnFEseFkWzgcGzGXky9MWL8TsC4IeFgtK4oAqOnG5vMVl1pCMVWQD7b/y5M6jLdflfvxfPked/nBQA0NDSChqnGVrLuGkES742NhJAdhAKAuk9yyUs5Gry7RQMZAARCWgivpQiPe71P5DUfH0xaqTL7m/iiLkJmphawa+e4SM2PvUyC4yUIBu8CnAQKAK53rCA5OUtQtStVpJ4Gw/FOBddZVKhCfq4MP4n6+at+DUsJm/e0G9JZzYEvI2tHwlEYjDxomkZ+3nG8WroRtHihZVOhVlorDQzh0okhcByDP4ZGcf+X9XAsvY5/RsBa7Kq5H/CqLctKyl/g08S2i6fq8W/MS3P34T9wNDVYSeDX1eTD9xhiLXbtB/Akwmmv6Kr+ICFkLpGhtNSM3qsSstS3oX8lSsmsxS6ZVn3j6PvVVqhUcvC8AtPxVPxwygVKvngN89WOjgVprggGA4eenjB4nsXsTASpC63I0wVTZYPR11FoKRB8Ax54PCFk6BhMTk5CPR3GSbHouGzknr/bYFq9EAvfc9Tu1sLjHcXNKxLuTOTgzOlOe7IHBc/beAXWpWmXlz8a84nhcLQ+ecVzsAEQrMWuMX+f9HZF2YPZ28FVSNfoPWqOzMUmqYMAJm7+/OOzXQFwHGpyEV+vi+yvtxBC9pDmpgJC4tvI3mo9GTitIxvW24nT7ug67HY/3eDs2bbyrVsrY2day70rV6kRfDAHk5lDLJqAmmeRiD9GJDKHvwb74R8G0mkTPjrQTTG122xkTTbwaV2b1H4u16JQKXGr7yG2b8/H1MQ09IsTSEmRwzf4CCwzD+dmE1re8CI7wwi5XNlFf9vaTXX4dWJg4LLl7h05fpNGwNAMWpp9CIVYNO/tRCzGwpDFQaVMQTS2CKY0BWr3GVGWNSXKACDDaA4Mh976pq9f5Sy09GgKlmeAMIBKzUKpU+BFoxJecRhUfAbMxDi4eADfHVmE79v7q575gvvYeVvjZ58LD5mwsKUyX0hnf0feslnQCWD4zxnc6reKisxsfH2oscqcmTmK/+Ow252cna7K52r+Bky6PqmoT5HBAAAAAElFTkSuQmCC',
+ 'Gnu': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoYAywUV5gQrwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADcElEQVQ4y43Tb0jjBRzH8c9v+7nNMebcUW21Cc78g/wcuhByIScoMRwoTBmFlZCmIJ14axqkgoYIkXIqKIVBEuJNUBEUPRlpqDC3Q2Ex0nTezun2YOaPLXNIv7Vvj7zgiOj1+PPk/eADjuNEuHN6ekqMw+H4IzMz8xChUCjV1NT0JbO7uxtfXFy8NZvNr21tbd0AAEQikY6I0m1tbQbx2NjYZiqV+vn29jY+PDw8xhYWFj45PDzcb25uhlQqfSTief6X0dFRpqKigvF4PPPipaWlY7lcXhCLxXJnZmY+ZTY2NnzX19ePGxsbHw0MDLivrq5mc3Jy2pPJZLVWq/2cdbvdDSzLholoNJ1OMy6Xq0Ymk5HNZktOTU29qMgA8HYqlaKDgwNKp9M0PT09BgAM/iGuqqoimUx2yPP8U5/P9wEAMB0dHRUKheJHiUTyeGhoqAUAnE7nR0qlsjcQCLwjlsvlz+bm5mQWi0VSWlr6bXV1tU6hUMj6+/vfN5lMN0xxcfG1zWZ7SETTSqWSGhoamPHxcajV6s+8Xu9Xou7u7t9VKtW00+mkSCTC6PV6aDQa8Dw/Wl9fP8UAQCgUosvLSyovL2eWl5dRUFBw7Ha7v9vc3By5K3g1EAg8FQSBiIguLi4IgBwA2LtEjuPuJxKJ62AwKFpdXf0eQBIvYVmW/cLlchEAWK1WAADT09NzX6PR/OTz+eKVlZUzKpVqTyqVvsnzfLCkpGSrtrb2t97eXnFeXl5ZKpWyZ2RkPPP7/UUnJyefGI3GU+zt7aU4jotOTk7mAUBfX1+b1Wq9kcvlBIAcDgctLCyQxWKhoqIi6uzs/BoAVlZW3qqpqbllZmdnf1hfX//Q4/HEzWbzX+3t7fcMBgMFg0EYjUYmEolAEAREo1Hk5+fT+fk5Mzg4GD86OpJ0dXXJGQBoaWl5Ra/XP6yrq3tQVlam2N7ehslkAsuySCaTUKvVSCQS2NnZSXAcJxYEQTEyMvKeIAhLDADY7fZ7BoPhm6ysLFpbWzuan5//WKvVvsHzPEWjUSYSiSA3N5d0Oh0TjUaf+/1+S2Nj46/4FwYAr7e2tnbF4/E/iYjC4TCFw+F0LBaj/f19mpiYeID/IAagAyABYLXb7cLZ2Rml02nyer3POY6rwv8hEr34u0IkEk1mZ2cTgGMA7768/RtL5JKsGzrLIgAAAABJRU5ErkJggg==',
+ 'CrunchBang': 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAQCAQAAAC45EetAAAA8ElEQVR4XnWOsUpCYQBGz1TIHYu2Qix6g0DEtSeQu/UIISJtUS8gJq61F1wcdMohcBDxKUR8hsz1xA/y44/cs3znbB+RJ0Skl3pSkeFQbUs79VAPzrwPFRmN1Ja0Ug/16I93+1oi4lKte+zMXv32WuoAm43lXMrqzbFncgWw21lORf4+/PREKpAhYqZuPXZ+T/3yXbZEajV1JavUQ104sRcq0myqc5mnHurWqc/7yhExVwuPncl+C4Bu13L60ueAwcByOtLhgAIRCzU38fRGTmSxUBvSSD3Ui1NvQkXWa7Uq1dRD9R17HiqyRUSy1NP6B7e1Yu2GtlUKAAAAAElFTkSuQmCC',
+ 'Yuno': 'iVBORw0KGgoAAAANSUhEUgAAABgAAAAPCAYAAAD+pA/bAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAABDtJREFUOE+FlHtMm1UYxrtsi8aEgCb+oTFmZur+WNS5RaPERU10C2qGaBgb6hgwLwMmHTIKlIKlQIHSQrmU24BSSmnpBVooUmihtEC5yKWDjVu5uOkcEca4lG5E93j6EQmELX7Jky/fOed9fu973vMdGu0xT3Cgz57yXMZLDdXcy821PFWLKmuA6HqLMqtLX5POl4iYb2ukWW8IOOFe/qfe3/M4n0eOjwyZD8//bldODOk37N1yDJgl+LVdjEGLFKO9KkzZm8hbje7mIrTXZ7sMtTydrJh15H8hHW11XvN/jGS7VudcD5w34ZZzeQYb67fwYO03LN4exo1+LWzNxbA05O5QuzbHqRYn+++CHDx4YK9WLfaedfQzV5em54g5Zbi8OIml+VFMDLWQ7GXoaSmFWZsDZVGCO2u0EbkhHTrhFqi9PmelSsQ8tAtSVch60dpUeGe4kxgZxegzVkBzlQ2NKBG2+iJIMqMok9r8OLRIMqApToSqmAWTmk9B2+o2YW79oshU7ABcuvAFrVGWXkVKpBYoSaBSxIS2mINpiwbjZiUMZRloVfJQyaXDKObBpimBScpHFe8KmmXpaKhK3arGrBVuVBclHN2CiPNin1OVs1tVJYlQlyZBxA6DviQVo6ZaOKd7sTplw53BVugruBBzfsRslw7rZPxaczWutSpQV/gzJPxo1JexyfaxKBBpuiEx+tw+CpKdEvGWTprGlhcwqbIzL5/DYKMYndpK3L1hxf3ZfkrzwybUZjPhnOqmvlcmutFF1jis9QSShOrcWNSXJ1MA0ou/NZWc8Ddfe4VGO3bk0JON1dyMMlK+gmxNrZCFhZF2Kng7YNO0awt4b7wLNp2EqtAsF6ImP56SG0B6siovTYpIjg15gapCVhAfJRUyIBFEo6k8AyuTtkcC/qvG/XbDexulWJvqgYH0o0nKhVHFJ40XwFQnWM5OCX+XMg86c3KvVMSMapCmPpSTIygTxGKZZOcOXhrr3Mp4uzkFuG6B3ajE3TELDDU8qEmsmvRATxquKkxAnSTFjwKEfv3JU9JC5unG6rQ1bTkbQ4Yq/DVgxOqwBWt2K9Yne3ZCZvrgHO2k5paHzOhSiVCZSkdNTgzy40JRlPgDhDHBCxUZdCs91G8fLeK87zOl6XSOICZYXMGNhDqX9fDP/mbK2DXVi/szm03eLpejl5pzOfqwOt4JBT8OeYwQt/4R/BR0OzXiLCM5LOCji/4nXt46rpywgG+zor5RxgSdupBzJdglSY+5ZZbl3XNY6mbn7W0Lcx06zBg1WBjtcC6OmG+OmRTrFrnIUZESZeVeCpwh8TpiPsQ47/tloM97T+/6m8mg55mT3tStyL54mhlwwtszNvjzD8/6HH8i7PvvPPRioZdRWuDBZUR6pEWG7I8P9Xs1Jsj36MfvvO5J/+rTw58dP7afJPfBgeef3XGz/gskFVpJc4HwGwAAAABJRU5ErkJggg=='
+ }
+ };
+
+ ExpandComment = {
+ init: function() {
+ if (g.VIEW !== 'index' || !Conf['Comment Expansion']) {
+ return;
+ }
+ if (g.BOARD.ID === 'g') {
+ this.callbacks.push(Fourchan.code);
+ }
+ if (g.BOARD.ID === 'sci') {
+ this.callbacks.push(Fourchan.math);
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Comment Expansion',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var a;
+
+ if (a = $('.abbr > a', this.nodes.comment)) {
+ return $.on(a, 'click', ExpandComment.cb);
+ }
+ },
+ callbacks: [],
+ cb: function(e) {
+ var post;
+
+ e.preventDefault();
+ post = Get.postFromNode(this);
+ return ExpandComment.expand(post);
+ },
+ expand: function(post) {
+ var a;
+
+ if (post.nodes.longComment && !post.nodes.longComment.parentNode) {
+ $.replace(post.nodes.shortComment, post.nodes.longComment);
+ post.nodes.comment = post.nodes.longComment;
+ return;
+ }
+ if (!(a = $('.abbr > a', post.nodes.comment))) {
+ return;
+ }
+ a.textContent = "Post No." + post + " Loading...";
+ return $.cache("//api.4chan.org" + a.pathname + ".json", function() {
+ return ExpandComment.parse(this, a, post);
+ });
+ },
+ contract: function(post) {
+ var a;
+
+ if (!post.nodes.shortComment) {
+ return;
+ }
+ a = $('.abbr > a', post.nodes.shortComment);
+ a.textContent = 'here';
+ $.replace(post.nodes.longComment, post.nodes.shortComment);
+ return post.nodes.comment = post.nodes.shortComment;
+ },
+ parse: function(req, a, post) {
+ var callback, clone, comment, href, postObj, posts, quote, spoilerRange, status, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
+
+ status = req.status;
+ if (![200, 304].contains(status)) {
+ a.textContent = "Error " + req.statusText + " (" + status + ")";
+ return;
+ }
+ posts = JSON.parse(req.response).posts;
+ if (spoilerRange = posts[0].custom_spoiler) {
+ Build.spoilerRange[g.BOARD] = spoilerRange;
+ }
+ for (_i = 0, _len = posts.length; _i < _len; _i++) {
+ postObj = posts[_i];
+ if (postObj.no === post.ID) {
+ break;
+ }
+ }
+ if (postObj.no !== post.ID) {
+ a.textContent = "Post No." + post + " not found.";
+ return;
+ }
+ comment = post.nodes.comment;
+ clone = comment.cloneNode(false);
+ clone.innerHTML = postObj.com;
+ _ref = $$('.quotelink', clone);
+ for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
+ quote = _ref[_j];
+ href = quote.getAttribute('href');
+ if (href[0] === '/') {
+ continue;
+ }
+ quote.href = "/" + post.board + "/res/" + href;
+ }
+ post.nodes.shortComment = comment;
+ $.replace(comment, clone);
+ post.nodes.comment = post.nodes.longComment = clone;
+ post.parseComment();
+ post.parseQuotes();
+ _ref1 = ExpandComment.callbacks;
+ for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
+ callback = _ref1[_k];
+ callback.call(post);
+ }
+ }
+ };
+
+ ExpandThread = {
+ init: function() {
+ if (g.VIEW !== 'index' || !Conf['Thread Expansion']) {
+ return;
+ }
+ return Thread.prototype.callbacks.push({
+ name: 'Thread Expansion',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var a, span;
+
+ if (!(span = $('.summary', this.OP.nodes.root.parentNode))) {
+ return;
+ }
+ a = $.el('a', {
+ textContent: "+ " + span.textContent,
+ className: 'summary',
+ href: 'javascript:;'
+ });
+ $.on(a, 'click', ExpandThread.cbToggle);
+ return $.replace(span, a);
+ },
+ cbToggle: function() {
+ var op;
+
+ op = Get.postFromRoot(this.previousElementSibling);
+ return ExpandThread.toggle(op.thread);
+ },
+ toggle: function(thread) {
+ var a, inlined, num, post, replies, reply, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
+
+ threadRoot = thread.OP.nodes.root.parentNode;
+ a = $('.summary', threadRoot);
+ switch (thread.isExpanded) {
+ case false:
+ case void 0:
+ thread.isExpanded = 'loading';
+ _ref = $$('.thread > .postContainer', threadRoot);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ post = _ref[_i];
+ ExpandComment.expand(Get.postFromRoot(post));
+ }
+ if (!a) {
+ thread.isExpanded = true;
+ return;
+ }
+ thread.isExpanded = 'loading';
+ a.textContent = a.textContent.replace('+', '× Loading...');
+ $.cache("//api.4chan.org/" + thread.board + "/res/" + thread + ".json", function() {
+ return ExpandThread.parse(this, thread, a);
+ });
+ break;
+ case 'loading':
+ thread.isExpanded = false;
+ if (!a) {
+ return;
+ }
+ a.textContent = a.textContent.replace('× Loading...', '+');
+ break;
+ case true:
+ thread.isExpanded = false;
+ if (a) {
+ a.textContent = a.textContent.replace('-', '+');
+ num = (function() {
+ if (thread.isSticky) {
+ return 1;
+ } else {
+ switch (g.BOARD.ID) {
+ case 'b':
+ case 'vg':
+ case 'q':
+ return 3;
+ case 't':
+ return 1;
+ default:
+ return 5;
+ }
+ }
+ })();
+ replies = $$('.thread > .replyContainer', threadRoot).slice(0, -num);
+ for (_j = 0, _len1 = replies.length; _j < _len1; _j++) {
+ reply = replies[_j];
+ if (Conf['Quote Inlining']) {
+ while (inlined = $('.inlined', reply)) {
+ inlined.click();
+ }
+ }
+ $.rm(reply);
+ }
+ }
+ _ref1 = $$('.thread > .postContainer', threadRoot);
+ for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
+ post = _ref1[_k];
+ ExpandComment.contract(Get.postFromRoot(post));
+ }
+ }
+ },
+ parse: function(req, thread, a) {
+ var link, node, nodes, post, posts, replies, reply, spoilerRange, status, _i, _len;
+
+ if (a.textContent[0] === '+') {
+ return;
+ }
+ status = req.status;
+ if (![200, 304].contains(status)) {
+ a.textContent = "Error " + req.statusText + " (" + status + ")";
+ $.off(a, 'click', ExpandThread.cb.toggle);
+ return;
+ }
+ thread.isExpanded = true;
+ a.textContent = a.textContent.replace('× Loading...', '-');
+ posts = JSON.parse(req.response).posts;
+ if (spoilerRange = posts[0].custom_spoiler) {
+ Build.spoilerRange[g.BOARD] = spoilerRange;
+ }
+ replies = posts.slice(1);
+ posts = [];
+ nodes = [];
+ for (_i = 0, _len = replies.length; _i < _len; _i++) {
+ reply = replies[_i];
+ if (post = thread.posts[reply.no]) {
+ nodes.push(post.nodes.root);
+ continue;
+ }
+ node = Build.postFromObject(reply, thread.board);
+ post = new Post(node, thread, thread.board);
+ link = $('a[title="Highlight this post"]', node);
+ link.href = "res/" + thread + "#p" + post;
+ link.nextSibling.href = "res/" + thread + "#q" + post;
+ posts.push(post);
+ nodes.push(node);
+ }
+ Main.callbackNodes(Post, posts);
+ $.after(a, nodes);
+ return Fourchan.parseThread(thread.ID, 1, nodes.length);
+ }
+ };
+
+ FileInfo = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['File Info Formatting']) {
+ return;
+ }
+ this.funk = this.createFunc(Conf['fileInfo']);
+ return Post.prototype.callbacks.push({
+ name: 'File Info Formatting',
+ cb: this.node
+ });
+ },
+ node: function() {
+ if (!this.file || this.isClone) {
+ return;
+ }
+ return this.file.text.innerHTML = FileInfo.funk(FileInfo, this);
+ },
+ createFunc: function(format) {
+ var code;
+
+ code = format.replace(/%(.)/g, function(s, c) {
+ if (c in FileInfo.formatters) {
+ return "' + FileInfo.formatters." + c + ".call(post) + '";
+ } else {
+ return s;
+ }
+ });
+ return Function('FileInfo', 'post', "return '" + code + "'");
+ },
+ convertUnit: function(size, unit) {
+ var i;
+
+ if (unit === 'B') {
+ return "" + (size.toFixed()) + " Bytes";
+ }
+ i = 1 + ['KB', 'MB'].indexOf(unit);
+ while (i--) {
+ size /= 1024;
+ }
+ size = unit === 'MB' ? Math.round(size * 100) / 100 : size.toFixed();
+ return "" + size + " " + unit;
+ },
+ escape: function(name) {
+ return name.replace(/<|>/g, function(c) {
+ return c === '<' && '<' || '>';
+ });
+ },
+ formatters: {
+ t: function() {
+ return this.file.URL.match(/\d+\..+$/)[0];
+ },
+ T: function() {
+ return "" + (FileInfo.formatters.t.call(this)) + "";
+ },
+ l: function() {
+ return "" + (FileInfo.formatters.n.call(this)) + "";
+ },
+ L: function() {
+ return "" + (FileInfo.formatters.N.call(this)) + "";
+ },
+ n: function() {
+ var fullname, shortname;
+
+ fullname = this.file.name;
+ shortname = Build.shortFilename(this.file.name, this.isReply);
+ if (fullname === shortname) {
+ return FileInfo.escape(fullname);
+ } else {
+ return "" + (FileInfo.escape(shortname)) + "" + (FileInfo.escape(fullname)) + "";
+ }
+ },
+ N: function() {
+ return FileInfo.escape(this.file.name);
+ },
+ p: function() {
+ if (this.file.isSpoiler) {
+ return 'Spoiler, ';
+ } else {
+ return '';
+ }
+ },
+ s: function() {
+ return this.file.size;
+ },
+ B: function() {
+ return FileInfo.convertUnit(this.file.sizeInBytes, 'B');
+ },
+ K: function() {
+ return FileInfo.convertUnit(this.file.sizeInBytes, 'KB');
+ },
+ M: function() {
+ return FileInfo.convertUnit(this.file.sizeInBytes, 'MB');
+ },
+ r: function() {
+ if (this.file.isImage) {
+ return this.file.dimensions;
+ } else {
+ return 'PDF';
+ }
+ }
+ }
+ };
+
+ Fourchan = {
+ init: function() {
+ var board;
+
+ if (g.VIEW === 'catalog') {
+ return;
+ }
+ board = g.BOARD.ID;
+ if (board === 'g') {
+ $.globalEval("window.addEventListener('prettyprint', function(e) {\n var pre = e.detail;\n pre.innerHTML = prettyPrintOne(pre.innerHTML);\n}, false);");
+ Post.prototype.callbacks.push({
+ name: 'Parse /g/ code',
+ cb: this.code
+ });
+ }
+ if (board === 'sci') {
+ $.globalEval("window.addEventListener('jsmath', function(e) {\n if (jsMath.loaded) {\n // process one post\n jsMath.ProcessBeforeShowing(e.detail);\n } else {\n // load jsMath and process whole document\n jsMath.Autoload.Script.Push('ProcessBeforeShowing', [null]);\n jsMath.Autoload.LoadJsMath();\n }\n}, false);");
+ return Post.prototype.callbacks.push({
+ name: 'Parse /sci/ math',
+ cb: this.math
+ });
+ }
+ },
+ code: function() {
+ var pre, _i, _len, _ref;
+
+ if (this.isClone) {
+ return;
+ }
+ _ref = $$('.prettyprint', this.nodes.comment);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ pre = _ref[_i];
+ $.event('prettyprint', pre, window);
+ }
+ },
+ math: function() {
+ if (this.isClone || !$('.math', this.nodes.comment)) {
+ return;
+ }
+ return $.event('jsmath', this.nodes.post, window);
+ },
+ parseThread: function(threadID, offset, limit) {
+ return $.event('4chanParsingDone', {
+ threadId: threadID,
+ offset: offset,
+ limit: limit
+ });
+ }
+ };
+
+ Keybinds = {
+ init: function() {
+ var init;
+
+ if (g.VIEW === 'catalog' || !Conf['Keybinds']) {
+ return;
+ }
+ init = function() {
+ var node, _i, _len, _ref;
+
+ $.off(d, '4chanXInitFinished', init);
+ $.on(d, 'keydown', Keybinds.keydown);
+ _ref = $$('[accesskey]');
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ node = _ref[_i];
+ node.removeAttribute('accesskey');
+ }
+ };
+ return $.on(d, '4chanXInitFinished', init);
+ },
+ keydown: function(e) {
+ var form, key, notification, notifications, op, target, thread, threadRoot, _i, _len;
+
+ if (!(key = Keybinds.keyCode(e))) {
+ return;
+ }
+ target = e.target;
+ if (['INPUT', 'TEXTAREA'].contains(target.nodeName)) {
+ if (!/(Esc|Alt|Ctrl|Meta)/.test(key)) {
+ return;
+ }
+ }
+ threadRoot = Nav.getThread();
+ if (op = $('.op', threadRoot)) {
+ thread = Get.postFromNode(op).thread;
+ }
+ switch (key) {
+ case Conf['Toggle board list']:
+ if (Conf['Custom Board Navigation']) {
+ Header.toggleBoardList();
+ }
+ break;
+ case Conf['Open empty QR']:
+ Keybinds.qr(threadRoot);
+ break;
+ case Conf['Open QR']:
+ Keybinds.qr(threadRoot, true);
+ break;
+ case Conf['Open settings']:
+ Settings.open();
+ break;
+ case Conf['Close']:
+ if (Settings.dialog) {
+ Settings.close();
+ } else if ((notifications = $$('.notification')).length) {
+ for (_i = 0, _len = notifications.length; _i < _len; _i++) {
+ notification = notifications[_i];
+ $('.close', notification).click();
+ }
+ } else if (QR.nodes) {
+ QR.close();
+ }
+ break;
+ case Conf['Spoiler tags']:
+ if (target.nodeName !== 'TEXTAREA') {
+ return;
+ }
+ Keybinds.tags('spoiler', target);
+ break;
+ case Conf['Code tags']:
+ if (target.nodeName !== 'TEXTAREA') {
+ return;
+ }
+ Keybinds.tags('code', target);
+ break;
+ case Conf['Eqn tags']:
+ if (target.nodeName !== 'TEXTAREA') {
+ return;
+ }
+ Keybinds.tags('eqn', target);
+ break;
+ case Conf['Math tags']:
+ if (target.nodeName !== 'TEXTAREA') {
+ return;
+ }
+ Keybinds.tags('math', target);
+ break;
+ case Conf['Toggle sage']:
+ if (QR.nodes) {
+ Keybinds.sage();
+ }
+ break;
+ case Conf['Submit QR']:
+ if (QR.nodes && !QR.status()) {
+ QR.submit();
+ }
+ break;
+ case Conf['Watch']:
+ ThreadWatcher.toggle(thread);
+ break;
+ case Conf['Update']:
+ ThreadUpdater.update();
+ break;
+ case Conf['Expand image']:
+ Keybinds.img(threadRoot);
+ break;
+ case Conf['Expand images']:
+ Keybinds.img(threadRoot, true);
+ break;
+ case Conf['fappeTyme']:
+ if (!$('#menu.left')) {
+ Header.menuButton.click();
+ }
+ FappeTyme.input.click();
+ break;
+ case Conf['Front page']:
+ window.location = "/" + g.BOARD + "/0#delform";
+ break;
+ case Conf['Open front page']:
+ $.open("/" + g.BOARD + "/#delform");
+ break;
+ case Conf['Next page']:
+ if (form = $('.next form')) {
+ window.location = form.action;
+ }
+ break;
+ case Conf['Previous page']:
+ if (form = $('.prev form')) {
+ window.location = form.action;
+ }
+ break;
+ case Conf['Open catalog']:
+ if (Conf['External Catalog']) {
+ window.location = CatalogLinks.external(g.BOARD.ID);
+ } else {
+ window.location = "/" + g.BOARD + "/catalog";
+ }
+ break;
+ case Conf['Next thread']:
+ if (g.VIEW === 'thread') {
+ return;
+ }
+ Nav.scroll(+1);
+ break;
+ case Conf['Previous thread']:
+ if (g.VIEW === 'thread') {
+ return;
+ }
+ Nav.scroll(-1);
+ break;
+ case Conf['Expand thread']:
+ ExpandThread.toggle(thread);
+ break;
+ case Conf['Open thread']:
+ Keybinds.open(thread);
+ break;
+ case Conf['Open thread tab']:
+ Keybinds.open(thread, true);
+ break;
+ case Conf['Next reply']:
+ Keybinds.hl(+1, threadRoot);
+ break;
+ case Conf['Previous reply']:
+ Keybinds.hl(-1, threadRoot);
+ break;
+ case Conf['Hide']:
+ if (g.VIEW === 'index') {
+ ThreadHiding.toggle(thread);
+ }
+ break;
+ default:
+ return;
+ }
+ e.preventDefault();
+ return e.stopPropagation();
+ },
+ keyCode: function(e) {
+ var kc, key;
+
+ key = (function() {
+ switch (kc = e.keyCode) {
+ case 8:
+ return '';
+ case 13:
+ return 'Enter';
+ case 27:
+ return 'Esc';
+ case 37:
+ return 'Left';
+ case 38:
+ return 'Up';
+ case 39:
+ return 'Right';
+ case 40:
+ return 'Down';
+ default:
+ if ((48 <= kc && kc <= 57) || (65 <= kc && kc <= 90)) {
+ return String.fromCharCode(kc).toLowerCase();
+ } else {
+ return null;
+ }
+ }
+ })();
+ if (key) {
+ if (e.altKey) {
+ key = 'Alt+' + key;
+ }
+ if (e.ctrlKey) {
+ key = 'Ctrl+' + key;
+ }
+ if (e.metaKey) {
+ key = 'Meta+' + key;
+ }
+ if (e.shiftKey) {
+ key = 'Shift+' + key;
+ }
+ }
+ return key;
+ },
+ qr: function(thread, quote) {
+ if (!(Conf['Quick Reply'] && QR.postingIsEnabled)) {
+ return;
+ }
+ QR.open();
+ if (quote) {
+ QR.quote.call($('input', $('.post.highlight', thread) || thread));
+ }
+ QR.nodes.com.focus();
+ if (Conf['QR Shortcut']) {
+ return $.rmClass($('.qr-shortcut'), 'disabled');
+ }
+ },
+ tags: function(tag, ta) {
+ var range, selEnd, selStart, value;
+
+ value = ta.value;
+ selStart = ta.selectionStart;
+ selEnd = ta.selectionEnd;
+ ta.value = value.slice(0, selStart) + ("[" + tag + "]") + value.slice(selStart, selEnd) + ("[/" + tag + "]") + value.slice(selEnd);
+ range = ("[" + tag + "]").length + selEnd;
+ ta.setSelectionRange(range, range);
+ return $.event('input', null, ta);
+ },
+ sage: function() {
+ var isSage;
+
+ isSage = /sage/i.test(QR.nodes.email.value);
+ return QR.nodes.email.value = isSage ? "" : "sage";
+ },
+ img: function(thread, all) {
+ var post;
+
+ if (all) {
+ return ImageExpand.cb.toggleAll();
+ } else {
+ post = Get.postFromNode($('.post.highlight', thread) || $('.op', thread));
+ return ImageExpand.toggle(post);
+ }
+ },
+ open: function(thread, tab) {
+ var url;
+
+ if (g.VIEW !== 'index') {
+ return;
+ }
+ url = "/" + thread.board + "/res/" + thread;
+ if (tab) {
+ return $.open(url);
+ } else {
+ return location.href = url;
+ }
+ },
+ hl: function(delta, thread) {
+ var headRect, next, postEl, rect, replies, reply, root, topMargin, _i, _len;
+
+ if (Conf['Fixed Header'] && Conf['Bottom header']) {
+ topMargin = 0;
+ } else {
+ headRect = Header.bar.getBoundingClientRect();
+ topMargin = headRect.top + headRect.height;
+ }
+ if (postEl = $('.reply.highlight', thread)) {
+ $.rmClass(postEl, 'highlight');
+ rect = postEl.getBoundingClientRect();
+ if (rect.bottom >= topMargin && rect.top <= doc.clientHeight) {
+ root = postEl.parentNode;
+ next = $.x('child::div[contains(@class,"post reply")]', delta === +1 ? root.nextElementSibling : root.previousElementSibling);
+ if (!next) {
+ this.focus(postEl);
+ return;
+ }
+ if (!(g.VIEW === 'thread' || $.x('ancestor::div[parent::div[@class="board"]]', next) === thread)) {
+ return;
+ }
+ rect = next.getBoundingClientRect();
+ if (rect.top < 0 || rect.bottom > doc.clientHeight) {
+ if (delta === -1) {
+ window.scrollBy(0, rect.top - topMargin);
+ } else {
+ next.scrollIntoView(false);
+ }
+ }
+ this.focus(next);
+ return;
+ }
+ }
+ replies = $$('.reply', thread);
+ if (delta === -1) {
+ replies.reverse();
+ }
+ for (_i = 0, _len = replies.length; _i < _len; _i++) {
+ reply = replies[_i];
+ rect = reply.getBoundingClientRect();
+ if (delta === +1 && rect.top >= topMargin || delta === -1 && rect.bottom <= doc.clientHeight) {
+ this.focus(reply);
+ return;
+ }
+ }
+ },
+ focus: function(post) {
+ return $.addClass(post, 'highlight');
+ }
+ };
+
+ Nav = {
+ init: function() {
+ var append, next, prev, span;
+
+ switch (g.VIEW) {
+ case 'index':
+ if (!Conf['Index Navigation']) {
+ return;
+ }
+ break;
+ case 'thread':
+ if (!Conf['Reply Navigation']) {
+ return;
+ }
+ break;
+ default:
+ return;
+ }
+ span = $.el('span', {
+ id: 'navlinks'
+ });
+ prev = $.el('a', {
+ textContent: '▲',
+ href: 'javascript:;'
+ });
+ next = $.el('a', {
+ textContent: '▼',
+ href: 'javascript:;'
+ });
+ $.on(prev, 'click', this.prev);
+ $.on(next, 'click', this.next);
+ $.add(span, [prev, $.tn(' '), next]);
+ append = function() {
+ $.off(d, '4chanXInitFinished', append);
+ return $.add(d.body, span);
+ };
+ return $.on(d, '4chanXInitFinished', append);
+ },
+ prev: function() {
+ if (g.VIEW === 'thread') {
+ return window.scrollTo(0, 0);
+ } else {
+ return Nav.scroll(-1);
+ }
+ },
+ next: function() {
+ if (g.VIEW === 'thread') {
+ return window.scrollTo(0, d.body.scrollHeight);
+ } else {
+ return Nav.scroll(+1);
+ }
+ },
+ getThread: function(full) {
+ var headRect, i, rect, thread, threads, topMargin, _i, _len;
+
+ if (Conf['Bottom header']) {
+ topMargin = 0;
+ } else {
+ headRect = Header.bar.getBoundingClientRect();
+ topMargin = headRect.top + headRect.height;
+ }
+ threads = $$('.thread:not([hidden])');
+ for (i = _i = 0, _len = threads.length; _i < _len; i = ++_i) {
+ thread = threads[i];
+ rect = thread.getBoundingClientRect();
+ if (rect.bottom > topMargin) {
+ if (full) {
+ return [threads, thread, i, rect, topMargin];
+ } else {
+ return thread;
+ }
+ }
+ }
+ return $('.board');
+ },
+ scroll: function(delta) {
+ var i, rect, thread, threads, top, topMargin, _ref, _ref1;
+
+ _ref = Nav.getThread(true), threads = _ref[0], thread = _ref[1], i = _ref[2], rect = _ref[3], topMargin = _ref[4];
+ top = rect.top - topMargin;
+ if (!((delta === -1 && Math.ceil(top) < 0) || (delta === +1 && top > 1))) {
+ i += delta;
+ }
+ top = ((_ref1 = threads[i]) != null ? _ref1.getBoundingClientRect().top : void 0) - topMargin;
+ return window.scrollBy(0, top);
+ }
+ };
+
+ RelativeDates = {
+ INTERVAL: $.MINUTE / 2,
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Relative Post Dates']) {
+ return;
+ }
+ $.on(d, 'visibilitychange ThreadUpdate', this.flush);
+ this.flush();
+ return Post.prototype.callbacks.push({
+ name: 'Relative Post Dates',
+ cb: this.node
+ });
+ },
+ node: function() {
+ var dateEl;
+
+ if (this.isClone) {
+ return;
+ }
+ dateEl = this.nodes.date;
+ dateEl.title = dateEl.textContent;
+ return RelativeDates.setUpdate(this);
+ },
+ relative: function(diff, now, date) {
+ var days, months, number, rounded, unit, years;
+
+ unit = (number = diff / $.DAY) >= 1 ? (years = now.getYear() - date.getYear(), months = now.getMonth() - date.getMonth(), days = now.getDate() - date.getDate(), years > 1 ? (number = years - (months < 0 || months === 0 && days < 0), 'year') : years === 1 && (months > 0 || months === 0 && days >= 0) ? (number = years, 'year') : (months = (months + 12) % 12) > 1 ? (number = months - (days < 0), 'month') : months === 1 && days >= 0 ? (number = months, 'month') : 'day') : (number = diff / $.HOUR) >= 1 ? 'hour' : (number = diff / $.MINUTE) >= 1 ? 'minute' : (number = Math.max(0, diff) / $.SECOND, 'second');
+ rounded = Math.round(number);
+ if (rounded !== 1) {
+ unit += 's';
+ }
+ return "" + rounded + " " + unit + " ago";
+ },
+ stale: [],
+ flush: function() {
+ var now, update, _i, _len, _ref;
+
+ if (d.hidden) {
+ return;
+ }
+ now = new Date();
+ _ref = RelativeDates.stale;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ update = _ref[_i];
+ update(now);
+ }
+ RelativeDates.stale = [];
+ clearTimeout(RelativeDates.timeout);
+ return RelativeDates.timeout = setTimeout(RelativeDates.flush, RelativeDates.INTERVAL);
+ },
+ setUpdate: function(post) {
+ var markStale, setOwnTimeout, update;
+
+ setOwnTimeout = function(diff) {
+ var delay;
+
+ delay = diff < $.MINUTE ? $.SECOND - (diff + $.SECOND / 2) % $.SECOND : diff < $.HOUR ? $.MINUTE - (diff + $.MINUTE / 2) % $.MINUTE : diff < $.DAY ? $.HOUR - (diff + $.HOUR / 2) % $.HOUR : $.DAY - (diff + $.DAY / 2) % $.DAY;
+ return setTimeout(markStale, delay);
+ };
+ update = function(now) {
+ var date, diff, relative, singlePost, _i, _len, _ref;
+
+ date = post.info.date;
+ diff = now - date;
+ relative = RelativeDates.relative(diff, now, date);
+ _ref = [post].concat(post.clones);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ singlePost = _ref[_i];
+ singlePost.nodes.date.firstChild.textContent = relative;
+ }
+ return setOwnTimeout(diff);
+ };
+ markStale = function() {
+ return RelativeDates.stale.push(update);
+ };
+ return update(new Date());
+ }
+ };
+
+ RemoveSpoilers = {
+ init: function() {
+ if (!Conf['Remove Spoilers']) {
+ return;
+ }
+ if (Conf['Indicate Spoilers']) {
+ this.wrapper = function(text) {
+ return "[spoiler]" + text + "[/spoiler]";
+ };
+ }
+ return Post.prototype.callbacks.push({
+ name: 'Reveal Spoilers',
+ cb: this.node
+ });
+ },
+ wrapper: function(text) {
+ return text;
+ },
+ node: function(post) {
+ var spoiler, spoilers, _i, _len;
+
+ spoilers = $$('s', this.nodes.comment);
+ for (_i = 0, _len = spoilers.length; _i < _len; _i++) {
+ spoiler = spoilers[_i];
+ $.replace(spoiler, $.tn(RemoveSpoilers.wrapper(spoiler.textContent)));
+ }
+ }
+ };
+
+ Report = {
+ init: function() {
+ if (!/report/.test(location.search)) {
+ return;
+ }
+ return $.ready(this.ready);
+ },
+ ready: function() {
+ var field, form;
+
+ form = $('form');
+ field = $.id('recaptcha_response_field');
+ $.on(field, 'keydown', function(e) {
+ if (e.keyCode === 8 && !field.value) {
+ return $.globalEval('Recaptcha.reload("t")');
+ }
+ });
+ return $.on(form, 'submit', function(e) {
+ var response;
+
+ e.preventDefault();
+ response = field.value.trim();
+ if (!/\s/.test(response)) {
+ field.value = "" + response + " " + response;
+ }
+ return form.submit();
+ });
+ }
+ };
+
+ Sauce = {
+ init: function() {
+ var link, links, _i, _len, _ref;
+
+ if (g.VIEW === 'catalog' || !Conf['Sauce']) {
+ return;
+ }
+ links = [];
+ _ref = Conf['sauces'].split('\n');
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ link = _ref[_i];
+ if (link[0] === '#') {
+ continue;
+ }
+ links.push(this.createSauceLink(link.trim()));
+ }
+ if (!links.length) {
+ return;
+ }
+ this.links = links;
+ this.link = $.el('a', {
+ target: '_blank'
+ });
+ return Post.prototype.callbacks.push({
+ name: 'Sauce',
+ cb: this.node
+ });
+ },
+ createSauceLink: function(link) {
+ var m, text;
+
+ link = link.replace(/%(T?URL|MD5|board)/ig, function(parameter) {
+ switch (parameter) {
+ case '%TURL':
+ return "' + encodeURIComponent(post.file.thumbURL) + '";
+ case '%URL':
+ return "' + encodeURIComponent(post.file.URL) + '";
+ case '%MD5':
+ return "' + encodeURIComponent(post.file.MD5) + '";
+ case '%board':
+ return "' + encodeURIComponent(post.board) + '";
+ default:
+ return parameter;
+ }
+ });
+ text = (m = link.match(/;text:(.+)$/)) ? m[1] : link.match(/(\w+)\.\w+\//)[1];
+ link = link.replace(/;text:.+$/, '');
+ return Function('post', 'a', "a.href = '" + link + "';\na.textContent = '" + text + "';\nreturn a;");
+ },
+ node: function() {
+ var link, nodes, _i, _len, _ref;
+
+ if (this.isClone || !this.file) {
+ return;
+ }
+ nodes = [];
+ _ref = Sauce.links;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ link = _ref[_i];
+ nodes.push($.tn('\u00A0'), link(this, Sauce.link.cloneNode(true)));
+ }
+ return $.add(this.file.info, nodes);
+ }
+ };
+
+ Time = {
+ init: function() {
+ if (g.VIEW === 'catalog' || !Conf['Time Formatting']) {
+ return;
+ }
+ this.funk = this.createFunc(Conf['time']);
+ return Post.prototype.callbacks.push({
+ name: 'Time Formatting',
+ cb: this.node
+ });
+ },
+ node: function() {
+ if (this.isClone) {
+ return;
+ }
+ return this.nodes.date.textContent = Time.funk(Time, this.info.date);
+ },
+ createFunc: function(format) {
+ var code;
+
+ code = format.replace(/%([A-Za-z])/g, function(s, c) {
+ if (c in Time.formatters) {
+ return "' + Time.formatters." + c + ".call(date) + '";
+ } else {
+ return s;
+ }
+ });
+ return Function('Time', 'date', "return '" + code + "'");
+ },
+ day: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
+ month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
+ zeroPad: function(n) {
+ if (n < 10) {
+ return "0" + n;
+ } else {
+ return n;
+ }
+ },
+ formatters: {
+ a: function() {
+ return Time.day[this.getDay()].slice(0, 3);
+ },
+ A: function() {
+ return Time.day[this.getDay()];
+ },
+ b: function() {
+ return Time.month[this.getMonth()].slice(0, 3);
+ },
+ B: function() {
+ return Time.month[this.getMonth()];
+ },
+ d: function() {
+ return Time.zeroPad(this.getDate());
+ },
+ e: function() {
+ return this.getDate();
+ },
+ H: function() {
+ return Time.zeroPad(this.getHours());
+ },
+ I: function() {
+ return Time.zeroPad(this.getHours() % 12 || 12);
+ },
+ k: function() {
+ return this.getHours();
+ },
+ l: function() {
+ return this.getHours() % 12 || 12;
+ },
+ m: function() {
+ return Time.zeroPad(this.getMonth() + 1);
+ },
+ M: function() {
+ return Time.zeroPad(this.getMinutes());
+ },
+ p: function() {
+ if (this.getHours() < 12) {
+ return 'AM';
+ } else {
+ return 'PM';
+ }
+ },
+ P: function() {
+ if (this.getHours() < 12) {
+ return 'am';
+ } else {
+ return 'pm';
+ }
+ },
+ S: function() {
+ return Time.zeroPad(this.getSeconds());
+ },
+ y: function() {
+ return this.getFullYear() - 2000;
+ }
+ }
+ };
+
Settings = {
init: function() {
var link, settings;
diff --git a/src/General/Main.coffee b/src/General/Main.coffee
index 530ed91c2..71e95377f 100644
--- a/src/General/Main.coffee
+++ b/src/General/Main.coffee
@@ -361,13 +361,13 @@ Main =
Main.thisPageIsLegit
css: """
- <%= grunt.file.read('src/css/style.css') %>
- <%= grunt.file.read('src/css/yotsuba.css') %>
- <%= grunt.file.read('src/css/yotsuba-b.css') %>
- <%= grunt.file.read('src/css/futaba.css') %>
- <%= grunt.file.read('src/css/burichan.css') %>
- <%= grunt.file.read('src/css/tomorrow.css') %>
- <%= grunt.file.read('src/css/photon.css') %>
+ <%= grunt.file.read('src/General/css/style.css') %>
+ <%= grunt.file.read('src/General/css/yotsuba.css') %>
+ <%= grunt.file.read('src/General/css/yotsuba-b.css') %>
+ <%= grunt.file.read('src/General/css/futaba.css') %>
+ <%= grunt.file.read('src/General/css/burichan.css') %>
+ <%= grunt.file.read('src/General/css/tomorrow.css') %>
+ <%= grunt.file.read('src/General/css/photon.css') %>
"""
Main.init()
diff --git a/src/General/meta/metadata.js b/src/General/meta/metadata.js
index 0507cbc80..72c28eaf0 100644
--- a/src/General/meta/metadata.js
+++ b/src/General/meta/metadata.js
@@ -16,5 +16,5 @@
// @run-at document-start
// @updateURL <%= meta.repo %>raw/stable/builds/<%= meta.files.metajs %>
// @downloadURL <%= meta.repo %>raw/stable/builds/<%= meta.files.userjs %>
-// @icon data:image/png;base64,<%= grunt.file.read('src/img/icon48.png', {encoding: 'base64'}) %>
+// @icon data:image/png;base64,<%= grunt.file.read('src/General/img/icon48.png', {encoding: 'base64'}) %>
// ==/UserScript==
\ No newline at end of file
diff --git a/src/Monitoring/Favicon.coffee b/src/Monitoring/Favicon.coffee
index 74adaece5..c05e33920 100644
--- a/src/Monitoring/Favicon.coffee
+++ b/src/Monitoring/Favicon.coffee
@@ -11,33 +11,33 @@ Favicon =
switch: ->
switch Conf['favicon']
when 'ferongr'
- Favicon.unreadDead = 'data:image/gif;base64,<%= grunt.file.read("src/img/favicons/ferongr/unreadDead.gif", {encoding: "base64"}) %>'
- Favicon.unreadDeadY = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/ferongr/unreadDeadY.png", {encoding: "base64"}) %>'
- Favicon.unreadSFW = 'data:image/gif;base64,<%= grunt.file.read("src/img/favicons/ferongr/unreadSFW.gif", {encoding: "base64"}) %>'
- Favicon.unreadSFWY = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/ferongr/unreadSFWY.png", {encoding: "base64"}) %>'
- Favicon.unreadNSFW = 'data:image/gif;base64,<%= grunt.file.read("src/img/favicons/ferongr/unreadNSFW.gif", {encoding: "base64"}) %>'
- Favicon.unreadNSFWY = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/ferongr/unreadNSFWY.png", {encoding: "base64"}) %>'
+ Favicon.unreadDead = 'data:image/gif;base64,<%= grunt.file.read("src/General/img/favicons/ferongr/unreadDead.gif", {encoding: "base64"}) %>'
+ Favicon.unreadDeadY = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/ferongr/unreadDeadY.png", {encoding: "base64"}) %>'
+ Favicon.unreadSFW = 'data:image/gif;base64,<%= grunt.file.read("src/General/img/favicons/ferongr/unreadSFW.gif", {encoding: "base64"}) %>'
+ Favicon.unreadSFWY = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/ferongr/unreadSFWY.png", {encoding: "base64"}) %>'
+ Favicon.unreadNSFW = 'data:image/gif;base64,<%= grunt.file.read("src/General/img/favicons/ferongr/unreadNSFW.gif", {encoding: "base64"}) %>'
+ Favicon.unreadNSFWY = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/ferongr/unreadNSFWY.png", {encoding: "base64"}) %>'
when 'xat-'
- Favicon.unreadDead = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/xat-/unreadDead.png", {encoding: "base64"}) %>'
- Favicon.unreadDeadY = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/xat-/unreadDeadY.png", {encoding: "base64"}) %>'
- Favicon.unreadSFW = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/xat-/unreadSFW.png", {encoding: "base64"}) %>'
- Favicon.unreadSFWY = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/xat-/unreadSFWY.png", {encoding: "base64"}) %>'
- Favicon.unreadNSFW = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/xat-/unreadNSFW.png", {encoding: "base64"}) %>'
- Favicon.unreadNSFWY = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/xat-/unreadNSFWY.png", {encoding: "base64"}) %>'
+ Favicon.unreadDead = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/xat-/unreadDead.png", {encoding: "base64"}) %>'
+ Favicon.unreadDeadY = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/xat-/unreadDeadY.png", {encoding: "base64"}) %>'
+ Favicon.unreadSFW = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/xat-/unreadSFW.png", {encoding: "base64"}) %>'
+ Favicon.unreadSFWY = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/xat-/unreadSFWY.png", {encoding: "base64"}) %>'
+ Favicon.unreadNSFW = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/xat-/unreadNSFW.png", {encoding: "base64"}) %>'
+ Favicon.unreadNSFWY = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/xat-/unreadNSFWY.png", {encoding: "base64"}) %>'
when 'Mayhem'
- Favicon.unreadDead = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/Mayhem/unreadDead.png", {encoding: "base64"}) %>'
- Favicon.unreadDeadY = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/Mayhem/unreadDeadY.png", {encoding: "base64"}) %>'
- Favicon.unreadSFW = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/Mayhem/unreadSFW.png", {encoding: "base64"}) %>'
- Favicon.unreadSFWY = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/Mayhem/unreadSFWY.png", {encoding: "base64"}) %>'
- Favicon.unreadNSFW = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/Mayhem/unreadNSFW.png", {encoding: "base64"}) %>'
- Favicon.unreadNSFWY = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/Mayhem/unreadNSFWY.png", {encoding: "base64"}) %>'
+ Favicon.unreadDead = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadDead.png", {encoding: "base64"}) %>'
+ Favicon.unreadDeadY = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadDeadY.png", {encoding: "base64"}) %>'
+ Favicon.unreadSFW = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadSFW.png", {encoding: "base64"}) %>'
+ Favicon.unreadSFWY = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadSFWY.png", {encoding: "base64"}) %>'
+ Favicon.unreadNSFW = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadNSFW.png", {encoding: "base64"}) %>'
+ Favicon.unreadNSFWY = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadNSFWY.png", {encoding: "base64"}) %>'
when 'Original'
- Favicon.unreadDead = 'data:image/gif;base64,<%= grunt.file.read("src/img/favicons/Original/unreadDead.gif", {encoding: "base64"}) %>'
- Favicon.unreadDeadY = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/Original/unreadDeadY.png", {encoding: "base64"}) %>'
- Favicon.unreadSFW = 'data:image/gif;base64,<%= grunt.file.read("src/img/favicons/Original/unreadSFW.gif", {encoding: "base64"}) %>'
- Favicon.unreadSFWY = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/Original/unreadSFWY.png", {encoding: "base64"}) %>'
- Favicon.unreadNSFW = 'data:image/gif;base64,<%= grunt.file.read("src/img/favicons/Original/unreadNSFW.gif", {encoding: "base64"}) %>'
- Favicon.unreadNSFWY = 'data:image/png;base64,<%= grunt.file.read("src/img/favicons/Original/unreadNSFWY.png", {encoding: "base64"}) %>'
+ Favicon.unreadDead = 'data:image/gif;base64,<%= grunt.file.read("src/General/img/favicons/Original/unreadDead.gif", {encoding: "base64"}) %>'
+ Favicon.unreadDeadY = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/Original/unreadDeadY.png", {encoding: "base64"}) %>'
+ Favicon.unreadSFW = 'data:image/gif;base64,<%= grunt.file.read("src/General/img/favicons/Original/unreadSFW.gif", {encoding: "base64"}) %>'
+ Favicon.unreadSFWY = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/Original/unreadSFWY.png", {encoding: "base64"}) %>'
+ Favicon.unreadNSFW = 'data:image/gif;base64,<%= grunt.file.read("src/General/img/favicons/Original/unreadNSFW.gif", {encoding: "base64"}) %>'
+ Favicon.unreadNSFWY = 'data:image/png;base64,<%= grunt.file.read("src/General/img/favicons/Original/unreadNSFWY.png", {encoding: "base64"}) %>'
if Favicon.SFW
Favicon.unread = Favicon.unreadSFW
Favicon.unreadY = Favicon.unreadSFWY
@@ -45,5 +45,5 @@ Favicon =
Favicon.unread = Favicon.unreadNSFW
Favicon.unreadY = Favicon.unreadNSFWY
- empty: 'data:image/gif;base64,<%= grunt.file.read("src/img/favicons/empty.gif", {encoding: "base64"}) %>'
- dead: 'data:image/gif;base64,<%= grunt.file.read("src/img/favicons/dead.gif", {encoding: "base64"}) %>'
\ No newline at end of file
+ empty: 'data:image/gif;base64,<%= grunt.file.read("src/General/img/favicons/empty.gif", {encoding: "base64"}) %>'
+ dead: 'data:image/gif;base64,<%= grunt.file.read("src/General/img/favicons/dead.gif", {encoding: "base64"}) %>'
\ No newline at end of file
diff --git a/src/Monitoring/ThreadUpdater.coffee b/src/Monitoring/ThreadUpdater.coffee
index 215e4411b..7180fc746 100644
--- a/src/Monitoring/ThreadUpdater.coffee
+++ b/src/Monitoring/ThreadUpdater.coffee
@@ -67,7 +67,7 @@ ThreadUpdater =
http://freesound.org/people/pierrecartoons1979/sounds/90112/
cc-by-nc-3.0
###
- beep: 'data:audio/wav;base64,<%= grunt.file.read("src/audio/beep.wav", {encoding: "base64"}) %>'
+ beep: 'data:audio/wav;base64,<%= grunt.file.read("src/General/audio/beep.wav", {encoding: "base64"}) %>'
cb:
online: ->