diff --git a/LICENSE b/LICENSE
index 90d0d3801..2920971b2 100755
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
/*
-* 4chan X - Version 1.2.27 - 2013-08-12
+* 4chan X - Version 1.2.27 - 2013-08-13
*
* Licensed under the MIT license.
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js
index 77d678b38..9173a2b0a 100755
--- a/builds/4chan-X.user.js
+++ b/builds/4chan-X.user.js
@@ -19,7 +19,7 @@
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAgMAAAAqbBEUAAAACVBMVEUAAGcAAABmzDNZt9VtAAAAAXRSTlMAQObYZgAAAHFJREFUKFOt0LENACEIBdBv4Qju4wgWanEj3D6OcIVMKaitYHEU/jwTCQj8W75kiVCSBvdQ5/AvfVHBin11BgdRq3ysBgfwBDRrj3MCIA+oAQaku/Q1cNctrAmyDl577tOThYt/Y1RBM4DgOHzM0HFTAyLukH/cmRnqAAAAAElFTkSuQmCC
// ==/UserScript==
/*
-* 4chan X - Version 1.2.27 - 2013-08-12
+* 4chan X - Version 1.2.27 - 2013-08-13
*
* Licensed under the MIT license.
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
@@ -134,7 +134,6 @@
'Index Navigation': [false, 'Add buttons to navigate between threads.'],
'Reply Navigation': [false, 'Add buttons to navigate to top / bottom of thread.'],
'Show Dice Roll': [true, 'Show dice that were entered into the email field.'],
- 'Check for Updates': [true, 'Check for updated versions of 4chan X.'],
'Show Updated Notifications': [true, 'Show notifications when 4chan X is successfully updated.'],
'Emoji': [false, 'Adds icons next to names for different emails'],
'Color User IDs': [false, 'Assign unique colors to user IDs on boards that use them'],
@@ -188,9 +187,7 @@
'Page Count in Stats': [false, 'Display the page count in the thread stats as well.'],
'Updater and Stats in Header': [true, 'Places the thread updater and thread stats in the header instead of floating them.'],
'Thread Watcher': [true, 'Bookmark threads.'],
- 'Toggleable Thread Watcher': [true, 'Adds a shortcut for the thread watcher, hides the watcher by default, and makes it scroll with the page.'],
- 'Auto Watch': [true, 'Automatically watch threads you start.'],
- 'Auto Watch Reply': [false, 'Automatically watch threads you reply to.']
+ 'Toggleable Thread Watcher': [true, 'Adds a shortcut for the thread watcher, hides the watcher by default, and makes it scroll with the page.']
},
'Posting': {
'Quick Reply': [true, 'All-in-one form to reply, create threads, automate dumping and more.'],
@@ -231,6 +228,12 @@
'Expand from here': [false, 'Expand all images only from current position to thread end.'],
'Advance on contract': [false, 'Advance to next post when contracting an expanded image.']
},
+ threadWatcher: {
+ 'Current Board': [false, 'Only show watched threads from the current board.'],
+ 'Auto Watch': [true, 'Automatically watch threads you start.'],
+ 'Auto Watch Reply': [false, 'Automatically watch threads you reply to.'],
+ 'Auto Prune': [false, 'Automatically prune 404\'d threads.']
+ },
filter: {
name: "# Filter any namefags:\n#/^(?!Anonymous$)/",
uniqueID: "# Filter a specific ID:\n#/Txhvk1Tl/",
@@ -418,25 +421,30 @@
}
};
- $.ajax = function(url, options, extra) {
- var form, headers, key, r, sync, type, upCallbacks, val;
- if (extra == null) {
- extra = {};
- }
- type = extra.type, headers = extra.headers, upCallbacks = extra.upCallbacks, form = extra.form, sync = extra.sync;
- r = new XMLHttpRequest();
- r.overrideMimeType('text/html');
- type || (type = form && 'post' || 'get');
- r.open(type, url, !sync);
- for (key in headers) {
- val = headers[key];
- r.setRequestHeader(key, val);
- }
- $.extend(r, options);
- $.extend(r.upload, upCallbacks);
- r.send(form);
- return r;
- };
+ $.ajax = (function() {
+ var lastModified;
+ lastModified = {};
+ return function(url, options, extra) {
+ var form, r, sync, type, upCallbacks, whenModified;
+ if (extra == null) {
+ extra = {};
+ }
+ type = extra.type, whenModified = extra.whenModified, upCallbacks = extra.upCallbacks, form = extra.form, sync = extra.sync;
+ r = new XMLHttpRequest();
+ type || (type = form && 'post' || 'get');
+ r.open(type, url, !sync);
+ if (whenModified) {
+ r.setRequestHeader('If-Modified-Since', lastModified[url] || '0');
+ $.on(r, 'load', function() {
+ return lastModified[url] = r.getResponseHeader('Last-Modified');
+ });
+ }
+ $.extend(r, options);
+ $.extend(r.upload, upCallbacks);
+ r.send(form);
+ return r;
+ };
+ })();
$.cache = (function() {
var reqs;
@@ -1162,16 +1170,18 @@
})(Post);
- DataBoards = ['hiddenThreads', 'hiddenPosts', 'lastReadPosts', 'yourPosts'];
+ DataBoards = ['hiddenThreads', 'hiddenPosts', 'lastReadPosts', 'yourPosts', 'watchedThreads'];
DataBoard = (function() {
- function DataBoard(key, sync) {
+ function DataBoard(key, sync, dontClean) {
var init,
_this = this;
this.key = key;
this.data = Conf[key];
$.sync(key, this.onSync.bind(this));
- this.clean();
+ if (!dontClean) {
+ this.clean();
+ }
if (!sync) {
return;
}
@@ -1182,6 +1192,10 @@
$.on(d, '4chanXInitFinished', init);
}
+ DataBoard.prototype.save = function() {
+ return $.set(this.key, this.data);
+ };
+
DataBoard.prototype["delete"] = function(_arg) {
var boardID, postID, threadID;
boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID;
@@ -1199,7 +1213,7 @@
} else {
delete this.data.boards[boardID];
}
- return $.set(this.key, this.data);
+ return this.save();
};
DataBoard.prototype.deleteIfEmpty = function(_arg) {
@@ -1227,7 +1241,7 @@
} else {
this.data.boards[boardID] = val;
}
- return $.set(this.key, this.data);
+ return this.save();
};
DataBoard.prototype.get = function(_arg) {
@@ -1269,7 +1283,7 @@
this.ajaxClean(boardID);
}
}
- return $.set(this.key, this.data);
+ return this.save();
};
DataBoard.prototype.ajaxClean = function(boardID) {
@@ -1297,7 +1311,7 @@
boardID: boardID
});
}
- return $.set(_this.key, _this.data);
+ return _this.save();
});
};
@@ -1358,8 +1372,24 @@
Polyfill = {
init: function() {
+ Polyfill.toBlob();
return Polyfill.visibility();
},
+ toBlob: function() {
+ var _base;
+ return (_base = HTMLCanvasElement.prototype).toBlob || (_base.toBlob = function(cb) {
+ var data, i, l, ui8a, _i;
+ data = atob(this.toDataURL().slice(22));
+ l = data.length;
+ ui8a = new Uint8Array(l);
+ for (i = _i = 0; 0 <= l ? _i < l : _i > l; i = 0 <= l ? ++_i : --_i) {
+ ui8a[i] = data.charCodeAt(i);
+ }
+ return cb(new Blob([ui8a], {
+ type: 'image/png'
+ }));
+ });
+ },
visibility: function() {
if (!('webkitHidden' in document)) {
return;
@@ -1761,7 +1791,7 @@
date: data.now,
dateUTC: data.time,
comment: data.com,
- capReps: data.capcode_replies,
+ capcodeReplies: data.capcode_replies,
isSticky: !!data.sticky,
isClosed: !!data.closed
};
@@ -1789,8 +1819,8 @@
@license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
*/
- var a, array, boardID, capReps, capcode, capcodeClass, capcodeReplies, capcodeStart, capcodeType, closed, comment, container, date, dateUTC, email, emailEnd, emailStart, ext, file, fileDims, fileHTML, fileInfo, fileSize, fileThumb, filename, flag, flagCode, flagName, generateCapcodeReplies, 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, capReps = o.capReps, file = o.file;
+ var a, boardID, capcode, capcodeClass, capcodeReplies, 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, capcodeReplies = o.capcodeReplies, file = o.file;
isOP = postID === threadID;
staticPath = '//static.4chan.org/image/';
if (email) {
@@ -1864,32 +1894,10 @@
tripcode = tripcode ? " " + tripcode + " " : '';
sticky = isSticky ? " " : '';
closed = isClosed ? " " : '';
- capcodeReplies = '';
- if (capReps) {
- generateCapcodeReplies = function(capcodeType, array) {
- return "" + ((function() {
- switch (capcodeType) {
- case 'admin':
- return 'Administrator';
- case 'mod':
- return 'Moderator';
- case 'developer':
- return 'Developer';
- }
- })()) + " Repl" + (array.length > 1 ? 'ies' : 'y') + ": " + (array.map(function(ID) {
- return ">>" + ID + " ";
- }).join(' ')) + " ";
- };
- for (capcodeType in capReps) {
- array = capReps[capcodeType];
- capcodeReplies += generateCapcodeReplies(capcodeType, array);
- }
- capcodeReplies = "" + capcodeReplies + " ";
- }
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 || '') + capcodeReplies + " " + " " + "
"
+ 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++) {
@@ -1900,7 +1908,46 @@
}
quote.href = "/" + boardID + "/res/" + href;
}
+ Build.capcodeReplies({
+ boardID: boardID,
+ threadID: threadID,
+ root: container,
+ capcodeReplies: capcodeReplies
+ });
return container;
+ },
+ capcodeReplies: function(_arg) {
+ var array, boardID, bq, capcodeReplies, capcodeType, generateCapcodeReplies, html, root, threadID;
+ boardID = _arg.boardID, threadID = _arg.threadID, bq = _arg.bq, root = _arg.root, capcodeReplies = _arg.capcodeReplies;
+ if (!capcodeReplies) {
+ return;
+ }
+ generateCapcodeReplies = function(capcodeType, array) {
+ return "" + ((function() {
+ switch (capcodeType) {
+ case 'admin':
+ return 'Administrator';
+ case 'mod':
+ return 'Moderator';
+ case 'developer':
+ return 'Developer';
+ }
+ })()) + " Repl" + (array.length > 1 ? 'ies' : 'y') + ": " + (array.map(function(ID) {
+ return ">>" + ID + " ";
+ }).join(' ')) + " ";
+ };
+ html = [];
+ for (capcodeType in capcodeReplies) {
+ array = capcodeReplies[capcodeType];
+ html.push(generateCapcodeReplies(capcodeType, array));
+ }
+ bq || (bq = $('blockquote', root));
+ return $.add(bq, [
+ $.el('br'), $.el('br'), $.el('span', {
+ className: 'capcodeReplies',
+ innerHTML: html.join('')
+ })
+ ]);
}
};
@@ -4221,7 +4268,7 @@
if (g.VIEW === 'catalog' || !Conf['Linkify']) {
return;
}
- this.regString = Conf['Allow False Positives'] ? /(\b([-a-z]+:\/\/|[a-z]{3,}\.[-a-z0-9]+\.[a-z]|[-a-z0-9]+\.[a-z]|[\d]+\.[\d]+\.[\d]+\.[\d]+\/|[a-z]{3,}:[a-z0-9?]|[^\s@]+@[a-z0-9.-]+\.[a-z0-9])[^\s'"]+)/gi : /(((magnet|mailto)\:|(www\.)|(news|(ht|f)tp(s?))\:\/\/){1}\S+)/gi;
+ this.regString = Conf['Allow False Positives'] ? /([-a-z]+:\/\/|[a-z]{3,}\.[-a-z0-9]+\.[a-z]|[-a-z0-9]+\.[a-z]|[\d]+\.[\d]+\.[\d]+\.[\d]+\/|[a-z]{3,}:[a-z0-9?]|[^\s@]+@[a-z0-9.-]+\.[a-z0-9])/i : /(((magnet|mailto)\:|(www\.)|(news|(ht|f)tp(s?))\:\/\/){1})/i;
if (Conf['Comment Expansion']) {
ExpandComment.callbacks.push(this.node);
}
@@ -4234,7 +4281,7 @@
});
},
node: function() {
- var data, el, i, items, links, node, range, snapshot, _i, _len, _ref;
+ var data, el, end, endNode, i, index, items, lIndex, length, link, links, node, range, result, saved, snapshot, space, test, text, _i, _len, _ref;
if (this.isClone) {
if (Conf['Embedding']) {
i = 0;
@@ -4248,16 +4295,49 @@
}
return;
}
+ test = /[^\s'"]+/g;
+ space = /[\s'"]/;
snapshot = $.X('.//br|.//text()', this.nodes.comment);
i = 0;
while (node = snapshot.snapshotItem(i++)) {
- if (node.parentElement.nodeName === "A") {
+ links = [];
+ data = node.data;
+ if (node.parentElement.nodeName === "A" || !data) {
continue;
}
- links = [];
- if (Linkify.regString.test(node.data)) {
- Linkify.regString.lastIndex = 0;
- Linkify.gatherLinks(snapshot, this, node, links, i);
+ while (result = test.exec(data)) {
+ index = result.index;
+ endNode = node;
+ if ((length = index + result[0].length) === data.length) {
+ while ((saved = snapshot.snapshotItem(i++))) {
+ if (saved.nodeName === 'BR') {
+ break;
+ }
+ endNode = saved;
+ length = saved.data.length;
+ if (end = space.exec(saved.data)) {
+ length = end.index;
+ i--;
+ break;
+ }
+ }
+ if (length === endNode.data.length) {
+ test.lastIndex = 0;
+ }
+ range = Linkify.makeRange(node, endNode, index, length);
+ if (link = Linkify.regString.exec(text = range.toString())) {
+ if (lIndex = link.index) {
+ range.setStart(node, lIndex + index);
+ }
+ links.push([range, text]);
+ }
+ break;
+ } else {
+ if (link = Linkify.regString.exec(result[0])) {
+ range = Linkify.makeRange(node, node, link.index, link.length);
+ links.push([range, link]);
+ }
+ }
}
_ref = links.reverse();
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
@@ -4281,57 +4361,23 @@
}
}
},
- gatherLinks: function(snapshot, post, node, links, i) {
- var data, index, len, len2, link, match, range;
- data = node.data;
- len = data.length;
- while ((match = Linkify.regString.exec(data))) {
- index = match.index;
- link = match[0];
- len2 = index + link.length;
- if (len === len2) {
- break;
- }
- range = document.createRange();
- range.setStart(node, index);
- range.setEnd(node, len2);
- links.push(range);
- }
- Linkify.regString.lastIndex = 0;
- if (match) {
- links.push(Linkify.seek(snapshot, post, node, links, match, i));
- }
- },
- seek: function(snapshot, post, node, links, match, i) {
- var data, index, link, next, range, result;
- link = match[0];
+ makeRange: function(startNode, endNode, startOffset, endOffset) {
+ var range;
range = document.createRange();
- range.setStart(node, match.index);
- while ((next = snapshot.snapshotItem(i++)) && next.nodeName !== 'BR') {
- node = next;
- data = node.data;
- if (result = /[\s'"]/.exec(data)) {
- index = result.index;
- range.setEnd(node, index);
- Linkify.regString.lastIndex = index;
- Linkify.gatherLinks(snapshot, post, node, links, i);
- return range;
- }
- }
- if (range.collapsed) {
- range.setEndAfter(node);
- }
+ range.setStart(startNode, startOffset);
+ range.setEnd(endNode, endOffset);
return range;
},
- makeLink: function(range) {
- var a, link;
- link = range.toString();
- link = link.contains(':') ? link : (link.contains('@') ? 'mailto:' : 'http://') + link;
+ makeLink: function(_arg) {
+ var a, range, text;
+ range = _arg[0], text = _arg[1];
+ text;
+ text = text.contains(':') ? text : (text.contains('@') ? 'mailto:' : 'http://') + text;
a = $.el('a', {
className: 'linkify',
rel: 'nofollow noreferrer',
target: '_blank',
- href: link
+ href: text
});
$.add(a, range.extractContents());
range.insertNode(a);
@@ -5407,7 +5453,7 @@
_this = this;
img = $.el('img');
img.onload = function() {
- var applyBlob, cv, data, height, i, l, s, ui8a, width, _i;
+ var cv, height, s, width;
s = 90 * 2;
if (_this.file.type === 'image/gif') {
s *= 3;
@@ -5430,23 +5476,10 @@
cv.width = img.width = width;
cv.getContext('2d').drawImage(img, 0, 0, width, height);
URL.revokeObjectURL(fileURL);
- applyBlob = function(blob) {
+ return cv.toBlob(function(blob) {
_this.URL = URL.createObjectURL(blob);
return _this.nodes.el.style.backgroundImage = "url(" + _this.URL + ")";
- };
- if (cv.toBlob) {
- cv.toBlob(applyBlob);
- return;
- }
- data = atob(cv.toDataURL().split(',')[1]);
- l = data.length;
- ui8a = new Uint8Array(l);
- for (i = _i = 0; 0 <= l ? _i < l : _i > l; i = 0 <= l ? ++_i : --_i) {
- ui8a[i] = data.charCodeAt(i);
- }
- return applyBlob(new Blob([ui8a], {
- type: 'image/png'
- }));
+ });
};
fileURL = URL.createObjectURL(this.file);
return img.src = fileURL;
@@ -6276,7 +6309,7 @@
},
menu: {
init: function() {
- var conf, createSubEntry, el, key, subEntries, _ref;
+ var conf, createSubEntry, el, name, subEntries, _ref;
if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
return;
}
@@ -6287,9 +6320,9 @@
createSubEntry = ImageExpand.menu.createSubEntry;
subEntries = [];
_ref = Config.imageExpansion;
- for (key in _ref) {
- conf = _ref[key];
- subEntries.push(createSubEntry(key, conf));
+ for (name in _ref) {
+ conf = _ref[name];
+ subEntries.push(createSubEntry(name, conf[1]));
}
return $.event('AddMenuEntry', {
type: 'header',
@@ -6298,21 +6331,19 @@
subEntries: subEntries
});
},
- createSubEntry: function(type, config) {
+ createSubEntry: function(name, desc) {
var input, label;
label = $.el('label', {
- innerHTML: " " + type
+ innerHTML: " " + name,
+ title: desc
});
input = label.firstElementChild;
- if (type === 'Fit width' || type === 'Fit height') {
+ if (name === 'Fit width' || name === '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);
- }
+ input.checked = Conf[name];
+ $.event('change', null, input);
+ $.on(input, 'change', $.cb.checked);
return {
el: label
};
@@ -6958,7 +6989,6 @@
this.postCountEl = $('#post-count', sc);
this.fileCountEl = $('#file-count', sc);
this.pageCountEl = $('#page-count', sc);
- this.lastModified = '0';
return Thread.prototype.callbacks.push({
name: 'Thread Stats',
cb: this.node
@@ -7010,18 +7040,12 @@
return $.ajax("//api.4chan.org/" + ThreadStats.thread.board + "/threads.json", {
onload: ThreadStats.onThreadsLoad
}, {
- headers: {
- 'If-Modified-Since': ThreadStats.lastModified
- }
+ whenModified: true
});
},
onThreadsLoad: function() {
var page, pages, thread, _i, _j, _len, _len1, _ref;
- if (!Conf["Page Count in Stats"]) {
- return;
- }
- ThreadStats.lastModified = this.getResponseHeader('Last-Modified');
- if (this.status !== 200) {
+ if (!(Conf["Page Count in Stats"] && this.status === 200)) {
return;
}
pages = JSON.parse(this.response);
@@ -7115,7 +7139,6 @@
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']
}));
@@ -7208,10 +7231,7 @@
case 200:
g.DEAD = false;
ThreadUpdater.parse(JSON.parse(req.response).posts);
- ThreadUpdater.lastModified = req.getResponseHeader('Last-Modified');
- if (Conf['Auto Update']) {
- ThreadUpdater.set('timer', ThreadUpdater.getInterval());
- }
+ ThreadUpdater.set('timer', ThreadUpdater.getInterval());
break;
case 404:
g.DEAD = true;
@@ -7225,16 +7245,8 @@
});
break;
default:
- if (Conf['Auto Update']) {
- 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.
- */
-
+ ThreadUpdater.outdateCount++;
+ ThreadUpdater.set('timer', ThreadUpdater.getInterval());
_ref = req.status === 304 ? [null, null] : ["" + req.statusText + " (" + req.status + ")", 'warning'], text = _ref[0], klass = _ref[1];
ThreadUpdater.set('status', text, klass);
}
@@ -7302,9 +7314,7 @@
return ThreadUpdater.req = $.ajax(url, {
onloadend: ThreadUpdater.cb.load
}, {
- headers: {
- 'If-Modified-Since': ThreadUpdater.lastModified
- }
+ whenModified: true
});
},
updateThreadStatus: function(title, OP) {
@@ -7439,7 +7449,7 @@
ThreadWatcher = {
init: function() {
- var sc;
+ var now, sc;
if (!Conf['Thread Watcher']) {
return;
}
@@ -7449,21 +7459,46 @@
href: 'javascript:;',
className: 'disabled'
});
- this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', '');
+ this.db = new DataBoard('watchedThreads', this.refresh, true);
+ this.dialog = UI.dialog('thread-watcher', 'top: 50px; left: 0px;', "
");
+ this.status = $('#watcher-status', this.dialog);
+ this.list = this.dialog.lastElementChild;
$.on(d, 'QRPostSuccessful', this.cb.post);
- $.sync('WatchedThreads', this.refresh);
+ if (g.VIEW === 'thread') {
+ $.on(d, 'ThreadUpdate', this.cb.threadUpdate);
+ }
$.on(sc, 'click', this.toggleWatcher);
$.on($('.move>.close', ThreadWatcher.dialog), 'click', this.toggleWatcher);
+ $.on(d, '4chanXInitFinished', this.ready);
if (Conf['Toggleable Thread Watcher']) {
Header.addShortcut(sc);
$.addClass(doc, 'fixed-watcher');
}
- $.ready(function() {
- ThreadWatcher.refresh();
- $.add(d.body, ThreadWatcher.dialog);
- if (Conf['Toggleable Thread Watcher']) {
- return ThreadWatcher.dialog.hidden = true;
+ now = Date.now();
+ if ((this.db.data.lastChecked || 0) < now - 2 * $.HOUR) {
+ this.db.data.lastChecked = now;
+ ThreadWatcher.fetchAllStatus();
+ this.db.save();
+ }
+ $.get('WatchedThreads', null, function(_arg) {
+ var WatchedThreads, boardID, data, threadID, threads, _ref;
+ WatchedThreads = _arg.WatchedThreads;
+ if (!WatchedThreads) {
+ return;
}
+ _ref = ThreadWatcher.convert(WatchedThreads);
+ for (boardID in _ref) {
+ threads = _ref[boardID];
+ for (threadID in threads) {
+ data = threads[threadID];
+ ThreadWatcher.db.set({
+ boardID: boardID,
+ threadID: threadID,
+ val: data
+ });
+ }
+ }
+ return $["delete"]('WatchedThreads');
});
return Thread.prototype.callbacks.push({
name: 'Thread Watcher',
@@ -7471,77 +7506,86 @@
});
},
node: function() {
- var favicon,
- _this = this;
- favicon = $.el('a', {
- className: 'watch-thread-link',
- href: 'javascript:;'
+ var toggler;
+ toggler = $.el('img', {
+ className: 'watcher-toggler'
});
- $.on(favicon, 'click', ThreadWatcher.cb.toggle);
- $.before($('input', this.OP.nodes.post), favicon);
- if (g.VIEW !== 'thread') {
+ $.on(toggler, 'click', ThreadWatcher.cb.toggle);
+ return $.before($('input', this.OP.nodes.post), toggler);
+ },
+ ready: function() {
+ $.off(d, '4chanXInitFinished', ThreadWatcher.ready);
+ if (!Main.isThisPageLegit()) {
return;
}
- return $.get('AutoWatch', 0, function(item) {
- if (item['AutoWatch'] !== _this.ID) {
+ ThreadWatcher.refresh();
+ $.add(d.body, ThreadWatcher.dialog);
+ if (Conf['Toggleable Thread Watcher']) {
+ ThreadWatcher.dialog.hidden = true;
+ }
+ if (!Conf['Auto Watch']) {
+ return;
+ }
+ return $.get('AutoWatch', 0, function(_arg) {
+ var AutoWatch, thread;
+ AutoWatch = _arg.AutoWatch;
+ if (!(thread = g.BOARD.threads[AutoWatch])) {
return;
}
- ThreadWatcher.watch(_this);
+ ThreadWatcher.add(thread);
return $["delete"]('AutoWatch');
});
},
- 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: '×',
- className: 'close',
- 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 = $('.watch-thread-link', thread.OP.nodes.post);
- if (ID in watched) {
- $.addClass(favicon, 'watched');
- } else {
- $.rmClass(favicon, 'watched');
- }
- }
- },
toggleWatcher: function() {
$.toggleClass(ThreadWatcher.shortcut, 'disabled');
return ThreadWatcher.dialog.hidden = !ThreadWatcher.dialog.hidden;
},
cb: {
+ openAll: function() {
+ var a, _i, _len, _ref;
+ if ($.hasClass(this, 'disabled')) {
+ return;
+ }
+ _ref = $$('a[title]', ThreadWatcher.list);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ a = _ref[_i];
+ $.open(a.href);
+ }
+ return $.event('CloseMenu');
+ },
+ checkThreads: function() {
+ if ($.hasClass(this, 'disabled')) {
+ return;
+ }
+ return ThreadWatcher.fetchAllStatus();
+ },
+ pruneDeads: function() {
+ var boardID, data, threadID, _i, _len, _ref, _ref1;
+ if ($.hasClass(this, 'disabled')) {
+ return;
+ }
+ _ref = ThreadWatcher.getAll();
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ _ref1 = _ref[_i], boardID = _ref1.boardID, threadID = _ref1.threadID, data = _ref1.data;
+ if (!data.isDead) {
+ continue;
+ }
+ delete ThreadWatcher.db.data.boards[boardID][threadID];
+ ThreadWatcher.db.deleteIfEmpty({
+ boardID: boardID
+ });
+ }
+ ThreadWatcher.db.save();
+ ThreadWatcher.refresh();
+ return $.event('CloseMenu');
+ },
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]);
+ rm: function() {
+ var boardID, threadID, _ref;
+ _ref = this.parentNode.dataset.fullID.split('.'), boardID = _ref[0], threadID = _ref[1];
+ return ThreadWatcher.rm(boardID, +threadID);
},
post: function(e) {
var board, postID, threadID, _ref;
@@ -7551,41 +7595,332 @@
return $.set('AutoWatch', threadID);
}
} else if (Conf['Auto Watch Reply']) {
- return ThreadWatcher.watch(board.threads[threadID]);
+ return ThreadWatcher.add(board.threads[threadID]);
}
+ },
+ threadUpdate: function(e) {
+ var thread;
+ thread = e.detail.thread;
+ if (!(e.detail[404] && ThreadWatcher.db.get({
+ boardID: thread.board.ID,
+ threadID: thread.ID
+ }))) {
+ return;
+ }
+ return ThreadWatcher.add(thread);
+ }
+ },
+ fetchCount: {
+ fetched: 0,
+ fetching: 0
+ },
+ fetchAllStatus: function() {
+ var thread, _i, _len, _ref;
+ ThreadWatcher.status.textContent = '...';
+ _ref = ThreadWatcher.getAll();
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ thread = _ref[_i];
+ ThreadWatcher.fetchStatus(thread);
+ }
+ },
+ fetchStatus: function(_arg) {
+ var boardID, data, fetchCount, threadID;
+ boardID = _arg.boardID, threadID = _arg.threadID, data = _arg.data;
+ if (data.isDead) {
+ return;
+ }
+ fetchCount = ThreadWatcher.fetchCount;
+ fetchCount.fetching++;
+ return $.ajax("//api.4chan.org/" + boardID + "/res/" + threadID + ".json", {
+ onloadend: function() {
+ var status;
+ fetchCount.fetched++;
+ if (fetchCount.fetched === fetchCount.fetching) {
+ fetchCount.fetched = 0;
+ fetchCount.fetching = 0;
+ status = '';
+ } else {
+ status = "" + (Math.round(fetchCount.fetched / fetchCount.fetching * 100)) + "%";
+ }
+ ThreadWatcher.status.textContent = status;
+ if (this.status !== 404) {
+ return;
+ }
+ if (Conf['Auto Prune']) {
+ ThreadWatcher.rm(boardID, threadID);
+ } else {
+ data.isDead = true;
+ ThreadWatcher.db.set({
+ boardID: boardID,
+ threadID: threadID,
+ val: data
+ });
+ }
+ return ThreadWatcher.refresh();
+ }
+ }, {
+ type: 'head'
+ });
+ },
+ getAll: function() {
+ var all, boardID, data, threadID, threads, _ref;
+ all = [];
+ _ref = ThreadWatcher.db.data.boards;
+ for (boardID in _ref) {
+ threads = _ref[boardID];
+ if (Conf['Current Board'] && boardID !== g.BOARD.ID) {
+ continue;
+ }
+ for (threadID in threads) {
+ data = threads[threadID];
+ all.push({
+ boardID: boardID,
+ threadID: threadID,
+ data: data
+ });
+ }
+ }
+ return all;
+ },
+ makeLine: function(boardID, threadID, data) {
+ var div, fullID, href, link, x;
+ x = $.el('a', {
+ textContent: '×',
+ href: 'javascript:;'
+ });
+ $.on(x, 'click', ThreadWatcher.cb.rm);
+ if (data.isDead) {
+ href = Redirect.to('thread', {
+ boardID: boardID,
+ threadID: threadID
+ });
+ }
+ link = $.el('a', {
+ href: href || ("/" + boardID + "/res/" + threadID),
+ textContent: data.excerpt,
+ title: data.excerpt
+ });
+ div = $.el('div');
+ fullID = "" + boardID + "." + threadID;
+ div.dataset.fullID = fullID;
+ if (g.VIEW === 'thread' && fullID === ("" + g.BOARD + "." + g.THREADID)) {
+ $.addClass(div, 'current');
+ }
+ if (data.isDead) {
+ $.addClass(div, 'dead-thread');
+ }
+ $.add(div, [x, $.tn(' '), link]);
+ return div;
+ },
+ refresh: function() {
+ var boardID, data, list, nodes, refresher, thread, threadID, toggler, watched, _i, _j, _len, _len1, _ref, _ref1, _ref2, _ref3;
+ nodes = [];
+ _ref = ThreadWatcher.getAll();
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ _ref1 = _ref[_i], boardID = _ref1.boardID, threadID = _ref1.threadID, data = _ref1.data;
+ nodes.push(ThreadWatcher.makeLine(boardID, threadID, data));
+ }
+ list = ThreadWatcher.list;
+ $.rmAll(list);
+ $.add(list, nodes);
+ _ref2 = g.BOARD.threads;
+ for (threadID in _ref2) {
+ thread = _ref2[threadID];
+ toggler = $('.watcher-toggler', thread.OP.nodes.post);
+ watched = ThreadWatcher.db.get({
+ boardID: thread.board.ID,
+ threadID: threadID
+ });
+ $[watched ? 'addClass' : 'rmClass'](toggler, 'watched');
+ }
+ _ref3 = ThreadWatcher.menu.refreshers;
+ for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) {
+ refresher = _ref3[_j];
+ refresher();
}
},
toggle: function(thread) {
- if (!$.hasClass($('.watch-thread-link', thread.OP.nodes.post), 'watched')) {
- return ThreadWatcher.watch(thread);
+ var boardID, threadID;
+ boardID = thread.board.ID;
+ threadID = thread.ID;
+ if (ThreadWatcher.db.get({
+ boardID: boardID,
+ threadID: threadID
+ })) {
+ return ThreadWatcher.rm(boardID, threadID);
} else {
- return ThreadWatcher.unwatch(thread.board, thread.ID);
+ return ThreadWatcher.add(thread);
}
},
- 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];
+ add: function(thread) {
+ var boardID, data, threadID;
+ data = {};
+ boardID = thread.board.ID;
+ threadID = thread.ID;
+ if (thread.isDead) {
+ if (Conf['Auto Prune'] && ThreadWatcher.db.get({
+ boardID: boardID,
+ threadID: threadID
+ })) {
+ ThreadWatcher.rm(boardID, threadID);
+ return;
}
- ThreadWatcher.refresh(watched);
- return $.set('WatchedThreads', watched);
+ data.isDead = true;
+ }
+ data.excerpt = Get.threadExcerpt(thread);
+ ThreadWatcher.db.set({
+ boardID: boardID,
+ threadID: threadID,
+ val: data
});
+ return ThreadWatcher.refresh();
},
- 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);
+ rm: function(boardID, threadID) {
+ ThreadWatcher.db["delete"]({
+ boardID: boardID,
+ threadID: threadID
});
+ return ThreadWatcher.refresh();
+ },
+ convert: function(oldFormat) {
+ var boardID, data, newFormat, threadID, threads;
+ newFormat = {};
+ for (boardID in oldFormat) {
+ threads = oldFormat[boardID];
+ for (threadID in threads) {
+ data = threads[threadID];
+ (newFormat[boardID] || (newFormat[boardID] = {}))[threadID] = {
+ excerpt: data.textContent
+ };
+ }
+ }
+ return newFormat;
+ },
+ menu: {
+ refreshers: [],
+ init: function() {
+ var menu;
+ if (!Conf['Thread Watcher']) {
+ return;
+ }
+ menu = new UI.Menu('thread watcher');
+ $.on($('.menu-button', ThreadWatcher.dialog), 'click', function(e) {
+ return menu.toggle(e, this, ThreadWatcher);
+ });
+ this.addHeaderMenuEntry();
+ return this.addMenuEntries();
+ },
+ addHeaderMenuEntry: function() {
+ var entryEl;
+ if (g.VIEW !== 'thread') {
+ return;
+ }
+ entryEl = $.el('a', {
+ href: 'javascript:;'
+ });
+ $.event('AddMenuEntry', {
+ type: 'header',
+ el: entryEl,
+ order: 60
+ });
+ $.on(entryEl, 'click', function() {
+ return ThreadWatcher.toggle(g.threads["" + g.BOARD + "." + g.THREADID]);
+ });
+ return this.refreshers.push(function() {
+ var addClass, rmClass, text, _ref;
+ _ref = $('.current', ThreadWatcher.list) ? ['unwatch-thread', 'watch-thread', 'Unwatch thread'] : ['watch-thread', 'unwatch-thread', 'Watch thread'], addClass = _ref[0], rmClass = _ref[1], text = _ref[2];
+ $.addClass(entryEl, addClass);
+ $.rmClass(entryEl, rmClass);
+ return entryEl.textContent = text;
+ });
+ },
+ addMenuEntries: function() {
+ var cb, conf, entries, entry, name, refresh, subEntries, _i, _len, _ref, _ref1, _results;
+ entries = [];
+ entries.push({
+ cb: ThreadWatcher.cb.openAll,
+ entry: {
+ type: 'thread watcher',
+ el: $.el('a', {
+ textContent: 'Open all threads'
+ })
+ },
+ refresh: function() {
+ return (ThreadWatcher.list.firstElementChild ? $.rmClass : $.addClass)(this.el, 'disabled');
+ }
+ });
+ entries.push({
+ cb: ThreadWatcher.cb.checkThreads,
+ entry: {
+ type: 'thread watcher',
+ el: $.el('a', {
+ textContent: 'Check 404\'d threads'
+ })
+ },
+ refresh: function() {
+ return ($('div:not(.dead-thread)', ThreadWatcher.list) ? $.rmClass : $.addClass)(this.el, 'disabled');
+ }
+ });
+ entries.push({
+ cb: ThreadWatcher.cb.pruneDeads,
+ entry: {
+ type: 'thread watcher',
+ el: $.el('a', {
+ textContent: 'Prune 404\'d threads'
+ })
+ },
+ refresh: function() {
+ return ($('.dead-thread', ThreadWatcher.list) ? $.rmClass : $.addClass)(this.el, 'disabled');
+ }
+ });
+ subEntries = [];
+ _ref = Config.threadWatcher;
+ for (name in _ref) {
+ conf = _ref[name];
+ subEntries.push(this.createSubEntry(name, conf[1]));
+ }
+ entries.push({
+ entry: {
+ type: 'thread watcher',
+ el: $.el('span', {
+ textContent: 'Settings'
+ }),
+ subEntries: subEntries
+ }
+ });
+ _results = [];
+ for (_i = 0, _len = entries.length; _i < _len; _i++) {
+ _ref1 = entries[_i], entry = _ref1.entry, cb = _ref1.cb, refresh = _ref1.refresh;
+ if (entry.el.nodeName === 'A') {
+ entry.el.href = 'javascript:;';
+ }
+ if (cb) {
+ $.on(entry.el, 'click', cb);
+ }
+ if (refresh) {
+ this.refreshers.push(refresh.bind(entry));
+ }
+ _results.push($.event('AddMenuEntry', entry));
+ }
+ return _results;
+ },
+ createSubEntry: function(name, desc) {
+ var entry, input;
+ entry = {
+ type: 'thread watcher',
+ el: $.el('label', {
+ innerHTML: " " + name,
+ title: desc
+ })
+ };
+ input = entry.el.firstElementChild;
+ input.checked = Conf[name];
+ $.on(input, 'change', $.cb.checked);
+ if (name === 'Current Board') {
+ $.on(input, 'change', ThreadWatcher.refresh);
+ }
+ return entry;
+ }
}
};
@@ -7912,8 +8247,8 @@
http: true,
https: true,
software: 'foolfuuka',
- boards: ['adv', 'asp', 'cm', 'i', 'lgbt', 'n', 'o', 'p', 's4s', 't', 'trv'],
- files: ['adv', 'asp', 'cm', 'i', 'lgbt', 'n', 'o', 'p', 's4s', 't', 'trv']
+ boards: ['adv', 'asp', 'cm', 'd', 'e', 'i', 'lgbt', 'n', 'o', 'p', 'pol', 's', 's4s', 't', 'trv', 'y'],
+ files: ['cm', 'd', 'e', 'i', 'n', 'o', 'p', 's', 'trv', 'y']
},
'Foolz Beta': {
domain: 'beta.foolz.us',
@@ -8319,10 +8654,8 @@
},
callbacks: [],
cb: function(e) {
- var post;
e.preventDefault();
- post = Get.postFromNode(this);
- return ExpandComment.expand(post);
+ return ExpandComment.expand(Get.postFromNode(this));
},
expand: function(post) {
var a;
@@ -8382,6 +8715,12 @@
}
quote.href = "/" + post.board + "/res/" + href;
}
+ Build.capcodeReplies({
+ boardID: post.board.ID,
+ threadID: post.thread.ID,
+ bq: clone,
+ capcodeReplies: postObj.capcode_replies
+ });
post.nodes.shortComment = comment;
$.replace(comment, clone);
post.nodes.comment = post.nodes.longComment = clone;
@@ -9392,7 +9731,8 @@
$.on(d, '4chanXInitFinished', Settings.open);
}
return $.set({
- lastchecked: Date.now(),
+ archives: Conf['archives'],
+ lastarchivecheck: now,
previousversion: g.VERSION
});
});
@@ -9578,7 +9918,6 @@
version: g.VERSION,
date: now
};
- Conf['WatchedThreads'] = {};
for (_i = 0, _len = DataBoards.length; _i < _len; _i++) {
db = DataBoards[_i];
Conf[db] = {
@@ -9710,14 +10049,13 @@
});
}
}
- data.Conf.WatchedThreads = data.WatchedThreads;
- } else if (version[0] === '3') {
- data = Settings.convertSettings(data, {
- 'Reply Hiding': 'Reply Hiding Buttons',
- 'Thread Hiding': 'Thread Hiding Buttons',
- 'Bottom header': 'Bottom Header',
- 'Unread Tab Icon': 'Unread Favicon'
- });
+ data.Conf['WatchedThreads'] = data.WatchedThreads;
+ }
+ if (data.Conf['WatchedThreads']) {
+ data.Conf['watchedThreads'] = {
+ boards: ThreadWatcher.convert(data.Conf['WatchedThreads'])
+ };
+ delete data.Conf['WatchedThreads'];
}
return $.set(data.Conf);
},
@@ -10144,6 +10482,7 @@
'Thread Stats': ThreadStats,
'Thread Updater': ThreadUpdater,
'Thread Watcher': ThreadWatcher,
+ 'Thread Watcher (Menu)': ThreadWatcher.menu,
'Index Navigation': Nav,
'Keybinds': Keybinds,
'Show Dice Roll': Dice
@@ -10238,8 +10577,7 @@
}
Main.callbackNodes(Thread, threads);
Main.callbackNodesDB(Post, posts, function() {
- $.event('4chanXInitFinished');
- return Main.checkUpdate();
+ return $.event('4chanXInitFinished');
});
if (styleSelector = $.id('styleSelector')) {
passLink = $.el('a', {
@@ -10259,8 +10597,7 @@
err = _error;
new Notification('warning', 'Cookies need to be enabled on 4chan for 4chan X to properly function.', 30);
}
- $.event('4chanXInitFinished');
- return Main.checkUpdate();
+ return $.event('4chanXInitFinished');
},
callbackNodes: function(klass, nodes) {
var callback, err, errors, i, len, node, _i, _len, _ref;
@@ -10362,37 +10699,6 @@
obj.callback.isAddon = true;
return Klass.prototype.callbacks.push(obj.callback);
},
- message: function(e) {
- var el, version;
- version = e.data.version;
- if (version && version !== g.VERSION) {
- el = $.el('span', {
- innerHTML: "Update: 4chan X v" + version + " is out, get it here ."
- });
- return new Notification('info', el, 120);
- }
- },
- checkUpdate: function() {
- var now;
- if (!(Conf['Check for Updates'] && Main.isThisPageLegit())) {
- return;
- }
- now = Date.now();
- return $.get('lastchecked', 0, function(_arg) {
- var lastchecked;
- lastchecked = _arg.lastchecked;
- if (lastchecked > now - $.DAY) {
- return;
- }
- return $.ready(function() {
- $.on(window, 'message', Main.message);
- $.set('lastchecked', now);
- return $.add(d.head, $.el('script', {
- src: 'https://github.com/seaweedchan/4chan-x/raw/master/latest.js'
- }));
- });
- });
- },
handleErrors: function(errors) {
var div, error, logs, _i, _len;
if (!(errors instanceof Array)) {
@@ -10443,7 +10749,7 @@
}
return Main.thisPageIsLegit;
},
- css: "/* General */\n.dialog {\nbox-shadow: 0 1px 2px rgba(0, 0, 0, .15);\nborder: 1px solid;\ndisplay: block;\npadding: 0;\n}\n.captcha-img,\n.field {\nbackground-color: #FFF;\nborder: 1px solid #CCC;\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\ncolor: #333;\nfont: 13px sans-serif;\noutline: none;\ntransition: color .25s, border-color .25s;\ntransition: color .25s, border-color .25s;\n}\n.field::-moz-placeholder,\n.field:hover::-moz-placeholder {\ncolor: #AAA !important;\nfont-size: 13px !important;\nopacity: 1.0 !important;\n}\n.captch-img:hover,\n.field:hover {\nborder-color: #999;\n}\n.field:hover, .field:focus {\ncolor: #000;\n}\n.field[disabled] {\nbackground-color: #F2F2F2;\ncolor: #888;\n}\n.move {\ncursor: move;\noverflow: hidden;\n}\nlabel, .favicon {\ncursor: pointer;\n}\na[href=\"javascript:;\"] {\ntext-decoration: none;\n}\n.warning {\ncolor: red;\n}\n#boardNavDesktop {\ndisplay: none !important;\n}\na {\noutline: none !important;\n}\n\n/* 4chan style fixes */\n.opContainer, .op {\ndisplay: block !important;\noverflow: visible !important;\n}\n[hidden] {\ndisplay: none !important;\n}\n\n/* fixed, z-index */\n#overlay,\n#fourchanx-settings,\n#qp, #ihover,\n#navlinks, .fixed #header-bar,\n:root.float #updater,\n:root.float #thread-stats,\n#qr {\nposition: fixed;\n}\n#fourchanx-settings {\nz-index: 999;\n}\n#overlay {\nz-index: 900;\n}\n#notifications {\nz-index: 70;\n}\n#qp, #ihover {\nz-index: 60;\n}\n#menu {\nz-index: 50;\n}\n#navlinks, #updater, #thread-stats {\nz-index: 40;\n}\n.fixed #header-bar.autohide {\nz-index: 35;\n}\n#qr {\nz-index: 30;\n}\n#watcher {\nz-index: 8;\n}\n:root.fixed-watcher #watcher {\nz-index: 20;\n}\n.fixed #header-bar {\nz-index: 10;\n}\n/* Header */\n.fixed.top body {\npadding-top: 2em;\n}\n.fixed.bottom body {\npadding-bottom: 2em;\n}\n.fixed #header-bar {\nright: 0;\nleft: 0;\npadding: 3px 4px 4px;\n}\n.fixed.top #header-bar {\ntop: 0;\n}\n.fixed.bottom #header-bar {\nbottom: 0;\n}\n#header-bar {\nborder-width: 0;\ntransition: all .1s .05s ease-in-out;\n}\n:root.centered-links #shortcuts {\nwidth: 300px;\ntext-align: right;\n}\n:root.centered-links #header-bar {\ntext-align: center;\n}\n:root.centered-links #custom-board-list {\nposition: relative;\nleft: 150px;\n}\n.fixed.top #header-bar {\nborder-bottom-width: 1px;\n}\n.fixed.bottom #header-bar {\nbox-shadow: 0 -1px 2px rgba(0, 0, 0, .15);\nborder-top-width: 1px;\n}\n.fixed.bottom #header-bar .menu-button i {\nborder-top: none;\nborder-bottom: 6px solid;\n}\n#board-list {\ntext-align: center;\n}\n.fixed #header-bar.autohide:not(:hover) {\nbox-shadow: none;\ntransition: all .8s .6s cubic-bezier(.55, .055, .675, .19);\n}\n.fixed.top #header-bar.autohide:not(:hover) {\nmargin-bottom: -1em;\n-webkit-transform: translateY(-100%);\ntransform: translateY(-100%);\n}\n.fixed.bottom #header-bar.autohide:not(:hover) {\n-webkit-transform: translateY(100%);\ntransform: translateY(100%);\n}\n#scroll-marker {\nleft: 0;\nright: 0;\nheight: 10px;\nposition: absolute;\n}\n:root:not(.autohide) #scroll-marker {\npointer-events: none;\n}\n#header-bar #scroll-marker {\ndisplay: none;\n}\n.fixed #header-bar #scroll-marker {\ndisplay: block;\n}\n.fixed.top #header-bar #scroll-marker {\ntop: 100%;\n}\n.fixed.bottom #header-bar #scroll-marker {\nbottom: 100%;\n}\n#header-bar a:not(.entry):not(.close) {\ntext-decoration: none;\npadding: 1px;\n}\n#header-bar input {\nmargin: 0;\nvertical-align: bottom;\n}\n#shortcuts:empty {\ndisplay: none;\n}\n.brackets-wrap::before {\ncontent: \"\\00a0[\";\n}\n.brackets-wrap::after {\ncontent: \"]\\00a0\";\n}\n.disabled,\n.expand-all-shortcut {\nopacity: .45;\n}\n#shortcuts {\nfloat: right;\n}\n.shortcut {\nmargin-left: 3px;\n}\n#navbotright,\n#navtopright {\ndisplay: none;\n}\n#toggleMsgBtn {\ndisplay: none !important;\n}\n.current {\nfont-weight: bold;\n}\n/* 4chan X link brackets */\n.fourchanx-link::after {\ncontent: \"]\";\n}\n.fourchanx-link::before {\ncontent: \"[\";\n}\n/* Notifications */\n#notifications {\nposition: fixed;\ntop: 0;\nheight: 0;\ntext-align: center;\nright: 0;\nleft: 0;\ntransition: all .8s .6s cubic-bezier(.55, .055, .675, .19);\n}\n.fixed.top #header-bar #notifications {\nposition: absolute;\ntop: 100%;\n}\n.notification {\ncolor: #FFF;\nfont-weight: 700;\ntext-shadow: 0 1px 2px rgba(0, 0, 0, .5);\nbox-shadow: 0 1px 2px rgba(0, 0, 0, .15);\nborder-radius: 2px;\nmargin: 1px auto;\nwidth: 500px;\nmax-width: 100%;\nposition: relative;\ntransition: all .25s ease-in-out;\n}\n.notification.error {\nbackground-color: hsla(0, 100%, 38%, .9);\n}\n.notification.warning {\nbackground-color: hsla(36, 100%, 38%, .9);\n}\n.notification.info {\nbackground-color: hsla(200, 100%, 38%, .9);\n}\n.notification.success {\nbackground-color: hsla(104, 100%, 38%, .9);\n}\n.notification a {\ncolor: white;\n}\n.notification > .close {\npadding: 6px;\ntop: 0;\nright: 5px;\nposition: absolute;\n}\n.message {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\npadding: 6px 20px;\nmax-height: 200px;\nwidth: 100%;\noverflow: auto;\n}\n\n/* Settings */\n:root.fourchan-x body {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\n}\n#overlay {\nbackground-color: rgba(0, 0, 0, .5);\ntop: 0;\nleft: 0;\nheight: 100%;\nwidth: 100%;\n}\n#fourchanx-settings {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\nbox-shadow: 0 0 15px rgba(0, 0, 0, .15);\nheight: 600px;\nmax-height: 100%;\nwidth: 900px;\nmax-width: 100%;\nmargin: auto;\npadding: 3px;\ntop: 50%;\nleft: 50%;\n-moz-transform: translate(-50%, -50%);\n-webkit-transform: translate(-50%, -50%);\ntransform: translate(-50%, -50%);\n}\n#fourchanx-settings > nav {\npadding: 2px 2px 0;\nheight: 15px;\n}\n#fourchanx-settings > nav a {\ntext-decoration: underline;\n}\n#fourchanx-settings > nav a.close {\ntext-decoration: none;\npadding: 2px;\n}\n.section-container {\noverflow: auto;\nposition: absolute;\ntop: 2.1em;\nright: 5px;\nbottom: 5px;\nleft: 5px;\npadding-right: 5px;\n}\n.sections-list {\npadding: 0 3px;\nfloat: left;\n}\n.credits {\nfloat: right;\n}\n.tab-selected {\nfont-weight: 700;\n}\n.section-sauce ul,\n.section-advanced ul {\nlist-style: none;\nmargin: 0;\n}\n.section-sauce ul {\npadding: 8px;\n}\n.section-advanced ul {\npadding: 0px;\n}\n.section-sauce li,\n.section-advanced li {\npadding-left: 4px;\n}\n.section-main label {\ntext-decoration: underline;\n}\n.section-filter ul {\npadding: 0;\n}\n.section-filter li {\nmargin: 10px 40px;\n}\n.section-filter textarea {\nheight: 500px;\n}\n.section-sauce textarea {\nheight: 350px;\n}\n.section-advanced .field[name=\"boardnav\"] {\nwidth: 100%;\n}\n.section-advanced textarea {\nheight: 150px;\n}\n.section-advanced .archive-cell {\nmin-width: 160px;\ntext-align: center;\n}\n.section-advanced #archive-board-select {\nposition: absolute;\n}\n.section-advanced .note {\nfont-size: 0.8em;\nfont-style: italic;\nmargin-left: 10px;\n}\n.section-advanced .note code {\nfont-style: normal;\nfont-size: 11px;\n}\n.section-keybinds .field {\nfont-family: monospace;\n} \n#fourchanx-settings fieldset {\nborder: 1px solid;\nborder-radius: 3px;\n}\n#fourchanx-settings legend {\nfont-weight: 700;\n}\n#fourchanx-settings textarea {\nfont-family: monospace;\nmin-width: 100%;\nmax-width: 100%;\n}\n#fourchanx-settings code {\ncolor: #000;\nbackground-color: #FFF;\npadding: 0 2px;\n}\n.unscroll {\noverflow: hidden;\n}\n\n/* Announcement Hiding */\n:root.hide-announcement #globalMessage {\ndisplay: none;\n}\na.hide-announcement {\nfloat: left;\n}\n\n/* Unread */\n#unread-line {\nmargin: 0;\nborder-color: rgb(255,0,0);\n}\n\n/* Thread Updater */\n#updater {\nbackground: none;\nborder: none;\nbox-shadow: none;\n}\n#updater > .move {\npadding: 5px 3px 0px;\nmargin-bottom: -3px;\n}\n#updater > div:last-child {\ntext-align: center;\n}\n#updater input[type=number] {\nwidth: 4em;\n}\n:root.float #updater {\npadding: 0px 3px;\n}\n.new {\ncolor: limegreen;\n}\n#update-status.new {\nmargin-right: 5px;\n}\n#update-timer {\ncursor: pointer;\n}\n\n/* Thread Watcher */\n#watcher {\nposition: absolute;\n}\n#watcher {\npadding-bottom: 3px;\noverflow: hidden;\nwhite-space: nowrap;\nmin-width: 120px;\nmax-height: 92%;\noverflow-y: auto;\n}\n:root.fixed-watcher #watcher {\nposition: fixed;\n}\n:root:not(.fixed-watcher) #watcher:not(:hover) {\nmax-height: 210px;\noverflow-y: hidden;\n}\n#watcher > .move {\npadding-top: 3px;\n}\n#watcher > div {\nmax-width: 250px;\noverflow: hidden;\npadding-left: 3px;\npadding-right: 3px;\ntext-overflow: ellipsis;\n}\n#watcher a {\ntext-decoration: none;\n}\n#watcher .move>.close {\nposition: absolute;\nright: 0px;\ntop: 0px;\npadding: 0px 4px;\n}\n.watch-thread-link {\npadding-top: 18px;\nwidth: 18px;\nheight: 0px;\ndisplay: inline-block;\nbackground-repeat: no-repeat;\nopacity: 0.2;\nposition: relative;\ntop: 1px;\n}\n.watch-thread-link.watched {\nopacity: 1;\n}\n\n/* Thread Stats */\n#thread-stats {\nbackground: none;\nborder: none;\nbox-shadow: none;\n}\n:root.float #post-count, :root.float #file-count {\npointer-events: none;\n}\n:root.float #thread-stats {\npadding: 0px 3px;\n}\n\n/* Quote */\n.deadlink {\ntext-decoration: none !important;\n}\n.backlink.deadlink:not(.forwardlink),\n.quotelink.deadlink:not(.forwardlink) {\ntext-decoration: underline !important;\n}\n.inlined {\nopacity: .5;\n}\n#qp input, .forwarded {\ndisplay: none;\n}\n.quotelink.forwardlink,\n.backlink.forwardlink {\ntext-decoration: none;\nborder-bottom: 1px dashed;\n}\n.filtered {\ntext-decoration: underline line-through;\n}\n:root.hide-backlinks .backlink.filtered {\ndisplay: none;\n}\n.inline {\nborder: 1px solid;\ndisplay: table;\nmargin: 2px 0;\n}\n.inline .post {\nborder: 0 !important;\nbackground-color: transparent !important;\ndisplay: table !important;\nmargin: 0 !important;\npadding: 1px 2px !important;\n}\n#qp > .opContainer::after {\ncontent: '';\nclear: both;\ndisplay: table;\n}\n#qp .post {\nborder: none;\nmargin: 0;\npadding: 2px 2px 5px;\n}\n#qp img {\nmax-height: 80vh;\nmax-width: 50vw;\n}\n.qphl {\noutline: 2px solid rgba(216, 94, 49, .7);\n}\n:root.highlight-own .yourPost > .reply,\n:root.highlight-you .quotesYou > .reply {\nborder-left: 2px solid rgba(221,0,0,.5);\n}\n/* Quote Threading */\n.threadContainer {\nmargin-left: 20px;\nborder-left: 1px solid rgba(128,128,128,.3);\n}\n.threadOP {\nclear: both;\n} \n\n/* File */\n.fileText:hover .fntrunc,\n.fileText:not(:hover) .fnfull,\n.expanded-image > .post > .file > .fileThumb > img[data-md5],\n:not(.expanded-image) > .post > .file > .fileThumb > .full-image {\ndisplay: none;\n}\n.expanding {\nopacity: .5;\n}\n:root.fit-height .full-image {\nmax-height: 100vh;\n}\n:root.fit-width .full-image {\nmax-width: 100%;\n}\n:root.gecko.fit-width .full-image {\nwidth: 100%;\n}\n#ihover {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\nmax-height: 100%;\nmax-width: 75%;\npadding-bottom: 16px;\n}\n.fappeTyme .thread > .noFile,\n.fappeTyme .threadContainer > .noFile {\ndisplay: none;\n}\n\n/* Index/Reply Navigation */\n#navlinks {\nfont-size: 16px;\ntop: 25px;\nright: 10px;\n}\n\n/* Filter */\n.opContainer.filter-highlight {\nbox-shadow: inset 5px 0 rgba(255, 0, 0, .5);\n}\n.filter-highlight > .reply {\nbox-shadow: -5px 0 rgba(255, 0, 0, .5);\n}\n\n/* Spoiler text */\n:root.reveal-spoilers s {\ncolor: white !important;\n}\n\n/* Thread & Reply Hiding */\n.hide-thread-button,\n.hide-reply-button {\nfloat: left;\nmargin-right: 2px;\n}\n.stub ~ * {\ndisplay: none !important;\n}\n.stub input {\ndisplay: inline-block;\n}\n\n/* QR */\n:root.hide-original-post-form #postForm,\n:root.hide-original-post-form .postingMode,\n:root.hide-original-post-form #togglePostForm,\n#qr.autohide:not(.has-focus):not(:hover) > form,\n.postingMode ~ #qr select,\n#file-n-submit:not(.has-file) #qr-filerm {\ndisplay: none;\n}\n#qr select,\n#dump-button,\n.remove,\n.captcha-img {\ncursor: pointer;\n}\n#qr {\nz-index: 20;\nposition: fixed;\npadding: 1px;\nborder: 1px solid transparent;\nmin-width: 300px;\nborder-radius: 3px 3px 0 0;\n}\n#qrtab {\nborder-radius: 3px 3px 0 0;\n}\n#qrtab {\nmargin-bottom: 1px;\n}\n#qr .close {\nfloat: right;\npadding: 0 3px;\n}\n#qr .warning {\nmin-height: 1.6em;\nvertical-align: middle;\npadding: 0 1px;\nborder-width: 1px;\nborder-style: solid;\n}\n.qr-link-container {\ntext-align: center;\n}\n.persona {\nwidth: 248px;\nmax-width: 100%;\nmin-width: 100%;\n}\n#dump-button {\nwidth: 10%;\nmargin: 0;\nmargin-right: 4px;\nfont: 13px sans-serif;\npadding: 1px 0px 2px;\nopacity: 0.6;\n}\n.persona .field:not(#dump) {\nwidth: 95px;\nmin-width: 33.3%;\nmax-width: 33.3%;\n}\n#qr textarea.field {\nheight: 14.8em;\nmin-height: 9em;\n}\n#qr.has-captcha textarea.field {\nheight: 9em;\n}\ninput.field.tripped:not(:hover):not(:focus) {\ncolor: transparent !important;\ntext-shadow: none !important;\n}\n#qr textarea {\nresize: both;\n}\n.captcha-img {\nmargin: 0px;\ntext-align: center;\nbackground-image: #fff;\nfont-size: 0px;\nmin-height: 59px;\nmin-width: 302px;\n}\n.captcha-input {\nwidth: 100%;\nmargin: 1px 0 0;\n}\n.captcha-input.error:focus {\nborder-color: rgb(255,0,0) !important;\n}\n.field {\n-moz-box-sizing: border-box;\nmargin: 0px;\npadding: 2px 4px 3px;\n}\n#qr textarea {\nmin-width: 100%;\n}\n#qr [type='submit'] {\nwidth: 25%;\nvertical-align: top;\n}\n:root.webkit #qr [type='submit'] {\nheight: 24px;\n}\n/* Fake File Input */\n#qr-filename,\n.has-file #qr-no-file {\ndisplay: none;\n}\n#qr-no-file,\n.has-file #qr-filename {\ndisplay: inline-block;\npadding: 0px 4px;\nmargin-bottom: 2px;\noverflow: hidden;\ntext-overflow: ellipsis;\nmax-width: 88%;\n}\n#qr-no-file {\ncolor: #AAA;\n}\n#qr-filename-container {\n-moz-box-sizing: border-box;\ndisplay: inline-block;\nposition: relative;\nwidth: 100px;\nmin-width: 74.6%;\nmax-width: 74.6%;\nmargin-right: 0.4%;\nmargin-top: 1px;\noverflow: hidden;\npadding: 2px 1px 0;\nheight: 22px;\n}\n#qr-filename-container:hover {\ncursor: text;\n}\n#qr-extras-container {\nposition: absolute;\nright: 0px;\n}\n#qr-filerm {\nmargin-right: 2px;\nz-index: 2;\n}\n#file-n-submit {\nheight: 23px;\n}\n#qr input[type=file] {\nvisibility: hidden;\nposition: absolute;\n}\n/* Thread Select / Spoiler Label */\n#qr select {\nfloat: right;\n}\n#qr.has-spoiler .has-file #qr-spoiler-label {\nwidth: 6.7%;\nmin-width: 6.7%;\nmax-width: 6.7%;\ndisplay: inline-block;\ntext-align: center;\nvertical-align: top;\n}\n#qr.has-spoiler #file-n-submit:not(.has-file) #qr-spoiler-label {\ndisplay: none;\n}\n#qr.has-spoiler .has-file #qr-filename-container {\nmax-width: 67.9%;\nmin-width: 67.9%;\n}\n#qr-spoiler-label input {\nposition: relative;\ntop: 3px;\n}\n/* Dumping UI */\n.dump #dump-list-container {\ndisplay: block;\n}\n#dump-list-container {\ndisplay: none;\nposition: relative;\noverflow-y: hidden;\nmargin-top: 1px;\n}\n#dump-list {\noverflow-x: auto;\noverflow-y: hidden;\nwhite-space: nowrap;\nwidth: 248px;\nmax-width: 100%;\nmin-width: 100%;\n}\n#dump-list:hover {\noverflow-x: auto;\n}\n.qr-preview {\n-moz-box-sizing: border-box;\ncounter-increment: thumbnails;\ncursor: move;\ndisplay: inline-block;\nheight: 90px;\nwidth: 90px;\npadding: 2px;\nopacity: .5;\noverflow: hidden;\nposition: relative;\ntext-shadow: 0 1px 1px #000;\n-moz-transition: opacity .25s ease-in-out;\nvertical-align: top;\nbackground-size: cover;\n}\n.qr-preview:hover,\n.qr-preview:focus {\nopacity: .9;\n}\n.qr-preview::before {\ncontent: counter(thumbnails);\ncolor: #fff;\nposition: absolute;\ntop: 3px;\nright: 3px;\ntext-shadow: 0 0 3px #000, 0 0 8px #000;\n}\n.qr-preview#selected {\nopacity: 1;\n}\n.qr-preview.drag {\nbox-shadow: 0 0 10px rgba(0,0,0,.5);\n}\n.qr-preview.over {\nborder-color: #fff;\n}\n.qr-preview > span {\ncolor: #fff;\n}\n.remove {\nbackground: none;\ncolor: #e00;\nfont-weight: 700;\npadding: 3px;\n}\na:only-of-type > .remove {\ndisplay: none;\n}\n.remove:hover::after {\ncontent: \" Remove\";\n}\n.qr-preview > label {\nbackground: rgba(0,0,0,.5);\ncolor: #fff;\nright: 0;\nbottom: 0;\nleft: 0;\nposition: absolute;\ntext-align: center;\n}\n.qr-preview > label > input {\nmargin: 0;\n}\n#add-post {\ncursor: pointer;\nfont-size: 2em;\nposition: absolute;\ntop: 50%;\nright: 10px;\n-moz-transform: translateY(-50%);\n}\n.textarea {\nposition: relative;\n}\n:root.webkit .textarea {\nmargin-bottom: -2px;\n}\n#char-count {\ncolor: #000;\nbackground: hsla(0, 0%, 100%, .5);\nfont-size: 8pt;\nposition: absolute;\nbottom: 1px;\nright: 1px;\npointer-events: none;\n}\n\n/* Menu */\n.menu-button {\ndisplay: inline-block;\nposition: relative;\ncursor: pointer;\n}\n.menu-button i {\nborder-top: 6px solid;\nborder-right: 4px solid transparent;\nborder-left: 4px solid transparent;\ndisplay: inline-block;\nmargin: 2px;\nvertical-align: middle;\n}\n#menu {\nposition: fixed;\noutline: none;\n}\n.entry {\nborder-bottom: 1px solid rgba(0,0,0,.25);\ncursor: pointer;\ndisplay: block;\noutline: none;\npadding: 3px 7px;\nposition: relative;\ntext-decoration: none;\nwhite-space: nowrap;\n}\n.left>.entry.has-submenu {\npadding-right: 17px !important;\n}\n.entry:last-child {\nborder-bottom: 0;\n}\n.has-submenu::after {\ncontent: \"\";\nborder-left: .5em solid;\nborder-top: .3em solid transparent;\nborder-bottom: .3em solid transparent;\ndisplay: inline-block;\nmargin: .3em;\nposition: absolute;\nright: 3px;\n}\n.left .has-submenu::after {\nborder-left: 0;\nborder-right: .5em solid;\n}\n.submenu {\ndisplay: none;\nposition: absolute;\nleft: 100%;\ntop: -1px;\n}\n.focused .submenu {\ndisplay: block;\n}\n.imp-exp-result {\nposition: absolute;\ntext-align: center;\nmargin: auto;\nright: 0px;\nleft: 0px;\nwidth: 200px;\n}\n.export, .import {\ncursor: pointer;\ntext-decoration: none !important;\n}\n/* Link Title Favicons */\n.linkify.YouTube {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAMCAYAAABr5z2BAAABIklEQVQoz53LvUrDUBjG8bOoOammSf1IoBSvoCB4JeIqOHgBLt6AIMRBBQelWurQ2kERnMRBsBUcIp5FJSBI5oQsJVkkUHh8W0o5nhaFHvjBgef/Mq+Q46RJBMkI/vE+aOus956tnEswIZe1LV0QyJ5sE2GzgZfVMtRNIdiDpccEssdlB1mW4bvTwdvWJtRdErM7U+8S/FJykCRJX5qm+KpVce8UMNLRLbulz4iSjTAMh6Iowsd5BeNadp3nUF0VlxAEwZBotXC0Usa4ll3meZdA1iguwvf9vpvDA2wvmKgYGtSud8suDB4TyGr2PF49D/vra9jRZ1BVdknMzgwuCGSnZEObwu6sBnVTCHZiaC7BhFx2PKdxUidiAH/4lLo9Mv0DELVs9qsOHXwAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.Vimeo {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAASJJREFUOE9jYAAC7ln7/pODQXrBmq333PvPu/YaSRikB6QXbACpmmHqsRoAMll7+20UQ0H8tmuv/pdffPFfZtNNuByGASBFIPDh5x+4IV6HHoDFYGDJgw+YBoBMBUkgA5BtIKduuvvy//svX+FSB+88wTTAc+/t/83bj/0HScLA5BPXwc7lKJ36f+L6XXDxhUfOYxrAPWUnWKFp9UQUm3iWQxSDXAEDSX3zcIcB96wD/x+8eA1XDNKMHAYg20GW4Y0FkCIYAAUqzEBQOIBciRzlWKMxZelOlMCEcVxq+jHSC1YDJPs3YBgA8jey0/F6ARRwsFAHORukmat9NdbUijMpg/wKcrJodDFOzSBXwA3Alh9AToZFI7a8Asu98BxJbnYGAJb5vYLDANzSAAAAAElFTkSuQmCC') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.SoundCloud {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABsklEQVQ4y5WTy2pUQRCGv2rbzDjJeAlIBmOyipGIIJqFEBDElwh4yULGeRFXPoEIBl/AvQ/gC2RnxCAoxijiwks852S6+3dxzslcHJCpTXVX11/Xv0097gLPgVNMJxnQNfX4zsqleWbnpoMf/oa9d988MM9MC/rp+E0a+A0dsVobMNMCOO8B6McRoABJI+A6gJmN3D2A8jgEBCEkSEMBrcrsDAzDWWn3AjgKFaDMmgRqniGFgsaDp1jrLOngDf1XT1D+A1dFc4MKAkkiCVKjjVu7g9+4Rzx4i1u6hjXbuMWr0O5QPNvCu7IaCZwEKQukLGDrm5x8uI0tr6MkiGlkiv7yLfzN+6S5i6QsIMABkEfcxhbWWYMkVAOjxvYAjc3HNHrbKI9VBQBFwF25XQKSBjqIf1YBuAurEMrczgDygD6/x2LCpFLXLUyQ+PoldphhBhYfIX09XU1+Flaukz7uYqs3SHs7cG4BmTsmkBUF9mmXEwa28BNLPaQPLepuNcbGSWQquQC2/Kdcox1FUGkcB0ykck1nA2+wTzMs8stGnP4rbWGw74EuS/GFQWfK7/wF6P4F7fzIAYkdmdEAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.audio {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAitJREFUOE9jYCAWKJWwavr0KyXWb/FIbDtUFFyzJx6nVofE2Xo5nXsj0rqPNSR0nVkR2Hjmgmfd+U9Otdf+m5Vf/6+SfeU/R9ChVVgNYDRtlfJuuPA/rPfe/4QpD/6nznj0P27Kw/9unff/69Xf+69c/+C/SO7N/0z+OAxgMmmRCe++/r9i3ev/KWvf/vdY8PK/bt/9/wrNV3/IN5y/IVt1YqNg4pGTTP4HsbuA2bhZ2qvpyn+xjIObxAp3VwqlrgngLFyryVy5nhPmZJHANS2cwYexG8BmVC/pWn3hP4NZlzWuQDJI3dIiFnUUuwEsQAOcq87jNcC7fHeLUtJxHF4AGmBWeAavAWH1+1rUUk7giAWjOknllON4DXAs2NEiG4/DBQxAF/CFHfrPYI4jDFSLuJVjNrUJhB/B7gIGo1pJRt99GAZYJK7wLJ1z7Xzl4vu/7aqv/GRBj0bjqAX2qb0nJ7mXH17C4HcUxQA+hymWtSue/C5a9up/9Ozn/7Vr7v1nRY7GqMb91T3b3v6vWvPmf/S0p/9ZQk+DDLCBRSOz06Jqk+o7/21nvfqvsebDf7kZL/5zBaxphkezd+OFn7HzXvz3Wvjmv9a8N//5Ek//ZTBpVYUrMG2X5wjcdl68+uI/wa5Lr3hSNjczGFeywOVZ/bbcVGp//F9izfv/Ql03f3P4LC/HSEQquYwMFnUCDJ7dzBhyjGZNQpye89M5gpfnMvtNUyE2h4PUAQBovvT7lyNljwAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.LiveLeak {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAydJREFUOE9Nk1tIk2EYx79NyUNqTk0o6KYrnZeChodLDxfeZpCbJk4RXU5Nm7tYRYhiYXbQlaeGutyW2gxtpB1RIyKDEjKwA6Ti2dR5KNDn+fq/S6TBj/f93r3P732e53s/qfnkSdej4GB2SBLbwf+jmB+gUMgOheLg/z7EdCUnO6Ref392SpK8Hyh3I+gBwBo7lUp2xcbyQEoKD6alyQOpqd754/h4FjJXZCRJTl9ftmEzoK5/wdQJxPgkLY2WV1dpc2uLtnZ2eHNnhza3t2nd46GhjAzuValY6jx0iIfS03msoIDuQ9COQCtoUSjohU5HuwgaN5loeXycd3d3aW9vzwvW2K5SkdTi58fvzGb+3tdHFggA3QONEAzn59PvjQ1yqNX0zenkvX0B4ffWaGRraChJd/385JGqKvlzTw/fRqOaIGkEd1DjU52O/3g83BkTw5MOh7yJuUCUM2o0yi2hoSw1IIOhykr+YLNRHYKu4XQvyKA/N5c8yMCCDD7Z7bz26xcJ1rH2rKKCG0UJdRAMlJbyG6uVrkJQjWAB5tSbk0Nr2HwDgvcQiIYur6zQyvo6ucvLueHIEZKuQPBQr+dXra1kRuqXEOwFArtWSytra1QdFUVjNhvPLS3R3OIiLUDUD0F1WBhJJtwDW2Ehu5uaqBICI4IFlRB0QLCEzaboaHrd0cHzCBYsIIuesjK+LAQXkEFrXh676uupGCWcR6AeghLQptGQONUAwfOuLp6Zn6eZuTmaXVig7pISrhI90ENgQbdHhoep32JhFzLpu3WLio8epUYIfs7OUjF6UKJW88XERLqYkEBNej11oG8XhCAvMFAuOn5cNiclsTkhQTbhmpri4lgbEMANWi1DwC/xit3t7bK7rY0Fo4OD3G4wyEURESzloAdnceezlErK8vH5N4KzPj50PTOTfkxP0+THj/RlYoInJyZI8HVqim5qNFwQHk7SucBAPo2PKRMNPLM/4pnFszYkhJsNBu6uqWFHba1sr61lQSveQFZQkFx07BhJmhMnrLn4NLMPH/aSExR0QDbmWhwgyEapwDvXoDxdWBiXnjrV/Bdm2kYUxLwmEgAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.Vocaroo {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAw9JREFUOE9jYMABuMwYmCyTJKUCGlSnFSy02TTzeOyCiQcDViX26qVz2TAyYtWmEMwuoZ3M7V40LcB79pHkc0svpvzY8jD//87nxf+3Pyn8v/ZO8v+VNyP/2mZJumI1QCWSI8232Hjumitlfw5+qPp/9l8TCt76JP//xkdx/wsXWCzjtWFkwTCkbWFe9plPk/+ga4Txz/xt/D/hkN//gMXif21a+NbyWjIwoRiy6GDT5rP/mlFsPfyp5n/NpOj/22+0gMUXXIz/H7hC/L/bFKFbPDZMrHAD5H35OPt2J9zacDv/f3V7xv9FhwrBGubsT/1//Pjx/1GJ/mD+/nfl/1v3Ovy3KRJNQbHdOlXCvOO03/+pm1P/v3v37n90hhtYw9HPtf8Xb2v937cmHswHeWPRxYj/LvkK3igGKARwicTO07118H3V/5kbi/4vPZMJtK3s/6YH2f+Pfq1B8VbjWrdnMu5s4nAD9CNFhKwz5DTUvLl419zKvAcLtG1P84BRl/b/5M/6/6f/NPzf/qzo84yj0Uus0xUU4Zor54bm9+4OfZG02OCuoAMTb9ZkC9ull1Nvrr2Z+XvRpaRfc65H/68F+jl9svEhzyLFWoccWVc+eyTHq/twydjlKRln7jX9bNMkMJnbhoFRL1xCqmKx6/yi2fYXa/c5/e846PV/5fW0/7OPx/yfcjzop34ulxdGGvDuU8mMXaX507lBuiN6ueadmQeT/p/93vf/1O+G//sP5fw/eL3o/5JLif8zVxs+Tlir9S26UyeFQQvJGBE7FvaFZ9LfN+1y+WjbItSb3GmXvXd15v8zroH/HxgE/D+aGPx/18vi/z07PeZNPRKxe/Kh0Ae8toxscCO4zBkYXArk9C1SxJUYjBkYPPIVtbbuTftz3cz//2O9wP/75iSAXdO72/dt2HL5F6YlfBW4MiJYXMiBiW3t7azHBx+V/t89N+H/8a+1//e9K/9attDp5LQjYX8SuvVL8RoAkmxa65299Erq1FnHo0qrl7t4BddriIs4MrM3rfWcFd+pGwVSAwBZ0bKP8yrZPAAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.pastebin {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAtZJREFUOE+NU91LWmEc7sJtQew/2MUY7INg7CLY3W5GMHazyzEQo9UmfYxZTbAiVlgRqLMSZ+XnDC3z2+Y0+8JGakKZTtR0Tl2wtgtLLQh29cz3ZZ3h3Q68vOc95zzP73l+z+/U1f292O09DRxubxOH23P//1bvtQts3dPnry7LZnXJhcUl5Avf8dHtwY+fv2AyW5DOfIXFakMm+w0G4wISyRRm55TQG0y/Wzv6mikJ52Xf9TmVBoFAAD6fDwqFAqFQCJubmzCbzZiensbp6SmkUikikQi0Wi0kEgm6ewVaStDCfXPDandifn6egoaGhrCzswO1Wg2Hw4HBwUGk02kIBAL4/X4IhUJMTk6ii8dfYggy2RwymQzOz88Rj8dRLpexv7+PSqWCYDCIQqGAra0tJBIJrK2t0XdVAjNDEIl+wfj4OEqlEq2wt7dHrchkMmrBYDCAz+fTIjweD7FYrJbgIJOlgLOzM8jlcip1eXmZ2rFarVAqlRCLxcjlchCJRFRljYJYPAG32418Pg+n04lsNouVlRUcHh7C4/FQIOlHNBqlezgcJgQWxkIgGMbExASVNjY2hvX1dVo9mUzS5wREFLhcLrqTcw2B//M2RkdHodPp4PV6oVKpqH+SCom3v7+fNnF4eJiJusbCJ6+PviSyScakiaR5RIHRaKQpmEwmbAdCeD8zB6vdhebHT8SMhcUlC83bbrdTJRsbG3RwiCVCRNJJpDIoVeNNJJJQzKryV+rrmxiCtyNCCmaz2VhdXQWXy6XDpNfrodFoYLXZUTw+pk222Z3lW3ca26rgSwzBwqIZAwMDlITMAVEwNTVFR5fEJpK8Qyp1AJvDVbrTeLenCmxgfiZ22+urCtWHyu7uLp2wVCpFKx0dHaFYLOLk5KT6Y9kgk89kb95ubK0BX7A8a+1qannRLeW0daj/rU51S3tn9dypfvDw0QiLxbpX/Z7FVK7e/AEj4Wf24/2f5AAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.gist {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAk1JREFUeNqUkzuIE1EUhv955MnsbB6r4kYQLUQQFncV3SnCIqJsoWGDYOGjsIiCtY2Kla1sjLBIsFFcXJC1kaSwENQmXUQSRSUSjCQSTCbkbR4z47lXEgtBNwcu3DNzvvO8R8jlcj7LshKmaWqYQERRTAmCcEru9/sJr9er0QF92BJMAVGr1TQ6CeZAc7lcGAwGkyQAxpTLZU0eDoc8crfbRTgcRjAYRCQSYSmi1WpxY7fbjU6ng1gshmaziXg8zhnGIpVKWbquW9ls1mLZsaMoiqWq6lgnBxY55He/328Vi0XOMFZmqVMD4fF4QBAajcY48khY9JE4HA4enTGMFVkaTHmy+ZzD/5NSqYSNB484w1h55ODO3TVu4FXcWDywl24Cmp0e1WBhyuWELAtIf/qKUrWOONmev3Lpt4NRCXq1gplpBS/v3cDc0nGg9h1o1ZkfwO4Atu1B8cM7HLt8k37V/y5B2b4bJxf2Y+7oEbyJrkMvUjki0YYJ03LidfQxAt4dOHdCw5RdGZcgGobBlQtnV/BDr1GfDai7ZiHZZRi9PoY/e5SCCTUwC9gk1GmMh5YWOcNYkR4Sv1y9uAJbYB82N57h4OnDmN7phjQ0qUkWRJuB+TMaPn/5iFfvv+Ha7eucYey4iWw8q6tRJJNJ3Fp7ClUawEkViBTfkCR0YUNTVHD/4Tpm/P4/U2CeKpUKfD4fJDIMhUKEhP45St50XedZyLQY6Xw+v8AUemVb2oNqtYpCocCWKi2TLLfb7ReZTGZ+kmUi7i2VvfxLgAEAZChMriPcl+IAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.image {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAs5JREFUOE+lk/tvi1EYx98/xT8gW4REIpGFMEQWl2FiM9ZMZhm2xRAyOsmujFFmdFRHu0tWm87UypxStr69zPauN5e5rHVp3IYhbOvHy+wHEQlxkm+ek+d8nm9OznkeSfrfldmgJC7QyUlTymsJTfuTZ25z4HdWYwyLreYhtpgekGPw0+kKvo1Eo+IXRSIiEhkWZuc9tqnsJD9EqTUopCxjSGTpB0iueczSo1HyW8cpsExQ1DbxI2pt45j9cXpexul4FEd79RnZphAa/SD7WvuFtO6UItbU9LC+YQxNI2w0wwYT5LRAdhOU3oBTIXC9gXP3oUSGgz2vST3gYHejR0jptT1C332f8yrUEYHrz8CgxDnpm6DKCUfc0KnmXa/AEVPPwnDcD0cvetA2uYRk67Ive/lpjO7YBO1PPuF8Df3vwf4cbNE4tqdw7YVq8HYyHx6FvhE1hkMEg8HDUqvFkjT4aIjMqkqyqkswDSrcfBfH+Q561YLAZ/B+BLda6FXlU/cPv0AoEPhuoP1h4Av7Wbh9E/Py15NWWUjeSR3nZDfeN+N0DY9hG/7K1eGP3P0S5/EYRFUF/IOTBrUXHPm9fT6mr1xEwupkZqxbzLyiDJYUZ5NSnkdqdSHpxyrYdFpPgdmAsdfJwPMI/Yr65bf7tZLGGBQ7DNdJWFtIYvoOZmbuZE7OXpIKKli86zAr9p9gTVktWTVnKTI2U95uRWe3U2IJUDbVB5p6hVm5x5m9Vc/cnedZUNzC8lILaQesZBy6hEZ3maKzgvJWFzVWD9XtXvVGQbSWASFtMATVRlJIKbOTWtlJXaeXepuPM1f6MNp9GLt8mLvvYLmp0OhQ2Fwvk6m7xaqDTvY0eYWUVtcnllXfYlGpnfklVuraHHg8HjxuN+6fktUHlWWZPaZeUo/ILK0UKttBcbNbSB9GP0yLxWJJUxoZGUn80zD9C/vXQ/4NHY10h3M1zmQAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.InstallGentoo {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAklJREFUOE9jYEAAASBTCorZkcSRmTjVCDLziCwG4hfM3EIvGNm44oC6WNEM4WXi5FsEkmfhFX3BxMmfAJSHW9Qr55Px3aZp3X/btq3/hQydPzKysMcCFbBBDeFj4uBdqBJR/gskb1W34j+PmulLoJwbzBJJoMm7dNO7/ntMP/XfpW/v//SKvk+7tl7fvXfTpx5pCdWVSiHFv1wnHQbLi9sE/Wdk5SwBauaCGQB3gUPb5v+7Lr/8/+fvr/9fv/z+f+Pyr/9bV735l9Wy/79Dx/b/Nk0bsLoAHgbeAVHv/v77/f8f0IB7N7+cu3DuecK54z9+7lzz639e9pK/7HwSWMMA5BJwCJeXtOm/fvVj1fcfv369f//92cN7X6ZcPvf9x6Htv//vXP3r/+T245UEYgpskPTNq08LgN749/PH7/93rv/6f/rw7//nj//4f+bU0zQcUQwWBkdVbGz62y+fv3wHeeXrlz//H9798//qpY//M3KqfzGxc8djiWKwZnBUuWQ2/fr46fv/P39+///x/ff/d69//z97+s7fyMb5/+y7d2GLYriDZikFF/1qXXXj/4Pbv/8/f/jn/5MH316/eP6jVlBAaIt6VO1/jxmn/zv27P7Pp2HxEajLD90ra9Sj6/979O37X73w0n+vqOL/0lJyMVBFq0EGgDSD0oKAlu1/oHg4ugGzVCKqfouYuL1Xj676Iajr8AnJFricGqYc3Bw+Zi6BVUxsXLHAdL6QiYMPFNrwpIxHDsUhgtAMAopKDjQn4pPDF7P45QC4hSmc1eX8WgAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n\n/* General */\n:root.yotsuba .dialog {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.yotsuba .field:focus {\nborder-color: #EA8;\n}\n\n/* Header */\n:root.yotsuba #header-bar, :root.yotsuba #notifications {\nfont-size: 9pt;\ncolor: #B86;\n}\n:root.yotsuba #header-bar a, :root.yotsuba #notifications a {\ncolor: #800000;\n}\n\n/* Settings */\n:root.yotsuba #fourchanx-settings fieldset {\nborder-color: #D9BFB7;\n}\n\n/* Quote */\n:root.yotsuba .backlink.deadlink {\ncolor: #00E !important;\n}\n:root.yotsuba .inline {\nborder-color: #D9BFB7;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.yotsuba #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.yotsuba .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.yotsuba #menu {\ncolor: #800000;\n}\n:root.yotsuba .entry {\nborder-bottom: 1px solid #D9BFB7;\nfont-size: 10pt;\n}\n:root.yotsuba .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.yotsuba .watch-thread-link\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.yotsuba-b .dialog {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.yotsuba-b .field:focus {\nborder-color: #98E;\n}\n\n/* Header */\n:root.yotsuba-b #header-bar, :root.yotsuba-b #notifications {\nfont-size: 9pt;\ncolor: #89A;\n}\n:root.yotsuba-b #header-bar a, :root.yotsuba-b #notifications a {\ncolor: #34345C;\n}\n\n/* Settings */\n:root.yotsuba-b #fourchanx-settings fieldset {\nborder-color: #B7C5D9;\n}\n\n/* Quote */\n:root.yotsuba-b .backlink.deadlink {\ncolor: #34345C !important;\n}\n:root.yotsuba-b .inline {\nborder-color: #B7C5D9;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.yotsuba-b #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.yotsuba-b .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.yotsuba-b #menu {\ncolor: #000;\n}\n:root.yotsuba-b .entry {\nborder-bottom: 1px solid #B7C5D9;\nfont-size: 10pt;\n}\n:root.yotsuba-b .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.yotsuba-b .watch-thread-link\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.futaba .dialog {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.futaba .field:focus {\nborder-color: #EA8;\n}\n\n/* Header */\n:root.futaba #header-bar, :root.futaba #notifications {\nfont-size: 11pt;\ncolor: #B86;\n}\n:root.futaba #header-bar a, :root.futaba #notifications a {\ncolor: #800000;\n}\n\n/* Settings */\n:root.futaba #fourchanx-settings fieldset {\nborder-color: #D9BFB7;\n}\n\n/* Quote */\n:root.futaba .backlink.deadlink {\ncolor: #00E !important;\n}\n:root.futaba .inline {\nborder-color: #D9BFB7;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.futaba #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.futaba .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.futaba #menu {\ncolor: #800000;\n}\n:root.futaba .entry {\nborder-bottom: 1px solid #D9BFB7;\nfont-size: 12pt;\n}\n:root.futaba .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.futaba .watch-thread-link\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.burichan .dialog {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.burichan .field:focus {\nborder-color: #98E;\n}\n\n/* Header */\n:root.burichan #header-bar, :root.burichan #header-bar #notifications {\nfont-size: 11pt;\ncolor: #89A;\n}\n:root.burichan #header-bar a, :root.burichan #header-bar #notifications a {\ncolor: #34345C;\n}\n\n/* Settings */\n:root.burichan #fourchanx-settings fieldset {\nborder-color: #B7C5D9;\n}\n\n/* Quote */\n:root.burichan .backlink.deadlink {\ncolor: #34345C !important;\n}\n:root.burichan .inline {\nborder-color: #B7C5D9;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.burichan #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.burichan .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.burichan #menu {\ncolor: #000000;\n}\n:root.burichan .entry {\nborder-bottom: 1px solid #B7C5D9;\nfont-size: 12pt;\n}\n:root.burichan .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.burichan .watch-thread-link\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.tomorrow .dialog {\nbackground-color: #282A2E;\nborder-color: #111;\n}\n\n/* Header */\n:root.tomorrow #header-bar, :root.tomorrow #notifications {\nfont-size: 9pt;\ncolor: #C5C8C6;\n}\n:root.tomorrow #header-bar a, :root.tomorrow #notifications a {\ncolor: #81A2BE;\n}\n\n/* Settings */\n:root.tomorrow #fourchanx-settings fieldset {\nborder-color: #111;\n}\n\n/* Quote */\n:root.tomorrow .backlink.deadlink {\ncolor: #81A2BE !important;\n}\n:root.tomorrow .inline {\nborder-color: #111;\nbackground-color: rgba(0, 0, 0, .14);\n}\n\n/* QR */\n.tomorrow #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #282A2E;\nborder-color: #111;\n}\n:root.tomorrow .qr-preview {\nbackground-color: rgba(255, 255, 255, .15);\n}\n:root.tomorrow #qr .field {\nbackground-color: rgb(26, 27, 29);\ncolor: rgb(197,200,198);\nborder-color: rgb(40, 41, 42);\n}\n:root.tomorrow #qr .field:focus {\nborder-color: rgb(129, 162, 190) !important;\nbackground-color: rgb(30,32,36);\n}\n\n/* Menu */\n:root.tomorrow #menu {\ncolor: #C5C8C6;\n}\n:root.tomorrow .entry {\nborder-bottom: 1px solid #111;\nfont-size: 10pt;\n}\n:root.tomorrow .focused.entry {\nbackground: rgba(0, 0, 0, .33);\n}\n\n/* Watcher Favicon */\n:root.tomorrow .watch-thread-link\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.photon .dialog {\nbackground-color: #DDD;\nborder-color: #CCC;\n}\n:root.photon .field:focus {\nborder-color: #EA8;\n}\n\n/* Header */\n:root.photon #header-bar, :root.photon #notifications {\nfont-size: 9pt;\ncolor: #333;\n}\n:root.photon #header-bar a, :root.photon #notifications a {\ncolor: #FF6600;\n}\n\n/* Settings */\n:root.photon #fourchanx-settings fieldset {\nborder-color: #CCC;\n}\n\n/* Quote */\n:root.photon .backlink.deadlink {\ncolor: #F60 !important;\n}\n:root.photon .inline {\nborder-color: #CCC;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.photon #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #DDD;\nborder-color: #CCC;\n}\n:root.photon .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.photon #menu {\ncolor: #333;\n}\n:root.photon .entry {\nborder-bottom: 1px solid #CCC;\nfont-size: 10pt;\n}\n:root.photon .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.photon .watch-thread-link\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n"
+ css: "/* General */\n.dialog {\nbox-shadow: 0 1px 2px rgba(0, 0, 0, .15);\nborder: 1px solid;\ndisplay: block;\npadding: 0;\n}\n.captcha-img,\n.field {\nbackground-color: #FFF;\nborder: 1px solid #CCC;\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\ncolor: #333;\nfont: 13px sans-serif;\noutline: none;\ntransition: color .25s, border-color .25s;\ntransition: color .25s, border-color .25s;\n}\n.field::-moz-placeholder,\n.field:hover::-moz-placeholder {\ncolor: #AAA !important;\nfont-size: 13px !important;\nopacity: 1.0 !important;\n}\n.captch-img:hover,\n.field:hover {\nborder-color: #999;\n}\n.field:hover, .field:focus {\ncolor: #000;\n}\n.field[disabled] {\nbackground-color: #F2F2F2;\ncolor: #888;\n}\n.move {\ncursor: move;\noverflow: hidden;\n}\nlabel,\n.watcher-toggler {\ncursor: pointer;\n}\na[href=\"javascript:;\"] {\ntext-decoration: none;\n}\n.warning {\ncolor: red;\n}\n#boardNavDesktop {\ndisplay: none !important;\n}\na {\noutline: none !important;\n}\n\n/* 4chan style fixes */\n.opContainer, .op {\ndisplay: block !important;\noverflow: visible !important;\n}\n[hidden] {\ndisplay: none !important;\n}\n\n/* fixed, z-index */\n#overlay,\n#fourchanx-settings,\n#qp, #ihover,\n#navlinks, .fixed #header-bar,\n:root.float #updater,\n:root.float #thread-stats,\n#qr {\nposition: fixed;\n}\n#fourchanx-settings {\nz-index: 999;\n}\n#overlay {\nz-index: 900;\n}\n#notifications {\nz-index: 70;\n}\n#qp, #ihover {\nz-index: 60;\n}\n#menu {\nz-index: 50;\n}\n#navlinks, #updater, #thread-stats {\nz-index: 40;\n}\n.fixed #header-bar.autohide {\nz-index: 35;\n}\n#qr {\nz-index: 30;\n}\n#thread-watcher {\nz-index: 8;\n}\n:root.fixed-watcher #thread-watcher {\nz-index: 20;\n}\n.fixed #header-bar {\nz-index: 10;\n}\n/* Header */\n.fixed.top body {\npadding-top: 2em;\n}\n.fixed.bottom body {\npadding-bottom: 2em;\n}\n.fixed #header-bar {\nright: 0;\nleft: 0;\npadding: 3px 4px 4px;\n}\n.fixed.top #header-bar {\ntop: 0;\n}\n.fixed.bottom #header-bar {\nbottom: 0;\n}\n#header-bar {\nborder-width: 0;\ntransition: all .1s .05s ease-in-out;\n}\n:root.centered-links #shortcuts {\nwidth: 300px;\ntext-align: right;\n}\n:root.centered-links #header-bar {\ntext-align: center;\n}\n:root.centered-links #custom-board-list {\nposition: relative;\nleft: 150px;\n}\n.fixed.top #header-bar {\nborder-bottom-width: 1px;\n}\n.fixed.bottom #header-bar {\nbox-shadow: 0 -1px 2px rgba(0, 0, 0, .15);\nborder-top-width: 1px;\n}\n.fixed.bottom #header-bar .menu-button i {\nborder-top: none;\nborder-bottom: 6px solid;\n}\n#board-list {\ntext-align: center;\n}\n.fixed #header-bar.autohide:not(:hover) {\nbox-shadow: none;\ntransition: all .8s .6s cubic-bezier(.55, .055, .675, .19);\n}\n.fixed.top #header-bar.autohide:not(:hover) {\nmargin-bottom: -1em;\n-webkit-transform: translateY(-100%);\ntransform: translateY(-100%);\n}\n.fixed.bottom #header-bar.autohide:not(:hover) {\n-webkit-transform: translateY(100%);\ntransform: translateY(100%);\n}\n#scroll-marker {\nleft: 0;\nright: 0;\nheight: 10px;\nposition: absolute;\n}\n:root:not(.autohide) #scroll-marker {\npointer-events: none;\n}\n#header-bar #scroll-marker {\ndisplay: none;\n}\n.fixed #header-bar #scroll-marker {\ndisplay: block;\n}\n.fixed.top #header-bar #scroll-marker {\ntop: 100%;\n}\n.fixed.bottom #header-bar #scroll-marker {\nbottom: 100%;\n}\n#header-bar a:not(.entry):not(.close) {\ntext-decoration: none;\npadding: 1px;\n}\n#header-bar input {\nmargin: 0;\nvertical-align: bottom;\n}\n#shortcuts:empty {\ndisplay: none;\n}\n.brackets-wrap::before {\ncontent: \"\\00a0[\";\n}\n.brackets-wrap::after {\ncontent: \"]\\00a0\";\n}\n.dead-thread,\n.disabled,\n.expand-all-shortcut {\nopacity: .45;\n}\n#shortcuts {\nfloat: right;\n}\n.shortcut {\nmargin-left: 3px;\n}\n#navbotright,\n#navtopright {\ndisplay: none;\n}\n#toggleMsgBtn {\ndisplay: none !important;\n}\n.current {\nfont-weight: bold;\n}\n/* 4chan X link brackets */\n.fourchanx-link::after {\ncontent: \"]\";\n}\n.fourchanx-link::before {\ncontent: \"[\";\n}\n/* Notifications */\n#notifications {\nposition: fixed;\ntop: 0;\nheight: 0;\ntext-align: center;\nright: 0;\nleft: 0;\ntransition: all .8s .6s cubic-bezier(.55, .055, .675, .19);\n}\n.fixed.top #header-bar #notifications {\nposition: absolute;\ntop: 100%;\n}\n.notification {\ncolor: #FFF;\nfont-weight: 700;\ntext-shadow: 0 1px 2px rgba(0, 0, 0, .5);\nbox-shadow: 0 1px 2px rgba(0, 0, 0, .15);\nborder-radius: 2px;\nmargin: 1px auto;\nwidth: 500px;\nmax-width: 100%;\nposition: relative;\ntransition: all .25s ease-in-out;\n}\n.notification.error {\nbackground-color: hsla(0, 100%, 38%, .9);\n}\n.notification.warning {\nbackground-color: hsla(36, 100%, 38%, .9);\n}\n.notification.info {\nbackground-color: hsla(200, 100%, 38%, .9);\n}\n.notification.success {\nbackground-color: hsla(104, 100%, 38%, .9);\n}\n.notification a {\ncolor: white;\n}\n.notification > .close {\npadding: 6px;\ntop: 0;\nright: 5px;\nposition: absolute;\n}\n.message {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\npadding: 6px 20px;\nmax-height: 200px;\nwidth: 100%;\noverflow: auto;\n}\n\n/* Settings */\n:root.fourchan-x body {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\n}\n#overlay {\nbackground-color: rgba(0, 0, 0, .5);\ntop: 0;\nleft: 0;\nheight: 100%;\nwidth: 100%;\n}\n#fourchanx-settings {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\nbox-shadow: 0 0 15px rgba(0, 0, 0, .15);\nheight: 600px;\nmax-height: 100%;\nwidth: 900px;\nmax-width: 100%;\nmargin: auto;\npadding: 3px;\ntop: 50%;\nleft: 50%;\n-moz-transform: translate(-50%, -50%);\n-webkit-transform: translate(-50%, -50%);\ntransform: translate(-50%, -50%);\n}\n#fourchanx-settings > nav {\npadding: 2px 2px 0;\nheight: 15px;\n}\n#fourchanx-settings > nav a {\ntext-decoration: underline;\n}\n#fourchanx-settings > nav a.close {\ntext-decoration: none;\npadding: 2px;\n}\n.section-container {\noverflow: auto;\nposition: absolute;\ntop: 2.1em;\nright: 5px;\nbottom: 5px;\nleft: 5px;\npadding-right: 5px;\n}\n.sections-list {\npadding: 0 3px;\nfloat: left;\n}\n.credits {\nfloat: right;\n}\n.tab-selected {\nfont-weight: 700;\n}\n.section-sauce ul,\n.section-advanced ul {\nlist-style: none;\nmargin: 0;\n}\n.section-sauce ul {\npadding: 8px;\n}\n.section-advanced ul {\npadding: 0px;\n}\n.section-sauce li,\n.section-advanced li {\npadding-left: 4px;\n}\n.section-main label {\ntext-decoration: underline;\n}\n.section-filter ul {\npadding: 0;\n}\n.section-filter li {\nmargin: 10px 40px;\n}\n.section-filter textarea {\nheight: 500px;\n}\n.section-sauce textarea {\nheight: 350px;\n}\n.section-advanced .field[name=\"boardnav\"] {\nwidth: 100%;\n}\n.section-advanced textarea {\nheight: 150px;\n}\n.section-advanced .archive-cell {\nmin-width: 160px;\ntext-align: center;\n}\n.section-advanced #archive-board-select {\nposition: absolute;\n}\n.section-advanced .note {\nfont-size: 0.8em;\nfont-style: italic;\nmargin-left: 10px;\n}\n.section-advanced .note code {\nfont-style: normal;\nfont-size: 11px;\n}\n.section-keybinds .field {\nfont-family: monospace;\n} \n#fourchanx-settings fieldset {\nborder: 1px solid;\nborder-radius: 3px;\n}\n#fourchanx-settings legend {\nfont-weight: 700;\n}\n#fourchanx-settings textarea {\nfont-family: monospace;\nmin-width: 100%;\nmax-width: 100%;\n}\n#fourchanx-settings code {\ncolor: #000;\nbackground-color: #FFF;\npadding: 0 2px;\n}\n.unscroll {\noverflow: hidden;\n}\n\n/* Announcement Hiding */\n:root.hide-announcement #globalMessage {\ndisplay: none;\n}\na.hide-announcement {\nfloat: left;\n}\n\n/* Unread */\n#unread-line {\nmargin: 0;\nborder-color: rgb(255,0,0);\n}\n\n/* Thread Updater */\n#updater {\nbackground: none;\nborder: none;\nbox-shadow: none;\n}\n#updater > .move {\npadding: 5px 3px 0px;\nmargin-bottom: -3px;\n}\n#updater > div:last-child {\ntext-align: center;\n}\n#updater input[type=number] {\nwidth: 4em;\n}\n:root.float #updater {\npadding: 0px 3px;\n}\n.new {\ncolor: limegreen;\n}\n#update-status.new {\nmargin-right: 5px;\n}\n#update-timer {\ncursor: pointer;\n}\n\n/* Thread Watcher */\n#thread-watcher {\nposition: absolute;\n}\n#thread-watcher {\npadding-bottom: 3px;\npadding-left: 3px;\noverflow: hidden;\nwhite-space: nowrap;\nmin-width: 136px;\nmax-height: 92%;\noverflow-y: auto;\n}\n#thread-watcher .menu-button {\nbottom: 1px;\n}\n:root.fixed-watcher #thread-watcher {\nposition: fixed;\n}\n:root:not(.fixed-watcher) #thread-watcher:not(:hover) {\nmax-height: 210px;\noverflow-y: hidden;\n}\n#thread-watcher > .move {\npadding-top: 3px;\n}\n#watched-threads > div {\nmax-width: 250px;\noverflow: hidden;\npadding-left: 3px;\npadding-right: 3px;\ntext-overflow: ellipsis;\n}\n#thread-watcher a {\ntext-decoration: none;\n}\n#thread-watcher .move>.close {\nposition: absolute;\nright: 0px;\ntop: 0px;\npadding: 0px 4px;\n}\n.watcher-toggler {\npadding-top: 18px;\nwidth: 18px;\nheight: 0px;\ndisplay: inline-block;\nbackground-repeat: no-repeat;\nopacity: 0.2;\nposition: relative;\ntop: 1px;\n}\n.watcher-toggler.watched {\nopacity: 1;\n}\n\n\n/* Thread Stats */\n#thread-stats {\nbackground: none;\nborder: none;\nbox-shadow: none;\n}\n:root.float #post-count, :root.float #file-count {\npointer-events: none;\n}\n:root.float #thread-stats {\npadding: 0px 3px;\n}\n\n/* Quote */\n.deadlink {\ntext-decoration: none !important;\n}\n.backlink.deadlink:not(.forwardlink),\n.quotelink.deadlink:not(.forwardlink) {\ntext-decoration: underline !important;\n}\n.inlined {\nopacity: .5;\n}\n#qp input, .forwarded {\ndisplay: none;\n}\n.quotelink.forwardlink,\n.backlink.forwardlink {\ntext-decoration: none;\nborder-bottom: 1px dashed;\n}\n.filtered {\ntext-decoration: underline line-through;\n}\n:root.hide-backlinks .backlink.filtered {\ndisplay: none;\n}\n.inline {\nborder: 1px solid;\ndisplay: table;\nmargin: 2px 0;\n}\n.inline .post {\nborder: 0 !important;\nbackground-color: transparent !important;\ndisplay: table !important;\nmargin: 0 !important;\npadding: 1px 2px !important;\n}\n#qp > .opContainer::after {\ncontent: '';\nclear: both;\ndisplay: table;\n}\n#qp .post {\nborder: none;\nmargin: 0;\npadding: 2px 2px 5px;\n}\n#qp img {\nmax-height: 80vh;\nmax-width: 50vw;\n}\n.qphl {\noutline: 2px solid rgba(216, 94, 49, .7);\n}\n:root.highlight-own .yourPost > .reply,\n:root.highlight-you .quotesYou > .reply {\nborder-left: 2px solid rgba(221,0,0,.5);\n}\n/* Quote Threading */\n.threadContainer {\nmargin-left: 20px;\nborder-left: 1px solid rgba(128,128,128,.3);\n}\n.threadOP {\nclear: both;\n} \n\n/* File */\n.fileText:hover .fntrunc,\n.fileText:not(:hover) .fnfull,\n.expanded-image > .post > .file > .fileThumb > img[data-md5],\n:not(.expanded-image) > .post > .file > .fileThumb > .full-image {\ndisplay: none;\n}\n.expanding {\nopacity: .5;\n}\n:root.fit-height .full-image {\nmax-height: 100vh;\n}\n:root.fit-width .full-image {\nmax-width: 100%;\n}\n:root.gecko.fit-width .full-image {\nwidth: 100%;\n}\n#ihover {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\nmax-height: 100%;\nmax-width: 75%;\npadding-bottom: 16px;\n}\n.fappeTyme .thread > .noFile,\n.fappeTyme .threadContainer > .noFile {\ndisplay: none;\n}\n\n/* Index/Reply Navigation */\n#navlinks {\nfont-size: 16px;\ntop: 25px;\nright: 10px;\n}\n\n/* Filter */\n.opContainer.filter-highlight {\nbox-shadow: inset 5px 0 rgba(255, 0, 0, .5);\n}\n.filter-highlight > .reply {\nbox-shadow: -5px 0 rgba(255, 0, 0, .5);\n}\n\n/* Spoiler text */\n:root.reveal-spoilers s {\ncolor: white !important;\n}\n\n/* Thread & Reply Hiding */\n.hide-thread-button,\n.hide-reply-button {\nfloat: left;\nmargin-right: 2px;\n}\n.stub ~ * {\ndisplay: none !important;\n}\n.stub input {\ndisplay: inline-block;\n}\n\n/* QR */\n:root.hide-original-post-form #postForm,\n:root.hide-original-post-form .postingMode,\n:root.hide-original-post-form #togglePostForm,\n#qr.autohide:not(.has-focus):not(:hover) > form,\n.postingMode ~ #qr select,\n#file-n-submit:not(.has-file) #qr-filerm {\ndisplay: none;\n}\n#qr select,\n#dump-button,\n.remove,\n.captcha-img {\ncursor: pointer;\n}\n#qr {\nz-index: 20;\nposition: fixed;\npadding: 1px;\nborder: 1px solid transparent;\nmin-width: 300px;\nborder-radius: 3px 3px 0 0;\n}\n#qrtab {\nborder-radius: 3px 3px 0 0;\n}\n#qrtab {\nmargin-bottom: 1px;\n}\n#qr .close {\nfloat: right;\npadding: 0 3px;\n}\n#qr .warning {\nmin-height: 1.6em;\nvertical-align: middle;\npadding: 0 1px;\nborder-width: 1px;\nborder-style: solid;\n}\n.qr-link-container {\ntext-align: center;\n}\n.persona {\nwidth: 248px;\nmax-width: 100%;\nmin-width: 100%;\n}\n#dump-button {\nwidth: 10%;\nmargin: 0;\nmargin-right: 4px;\nfont: 13px sans-serif;\npadding: 1px 0px 2px;\nopacity: 0.6;\n}\n.persona .field:not(#dump) {\nwidth: 95px;\nmin-width: 33.3%;\nmax-width: 33.3%;\n}\n#qr textarea.field {\nheight: 14.8em;\nmin-height: 9em;\n}\n#qr.has-captcha textarea.field {\nheight: 9em;\n}\ninput.field.tripped:not(:hover):not(:focus) {\ncolor: transparent !important;\ntext-shadow: none !important;\n}\n#qr textarea {\nresize: both;\n}\n.captcha-img {\nmargin: 0px;\ntext-align: center;\nbackground-image: #fff;\nfont-size: 0px;\nmin-height: 59px;\nmin-width: 302px;\n}\n.captcha-input {\nwidth: 100%;\nmargin: 1px 0 0;\n}\n.captcha-input.error:focus {\nborder-color: rgb(255,0,0) !important;\n}\n.field {\n-moz-box-sizing: border-box;\nmargin: 0px;\npadding: 2px 4px 3px;\n}\n#qr textarea {\nmin-width: 100%;\n}\n#qr [type='submit'] {\nwidth: 25%;\nvertical-align: top;\n}\n:root.webkit #qr [type='submit'] {\nheight: 24px;\n}\n/* Fake File Input */\n#qr-filename,\n.has-file #qr-no-file {\ndisplay: none;\n}\n#qr-no-file,\n.has-file #qr-filename {\ndisplay: inline-block;\npadding: 0px 4px;\nmargin-bottom: 2px;\noverflow: hidden;\ntext-overflow: ellipsis;\nmax-width: 88%;\n}\n#qr-no-file {\ncolor: #AAA;\n}\n#qr-filename-container {\n-moz-box-sizing: border-box;\ndisplay: inline-block;\nposition: relative;\nwidth: 100px;\nmin-width: 74.6%;\nmax-width: 74.6%;\nmargin-right: 0.4%;\nmargin-top: 1px;\noverflow: hidden;\npadding: 2px 1px 0;\nheight: 22px;\n}\n#qr-filename-container:hover {\ncursor: text;\n}\n#qr-extras-container {\nposition: absolute;\nright: 0px;\n}\n#qr-filerm {\nmargin-right: 2px;\nz-index: 2;\n}\n#file-n-submit {\nheight: 23px;\n}\n#qr input[type=file] {\nvisibility: hidden;\nposition: absolute;\n}\n/* Thread Select / Spoiler Label */\n#qr select {\nfloat: right;\n}\n#qr.has-spoiler .has-file #qr-spoiler-label {\nwidth: 6.7%;\nmin-width: 6.7%;\nmax-width: 6.7%;\ndisplay: inline-block;\ntext-align: center;\nvertical-align: top;\n}\n#qr.has-spoiler #file-n-submit:not(.has-file) #qr-spoiler-label {\ndisplay: none;\n}\n#qr.has-spoiler .has-file #qr-filename-container {\nmax-width: 67.9%;\nmin-width: 67.9%;\n}\n#qr-spoiler-label input {\nposition: relative;\ntop: 3px;\n}\n/* Dumping UI */\n.dump #dump-list-container {\ndisplay: block;\n}\n#dump-list-container {\ndisplay: none;\nposition: relative;\noverflow-y: hidden;\nmargin-top: 1px;\n}\n#dump-list {\noverflow-x: auto;\noverflow-y: hidden;\nwhite-space: nowrap;\nwidth: 248px;\nmax-width: 100%;\nmin-width: 100%;\n}\n#dump-list:hover {\noverflow-x: auto;\n}\n.qr-preview {\n-moz-box-sizing: border-box;\ncounter-increment: thumbnails;\ncursor: move;\ndisplay: inline-block;\nheight: 90px;\nwidth: 90px;\npadding: 2px;\nopacity: .5;\noverflow: hidden;\nposition: relative;\ntext-shadow: 0 1px 1px #000;\n-moz-transition: opacity .25s ease-in-out;\nvertical-align: top;\nbackground-size: cover;\n}\n.qr-preview:hover,\n.qr-preview:focus {\nopacity: .9;\n}\n.qr-preview::before {\ncontent: counter(thumbnails);\ncolor: #fff;\nposition: absolute;\ntop: 3px;\nright: 3px;\ntext-shadow: 0 0 3px #000, 0 0 8px #000;\n}\n.qr-preview#selected {\nopacity: 1;\n}\n.qr-preview.drag {\nbox-shadow: 0 0 10px rgba(0,0,0,.5);\n}\n.qr-preview.over {\nborder-color: #fff;\n}\n.qr-preview > span {\ncolor: #fff;\n}\n.remove {\nbackground: none;\ncolor: #e00;\nfont-weight: 700;\npadding: 3px;\n}\na:only-of-type > .remove {\ndisplay: none;\n}\n.remove:hover::after {\ncontent: \" Remove\";\n}\n.qr-preview > label {\nbackground: rgba(0,0,0,.5);\ncolor: #fff;\nright: 0;\nbottom: 0;\nleft: 0;\nposition: absolute;\ntext-align: center;\n}\n.qr-preview > label > input {\nmargin: 0;\n}\n#add-post {\ncursor: pointer;\nfont-size: 2em;\nposition: absolute;\ntop: 50%;\nright: 10px;\n-moz-transform: translateY(-50%);\n}\n.textarea {\nposition: relative;\n}\n:root.webkit .textarea {\nmargin-bottom: -2px;\n}\n#char-count {\ncolor: #000;\nbackground: hsla(0, 0%, 100%, .5);\nfont-size: 8pt;\nposition: absolute;\nbottom: 1px;\nright: 1px;\npointer-events: none;\n}\n\n/* Menu */\n.menu-button {\ndisplay: inline-block;\nposition: relative;\ncursor: pointer;\n}\n.menu-button i {\nborder-top: 6px solid;\nborder-right: 4px solid transparent;\nborder-left: 4px solid transparent;\ndisplay: inline-block;\nmargin: 2px;\nvertical-align: middle;\n}\n#menu {\nposition: fixed;\noutline: none;\n}\n.entry {\nborder-bottom: 1px solid rgba(0,0,0,.25);\ncursor: pointer;\ndisplay: block;\noutline: none;\npadding: 3px 7px;\nposition: relative;\ntext-decoration: none;\nwhite-space: nowrap;\n}\n.left>.entry.has-submenu {\npadding-right: 17px !important;\n}\n.entry:last-child {\nborder-bottom: 0;\n}\n.has-submenu::after {\ncontent: \"\";\nborder-left: .5em solid;\nborder-top: .3em solid transparent;\nborder-bottom: .3em solid transparent;\ndisplay: inline-block;\nmargin: .3em;\nposition: absolute;\nright: 3px;\n}\n.left .has-submenu::after {\nborder-left: 0;\nborder-right: .5em solid;\n}\n.submenu {\ndisplay: none;\nposition: absolute;\nleft: 100%;\ntop: -1px;\n}\n.focused .submenu {\ndisplay: block;\n}\n.imp-exp-result {\nposition: absolute;\ntext-align: center;\nmargin: auto;\nright: 0px;\nleft: 0px;\nwidth: 200px;\n}\n.export, .import {\ncursor: pointer;\ntext-decoration: none !important;\n}\n/* Link Title Favicons */\n.linkify.YouTube {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAMCAYAAABr5z2BAAABIklEQVQoz53LvUrDUBjG8bOoOammSf1IoBSvoCB4JeIqOHgBLt6AIMRBBQelWurQ2kERnMRBsBUcIp5FJSBI5oQsJVkkUHh8W0o5nhaFHvjBgef/Mq+Q46RJBMkI/vE+aOus956tnEswIZe1LV0QyJ5sE2GzgZfVMtRNIdiDpccEssdlB1mW4bvTwdvWJtRdErM7U+8S/FJykCRJX5qm+KpVce8UMNLRLbulz4iSjTAMh6Iowsd5BeNadp3nUF0VlxAEwZBotXC0Usa4ll3meZdA1iguwvf9vpvDA2wvmKgYGtSud8suDB4TyGr2PF49D/vra9jRZ1BVdknMzgwuCGSnZEObwu6sBnVTCHZiaC7BhFx2PKdxUidiAH/4lLo9Mv0DELVs9qsOHXwAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.Vimeo {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAASJJREFUOE9jYAAC7ln7/pODQXrBmq333PvPu/YaSRikB6QXbACpmmHqsRoAMll7+20UQ0H8tmuv/pdffPFfZtNNuByGASBFIPDh5x+4IV6HHoDFYGDJgw+YBoBMBUkgA5BtIKduuvvy//svX+FSB+88wTTAc+/t/83bj/0HScLA5BPXwc7lKJ36f+L6XXDxhUfOYxrAPWUnWKFp9UQUm3iWQxSDXAEDSX3zcIcB96wD/x+8eA1XDNKMHAYg20GW4Y0FkCIYAAUqzEBQOIBciRzlWKMxZelOlMCEcVxq+jHSC1YDJPs3YBgA8jey0/F6ARRwsFAHORukmat9NdbUijMpg/wKcrJodDFOzSBXwA3Alh9AToZFI7a8Asu98BxJbnYGAJb5vYLDANzSAAAAAElFTkSuQmCC') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.SoundCloud {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABsklEQVQ4y5WTy2pUQRCGv2rbzDjJeAlIBmOyipGIIJqFEBDElwh4yULGeRFXPoEIBl/AvQ/gC2RnxCAoxijiwks852S6+3dxzslcHJCpTXVX11/Xv0097gLPgVNMJxnQNfX4zsqleWbnpoMf/oa9d988MM9MC/rp+E0a+A0dsVobMNMCOO8B6McRoABJI+A6gJmN3D2A8jgEBCEkSEMBrcrsDAzDWWn3AjgKFaDMmgRqniGFgsaDp1jrLOngDf1XT1D+A1dFc4MKAkkiCVKjjVu7g9+4Rzx4i1u6hjXbuMWr0O5QPNvCu7IaCZwEKQukLGDrm5x8uI0tr6MkiGlkiv7yLfzN+6S5i6QsIMABkEfcxhbWWYMkVAOjxvYAjc3HNHrbKI9VBQBFwF25XQKSBjqIf1YBuAurEMrczgDygD6/x2LCpFLXLUyQ+PoldphhBhYfIX09XU1+Flaukz7uYqs3SHs7cG4BmTsmkBUF9mmXEwa28BNLPaQPLepuNcbGSWQquQC2/Kdcox1FUGkcB0ykck1nA2+wTzMs8stGnP4rbWGw74EuS/GFQWfK7/wF6P4F7fzIAYkdmdEAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.audio {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAitJREFUOE9jYCAWKJWwavr0KyXWb/FIbDtUFFyzJx6nVofE2Xo5nXsj0rqPNSR0nVkR2Hjmgmfd+U9Otdf+m5Vf/6+SfeU/R9ChVVgNYDRtlfJuuPA/rPfe/4QpD/6nznj0P27Kw/9unff/69Xf+69c/+C/SO7N/0z+OAxgMmmRCe++/r9i3ev/KWvf/vdY8PK/bt/9/wrNV3/IN5y/IVt1YqNg4pGTTP4HsbuA2bhZ2qvpyn+xjIObxAp3VwqlrgngLFyryVy5nhPmZJHANS2cwYexG8BmVC/pWn3hP4NZlzWuQDJI3dIiFnUUuwEsQAOcq87jNcC7fHeLUtJxHF4AGmBWeAavAWH1+1rUUk7giAWjOknllON4DXAs2NEiG4/DBQxAF/CFHfrPYI4jDFSLuJVjNrUJhB/B7gIGo1pJRt99GAZYJK7wLJ1z7Xzl4vu/7aqv/GRBj0bjqAX2qb0nJ7mXH17C4HcUxQA+hymWtSue/C5a9up/9Ozn/7Vr7v1nRY7GqMb91T3b3v6vWvPmf/S0p/9ZQk+DDLCBRSOz06Jqk+o7/21nvfqvsebDf7kZL/5zBaxphkezd+OFn7HzXvz3Wvjmv9a8N//5Ek//ZTBpVYUrMG2X5wjcdl68+uI/wa5Lr3hSNjczGFeywOVZ/bbcVGp//F9izfv/Ql03f3P4LC/HSEQquYwMFnUCDJ7dzBhyjGZNQpye89M5gpfnMvtNUyE2h4PUAQBovvT7lyNljwAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.LiveLeak {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAydJREFUOE9Nk1tIk2EYx79NyUNqTk0o6KYrnZeChodLDxfeZpCbJk4RXU5Nm7tYRYhiYXbQlaeGutyW2gxtpB1RIyKDEjKwA6Ti2dR5KNDn+fq/S6TBj/f93r3P732e53s/qfnkSdej4GB2SBLbwf+jmB+gUMgOheLg/z7EdCUnO6Ref392SpK8Hyh3I+gBwBo7lUp2xcbyQEoKD6alyQOpqd754/h4FjJXZCRJTl9ftmEzoK5/wdQJxPgkLY2WV1dpc2uLtnZ2eHNnhza3t2nd46GhjAzuValY6jx0iIfS03msoIDuQ9COQCtoUSjohU5HuwgaN5loeXycd3d3aW9vzwvW2K5SkdTi58fvzGb+3tdHFggA3QONEAzn59PvjQ1yqNX0zenkvX0B4ffWaGRraChJd/385JGqKvlzTw/fRqOaIGkEd1DjU52O/3g83BkTw5MOh7yJuUCUM2o0yi2hoSw1IIOhykr+YLNRHYKu4XQvyKA/N5c8yMCCDD7Z7bz26xcJ1rH2rKKCG0UJdRAMlJbyG6uVrkJQjWAB5tSbk0Nr2HwDgvcQiIYur6zQyvo6ucvLueHIEZKuQPBQr+dXra1kRuqXEOwFArtWSytra1QdFUVjNhvPLS3R3OIiLUDUD0F1WBhJJtwDW2Ehu5uaqBICI4IFlRB0QLCEzaboaHrd0cHzCBYsIIuesjK+LAQXkEFrXh676uupGCWcR6AeghLQptGQONUAwfOuLp6Zn6eZuTmaXVig7pISrhI90ENgQbdHhoep32JhFzLpu3WLio8epUYIfs7OUjF6UKJW88XERLqYkEBNej11oG8XhCAvMFAuOn5cNiclsTkhQTbhmpri4lgbEMANWi1DwC/xit3t7bK7rY0Fo4OD3G4wyEURESzloAdnceezlErK8vH5N4KzPj50PTOTfkxP0+THj/RlYoInJyZI8HVqim5qNFwQHk7SucBAPo2PKRMNPLM/4pnFszYkhJsNBu6uqWFHba1sr61lQSveQFZQkFx07BhJmhMnrLn4NLMPH/aSExR0QDbmWhwgyEapwDvXoDxdWBiXnjrV/Bdm2kYUxLwmEgAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.Vocaroo {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAw9JREFUOE9jYMABuMwYmCyTJKUCGlSnFSy02TTzeOyCiQcDViX26qVz2TAyYtWmEMwuoZ3M7V40LcB79pHkc0svpvzY8jD//87nxf+3Pyn8v/ZO8v+VNyP/2mZJumI1QCWSI8232Hjumitlfw5+qPp/9l8TCt76JP//xkdx/wsXWCzjtWFkwTCkbWFe9plPk/+ga4Txz/xt/D/hkN//gMXif21a+NbyWjIwoRiy6GDT5rP/mlFsPfyp5n/NpOj/22+0gMUXXIz/H7hC/L/bFKFbPDZMrHAD5H35OPt2J9zacDv/f3V7xv9FhwrBGubsT/1//Pjx/1GJ/mD+/nfl/1v3Ovy3KRJNQbHdOlXCvOO03/+pm1P/v3v37n90hhtYw9HPtf8Xb2v937cmHswHeWPRxYj/LvkK3igGKARwicTO07118H3V/5kbi/4vPZMJtK3s/6YH2f+Pfq1B8VbjWrdnMu5s4nAD9CNFhKwz5DTUvLl419zKvAcLtG1P84BRl/b/5M/6/6f/NPzf/qzo84yj0Uus0xUU4Zor54bm9+4OfZG02OCuoAMTb9ZkC9ull1Nvrr2Z+XvRpaRfc65H/68F+jl9svEhzyLFWoccWVc+eyTHq/twydjlKRln7jX9bNMkMJnbhoFRL1xCqmKx6/yi2fYXa/c5/e846PV/5fW0/7OPx/yfcjzop34ulxdGGvDuU8mMXaX507lBuiN6ueadmQeT/p/93vf/1O+G//sP5fw/eL3o/5JLif8zVxs+Tlir9S26UyeFQQvJGBE7FvaFZ9LfN+1y+WjbItSb3GmXvXd15v8zroH/HxgE/D+aGPx/18vi/z07PeZNPRKxe/Kh0Ae8toxscCO4zBkYXArk9C1SxJUYjBkYPPIVtbbuTftz3cz//2O9wP/75iSAXdO72/dt2HL5F6YlfBW4MiJYXMiBiW3t7azHBx+V/t89N+H/8a+1//e9K/9attDp5LQjYX8SuvVL8RoAkmxa65299Erq1FnHo0qrl7t4BddriIs4MrM3rfWcFd+pGwVSAwBZ0bKP8yrZPAAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.pastebin {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAtZJREFUOE+NU91LWmEc7sJtQew/2MUY7INg7CLY3W5GMHazyzEQo9UmfYxZTbAiVlgRqLMSZ+XnDC3z2+Y0+8JGakKZTtR0Tl2wtgtLLQh29cz3ZZ3h3Q68vOc95zzP73l+z+/U1f292O09DRxubxOH23P//1bvtQts3dPnry7LZnXJhcUl5Avf8dHtwY+fv2AyW5DOfIXFakMm+w0G4wISyRRm55TQG0y/Wzv6mikJ52Xf9TmVBoFAAD6fDwqFAqFQCJubmzCbzZiensbp6SmkUikikQi0Wi0kEgm6ewVaStDCfXPDandifn6egoaGhrCzswO1Wg2Hw4HBwUGk02kIBAL4/X4IhUJMTk6ii8dfYggy2RwymQzOz88Rj8dRLpexv7+PSqWCYDCIQqGAra0tJBIJrK2t0XdVAjNDEIl+wfj4OEqlEq2wt7dHrchkMmrBYDCAz+fTIjweD7FYrJbgIJOlgLOzM8jlcip1eXmZ2rFarVAqlRCLxcjlchCJRFRljYJYPAG32418Pg+n04lsNouVlRUcHh7C4/FQIOlHNBqlezgcJgQWxkIgGMbExASVNjY2hvX1dVo9mUzS5wREFLhcLrqTcw2B//M2RkdHodPp4PV6oVKpqH+SCom3v7+fNnF4eJiJusbCJ6+PviSyScakiaR5RIHRaKQpmEwmbAdCeD8zB6vdhebHT8SMhcUlC83bbrdTJRsbG3RwiCVCRNJJpDIoVeNNJJJQzKryV+rrmxiCtyNCCmaz2VhdXQWXy6XDpNfrodFoYLXZUTw+pk222Z3lW3ca26rgSwzBwqIZAwMDlITMAVEwNTVFR5fEJpK8Qyp1AJvDVbrTeLenCmxgfiZ22+urCtWHyu7uLp2wVCpFKx0dHaFYLOLk5KT6Y9kgk89kb95ubK0BX7A8a+1qannRLeW0daj/rU51S3tn9dypfvDw0QiLxbpX/Z7FVK7e/AEj4Wf24/2f5AAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.gist {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAk1JREFUeNqUkzuIE1EUhv955MnsbB6r4kYQLUQQFncV3SnCIqJsoWGDYOGjsIiCtY2Kla1sjLBIsFFcXJC1kaSwENQmXUQSRSUSjCQSTCbkbR4z47lXEgtBNwcu3DNzvvO8R8jlcj7LshKmaWqYQERRTAmCcEru9/sJr9er0QF92BJMAVGr1TQ6CeZAc7lcGAwGkyQAxpTLZU0eDoc8crfbRTgcRjAYRCQSYSmi1WpxY7fbjU6ng1gshmaziXg8zhnGIpVKWbquW9ls1mLZsaMoiqWq6lgnBxY55He/328Vi0XOMFZmqVMD4fF4QBAajcY48khY9JE4HA4enTGMFVkaTHmy+ZzD/5NSqYSNB484w1h55ODO3TVu4FXcWDywl24Cmp0e1WBhyuWELAtIf/qKUrWOONmev3Lpt4NRCXq1gplpBS/v3cDc0nGg9h1o1ZkfwO4Atu1B8cM7HLt8k37V/y5B2b4bJxf2Y+7oEbyJrkMvUjki0YYJ03LidfQxAt4dOHdCw5RdGZcgGobBlQtnV/BDr1GfDai7ZiHZZRi9PoY/e5SCCTUwC9gk1GmMh5YWOcNYkR4Sv1y9uAJbYB82N57h4OnDmN7phjQ0qUkWRJuB+TMaPn/5iFfvv+Ha7eucYey4iWw8q6tRJJNJ3Fp7ClUawEkViBTfkCR0YUNTVHD/4Tpm/P4/U2CeKpUKfD4fJDIMhUKEhP45St50XedZyLQY6Xw+v8AUemVb2oNqtYpCocCWKi2TLLfb7ReZTGZ+kmUi7i2VvfxLgAEAZChMriPcl+IAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.image {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAs5JREFUOE+lk/tvi1EYx98/xT8gW4REIpGFMEQWl2FiM9ZMZhm2xRAyOsmujFFmdFRHu0tWm87UypxStr69zPauN5e5rHVp3IYhbOvHy+wHEQlxkm+ek+d8nm9OznkeSfrfldmgJC7QyUlTymsJTfuTZ25z4HdWYwyLreYhtpgekGPw0+kKvo1Eo+IXRSIiEhkWZuc9tqnsJD9EqTUopCxjSGTpB0iueczSo1HyW8cpsExQ1DbxI2pt45j9cXpexul4FEd79RnZphAa/SD7WvuFtO6UItbU9LC+YQxNI2w0wwYT5LRAdhOU3oBTIXC9gXP3oUSGgz2vST3gYHejR0jptT1C332f8yrUEYHrz8CgxDnpm6DKCUfc0KnmXa/AEVPPwnDcD0cvetA2uYRk67Ive/lpjO7YBO1PPuF8Df3vwf4cbNE4tqdw7YVq8HYyHx6FvhE1hkMEg8HDUqvFkjT4aIjMqkqyqkswDSrcfBfH+Q561YLAZ/B+BLda6FXlU/cPv0AoEPhuoP1h4Av7Wbh9E/Py15NWWUjeSR3nZDfeN+N0DY9hG/7K1eGP3P0S5/EYRFUF/IOTBrUXHPm9fT6mr1xEwupkZqxbzLyiDJYUZ5NSnkdqdSHpxyrYdFpPgdmAsdfJwPMI/Yr65bf7tZLGGBQ7DNdJWFtIYvoOZmbuZE7OXpIKKli86zAr9p9gTVktWTVnKTI2U95uRWe3U2IJUDbVB5p6hVm5x5m9Vc/cnedZUNzC8lILaQesZBy6hEZ3maKzgvJWFzVWD9XtXvVGQbSWASFtMATVRlJIKbOTWtlJXaeXepuPM1f6MNp9GLt8mLvvYLmp0OhQ2Fwvk6m7xaqDTvY0eYWUVtcnllXfYlGpnfklVuraHHg8HjxuN+6fktUHlWWZPaZeUo/ILK0UKttBcbNbSB9GP0yLxWJJUxoZGUn80zD9C/vXQ/4NHY10h3M1zmQAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.InstallGentoo {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAklJREFUOE9jYEAAASBTCorZkcSRmTjVCDLziCwG4hfM3EIvGNm44oC6WNEM4WXi5FsEkmfhFX3BxMmfAJSHW9Qr55Px3aZp3X/btq3/hQydPzKysMcCFbBBDeFj4uBdqBJR/gskb1W34j+PmulLoJwbzBJJoMm7dNO7/ntMP/XfpW/v//SKvk+7tl7fvXfTpx5pCdWVSiHFv1wnHQbLi9sE/Wdk5SwBauaCGQB3gUPb5v+7Lr/8/+fvr/9fv/z+f+Pyr/9bV735l9Wy/79Dx/b/Nk0bsLoAHgbeAVHv/v77/f8f0IB7N7+cu3DuecK54z9+7lzz639e9pK/7HwSWMMA5BJwCJeXtOm/fvVj1fcfv369f//92cN7X6ZcPvf9x6Htv//vXP3r/+T245UEYgpskPTNq08LgN749/PH7/93rv/6f/rw7//nj//4f+bU0zQcUQwWBkdVbGz62y+fv3wHeeXrlz//H9798//qpY//M3KqfzGxc8djiWKwZnBUuWQ2/fr46fv/P39+///x/ff/d69//z97+s7fyMb5/+y7d2GLYriDZikFF/1qXXXj/4Pbv/8/f/jn/5MH316/eP6jVlBAaIt6VO1/jxmn/zv27P7Pp2HxEajLD90ra9Sj6/979O37X73w0n+vqOL/0lJyMVBFq0EGgDSD0oKAlu1/oHg4ugGzVCKqfouYuL1Xj676Iajr8AnJFricGqYc3Bw+Zi6BVUxsXLHAdL6QiYMPFNrwpIxHDsUhgtAMAopKDjQn4pPDF7P45QC4hSmc1eX8WgAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n\n/* General */\n:root.yotsuba .dialog {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.yotsuba .field:focus {\nborder-color: #EA8;\n}\n\n/* Header */\n:root.yotsuba #header-bar, :root.yotsuba #notifications {\nfont-size: 9pt;\ncolor: #B86;\n}\n:root.yotsuba #header-bar a, :root.yotsuba #notifications a {\ncolor: #800000;\n}\n\n/* Settings */\n:root.yotsuba #fourchanx-settings fieldset {\nborder-color: #D9BFB7;\n}\n\n/* Quote */\n:root.yotsuba .backlink.deadlink {\ncolor: #00E !important;\n}\n:root.yotsuba .inline {\nborder-color: #D9BFB7;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.yotsuba #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.yotsuba .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.yotsuba #menu {\ncolor: #800000;\n}\n:root.yotsuba .entry {\nborder-bottom: 1px solid #D9BFB7;\nfont-size: 10pt;\n}\n:root.yotsuba .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.yotsuba .watcher-toggler\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.yotsuba-b .dialog {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.yotsuba-b .field:focus {\nborder-color: #98E;\n}\n\n/* Header */\n:root.yotsuba-b #header-bar, :root.yotsuba-b #notifications {\nfont-size: 9pt;\ncolor: #89A;\n}\n:root.yotsuba-b #header-bar a, :root.yotsuba-b #notifications a {\ncolor: #34345C;\n}\n\n/* Settings */\n:root.yotsuba-b #fourchanx-settings fieldset {\nborder-color: #B7C5D9;\n}\n\n/* Quote */\n:root.yotsuba-b .backlink.deadlink {\ncolor: #34345C !important;\n}\n:root.yotsuba-b .inline {\nborder-color: #B7C5D9;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.yotsuba-b #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.yotsuba-b .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.yotsuba-b #menu {\ncolor: #000;\n}\n:root.yotsuba-b .entry {\nborder-bottom: 1px solid #B7C5D9;\nfont-size: 10pt;\n}\n:root.yotsuba-b .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.yotsuba-b .watcher-toggler\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.futaba .dialog {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.futaba .field:focus {\nborder-color: #EA8;\n}\n\n/* Header */\n:root.futaba #header-bar, :root.futaba #notifications {\nfont-size: 11pt;\ncolor: #B86;\n}\n:root.futaba #header-bar a, :root.futaba #notifications a {\ncolor: #800000;\n}\n\n/* Settings */\n:root.futaba #fourchanx-settings fieldset {\nborder-color: #D9BFB7;\n}\n\n/* Quote */\n:root.futaba .backlink.deadlink {\ncolor: #00E !important;\n}\n:root.futaba .inline {\nborder-color: #D9BFB7;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.futaba #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.futaba .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.futaba #menu {\ncolor: #800000;\n}\n:root.futaba .entry {\nborder-bottom: 1px solid #D9BFB7;\nfont-size: 12pt;\n}\n:root.futaba .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.futaba .watcher-toggler\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.burichan .dialog {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.burichan .field:focus {\nborder-color: #98E;\n}\n\n/* Header */\n:root.burichan #header-bar, :root.burichan #header-bar #notifications {\nfont-size: 11pt;\ncolor: #89A;\n}\n:root.burichan #header-bar a, :root.burichan #header-bar #notifications a {\ncolor: #34345C;\n}\n\n/* Settings */\n:root.burichan #fourchanx-settings fieldset {\nborder-color: #B7C5D9;\n}\n\n/* Quote */\n:root.burichan .backlink.deadlink {\ncolor: #34345C !important;\n}\n:root.burichan .inline {\nborder-color: #B7C5D9;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.burichan #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.burichan .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.burichan #menu {\ncolor: #000000;\n}\n:root.burichan .entry {\nborder-bottom: 1px solid #B7C5D9;\nfont-size: 12pt;\n}\n:root.burichan .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.burichan .watcher-toggler\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.tomorrow .dialog {\nbackground-color: #282A2E;\nborder-color: #111;\n}\n\n/* Header */\n:root.tomorrow #header-bar, :root.tomorrow #notifications {\nfont-size: 9pt;\ncolor: #C5C8C6;\n}\n:root.tomorrow #header-bar a, :root.tomorrow #notifications a {\ncolor: #81A2BE;\n}\n\n/* Settings */\n:root.tomorrow #fourchanx-settings fieldset {\nborder-color: #111;\n}\n\n/* Quote */\n:root.tomorrow .backlink.deadlink {\ncolor: #81A2BE !important;\n}\n:root.tomorrow .inline {\nborder-color: #111;\nbackground-color: rgba(0, 0, 0, .14);\n}\n\n/* QR */\n.tomorrow #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #282A2E;\nborder-color: #111;\n}\n:root.tomorrow .qr-preview {\nbackground-color: rgba(255, 255, 255, .15);\n}\n:root.tomorrow #qr .field {\nbackground-color: rgb(26, 27, 29);\ncolor: rgb(197,200,198);\nborder-color: rgb(40, 41, 42);\n}\n:root.tomorrow #qr .field:focus {\nborder-color: rgb(129, 162, 190) !important;\nbackground-color: rgb(30,32,36);\n}\n\n/* Menu */\n:root.tomorrow #menu {\ncolor: #C5C8C6;\n}\n:root.tomorrow .entry {\nborder-bottom: 1px solid #111;\nfont-size: 10pt;\n}\n:root.tomorrow .focused.entry {\nbackground: rgba(0, 0, 0, .33);\n}\n\n/* Watcher Favicon */\n:root.tomorrow .watcher-toggler\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.photon .dialog {\nbackground-color: #DDD;\nborder-color: #CCC;\n}\n:root.photon .field:focus {\nborder-color: #EA8;\n}\n\n/* Header */\n:root.photon #header-bar, :root.photon #notifications {\nfont-size: 9pt;\ncolor: #333;\n}\n:root.photon #header-bar a, :root.photon #notifications a {\ncolor: #FF6600;\n}\n\n/* Settings */\n:root.photon #fourchanx-settings fieldset {\nborder-color: #CCC;\n}\n\n/* Quote */\n:root.photon .backlink.deadlink {\ncolor: #F60 !important;\n}\n:root.photon .inline {\nborder-color: #CCC;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.photon #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #DDD;\nborder-color: #CCC;\n}\n:root.photon .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.photon #menu {\ncolor: #333;\n}\n:root.photon .entry {\nborder-bottom: 1px solid #CCC;\nfont-size: 10pt;\n}\n:root.photon .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.photon .watcher-toggler\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n"
};
Main.init();
diff --git a/builds/crx/script.js b/builds/crx/script.js
index 517371033..f046693a8 100755
--- a/builds/crx/script.js
+++ b/builds/crx/script.js
@@ -1,6 +1,6 @@
// Generated by CoffeeScript
/*
-* 4chan X - Version 1.2.27 - 2013-08-12
+* 4chan X - Version 1.2.27 - 2013-08-13
*
* Licensed under the MIT license.
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
@@ -170,9 +170,7 @@
'Page Count in Stats': [false, 'Display the page count in the thread stats as well.'],
'Updater and Stats in Header': [true, 'Places the thread updater and thread stats in the header instead of floating them.'],
'Thread Watcher': [true, 'Bookmark threads.'],
- 'Toggleable Thread Watcher': [true, 'Adds a shortcut for the thread watcher, hides the watcher by default, and makes it scroll with the page.'],
- 'Auto Watch': [true, 'Automatically watch threads you start.'],
- 'Auto Watch Reply': [false, 'Automatically watch threads you reply to.']
+ 'Toggleable Thread Watcher': [true, 'Adds a shortcut for the thread watcher, hides the watcher by default, and makes it scroll with the page.']
},
'Posting': {
'Quick Reply': [true, 'All-in-one form to reply, create threads, automate dumping and more.'],
@@ -212,6 +210,12 @@
'Expand from here': [false, 'Expand all images only from current position to thread end.'],
'Advance on contract': [false, 'Advance to next post when contracting an expanded image.']
},
+ threadWatcher: {
+ 'Current Board': [false, 'Only show watched threads from the current board.'],
+ 'Auto Watch': [true, 'Automatically watch threads you start.'],
+ 'Auto Watch Reply': [false, 'Automatically watch threads you reply to.'],
+ 'Auto Prune': [false, 'Automatically prune 404\'d threads.']
+ },
filter: {
name: "# Filter any namefags:\n#/^(?!Anonymous$)/",
uniqueID: "# Filter a specific ID:\n#/Txhvk1Tl/",
@@ -399,25 +403,30 @@
}
};
- $.ajax = function(url, options, extra) {
- var form, headers, key, r, sync, type, upCallbacks, val;
- if (extra == null) {
- extra = {};
- }
- type = extra.type, headers = extra.headers, upCallbacks = extra.upCallbacks, form = extra.form, sync = extra.sync;
- r = new XMLHttpRequest();
- r.overrideMimeType('text/html');
- type || (type = form && 'post' || 'get');
- r.open(type, url, !sync);
- for (key in headers) {
- val = headers[key];
- r.setRequestHeader(key, val);
- }
- $.extend(r, options);
- $.extend(r.upload, upCallbacks);
- r.send(form);
- return r;
- };
+ $.ajax = (function() {
+ var lastModified;
+ lastModified = {};
+ return function(url, options, extra) {
+ var form, r, sync, type, upCallbacks, whenModified;
+ if (extra == null) {
+ extra = {};
+ }
+ type = extra.type, whenModified = extra.whenModified, upCallbacks = extra.upCallbacks, form = extra.form, sync = extra.sync;
+ r = new XMLHttpRequest();
+ type || (type = form && 'post' || 'get');
+ r.open(type, url, !sync);
+ if (whenModified) {
+ r.setRequestHeader('If-Modified-Since', lastModified[url] || '0');
+ $.on(r, 'load', function() {
+ return lastModified[url] = r.getResponseHeader('Last-Modified');
+ });
+ }
+ $.extend(r, options);
+ $.extend(r.upload, upCallbacks);
+ r.send(form);
+ return r;
+ };
+ })();
$.cache = (function() {
var reqs;
@@ -1174,16 +1183,18 @@
})(Post);
- DataBoards = ['hiddenThreads', 'hiddenPosts', 'lastReadPosts', 'yourPosts'];
+ DataBoards = ['hiddenThreads', 'hiddenPosts', 'lastReadPosts', 'yourPosts', 'watchedThreads'];
DataBoard = (function() {
- function DataBoard(key, sync) {
+ function DataBoard(key, sync, dontClean) {
var init,
_this = this;
this.key = key;
this.data = Conf[key];
$.sync(key, this.onSync.bind(this));
- this.clean();
+ if (!dontClean) {
+ this.clean();
+ }
if (!sync) {
return;
}
@@ -1194,6 +1205,10 @@
$.on(d, '4chanXInitFinished', init);
}
+ DataBoard.prototype.save = function() {
+ return $.set(this.key, this.data);
+ };
+
DataBoard.prototype["delete"] = function(_arg) {
var boardID, postID, threadID;
boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID;
@@ -1211,7 +1226,7 @@
} else {
delete this.data.boards[boardID];
}
- return $.set(this.key, this.data);
+ return this.save();
};
DataBoard.prototype.deleteIfEmpty = function(_arg) {
@@ -1239,7 +1254,7 @@
} else {
this.data.boards[boardID] = val;
}
- return $.set(this.key, this.data);
+ return this.save();
};
DataBoard.prototype.get = function(_arg) {
@@ -1281,7 +1296,7 @@
this.ajaxClean(boardID);
}
}
- return $.set(this.key, this.data);
+ return this.save();
};
DataBoard.prototype.ajaxClean = function(boardID) {
@@ -1309,7 +1324,7 @@
boardID: boardID
});
}
- return $.set(_this.key, _this.data);
+ return _this.save();
});
};
@@ -1370,8 +1385,24 @@
Polyfill = {
init: function() {
+ Polyfill.toBlob();
return Polyfill.visibility();
},
+ toBlob: function() {
+ var _base;
+ return (_base = HTMLCanvasElement.prototype).toBlob || (_base.toBlob = function(cb) {
+ var data, i, l, ui8a, _i;
+ data = atob(this.toDataURL().slice(22));
+ l = data.length;
+ ui8a = new Uint8Array(l);
+ for (i = _i = 0; 0 <= l ? _i < l : _i > l; i = 0 <= l ? ++_i : --_i) {
+ ui8a[i] = data.charCodeAt(i);
+ }
+ return cb(new Blob([ui8a], {
+ type: 'image/png'
+ }));
+ });
+ },
visibility: function() {
if (!('webkitHidden' in document)) {
return;
@@ -1773,7 +1804,7 @@
date: data.now,
dateUTC: data.time,
comment: data.com,
- capReps: data.capcode_replies,
+ capcodeReplies: data.capcode_replies,
isSticky: !!data.sticky,
isClosed: !!data.closed
};
@@ -1801,8 +1832,8 @@
@license: https://github.com/4chan/4chan-JS/blob/master/LICENSE
*/
- var a, array, boardID, capReps, capcode, capcodeClass, capcodeReplies, capcodeStart, capcodeType, closed, comment, container, date, dateUTC, email, emailEnd, emailStart, ext, file, fileDims, fileHTML, fileInfo, fileSize, fileThumb, filename, flag, flagCode, flagName, generateCapcodeReplies, 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, capReps = o.capReps, file = o.file;
+ var a, boardID, capcode, capcodeClass, capcodeReplies, 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, capcodeReplies = o.capcodeReplies, file = o.file;
isOP = postID === threadID;
staticPath = '//static.4chan.org/image/';
if (email) {
@@ -1876,32 +1907,10 @@
tripcode = tripcode ? " " + tripcode + " " : '';
sticky = isSticky ? " " : '';
closed = isClosed ? " " : '';
- capcodeReplies = '';
- if (capReps) {
- generateCapcodeReplies = function(capcodeType, array) {
- return "" + ((function() {
- switch (capcodeType) {
- case 'admin':
- return 'Administrator';
- case 'mod':
- return 'Moderator';
- case 'developer':
- return 'Developer';
- }
- })()) + " Repl" + (array.length > 1 ? 'ies' : 'y') + ": " + (array.map(function(ID) {
- return ">>" + ID + " ";
- }).join(' ')) + " ";
- };
- for (capcodeType in capReps) {
- array = capReps[capcodeType];
- capcodeReplies += generateCapcodeReplies(capcodeType, array);
- }
- capcodeReplies = "" + capcodeReplies + " ";
- }
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 || '') + capcodeReplies + " " + " " + "
"
+ 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++) {
@@ -1912,7 +1921,46 @@
}
quote.href = "/" + boardID + "/res/" + href;
}
+ Build.capcodeReplies({
+ boardID: boardID,
+ threadID: threadID,
+ root: container,
+ capcodeReplies: capcodeReplies
+ });
return container;
+ },
+ capcodeReplies: function(_arg) {
+ var array, boardID, bq, capcodeReplies, capcodeType, generateCapcodeReplies, html, root, threadID;
+ boardID = _arg.boardID, threadID = _arg.threadID, bq = _arg.bq, root = _arg.root, capcodeReplies = _arg.capcodeReplies;
+ if (!capcodeReplies) {
+ return;
+ }
+ generateCapcodeReplies = function(capcodeType, array) {
+ return "" + ((function() {
+ switch (capcodeType) {
+ case 'admin':
+ return 'Administrator';
+ case 'mod':
+ return 'Moderator';
+ case 'developer':
+ return 'Developer';
+ }
+ })()) + " Repl" + (array.length > 1 ? 'ies' : 'y') + ": " + (array.map(function(ID) {
+ return ">>" + ID + " ";
+ }).join(' ')) + " ";
+ };
+ html = [];
+ for (capcodeType in capcodeReplies) {
+ array = capcodeReplies[capcodeType];
+ html.push(generateCapcodeReplies(capcodeType, array));
+ }
+ bq || (bq = $('blockquote', root));
+ return $.add(bq, [
+ $.el('br'), $.el('br'), $.el('span', {
+ className: 'capcodeReplies',
+ innerHTML: html.join('')
+ })
+ ]);
}
};
@@ -4226,7 +4274,7 @@
if (g.VIEW === 'catalog' || !Conf['Linkify']) {
return;
}
- this.regString = Conf['Allow False Positives'] ? /(\b([-a-z]+:\/\/|[a-z]{3,}\.[-a-z0-9]+\.[a-z]|[-a-z0-9]+\.[a-z]|[\d]+\.[\d]+\.[\d]+\.[\d]+\/|[a-z]{3,}:[a-z0-9?]|[^\s@]+@[a-z0-9.-]+\.[a-z0-9])[^\s'"]+)/gi : /(((magnet|mailto)\:|(www\.)|(news|(ht|f)tp(s?))\:\/\/){1}\S+)/gi;
+ this.regString = Conf['Allow False Positives'] ? /([-a-z]+:\/\/|[a-z]{3,}\.[-a-z0-9]+\.[a-z]|[-a-z0-9]+\.[a-z]|[\d]+\.[\d]+\.[\d]+\.[\d]+\/|[a-z]{3,}:[a-z0-9?]|[^\s@]+@[a-z0-9.-]+\.[a-z0-9])/i : /(((magnet|mailto)\:|(www\.)|(news|(ht|f)tp(s?))\:\/\/){1})/i;
if (Conf['Comment Expansion']) {
ExpandComment.callbacks.push(this.node);
}
@@ -4239,7 +4287,7 @@
});
},
node: function() {
- var data, el, i, items, links, node, range, snapshot, _i, _len, _ref;
+ var data, el, end, endNode, i, index, items, lIndex, length, link, links, node, range, result, saved, snapshot, space, test, text, _i, _len, _ref;
if (this.isClone) {
if (Conf['Embedding']) {
i = 0;
@@ -4253,16 +4301,49 @@
}
return;
}
+ test = /[^\s'"]+/g;
+ space = /[\s'"]/;
snapshot = $.X('.//br|.//text()', this.nodes.comment);
i = 0;
while (node = snapshot.snapshotItem(i++)) {
- if (node.parentElement.nodeName === "A") {
+ links = [];
+ data = node.data;
+ if (node.parentElement.nodeName === "A" || !data) {
continue;
}
- links = [];
- if (Linkify.regString.test(node.data)) {
- Linkify.regString.lastIndex = 0;
- Linkify.gatherLinks(snapshot, this, node, links, i);
+ while (result = test.exec(data)) {
+ index = result.index;
+ endNode = node;
+ if ((length = index + result[0].length) === data.length) {
+ while ((saved = snapshot.snapshotItem(i++))) {
+ if (saved.nodeName === 'BR') {
+ break;
+ }
+ endNode = saved;
+ length = saved.data.length;
+ if (end = space.exec(saved.data)) {
+ length = end.index;
+ i--;
+ break;
+ }
+ }
+ if (length === endNode.data.length) {
+ test.lastIndex = 0;
+ }
+ range = Linkify.makeRange(node, endNode, index, length);
+ if (link = Linkify.regString.exec(text = range.toString())) {
+ if (lIndex = link.index) {
+ range.setStart(node, lIndex + index);
+ }
+ links.push([range, text]);
+ }
+ break;
+ } else {
+ if (link = Linkify.regString.exec(result[0])) {
+ range = Linkify.makeRange(node, node, link.index, link.length);
+ links.push([range, link]);
+ }
+ }
}
_ref = links.reverse();
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
@@ -4286,57 +4367,23 @@
}
}
},
- gatherLinks: function(snapshot, post, node, links, i) {
- var data, index, len, len2, link, match, range;
- data = node.data;
- len = data.length;
- while ((match = Linkify.regString.exec(data))) {
- index = match.index;
- link = match[0];
- len2 = index + link.length;
- if (len === len2) {
- break;
- }
- range = document.createRange();
- range.setStart(node, index);
- range.setEnd(node, len2);
- links.push(range);
- }
- Linkify.regString.lastIndex = 0;
- if (match) {
- links.push(Linkify.seek(snapshot, post, node, links, match, i));
- }
- },
- seek: function(snapshot, post, node, links, match, i) {
- var data, index, link, next, range, result;
- link = match[0];
+ makeRange: function(startNode, endNode, startOffset, endOffset) {
+ var range;
range = document.createRange();
- range.setStart(node, match.index);
- while ((next = snapshot.snapshotItem(i++)) && next.nodeName !== 'BR') {
- node = next;
- data = node.data;
- if (result = /[\s'"]/.exec(data)) {
- index = result.index;
- range.setEnd(node, index);
- Linkify.regString.lastIndex = index;
- Linkify.gatherLinks(snapshot, post, node, links, i);
- return range;
- }
- }
- if (range.collapsed) {
- range.setEndAfter(node);
- }
+ range.setStart(startNode, startOffset);
+ range.setEnd(endNode, endOffset);
return range;
},
- makeLink: function(range) {
- var a, link;
- link = range.toString();
- link = link.contains(':') ? link : (link.contains('@') ? 'mailto:' : 'http://') + link;
+ makeLink: function(_arg) {
+ var a, range, text;
+ range = _arg[0], text = _arg[1];
+ text;
+ text = text.contains(':') ? text : (text.contains('@') ? 'mailto:' : 'http://') + text;
a = $.el('a', {
className: 'linkify',
rel: 'nofollow noreferrer',
target: '_blank',
- href: link
+ href: text
});
$.add(a, range.extractContents());
range.insertNode(a);
@@ -5407,7 +5454,7 @@
_this = this;
img = $.el('img');
img.onload = function() {
- var applyBlob, cv, data, height, i, l, s, ui8a, width, _i;
+ var cv, height, s, width;
s = 90 * 2;
if (_this.file.type === 'image/gif') {
s *= 3;
@@ -5430,23 +5477,10 @@
cv.width = img.width = width;
cv.getContext('2d').drawImage(img, 0, 0, width, height);
URL.revokeObjectURL(fileURL);
- applyBlob = function(blob) {
+ return cv.toBlob(function(blob) {
_this.URL = URL.createObjectURL(blob);
return _this.nodes.el.style.backgroundImage = "url(" + _this.URL + ")";
- };
- if (cv.toBlob) {
- cv.toBlob(applyBlob);
- return;
- }
- data = atob(cv.toDataURL().split(',')[1]);
- l = data.length;
- ui8a = new Uint8Array(l);
- for (i = _i = 0; 0 <= l ? _i < l : _i > l; i = 0 <= l ? ++_i : --_i) {
- ui8a[i] = data.charCodeAt(i);
- }
- return applyBlob(new Blob([ui8a], {
- type: 'image/png'
- }));
+ });
};
fileURL = URL.createObjectURL(this.file);
return img.src = fileURL;
@@ -6257,7 +6291,7 @@
},
menu: {
init: function() {
- var conf, createSubEntry, el, key, subEntries, _ref;
+ var conf, createSubEntry, el, name, subEntries, _ref;
if (g.VIEW === 'catalog' || !Conf['Image Expansion']) {
return;
}
@@ -6268,9 +6302,9 @@
createSubEntry = ImageExpand.menu.createSubEntry;
subEntries = [];
_ref = Config.imageExpansion;
- for (key in _ref) {
- conf = _ref[key];
- subEntries.push(createSubEntry(key, conf));
+ for (name in _ref) {
+ conf = _ref[name];
+ subEntries.push(createSubEntry(name, conf[1]));
}
return $.event('AddMenuEntry', {
type: 'header',
@@ -6279,21 +6313,19 @@
subEntries: subEntries
});
},
- createSubEntry: function(type, config) {
+ createSubEntry: function(name, desc) {
var input, label;
label = $.el('label', {
- innerHTML: " " + type
+ innerHTML: " " + name,
+ title: desc
});
input = label.firstElementChild;
- if (type === 'Fit width' || type === 'Fit height') {
+ if (name === 'Fit width' || name === '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);
- }
+ input.checked = Conf[name];
+ $.event('change', null, input);
+ $.on(input, 'change', $.cb.checked);
return {
el: label
};
@@ -6939,7 +6971,6 @@
this.postCountEl = $('#post-count', sc);
this.fileCountEl = $('#file-count', sc);
this.pageCountEl = $('#page-count', sc);
- this.lastModified = '0';
return Thread.prototype.callbacks.push({
name: 'Thread Stats',
cb: this.node
@@ -6991,18 +7022,12 @@
return $.ajax("//api.4chan.org/" + ThreadStats.thread.board + "/threads.json", {
onload: ThreadStats.onThreadsLoad
}, {
- headers: {
- 'If-Modified-Since': ThreadStats.lastModified
- }
+ whenModified: true
});
},
onThreadsLoad: function() {
var page, pages, thread, _i, _j, _len, _len1, _ref;
- if (!Conf["Page Count in Stats"]) {
- return;
- }
- ThreadStats.lastModified = this.getResponseHeader('Last-Modified');
- if (this.status !== 200) {
+ if (!(Conf["Page Count in Stats"] && this.status === 200)) {
return;
}
pages = JSON.parse(this.response);
@@ -7096,7 +7121,6 @@
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']
}));
@@ -7189,10 +7213,7 @@
case 200:
g.DEAD = false;
ThreadUpdater.parse(JSON.parse(req.response).posts);
- ThreadUpdater.lastModified = req.getResponseHeader('Last-Modified');
- if (Conf['Auto Update']) {
- ThreadUpdater.set('timer', ThreadUpdater.getInterval());
- }
+ ThreadUpdater.set('timer', ThreadUpdater.getInterval());
break;
case 404:
g.DEAD = true;
@@ -7206,16 +7227,8 @@
});
break;
default:
- if (Conf['Auto Update']) {
- 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.
- */
-
+ ThreadUpdater.outdateCount++;
+ ThreadUpdater.set('timer', ThreadUpdater.getInterval());
_ref = req.status === 304 ? [null, null] : ["" + req.statusText + " (" + req.status + ")", 'warning'], text = _ref[0], klass = _ref[1];
ThreadUpdater.set('status', text, klass);
}
@@ -7283,9 +7296,7 @@
return ThreadUpdater.req = $.ajax(url, {
onloadend: ThreadUpdater.cb.load
}, {
- headers: {
- 'If-Modified-Since': ThreadUpdater.lastModified
- }
+ whenModified: true
});
},
updateThreadStatus: function(title, OP) {
@@ -7420,7 +7431,7 @@
ThreadWatcher = {
init: function() {
- var sc;
+ var now, sc;
if (!Conf['Thread Watcher']) {
return;
}
@@ -7430,21 +7441,46 @@
href: 'javascript:;',
className: 'disabled'
});
- this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', '');
+ this.db = new DataBoard('watchedThreads', this.refresh, true);
+ this.dialog = UI.dialog('thread-watcher', 'top: 50px; left: 0px;', "
");
+ this.status = $('#watcher-status', this.dialog);
+ this.list = this.dialog.lastElementChild;
$.on(d, 'QRPostSuccessful', this.cb.post);
- $.sync('WatchedThreads', this.refresh);
+ if (g.VIEW === 'thread') {
+ $.on(d, 'ThreadUpdate', this.cb.threadUpdate);
+ }
$.on(sc, 'click', this.toggleWatcher);
$.on($('.move>.close', ThreadWatcher.dialog), 'click', this.toggleWatcher);
+ $.on(d, '4chanXInitFinished', this.ready);
if (Conf['Toggleable Thread Watcher']) {
Header.addShortcut(sc);
$.addClass(doc, 'fixed-watcher');
}
- $.ready(function() {
- ThreadWatcher.refresh();
- $.add(d.body, ThreadWatcher.dialog);
- if (Conf['Toggleable Thread Watcher']) {
- return ThreadWatcher.dialog.hidden = true;
+ now = Date.now();
+ if ((this.db.data.lastChecked || 0) < now - 2 * $.HOUR) {
+ this.db.data.lastChecked = now;
+ ThreadWatcher.fetchAllStatus();
+ this.db.save();
+ }
+ $.get('WatchedThreads', null, function(_arg) {
+ var WatchedThreads, boardID, data, threadID, threads, _ref;
+ WatchedThreads = _arg.WatchedThreads;
+ if (!WatchedThreads) {
+ return;
}
+ _ref = ThreadWatcher.convert(WatchedThreads);
+ for (boardID in _ref) {
+ threads = _ref[boardID];
+ for (threadID in threads) {
+ data = threads[threadID];
+ ThreadWatcher.db.set({
+ boardID: boardID,
+ threadID: threadID,
+ val: data
+ });
+ }
+ }
+ return $["delete"]('WatchedThreads');
});
return Thread.prototype.callbacks.push({
name: 'Thread Watcher',
@@ -7452,77 +7488,86 @@
});
},
node: function() {
- var favicon,
- _this = this;
- favicon = $.el('a', {
- className: 'watch-thread-link',
- href: 'javascript:;'
+ var toggler;
+ toggler = $.el('img', {
+ className: 'watcher-toggler'
});
- $.on(favicon, 'click', ThreadWatcher.cb.toggle);
- $.before($('input', this.OP.nodes.post), favicon);
- if (g.VIEW !== 'thread') {
+ $.on(toggler, 'click', ThreadWatcher.cb.toggle);
+ return $.before($('input', this.OP.nodes.post), toggler);
+ },
+ ready: function() {
+ $.off(d, '4chanXInitFinished', ThreadWatcher.ready);
+ if (!Main.isThisPageLegit()) {
return;
}
- return $.get('AutoWatch', 0, function(item) {
- if (item['AutoWatch'] !== _this.ID) {
+ ThreadWatcher.refresh();
+ $.add(d.body, ThreadWatcher.dialog);
+ if (Conf['Toggleable Thread Watcher']) {
+ ThreadWatcher.dialog.hidden = true;
+ }
+ if (!Conf['Auto Watch']) {
+ return;
+ }
+ return $.get('AutoWatch', 0, function(_arg) {
+ var AutoWatch, thread;
+ AutoWatch = _arg.AutoWatch;
+ if (!(thread = g.BOARD.threads[AutoWatch])) {
return;
}
- ThreadWatcher.watch(_this);
+ ThreadWatcher.add(thread);
return $["delete"]('AutoWatch');
});
},
- 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: '×',
- className: 'close',
- 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 = $('.watch-thread-link', thread.OP.nodes.post);
- if (ID in watched) {
- $.addClass(favicon, 'watched');
- } else {
- $.rmClass(favicon, 'watched');
- }
- }
- },
toggleWatcher: function() {
$.toggleClass(ThreadWatcher.shortcut, 'disabled');
return ThreadWatcher.dialog.hidden = !ThreadWatcher.dialog.hidden;
},
cb: {
+ openAll: function() {
+ var a, _i, _len, _ref;
+ if ($.hasClass(this, 'disabled')) {
+ return;
+ }
+ _ref = $$('a[title]', ThreadWatcher.list);
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ a = _ref[_i];
+ $.open(a.href);
+ }
+ return $.event('CloseMenu');
+ },
+ checkThreads: function() {
+ if ($.hasClass(this, 'disabled')) {
+ return;
+ }
+ return ThreadWatcher.fetchAllStatus();
+ },
+ pruneDeads: function() {
+ var boardID, data, threadID, _i, _len, _ref, _ref1;
+ if ($.hasClass(this, 'disabled')) {
+ return;
+ }
+ _ref = ThreadWatcher.getAll();
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ _ref1 = _ref[_i], boardID = _ref1.boardID, threadID = _ref1.threadID, data = _ref1.data;
+ if (!data.isDead) {
+ continue;
+ }
+ delete ThreadWatcher.db.data.boards[boardID][threadID];
+ ThreadWatcher.db.deleteIfEmpty({
+ boardID: boardID
+ });
+ }
+ ThreadWatcher.db.save();
+ ThreadWatcher.refresh();
+ return $.event('CloseMenu');
+ },
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]);
+ rm: function() {
+ var boardID, threadID, _ref;
+ _ref = this.parentNode.dataset.fullID.split('.'), boardID = _ref[0], threadID = _ref[1];
+ return ThreadWatcher.rm(boardID, +threadID);
},
post: function(e) {
var board, postID, threadID, _ref;
@@ -7532,41 +7577,332 @@
return $.set('AutoWatch', threadID);
}
} else if (Conf['Auto Watch Reply']) {
- return ThreadWatcher.watch(board.threads[threadID]);
+ return ThreadWatcher.add(board.threads[threadID]);
}
+ },
+ threadUpdate: function(e) {
+ var thread;
+ thread = e.detail.thread;
+ if (!(e.detail[404] && ThreadWatcher.db.get({
+ boardID: thread.board.ID,
+ threadID: thread.ID
+ }))) {
+ return;
+ }
+ return ThreadWatcher.add(thread);
+ }
+ },
+ fetchCount: {
+ fetched: 0,
+ fetching: 0
+ },
+ fetchAllStatus: function() {
+ var thread, _i, _len, _ref;
+ ThreadWatcher.status.textContent = '...';
+ _ref = ThreadWatcher.getAll();
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ thread = _ref[_i];
+ ThreadWatcher.fetchStatus(thread);
+ }
+ },
+ fetchStatus: function(_arg) {
+ var boardID, data, fetchCount, threadID;
+ boardID = _arg.boardID, threadID = _arg.threadID, data = _arg.data;
+ if (data.isDead) {
+ return;
+ }
+ fetchCount = ThreadWatcher.fetchCount;
+ fetchCount.fetching++;
+ return $.ajax("//api.4chan.org/" + boardID + "/res/" + threadID + ".json", {
+ onloadend: function() {
+ var status;
+ fetchCount.fetched++;
+ if (fetchCount.fetched === fetchCount.fetching) {
+ fetchCount.fetched = 0;
+ fetchCount.fetching = 0;
+ status = '';
+ } else {
+ status = "" + (Math.round(fetchCount.fetched / fetchCount.fetching * 100)) + "%";
+ }
+ ThreadWatcher.status.textContent = status;
+ if (this.status !== 404) {
+ return;
+ }
+ if (Conf['Auto Prune']) {
+ ThreadWatcher.rm(boardID, threadID);
+ } else {
+ data.isDead = true;
+ ThreadWatcher.db.set({
+ boardID: boardID,
+ threadID: threadID,
+ val: data
+ });
+ }
+ return ThreadWatcher.refresh();
+ }
+ }, {
+ type: 'head'
+ });
+ },
+ getAll: function() {
+ var all, boardID, data, threadID, threads, _ref;
+ all = [];
+ _ref = ThreadWatcher.db.data.boards;
+ for (boardID in _ref) {
+ threads = _ref[boardID];
+ if (Conf['Current Board'] && boardID !== g.BOARD.ID) {
+ continue;
+ }
+ for (threadID in threads) {
+ data = threads[threadID];
+ all.push({
+ boardID: boardID,
+ threadID: threadID,
+ data: data
+ });
+ }
+ }
+ return all;
+ },
+ makeLine: function(boardID, threadID, data) {
+ var div, fullID, href, link, x;
+ x = $.el('a', {
+ textContent: '×',
+ href: 'javascript:;'
+ });
+ $.on(x, 'click', ThreadWatcher.cb.rm);
+ if (data.isDead) {
+ href = Redirect.to('thread', {
+ boardID: boardID,
+ threadID: threadID
+ });
+ }
+ link = $.el('a', {
+ href: href || ("/" + boardID + "/res/" + threadID),
+ textContent: data.excerpt,
+ title: data.excerpt
+ });
+ div = $.el('div');
+ fullID = "" + boardID + "." + threadID;
+ div.dataset.fullID = fullID;
+ if (g.VIEW === 'thread' && fullID === ("" + g.BOARD + "." + g.THREADID)) {
+ $.addClass(div, 'current');
+ }
+ if (data.isDead) {
+ $.addClass(div, 'dead-thread');
+ }
+ $.add(div, [x, $.tn(' '), link]);
+ return div;
+ },
+ refresh: function() {
+ var boardID, data, list, nodes, refresher, thread, threadID, toggler, watched, _i, _j, _len, _len1, _ref, _ref1, _ref2, _ref3;
+ nodes = [];
+ _ref = ThreadWatcher.getAll();
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ _ref1 = _ref[_i], boardID = _ref1.boardID, threadID = _ref1.threadID, data = _ref1.data;
+ nodes.push(ThreadWatcher.makeLine(boardID, threadID, data));
+ }
+ list = ThreadWatcher.list;
+ $.rmAll(list);
+ $.add(list, nodes);
+ _ref2 = g.BOARD.threads;
+ for (threadID in _ref2) {
+ thread = _ref2[threadID];
+ toggler = $('.watcher-toggler', thread.OP.nodes.post);
+ watched = ThreadWatcher.db.get({
+ boardID: thread.board.ID,
+ threadID: threadID
+ });
+ $[watched ? 'addClass' : 'rmClass'](toggler, 'watched');
+ }
+ _ref3 = ThreadWatcher.menu.refreshers;
+ for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) {
+ refresher = _ref3[_j];
+ refresher();
}
},
toggle: function(thread) {
- if (!$.hasClass($('.watch-thread-link', thread.OP.nodes.post), 'watched')) {
- return ThreadWatcher.watch(thread);
+ var boardID, threadID;
+ boardID = thread.board.ID;
+ threadID = thread.ID;
+ if (ThreadWatcher.db.get({
+ boardID: boardID,
+ threadID: threadID
+ })) {
+ return ThreadWatcher.rm(boardID, threadID);
} else {
- return ThreadWatcher.unwatch(thread.board, thread.ID);
+ return ThreadWatcher.add(thread);
}
},
- 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];
+ add: function(thread) {
+ var boardID, data, threadID;
+ data = {};
+ boardID = thread.board.ID;
+ threadID = thread.ID;
+ if (thread.isDead) {
+ if (Conf['Auto Prune'] && ThreadWatcher.db.get({
+ boardID: boardID,
+ threadID: threadID
+ })) {
+ ThreadWatcher.rm(boardID, threadID);
+ return;
}
- ThreadWatcher.refresh(watched);
- return $.set('WatchedThreads', watched);
+ data.isDead = true;
+ }
+ data.excerpt = Get.threadExcerpt(thread);
+ ThreadWatcher.db.set({
+ boardID: boardID,
+ threadID: threadID,
+ val: data
});
+ return ThreadWatcher.refresh();
},
- 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);
+ rm: function(boardID, threadID) {
+ ThreadWatcher.db["delete"]({
+ boardID: boardID,
+ threadID: threadID
});
+ return ThreadWatcher.refresh();
+ },
+ convert: function(oldFormat) {
+ var boardID, data, newFormat, threadID, threads;
+ newFormat = {};
+ for (boardID in oldFormat) {
+ threads = oldFormat[boardID];
+ for (threadID in threads) {
+ data = threads[threadID];
+ (newFormat[boardID] || (newFormat[boardID] = {}))[threadID] = {
+ excerpt: data.textContent
+ };
+ }
+ }
+ return newFormat;
+ },
+ menu: {
+ refreshers: [],
+ init: function() {
+ var menu;
+ if (!Conf['Thread Watcher']) {
+ return;
+ }
+ menu = new UI.Menu('thread watcher');
+ $.on($('.menu-button', ThreadWatcher.dialog), 'click', function(e) {
+ return menu.toggle(e, this, ThreadWatcher);
+ });
+ this.addHeaderMenuEntry();
+ return this.addMenuEntries();
+ },
+ addHeaderMenuEntry: function() {
+ var entryEl;
+ if (g.VIEW !== 'thread') {
+ return;
+ }
+ entryEl = $.el('a', {
+ href: 'javascript:;'
+ });
+ $.event('AddMenuEntry', {
+ type: 'header',
+ el: entryEl,
+ order: 60
+ });
+ $.on(entryEl, 'click', function() {
+ return ThreadWatcher.toggle(g.threads["" + g.BOARD + "." + g.THREADID]);
+ });
+ return this.refreshers.push(function() {
+ var addClass, rmClass, text, _ref;
+ _ref = $('.current', ThreadWatcher.list) ? ['unwatch-thread', 'watch-thread', 'Unwatch thread'] : ['watch-thread', 'unwatch-thread', 'Watch thread'], addClass = _ref[0], rmClass = _ref[1], text = _ref[2];
+ $.addClass(entryEl, addClass);
+ $.rmClass(entryEl, rmClass);
+ return entryEl.textContent = text;
+ });
+ },
+ addMenuEntries: function() {
+ var cb, conf, entries, entry, name, refresh, subEntries, _i, _len, _ref, _ref1, _results;
+ entries = [];
+ entries.push({
+ cb: ThreadWatcher.cb.openAll,
+ entry: {
+ type: 'thread watcher',
+ el: $.el('a', {
+ textContent: 'Open all threads'
+ })
+ },
+ refresh: function() {
+ return (ThreadWatcher.list.firstElementChild ? $.rmClass : $.addClass)(this.el, 'disabled');
+ }
+ });
+ entries.push({
+ cb: ThreadWatcher.cb.checkThreads,
+ entry: {
+ type: 'thread watcher',
+ el: $.el('a', {
+ textContent: 'Check 404\'d threads'
+ })
+ },
+ refresh: function() {
+ return ($('div:not(.dead-thread)', ThreadWatcher.list) ? $.rmClass : $.addClass)(this.el, 'disabled');
+ }
+ });
+ entries.push({
+ cb: ThreadWatcher.cb.pruneDeads,
+ entry: {
+ type: 'thread watcher',
+ el: $.el('a', {
+ textContent: 'Prune 404\'d threads'
+ })
+ },
+ refresh: function() {
+ return ($('.dead-thread', ThreadWatcher.list) ? $.rmClass : $.addClass)(this.el, 'disabled');
+ }
+ });
+ subEntries = [];
+ _ref = Config.threadWatcher;
+ for (name in _ref) {
+ conf = _ref[name];
+ subEntries.push(this.createSubEntry(name, conf[1]));
+ }
+ entries.push({
+ entry: {
+ type: 'thread watcher',
+ el: $.el('span', {
+ textContent: 'Settings'
+ }),
+ subEntries: subEntries
+ }
+ });
+ _results = [];
+ for (_i = 0, _len = entries.length; _i < _len; _i++) {
+ _ref1 = entries[_i], entry = _ref1.entry, cb = _ref1.cb, refresh = _ref1.refresh;
+ if (entry.el.nodeName === 'A') {
+ entry.el.href = 'javascript:;';
+ }
+ if (cb) {
+ $.on(entry.el, 'click', cb);
+ }
+ if (refresh) {
+ this.refreshers.push(refresh.bind(entry));
+ }
+ _results.push($.event('AddMenuEntry', entry));
+ }
+ return _results;
+ },
+ createSubEntry: function(name, desc) {
+ var entry, input;
+ entry = {
+ type: 'thread watcher',
+ el: $.el('label', {
+ innerHTML: " " + name,
+ title: desc
+ })
+ };
+ input = entry.el.firstElementChild;
+ input.checked = Conf[name];
+ $.on(input, 'change', $.cb.checked);
+ if (name === 'Current Board') {
+ $.on(input, 'change', ThreadWatcher.refresh);
+ }
+ return entry;
+ }
}
};
@@ -7898,8 +8234,8 @@
http: true,
https: true,
software: 'foolfuuka',
- boards: ['adv', 'asp', 'cm', 'i', 'lgbt', 'n', 'o', 'p', 's4s', 't', 'trv'],
- files: ['adv', 'asp', 'cm', 'i', 'lgbt', 'n', 'o', 'p', 's4s', 't', 'trv']
+ boards: ['adv', 'asp', 'cm', 'd', 'e', 'i', 'lgbt', 'n', 'o', 'p', 'pol', 's', 's4s', 't', 'trv', 'y'],
+ files: ['cm', 'd', 'e', 'i', 'n', 'o', 'p', 's', 'trv', 'y']
},
'Foolz Beta': {
domain: 'beta.foolz.us',
@@ -8305,10 +8641,8 @@
},
callbacks: [],
cb: function(e) {
- var post;
e.preventDefault();
- post = Get.postFromNode(this);
- return ExpandComment.expand(post);
+ return ExpandComment.expand(Get.postFromNode(this));
},
expand: function(post) {
var a;
@@ -8368,6 +8702,12 @@
}
quote.href = "/" + post.board + "/res/" + href;
}
+ Build.capcodeReplies({
+ boardID: post.board.ID,
+ threadID: post.thread.ID,
+ bq: clone,
+ capcodeReplies: postObj.capcode_replies
+ });
post.nodes.shortComment = comment;
$.replace(comment, clone);
post.nodes.comment = post.nodes.longComment = clone;
@@ -9378,7 +9718,8 @@
$.on(d, '4chanXInitFinished', Settings.open);
}
return $.set({
- lastchecked: Date.now(),
+ archives: Conf['archives'],
+ lastarchivecheck: now,
previousversion: g.VERSION
});
});
@@ -9564,7 +9905,6 @@
version: g.VERSION,
date: now
};
- Conf['WatchedThreads'] = {};
for (_i = 0, _len = DataBoards.length; _i < _len; _i++) {
db = DataBoards[_i];
Conf[db] = {
@@ -9694,14 +10034,13 @@
});
}
}
- data.Conf.WatchedThreads = data.WatchedThreads;
- } else if (version[0] === '3') {
- data = Settings.convertSettings(data, {
- 'Reply Hiding': 'Reply Hiding Buttons',
- 'Thread Hiding': 'Thread Hiding Buttons',
- 'Bottom header': 'Bottom Header',
- 'Unread Tab Icon': 'Unread Favicon'
- });
+ data.Conf['WatchedThreads'] = data.WatchedThreads;
+ }
+ if (data.Conf['WatchedThreads']) {
+ data.Conf['watchedThreads'] = {
+ boards: ThreadWatcher.convert(data.Conf['WatchedThreads'])
+ };
+ delete data.Conf['WatchedThreads'];
}
return $.set(data.Conf);
},
@@ -10128,6 +10467,7 @@
'Thread Stats': ThreadStats,
'Thread Updater': ThreadUpdater,
'Thread Watcher': ThreadWatcher,
+ 'Thread Watcher (Menu)': ThreadWatcher.menu,
'Index Navigation': Nav,
'Keybinds': Keybinds,
'Show Dice Roll': Dice
@@ -10394,7 +10734,7 @@
}
return Main.thisPageIsLegit;
},
- css: "/* General */\n.dialog {\nbox-shadow: 0 1px 2px rgba(0, 0, 0, .15);\nborder: 1px solid;\ndisplay: block;\npadding: 0;\n}\n.captcha-img,\n.field {\nbackground-color: #FFF;\nborder: 1px solid #CCC;\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\ncolor: #333;\nfont: 13px sans-serif;\noutline: none;\ntransition: color .25s, border-color .25s;\ntransition: color .25s, border-color .25s;\n}\n.field::-moz-placeholder,\n.field:hover::-moz-placeholder {\ncolor: #AAA !important;\nfont-size: 13px !important;\nopacity: 1.0 !important;\n}\n.captch-img:hover,\n.field:hover {\nborder-color: #999;\n}\n.field:hover, .field:focus {\ncolor: #000;\n}\n.field[disabled] {\nbackground-color: #F2F2F2;\ncolor: #888;\n}\n.move {\ncursor: move;\noverflow: hidden;\n}\nlabel, .favicon {\ncursor: pointer;\n}\na[href=\"javascript:;\"] {\ntext-decoration: none;\n}\n.warning {\ncolor: red;\n}\n#boardNavDesktop {\ndisplay: none !important;\n}\na {\noutline: none !important;\n}\n\n/* 4chan style fixes */\n.opContainer, .op {\ndisplay: block !important;\noverflow: visible !important;\n}\n[hidden] {\ndisplay: none !important;\n}\n\n/* fixed, z-index */\n#overlay,\n#fourchanx-settings,\n#qp, #ihover,\n#navlinks, .fixed #header-bar,\n:root.float #updater,\n:root.float #thread-stats,\n#qr {\nposition: fixed;\n}\n#fourchanx-settings {\nz-index: 999;\n}\n#overlay {\nz-index: 900;\n}\n#notifications {\nz-index: 70;\n}\n#qp, #ihover {\nz-index: 60;\n}\n#menu {\nz-index: 50;\n}\n#navlinks, #updater, #thread-stats {\nz-index: 40;\n}\n.fixed #header-bar.autohide {\nz-index: 35;\n}\n#qr {\nz-index: 30;\n}\n#watcher {\nz-index: 8;\n}\n:root.fixed-watcher #watcher {\nz-index: 20;\n}\n.fixed #header-bar {\nz-index: 10;\n}\n/* Header */\n.fixed.top body {\npadding-top: 2em;\n}\n.fixed.bottom body {\npadding-bottom: 2em;\n}\n.fixed #header-bar {\nright: 0;\nleft: 0;\npadding: 3px 4px 4px;\n}\n.fixed.top #header-bar {\ntop: 0;\n}\n.fixed.bottom #header-bar {\nbottom: 0;\n}\n#header-bar {\nborder-width: 0;\ntransition: all .1s .05s ease-in-out;\n}\n:root.centered-links #shortcuts {\nwidth: 300px;\ntext-align: right;\n}\n:root.centered-links #header-bar {\ntext-align: center;\n}\n:root.centered-links #custom-board-list {\nposition: relative;\nleft: 150px;\n}\n.fixed.top #header-bar {\nborder-bottom-width: 1px;\n}\n.fixed.bottom #header-bar {\nbox-shadow: 0 -1px 2px rgba(0, 0, 0, .15);\nborder-top-width: 1px;\n}\n.fixed.bottom #header-bar .menu-button i {\nborder-top: none;\nborder-bottom: 6px solid;\n}\n#board-list {\ntext-align: center;\n}\n.fixed #header-bar.autohide:not(:hover) {\nbox-shadow: none;\ntransition: all .8s .6s cubic-bezier(.55, .055, .675, .19);\n}\n.fixed.top #header-bar.autohide:not(:hover) {\nmargin-bottom: -1em;\n-webkit-transform: translateY(-100%);\ntransform: translateY(-100%);\n}\n.fixed.bottom #header-bar.autohide:not(:hover) {\n-webkit-transform: translateY(100%);\ntransform: translateY(100%);\n}\n#scroll-marker {\nleft: 0;\nright: 0;\nheight: 10px;\nposition: absolute;\n}\n:root:not(.autohide) #scroll-marker {\npointer-events: none;\n}\n#header-bar #scroll-marker {\ndisplay: none;\n}\n.fixed #header-bar #scroll-marker {\ndisplay: block;\n}\n.fixed.top #header-bar #scroll-marker {\ntop: 100%;\n}\n.fixed.bottom #header-bar #scroll-marker {\nbottom: 100%;\n}\n#header-bar a:not(.entry):not(.close) {\ntext-decoration: none;\npadding: 1px;\n}\n#header-bar input {\nmargin: 0;\nvertical-align: bottom;\n}\n#shortcuts:empty {\ndisplay: none;\n}\n.brackets-wrap::before {\ncontent: \"\\00a0[\";\n}\n.brackets-wrap::after {\ncontent: \"]\\00a0\";\n}\n.disabled,\n.expand-all-shortcut {\nopacity: .45;\n}\n#shortcuts {\nfloat: right;\n}\n.shortcut {\nmargin-left: 3px;\n}\n#navbotright,\n#navtopright {\ndisplay: none;\n}\n#toggleMsgBtn {\ndisplay: none !important;\n}\n.current {\nfont-weight: bold;\n}\n/* 4chan X link brackets */\n.fourchanx-link::after {\ncontent: \"]\";\n}\n.fourchanx-link::before {\ncontent: \"[\";\n}\n/* Notifications */\n#notifications {\nposition: fixed;\ntop: 0;\nheight: 0;\ntext-align: center;\nright: 0;\nleft: 0;\ntransition: all .8s .6s cubic-bezier(.55, .055, .675, .19);\n}\n.fixed.top #header-bar #notifications {\nposition: absolute;\ntop: 100%;\n}\n.notification {\ncolor: #FFF;\nfont-weight: 700;\ntext-shadow: 0 1px 2px rgba(0, 0, 0, .5);\nbox-shadow: 0 1px 2px rgba(0, 0, 0, .15);\nborder-radius: 2px;\nmargin: 1px auto;\nwidth: 500px;\nmax-width: 100%;\nposition: relative;\ntransition: all .25s ease-in-out;\n}\n.notification.error {\nbackground-color: hsla(0, 100%, 38%, .9);\n}\n.notification.warning {\nbackground-color: hsla(36, 100%, 38%, .9);\n}\n.notification.info {\nbackground-color: hsla(200, 100%, 38%, .9);\n}\n.notification.success {\nbackground-color: hsla(104, 100%, 38%, .9);\n}\n.notification a {\ncolor: white;\n}\n.notification > .close {\npadding: 6px;\ntop: 0;\nright: 5px;\nposition: absolute;\n}\n.message {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\npadding: 6px 20px;\nmax-height: 200px;\nwidth: 100%;\noverflow: auto;\n}\n\n/* Settings */\n:root.fourchan-x body {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\n}\n#overlay {\nbackground-color: rgba(0, 0, 0, .5);\ntop: 0;\nleft: 0;\nheight: 100%;\nwidth: 100%;\n}\n#fourchanx-settings {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\nbox-shadow: 0 0 15px rgba(0, 0, 0, .15);\nheight: 600px;\nmax-height: 100%;\nwidth: 900px;\nmax-width: 100%;\nmargin: auto;\npadding: 3px;\ntop: 50%;\nleft: 50%;\n-moz-transform: translate(-50%, -50%);\n-webkit-transform: translate(-50%, -50%);\ntransform: translate(-50%, -50%);\n}\n#fourchanx-settings > nav {\npadding: 2px 2px 0;\nheight: 15px;\n}\n#fourchanx-settings > nav a {\ntext-decoration: underline;\n}\n#fourchanx-settings > nav a.close {\ntext-decoration: none;\npadding: 2px;\n}\n.section-container {\noverflow: auto;\nposition: absolute;\ntop: 2.1em;\nright: 5px;\nbottom: 5px;\nleft: 5px;\npadding-right: 5px;\n}\n.sections-list {\npadding: 0 3px;\nfloat: left;\n}\n.credits {\nfloat: right;\n}\n.tab-selected {\nfont-weight: 700;\n}\n.section-sauce ul,\n.section-advanced ul {\nlist-style: none;\nmargin: 0;\n}\n.section-sauce ul {\npadding: 8px;\n}\n.section-advanced ul {\npadding: 0px;\n}\n.section-sauce li,\n.section-advanced li {\npadding-left: 4px;\n}\n.section-main label {\ntext-decoration: underline;\n}\n.section-filter ul {\npadding: 0;\n}\n.section-filter li {\nmargin: 10px 40px;\n}\n.section-filter textarea {\nheight: 500px;\n}\n.section-sauce textarea {\nheight: 350px;\n}\n.section-advanced .field[name=\"boardnav\"] {\nwidth: 100%;\n}\n.section-advanced textarea {\nheight: 150px;\n}\n.section-advanced .archive-cell {\nmin-width: 160px;\ntext-align: center;\n}\n.section-advanced #archive-board-select {\nposition: absolute;\n}\n.section-advanced .note {\nfont-size: 0.8em;\nfont-style: italic;\nmargin-left: 10px;\n}\n.section-advanced .note code {\nfont-style: normal;\nfont-size: 11px;\n}\n.section-keybinds .field {\nfont-family: monospace;\n} \n#fourchanx-settings fieldset {\nborder: 1px solid;\nborder-radius: 3px;\n}\n#fourchanx-settings legend {\nfont-weight: 700;\n}\n#fourchanx-settings textarea {\nfont-family: monospace;\nmin-width: 100%;\nmax-width: 100%;\n}\n#fourchanx-settings code {\ncolor: #000;\nbackground-color: #FFF;\npadding: 0 2px;\n}\n.unscroll {\noverflow: hidden;\n}\n\n/* Announcement Hiding */\n:root.hide-announcement #globalMessage {\ndisplay: none;\n}\na.hide-announcement {\nfloat: left;\n}\n\n/* Unread */\n#unread-line {\nmargin: 0;\nborder-color: rgb(255,0,0);\n}\n\n/* Thread Updater */\n#updater {\nbackground: none;\nborder: none;\nbox-shadow: none;\n}\n#updater > .move {\npadding: 5px 3px 0px;\nmargin-bottom: -3px;\n}\n#updater > div:last-child {\ntext-align: center;\n}\n#updater input[type=number] {\nwidth: 4em;\n}\n:root.float #updater {\npadding: 0px 3px;\n}\n.new {\ncolor: limegreen;\n}\n#update-status.new {\nmargin-right: 5px;\n}\n#update-timer {\ncursor: pointer;\n}\n\n/* Thread Watcher */\n#watcher {\nposition: absolute;\n}\n#watcher {\npadding-bottom: 3px;\noverflow: hidden;\nwhite-space: nowrap;\nmin-width: 120px;\nmax-height: 92%;\noverflow-y: auto;\n}\n:root.fixed-watcher #watcher {\nposition: fixed;\n}\n:root:not(.fixed-watcher) #watcher:not(:hover) {\nmax-height: 210px;\noverflow-y: hidden;\n}\n#watcher > .move {\npadding-top: 3px;\n}\n#watcher > div {\nmax-width: 250px;\noverflow: hidden;\npadding-left: 3px;\npadding-right: 3px;\ntext-overflow: ellipsis;\n}\n#watcher a {\ntext-decoration: none;\n}\n#watcher .move>.close {\nposition: absolute;\nright: 0px;\ntop: 0px;\npadding: 0px 4px;\n}\n.watch-thread-link {\npadding-top: 18px;\nwidth: 18px;\nheight: 0px;\ndisplay: inline-block;\nbackground-repeat: no-repeat;\nopacity: 0.2;\nposition: relative;\ntop: 1px;\n}\n.watch-thread-link.watched {\nopacity: 1;\n}\n\n/* Thread Stats */\n#thread-stats {\nbackground: none;\nborder: none;\nbox-shadow: none;\n}\n:root.float #post-count, :root.float #file-count {\npointer-events: none;\n}\n:root.float #thread-stats {\npadding: 0px 3px;\n}\n\n/* Quote */\n.deadlink {\ntext-decoration: none !important;\n}\n.backlink.deadlink:not(.forwardlink),\n.quotelink.deadlink:not(.forwardlink) {\ntext-decoration: underline !important;\n}\n.inlined {\nopacity: .5;\n}\n#qp input, .forwarded {\ndisplay: none;\n}\n.quotelink.forwardlink,\n.backlink.forwardlink {\ntext-decoration: none;\nborder-bottom: 1px dashed;\n}\n.filtered {\ntext-decoration: underline line-through;\n}\n:root.hide-backlinks .backlink.filtered {\ndisplay: none;\n}\n.inline {\nborder: 1px solid;\ndisplay: table;\nmargin: 2px 0;\n}\n.inline .post {\nborder: 0 !important;\nbackground-color: transparent !important;\ndisplay: table !important;\nmargin: 0 !important;\npadding: 1px 2px !important;\n}\n#qp > .opContainer::after {\ncontent: '';\nclear: both;\ndisplay: table;\n}\n#qp .post {\nborder: none;\nmargin: 0;\npadding: 2px 2px 5px;\n}\n#qp img {\nmax-height: 80vh;\nmax-width: 50vw;\n}\n.qphl {\noutline: 2px solid rgba(216, 94, 49, .7);\n}\n:root.highlight-own .yourPost > .reply,\n:root.highlight-you .quotesYou > .reply {\nborder-left: 2px solid rgba(221,0,0,.5);\n}\n/* Quote Threading */\n.threadContainer {\nmargin-left: 20px;\nborder-left: 1px solid rgba(128,128,128,.3);\n}\n.threadOP {\nclear: both;\n} \n\n/* File */\n.fileText:hover .fntrunc,\n.fileText:not(:hover) .fnfull,\n.expanded-image > .post > .file > .fileThumb > img[data-md5],\n:not(.expanded-image) > .post > .file > .fileThumb > .full-image {\ndisplay: none;\n}\n.expanding {\nopacity: .5;\n}\n:root.fit-height .full-image {\nmax-height: 100vh;\n}\n:root.fit-width .full-image {\nmax-width: 100%;\n}\n:root.gecko.fit-width .full-image {\nwidth: 100%;\n}\n#ihover {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\nmax-height: 100%;\nmax-width: 75%;\npadding-bottom: 16px;\n}\n.fappeTyme .thread > .noFile,\n.fappeTyme .threadContainer > .noFile {\ndisplay: none;\n}\n\n/* Index/Reply Navigation */\n#navlinks {\nfont-size: 16px;\ntop: 25px;\nright: 10px;\n}\n\n/* Filter */\n.opContainer.filter-highlight {\nbox-shadow: inset 5px 0 rgba(255, 0, 0, .5);\n}\n.filter-highlight > .reply {\nbox-shadow: -5px 0 rgba(255, 0, 0, .5);\n}\n\n/* Spoiler text */\n:root.reveal-spoilers s {\ncolor: white !important;\n}\n\n/* Thread & Reply Hiding */\n.hide-thread-button,\n.hide-reply-button {\nfloat: left;\nmargin-right: 2px;\n}\n.stub ~ * {\ndisplay: none !important;\n}\n.stub input {\ndisplay: inline-block;\n}\n\n/* QR */\n:root.hide-original-post-form #postForm,\n:root.hide-original-post-form .postingMode,\n:root.hide-original-post-form #togglePostForm,\n#qr.autohide:not(.has-focus):not(:hover) > form,\n.postingMode ~ #qr select,\n#file-n-submit:not(.has-file) #qr-filerm {\ndisplay: none;\n}\n#qr select,\n#dump-button,\n.remove,\n.captcha-img {\ncursor: pointer;\n}\n#qr {\nz-index: 20;\nposition: fixed;\npadding: 1px;\nborder: 1px solid transparent;\nmin-width: 300px;\nborder-radius: 3px 3px 0 0;\n}\n#qrtab {\nborder-radius: 3px 3px 0 0;\n}\n#qrtab {\nmargin-bottom: 1px;\n}\n#qr .close {\nfloat: right;\npadding: 0 3px;\n}\n#qr .warning {\nmin-height: 1.6em;\nvertical-align: middle;\npadding: 0 1px;\nborder-width: 1px;\nborder-style: solid;\n}\n.qr-link-container {\ntext-align: center;\n}\n.persona {\nwidth: 248px;\nmax-width: 100%;\nmin-width: 100%;\n}\n#dump-button {\nwidth: 10%;\nmargin: 0;\nmargin-right: 4px;\nfont: 13px sans-serif;\npadding: 1px 0px 2px;\nopacity: 0.6;\n}\n.persona .field:not(#dump) {\nwidth: 95px;\nmin-width: 33.3%;\nmax-width: 33.3%;\n}\n#qr textarea.field {\nheight: 14.8em;\nmin-height: 9em;\n}\n#qr.has-captcha textarea.field {\nheight: 9em;\n}\ninput.field.tripped:not(:hover):not(:focus) {\ncolor: transparent !important;\ntext-shadow: none !important;\n}\n#qr textarea {\nresize: both;\n}\n.captcha-img {\nmargin: 0px;\ntext-align: center;\nbackground-image: #fff;\nfont-size: 0px;\nmin-height: 59px;\nmin-width: 302px;\n}\n.captcha-input {\nwidth: 100%;\nmargin: 1px 0 0;\n}\n.captcha-input.error:focus {\nborder-color: rgb(255,0,0) !important;\n}\n.field {\n-moz-box-sizing: border-box;\nmargin: 0px;\npadding: 2px 4px 3px;\n}\n#qr textarea {\nmin-width: 100%;\n}\n#qr [type='submit'] {\nwidth: 25%;\nvertical-align: top;\n}\n:root.webkit #qr [type='submit'] {\nheight: 24px;\n}\n/* Fake File Input */\n#qr-filename,\n.has-file #qr-no-file {\ndisplay: none;\n}\n#qr-no-file,\n.has-file #qr-filename {\ndisplay: inline-block;\npadding: 0px 4px;\nmargin-bottom: 2px;\noverflow: hidden;\ntext-overflow: ellipsis;\nmax-width: 88%;\n}\n#qr-no-file {\ncolor: #AAA;\n}\n#qr-filename-container {\n-moz-box-sizing: border-box;\ndisplay: inline-block;\nposition: relative;\nwidth: 100px;\nmin-width: 74.6%;\nmax-width: 74.6%;\nmargin-right: 0.4%;\nmargin-top: 1px;\noverflow: hidden;\npadding: 2px 1px 0;\nheight: 22px;\n}\n#qr-filename-container:hover {\ncursor: text;\n}\n#qr-extras-container {\nposition: absolute;\nright: 0px;\n}\n#qr-filerm {\nmargin-right: 2px;\nz-index: 2;\n}\n#file-n-submit {\nheight: 23px;\n}\n#qr input[type=file] {\nvisibility: hidden;\nposition: absolute;\n}\n/* Thread Select / Spoiler Label */\n#qr select {\nfloat: right;\n}\n#qr.has-spoiler .has-file #qr-spoiler-label {\nwidth: 6.7%;\nmin-width: 6.7%;\nmax-width: 6.7%;\ndisplay: inline-block;\ntext-align: center;\nvertical-align: top;\n}\n#qr.has-spoiler #file-n-submit:not(.has-file) #qr-spoiler-label {\ndisplay: none;\n}\n#qr.has-spoiler .has-file #qr-filename-container {\nmax-width: 67.9%;\nmin-width: 67.9%;\n}\n#qr-spoiler-label input {\nposition: relative;\ntop: 3px;\n}\n/* Dumping UI */\n.dump #dump-list-container {\ndisplay: block;\n}\n#dump-list-container {\ndisplay: none;\nposition: relative;\noverflow-y: hidden;\nmargin-top: 1px;\n}\n#dump-list {\noverflow-x: auto;\noverflow-y: hidden;\nwhite-space: nowrap;\nwidth: 248px;\nmax-width: 100%;\nmin-width: 100%;\n}\n#dump-list:hover {\noverflow-x: auto;\n}\n.qr-preview {\n-moz-box-sizing: border-box;\ncounter-increment: thumbnails;\ncursor: move;\ndisplay: inline-block;\nheight: 90px;\nwidth: 90px;\npadding: 2px;\nopacity: .5;\noverflow: hidden;\nposition: relative;\ntext-shadow: 0 1px 1px #000;\n-moz-transition: opacity .25s ease-in-out;\nvertical-align: top;\nbackground-size: cover;\n}\n.qr-preview:hover,\n.qr-preview:focus {\nopacity: .9;\n}\n.qr-preview::before {\ncontent: counter(thumbnails);\ncolor: #fff;\nposition: absolute;\ntop: 3px;\nright: 3px;\ntext-shadow: 0 0 3px #000, 0 0 8px #000;\n}\n.qr-preview#selected {\nopacity: 1;\n}\n.qr-preview.drag {\nbox-shadow: 0 0 10px rgba(0,0,0,.5);\n}\n.qr-preview.over {\nborder-color: #fff;\n}\n.qr-preview > span {\ncolor: #fff;\n}\n.remove {\nbackground: none;\ncolor: #e00;\nfont-weight: 700;\npadding: 3px;\n}\na:only-of-type > .remove {\ndisplay: none;\n}\n.remove:hover::after {\ncontent: \" Remove\";\n}\n.qr-preview > label {\nbackground: rgba(0,0,0,.5);\ncolor: #fff;\nright: 0;\nbottom: 0;\nleft: 0;\nposition: absolute;\ntext-align: center;\n}\n.qr-preview > label > input {\nmargin: 0;\n}\n#add-post {\ncursor: pointer;\nfont-size: 2em;\nposition: absolute;\ntop: 50%;\nright: 10px;\n-moz-transform: translateY(-50%);\n}\n.textarea {\nposition: relative;\n}\n:root.webkit .textarea {\nmargin-bottom: -2px;\n}\n#char-count {\ncolor: #000;\nbackground: hsla(0, 0%, 100%, .5);\nfont-size: 8pt;\nposition: absolute;\nbottom: 1px;\nright: 1px;\npointer-events: none;\n}\n\n/* Menu */\n.menu-button {\ndisplay: inline-block;\nposition: relative;\ncursor: pointer;\n}\n.menu-button i {\nborder-top: 6px solid;\nborder-right: 4px solid transparent;\nborder-left: 4px solid transparent;\ndisplay: inline-block;\nmargin: 2px;\nvertical-align: middle;\n}\n#menu {\nposition: fixed;\noutline: none;\n}\n.entry {\nborder-bottom: 1px solid rgba(0,0,0,.25);\ncursor: pointer;\ndisplay: block;\noutline: none;\npadding: 3px 7px;\nposition: relative;\ntext-decoration: none;\nwhite-space: nowrap;\n}\n.left>.entry.has-submenu {\npadding-right: 17px !important;\n}\n.entry:last-child {\nborder-bottom: 0;\n}\n.has-submenu::after {\ncontent: \"\";\nborder-left: .5em solid;\nborder-top: .3em solid transparent;\nborder-bottom: .3em solid transparent;\ndisplay: inline-block;\nmargin: .3em;\nposition: absolute;\nright: 3px;\n}\n.left .has-submenu::after {\nborder-left: 0;\nborder-right: .5em solid;\n}\n.submenu {\ndisplay: none;\nposition: absolute;\nleft: 100%;\ntop: -1px;\n}\n.focused .submenu {\ndisplay: block;\n}\n.imp-exp-result {\nposition: absolute;\ntext-align: center;\nmargin: auto;\nright: 0px;\nleft: 0px;\nwidth: 200px;\n}\n.export, .import {\ncursor: pointer;\ntext-decoration: none !important;\n}\n/* Link Title Favicons */\n.linkify.YouTube {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAMCAYAAABr5z2BAAABIklEQVQoz53LvUrDUBjG8bOoOammSf1IoBSvoCB4JeIqOHgBLt6AIMRBBQelWurQ2kERnMRBsBUcIp5FJSBI5oQsJVkkUHh8W0o5nhaFHvjBgef/Mq+Q46RJBMkI/vE+aOus956tnEswIZe1LV0QyJ5sE2GzgZfVMtRNIdiDpccEssdlB1mW4bvTwdvWJtRdErM7U+8S/FJykCRJX5qm+KpVce8UMNLRLbulz4iSjTAMh6Iowsd5BeNadp3nUF0VlxAEwZBotXC0Usa4ll3meZdA1iguwvf9vpvDA2wvmKgYGtSud8suDB4TyGr2PF49D/vra9jRZ1BVdknMzgwuCGSnZEObwu6sBnVTCHZiaC7BhFx2PKdxUidiAH/4lLo9Mv0DELVs9qsOHXwAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.Vimeo {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAASJJREFUOE9jYAAC7ln7/pODQXrBmq333PvPu/YaSRikB6QXbACpmmHqsRoAMll7+20UQ0H8tmuv/pdffPFfZtNNuByGASBFIPDh5x+4IV6HHoDFYGDJgw+YBoBMBUkgA5BtIKduuvvy//svX+FSB+88wTTAc+/t/83bj/0HScLA5BPXwc7lKJ36f+L6XXDxhUfOYxrAPWUnWKFp9UQUm3iWQxSDXAEDSX3zcIcB96wD/x+8eA1XDNKMHAYg20GW4Y0FkCIYAAUqzEBQOIBciRzlWKMxZelOlMCEcVxq+jHSC1YDJPs3YBgA8jey0/F6ARRwsFAHORukmat9NdbUijMpg/wKcrJodDFOzSBXwA3Alh9AToZFI7a8Asu98BxJbnYGAJb5vYLDANzSAAAAAElFTkSuQmCC') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.SoundCloud {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABsklEQVQ4y5WTy2pUQRCGv2rbzDjJeAlIBmOyipGIIJqFEBDElwh4yULGeRFXPoEIBl/AvQ/gC2RnxCAoxijiwks852S6+3dxzslcHJCpTXVX11/Xv0097gLPgVNMJxnQNfX4zsqleWbnpoMf/oa9d988MM9MC/rp+E0a+A0dsVobMNMCOO8B6McRoABJI+A6gJmN3D2A8jgEBCEkSEMBrcrsDAzDWWn3AjgKFaDMmgRqniGFgsaDp1jrLOngDf1XT1D+A1dFc4MKAkkiCVKjjVu7g9+4Rzx4i1u6hjXbuMWr0O5QPNvCu7IaCZwEKQukLGDrm5x8uI0tr6MkiGlkiv7yLfzN+6S5i6QsIMABkEfcxhbWWYMkVAOjxvYAjc3HNHrbKI9VBQBFwF25XQKSBjqIf1YBuAurEMrczgDygD6/x2LCpFLXLUyQ+PoldphhBhYfIX09XU1+Flaukz7uYqs3SHs7cG4BmTsmkBUF9mmXEwa28BNLPaQPLepuNcbGSWQquQC2/Kdcox1FUGkcB0ykck1nA2+wTzMs8stGnP4rbWGw74EuS/GFQWfK7/wF6P4F7fzIAYkdmdEAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.audio {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAitJREFUOE9jYCAWKJWwavr0KyXWb/FIbDtUFFyzJx6nVofE2Xo5nXsj0rqPNSR0nVkR2Hjmgmfd+U9Otdf+m5Vf/6+SfeU/R9ChVVgNYDRtlfJuuPA/rPfe/4QpD/6nznj0P27Kw/9unff/69Xf+69c/+C/SO7N/0z+OAxgMmmRCe++/r9i3ev/KWvf/vdY8PK/bt/9/wrNV3/IN5y/IVt1YqNg4pGTTP4HsbuA2bhZ2qvpyn+xjIObxAp3VwqlrgngLFyryVy5nhPmZJHANS2cwYexG8BmVC/pWn3hP4NZlzWuQDJI3dIiFnUUuwEsQAOcq87jNcC7fHeLUtJxHF4AGmBWeAavAWH1+1rUUk7giAWjOknllON4DXAs2NEiG4/DBQxAF/CFHfrPYI4jDFSLuJVjNrUJhB/B7gIGo1pJRt99GAZYJK7wLJ1z7Xzl4vu/7aqv/GRBj0bjqAX2qb0nJ7mXH17C4HcUxQA+hymWtSue/C5a9up/9Ozn/7Vr7v1nRY7GqMb91T3b3v6vWvPmf/S0p/9ZQk+DDLCBRSOz06Jqk+o7/21nvfqvsebDf7kZL/5zBaxphkezd+OFn7HzXvz3Wvjmv9a8N//5Ek//ZTBpVYUrMG2X5wjcdl68+uI/wa5Lr3hSNjczGFeywOVZ/bbcVGp//F9izfv/Ql03f3P4LC/HSEQquYwMFnUCDJ7dzBhyjGZNQpye89M5gpfnMvtNUyE2h4PUAQBovvT7lyNljwAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.LiveLeak {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAydJREFUOE9Nk1tIk2EYx79NyUNqTk0o6KYrnZeChodLDxfeZpCbJk4RXU5Nm7tYRYhiYXbQlaeGutyW2gxtpB1RIyKDEjKwA6Ti2dR5KNDn+fq/S6TBj/f93r3P732e53s/qfnkSdej4GB2SBLbwf+jmB+gUMgOheLg/z7EdCUnO6Ref392SpK8Hyh3I+gBwBo7lUp2xcbyQEoKD6alyQOpqd754/h4FjJXZCRJTl9ftmEzoK5/wdQJxPgkLY2WV1dpc2uLtnZ2eHNnhza3t2nd46GhjAzuValY6jx0iIfS03msoIDuQ9COQCtoUSjohU5HuwgaN5loeXycd3d3aW9vzwvW2K5SkdTi58fvzGb+3tdHFggA3QONEAzn59PvjQ1yqNX0zenkvX0B4ffWaGRraChJd/385JGqKvlzTw/fRqOaIGkEd1DjU52O/3g83BkTw5MOh7yJuUCUM2o0yi2hoSw1IIOhykr+YLNRHYKu4XQvyKA/N5c8yMCCDD7Z7bz26xcJ1rH2rKKCG0UJdRAMlJbyG6uVrkJQjWAB5tSbk0Nr2HwDgvcQiIYur6zQyvo6ucvLueHIEZKuQPBQr+dXra1kRuqXEOwFArtWSytra1QdFUVjNhvPLS3R3OIiLUDUD0F1WBhJJtwDW2Ehu5uaqBICI4IFlRB0QLCEzaboaHrd0cHzCBYsIIuesjK+LAQXkEFrXh676uupGCWcR6AeghLQptGQONUAwfOuLp6Zn6eZuTmaXVig7pISrhI90ENgQbdHhoep32JhFzLpu3WLio8epUYIfs7OUjF6UKJW88XERLqYkEBNej11oG8XhCAvMFAuOn5cNiclsTkhQTbhmpri4lgbEMANWi1DwC/xit3t7bK7rY0Fo4OD3G4wyEURESzloAdnceezlErK8vH5N4KzPj50PTOTfkxP0+THj/RlYoInJyZI8HVqim5qNFwQHk7SucBAPo2PKRMNPLM/4pnFszYkhJsNBu6uqWFHba1sr61lQSveQFZQkFx07BhJmhMnrLn4NLMPH/aSExR0QDbmWhwgyEapwDvXoDxdWBiXnjrV/Bdm2kYUxLwmEgAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.Vocaroo {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAw9JREFUOE9jYMABuMwYmCyTJKUCGlSnFSy02TTzeOyCiQcDViX26qVz2TAyYtWmEMwuoZ3M7V40LcB79pHkc0svpvzY8jD//87nxf+3Pyn8v/ZO8v+VNyP/2mZJumI1QCWSI8232Hjumitlfw5+qPp/9l8TCt76JP//xkdx/wsXWCzjtWFkwTCkbWFe9plPk/+ga4Txz/xt/D/hkN//gMXif21a+NbyWjIwoRiy6GDT5rP/mlFsPfyp5n/NpOj/22+0gMUXXIz/H7hC/L/bFKFbPDZMrHAD5H35OPt2J9zacDv/f3V7xv9FhwrBGubsT/1//Pjx/1GJ/mD+/nfl/1v3Ovy3KRJNQbHdOlXCvOO03/+pm1P/v3v37n90hhtYw9HPtf8Xb2v937cmHswHeWPRxYj/LvkK3igGKARwicTO07118H3V/5kbi/4vPZMJtK3s/6YH2f+Pfq1B8VbjWrdnMu5s4nAD9CNFhKwz5DTUvLl419zKvAcLtG1P84BRl/b/5M/6/6f/NPzf/qzo84yj0Uus0xUU4Zor54bm9+4OfZG02OCuoAMTb9ZkC9ull1Nvrr2Z+XvRpaRfc65H/68F+jl9svEhzyLFWoccWVc+eyTHq/twydjlKRln7jX9bNMkMJnbhoFRL1xCqmKx6/yi2fYXa/c5/e846PV/5fW0/7OPx/yfcjzop34ulxdGGvDuU8mMXaX507lBuiN6ueadmQeT/p/93vf/1O+G//sP5fw/eL3o/5JLif8zVxs+Tlir9S26UyeFQQvJGBE7FvaFZ9LfN+1y+WjbItSb3GmXvXd15v8zroH/HxgE/D+aGPx/18vi/z07PeZNPRKxe/Kh0Ae8toxscCO4zBkYXArk9C1SxJUYjBkYPPIVtbbuTftz3cz//2O9wP/75iSAXdO72/dt2HL5F6YlfBW4MiJYXMiBiW3t7azHBx+V/t89N+H/8a+1//e9K/9attDp5LQjYX8SuvVL8RoAkmxa65299Erq1FnHo0qrl7t4BddriIs4MrM3rfWcFd+pGwVSAwBZ0bKP8yrZPAAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.pastebin {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAtZJREFUOE+NU91LWmEc7sJtQew/2MUY7INg7CLY3W5GMHazyzEQo9UmfYxZTbAiVlgRqLMSZ+XnDC3z2+Y0+8JGakKZTtR0Tl2wtgtLLQh29cz3ZZ3h3Q68vOc95zzP73l+z+/U1f292O09DRxubxOH23P//1bvtQts3dPnry7LZnXJhcUl5Avf8dHtwY+fv2AyW5DOfIXFakMm+w0G4wISyRRm55TQG0y/Wzv6mikJ52Xf9TmVBoFAAD6fDwqFAqFQCJubmzCbzZiensbp6SmkUikikQi0Wi0kEgm6ewVaStDCfXPDandifn6egoaGhrCzswO1Wg2Hw4HBwUGk02kIBAL4/X4IhUJMTk6ii8dfYggy2RwymQzOz88Rj8dRLpexv7+PSqWCYDCIQqGAra0tJBIJrK2t0XdVAjNDEIl+wfj4OEqlEq2wt7dHrchkMmrBYDCAz+fTIjweD7FYrJbgIJOlgLOzM8jlcip1eXmZ2rFarVAqlRCLxcjlchCJRFRljYJYPAG32418Pg+n04lsNouVlRUcHh7C4/FQIOlHNBqlezgcJgQWxkIgGMbExASVNjY2hvX1dVo9mUzS5wREFLhcLrqTcw2B//M2RkdHodPp4PV6oVKpqH+SCom3v7+fNnF4eJiJusbCJ6+PviSyScakiaR5RIHRaKQpmEwmbAdCeD8zB6vdhebHT8SMhcUlC83bbrdTJRsbG3RwiCVCRNJJpDIoVeNNJJJQzKryV+rrmxiCtyNCCmaz2VhdXQWXy6XDpNfrodFoYLXZUTw+pk222Z3lW3ca26rgSwzBwqIZAwMDlITMAVEwNTVFR5fEJpK8Qyp1AJvDVbrTeLenCmxgfiZ22+urCtWHyu7uLp2wVCpFKx0dHaFYLOLk5KT6Y9kgk89kb95ubK0BX7A8a+1qannRLeW0daj/rU51S3tn9dypfvDw0QiLxbpX/Z7FVK7e/AEj4Wf24/2f5AAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.gist {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAk1JREFUeNqUkzuIE1EUhv955MnsbB6r4kYQLUQQFncV3SnCIqJsoWGDYOGjsIiCtY2Kla1sjLBIsFFcXJC1kaSwENQmXUQSRSUSjCQSTCbkbR4z47lXEgtBNwcu3DNzvvO8R8jlcj7LshKmaWqYQERRTAmCcEru9/sJr9er0QF92BJMAVGr1TQ6CeZAc7lcGAwGkyQAxpTLZU0eDoc8crfbRTgcRjAYRCQSYSmi1WpxY7fbjU6ng1gshmaziXg8zhnGIpVKWbquW9ls1mLZsaMoiqWq6lgnBxY55He/328Vi0XOMFZmqVMD4fF4QBAajcY48khY9JE4HA4enTGMFVkaTHmy+ZzD/5NSqYSNB484w1h55ODO3TVu4FXcWDywl24Cmp0e1WBhyuWELAtIf/qKUrWOONmev3Lpt4NRCXq1gplpBS/v3cDc0nGg9h1o1ZkfwO4Atu1B8cM7HLt8k37V/y5B2b4bJxf2Y+7oEbyJrkMvUjki0YYJ03LidfQxAt4dOHdCw5RdGZcgGobBlQtnV/BDr1GfDai7ZiHZZRi9PoY/e5SCCTUwC9gk1GmMh5YWOcNYkR4Sv1y9uAJbYB82N57h4OnDmN7phjQ0qUkWRJuB+TMaPn/5iFfvv+Ha7eucYey4iWw8q6tRJJNJ3Fp7ClUawEkViBTfkCR0YUNTVHD/4Tpm/P4/U2CeKpUKfD4fJDIMhUKEhP45St50XedZyLQY6Xw+v8AUemVb2oNqtYpCocCWKi2TLLfb7ReZTGZ+kmUi7i2VvfxLgAEAZChMriPcl+IAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.image {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAs5JREFUOE+lk/tvi1EYx98/xT8gW4REIpGFMEQWl2FiM9ZMZhm2xRAyOsmujFFmdFRHu0tWm87UypxStr69zPauN5e5rHVp3IYhbOvHy+wHEQlxkm+ek+d8nm9OznkeSfrfldmgJC7QyUlTymsJTfuTZ25z4HdWYwyLreYhtpgekGPw0+kKvo1Eo+IXRSIiEhkWZuc9tqnsJD9EqTUopCxjSGTpB0iueczSo1HyW8cpsExQ1DbxI2pt45j9cXpexul4FEd79RnZphAa/SD7WvuFtO6UItbU9LC+YQxNI2w0wwYT5LRAdhOU3oBTIXC9gXP3oUSGgz2vST3gYHejR0jptT1C332f8yrUEYHrz8CgxDnpm6DKCUfc0KnmXa/AEVPPwnDcD0cvetA2uYRk67Ive/lpjO7YBO1PPuF8Df3vwf4cbNE4tqdw7YVq8HYyHx6FvhE1hkMEg8HDUqvFkjT4aIjMqkqyqkswDSrcfBfH+Q561YLAZ/B+BLda6FXlU/cPv0AoEPhuoP1h4Av7Wbh9E/Py15NWWUjeSR3nZDfeN+N0DY9hG/7K1eGP3P0S5/EYRFUF/IOTBrUXHPm9fT6mr1xEwupkZqxbzLyiDJYUZ5NSnkdqdSHpxyrYdFpPgdmAsdfJwPMI/Yr65bf7tZLGGBQ7DNdJWFtIYvoOZmbuZE7OXpIKKli86zAr9p9gTVktWTVnKTI2U95uRWe3U2IJUDbVB5p6hVm5x5m9Vc/cnedZUNzC8lILaQesZBy6hEZ3maKzgvJWFzVWD9XtXvVGQbSWASFtMATVRlJIKbOTWtlJXaeXepuPM1f6MNp9GLt8mLvvYLmp0OhQ2Fwvk6m7xaqDTvY0eYWUVtcnllXfYlGpnfklVuraHHg8HjxuN+6fktUHlWWZPaZeUo/ILK0UKttBcbNbSB9GP0yLxWJJUxoZGUn80zD9C/vXQ/4NHY10h3M1zmQAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.InstallGentoo {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAklJREFUOE9jYEAAASBTCorZkcSRmTjVCDLziCwG4hfM3EIvGNm44oC6WNEM4WXi5FsEkmfhFX3BxMmfAJSHW9Qr55Px3aZp3X/btq3/hQydPzKysMcCFbBBDeFj4uBdqBJR/gskb1W34j+PmulLoJwbzBJJoMm7dNO7/ntMP/XfpW/v//SKvk+7tl7fvXfTpx5pCdWVSiHFv1wnHQbLi9sE/Wdk5SwBauaCGQB3gUPb5v+7Lr/8/+fvr/9fv/z+f+Pyr/9bV735l9Wy/79Dx/b/Nk0bsLoAHgbeAVHv/v77/f8f0IB7N7+cu3DuecK54z9+7lzz639e9pK/7HwSWMMA5BJwCJeXtOm/fvVj1fcfv369f//92cN7X6ZcPvf9x6Htv//vXP3r/+T245UEYgpskPTNq08LgN749/PH7/93rv/6f/rw7//nj//4f+bU0zQcUQwWBkdVbGz62y+fv3wHeeXrlz//H9798//qpY//M3KqfzGxc8djiWKwZnBUuWQ2/fr46fv/P39+///x/ff/d69//z97+s7fyMb5/+y7d2GLYriDZikFF/1qXXXj/4Pbv/8/f/jn/5MH316/eP6jVlBAaIt6VO1/jxmn/zv27P7Pp2HxEajLD90ra9Sj6/979O37X73w0n+vqOL/0lJyMVBFq0EGgDSD0oKAlu1/oHg4ugGzVCKqfouYuL1Xj676Iajr8AnJFricGqYc3Bw+Zi6BVUxsXLHAdL6QiYMPFNrwpIxHDsUhgtAMAopKDjQn4pPDF7P45QC4hSmc1eX8WgAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n\n/* General */\n:root.yotsuba .dialog {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.yotsuba .field:focus {\nborder-color: #EA8;\n}\n\n/* Header */\n:root.yotsuba #header-bar, :root.yotsuba #notifications {\nfont-size: 9pt;\ncolor: #B86;\n}\n:root.yotsuba #header-bar a, :root.yotsuba #notifications a {\ncolor: #800000;\n}\n\n/* Settings */\n:root.yotsuba #fourchanx-settings fieldset {\nborder-color: #D9BFB7;\n}\n\n/* Quote */\n:root.yotsuba .backlink.deadlink {\ncolor: #00E !important;\n}\n:root.yotsuba .inline {\nborder-color: #D9BFB7;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.yotsuba #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.yotsuba .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.yotsuba #menu {\ncolor: #800000;\n}\n:root.yotsuba .entry {\nborder-bottom: 1px solid #D9BFB7;\nfont-size: 10pt;\n}\n:root.yotsuba .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.yotsuba .watch-thread-link\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.yotsuba-b .dialog {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.yotsuba-b .field:focus {\nborder-color: #98E;\n}\n\n/* Header */\n:root.yotsuba-b #header-bar, :root.yotsuba-b #notifications {\nfont-size: 9pt;\ncolor: #89A;\n}\n:root.yotsuba-b #header-bar a, :root.yotsuba-b #notifications a {\ncolor: #34345C;\n}\n\n/* Settings */\n:root.yotsuba-b #fourchanx-settings fieldset {\nborder-color: #B7C5D9;\n}\n\n/* Quote */\n:root.yotsuba-b .backlink.deadlink {\ncolor: #34345C !important;\n}\n:root.yotsuba-b .inline {\nborder-color: #B7C5D9;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.yotsuba-b #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.yotsuba-b .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.yotsuba-b #menu {\ncolor: #000;\n}\n:root.yotsuba-b .entry {\nborder-bottom: 1px solid #B7C5D9;\nfont-size: 10pt;\n}\n:root.yotsuba-b .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.yotsuba-b .watch-thread-link\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.futaba .dialog {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.futaba .field:focus {\nborder-color: #EA8;\n}\n\n/* Header */\n:root.futaba #header-bar, :root.futaba #notifications {\nfont-size: 11pt;\ncolor: #B86;\n}\n:root.futaba #header-bar a, :root.futaba #notifications a {\ncolor: #800000;\n}\n\n/* Settings */\n:root.futaba #fourchanx-settings fieldset {\nborder-color: #D9BFB7;\n}\n\n/* Quote */\n:root.futaba .backlink.deadlink {\ncolor: #00E !important;\n}\n:root.futaba .inline {\nborder-color: #D9BFB7;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.futaba #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.futaba .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.futaba #menu {\ncolor: #800000;\n}\n:root.futaba .entry {\nborder-bottom: 1px solid #D9BFB7;\nfont-size: 12pt;\n}\n:root.futaba .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.futaba .watch-thread-link\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.burichan .dialog {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.burichan .field:focus {\nborder-color: #98E;\n}\n\n/* Header */\n:root.burichan #header-bar, :root.burichan #header-bar #notifications {\nfont-size: 11pt;\ncolor: #89A;\n}\n:root.burichan #header-bar a, :root.burichan #header-bar #notifications a {\ncolor: #34345C;\n}\n\n/* Settings */\n:root.burichan #fourchanx-settings fieldset {\nborder-color: #B7C5D9;\n}\n\n/* Quote */\n:root.burichan .backlink.deadlink {\ncolor: #34345C !important;\n}\n:root.burichan .inline {\nborder-color: #B7C5D9;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.burichan #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.burichan .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.burichan #menu {\ncolor: #000000;\n}\n:root.burichan .entry {\nborder-bottom: 1px solid #B7C5D9;\nfont-size: 12pt;\n}\n:root.burichan .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.burichan .watch-thread-link\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.tomorrow .dialog {\nbackground-color: #282A2E;\nborder-color: #111;\n}\n\n/* Header */\n:root.tomorrow #header-bar, :root.tomorrow #notifications {\nfont-size: 9pt;\ncolor: #C5C8C6;\n}\n:root.tomorrow #header-bar a, :root.tomorrow #notifications a {\ncolor: #81A2BE;\n}\n\n/* Settings */\n:root.tomorrow #fourchanx-settings fieldset {\nborder-color: #111;\n}\n\n/* Quote */\n:root.tomorrow .backlink.deadlink {\ncolor: #81A2BE !important;\n}\n:root.tomorrow .inline {\nborder-color: #111;\nbackground-color: rgba(0, 0, 0, .14);\n}\n\n/* QR */\n.tomorrow #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #282A2E;\nborder-color: #111;\n}\n:root.tomorrow .qr-preview {\nbackground-color: rgba(255, 255, 255, .15);\n}\n:root.tomorrow #qr .field {\nbackground-color: rgb(26, 27, 29);\ncolor: rgb(197,200,198);\nborder-color: rgb(40, 41, 42);\n}\n:root.tomorrow #qr .field:focus {\nborder-color: rgb(129, 162, 190) !important;\nbackground-color: rgb(30,32,36);\n}\n\n/* Menu */\n:root.tomorrow #menu {\ncolor: #C5C8C6;\n}\n:root.tomorrow .entry {\nborder-bottom: 1px solid #111;\nfont-size: 10pt;\n}\n:root.tomorrow .focused.entry {\nbackground: rgba(0, 0, 0, .33);\n}\n\n/* Watcher Favicon */\n:root.tomorrow .watch-thread-link\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.photon .dialog {\nbackground-color: #DDD;\nborder-color: #CCC;\n}\n:root.photon .field:focus {\nborder-color: #EA8;\n}\n\n/* Header */\n:root.photon #header-bar, :root.photon #notifications {\nfont-size: 9pt;\ncolor: #333;\n}\n:root.photon #header-bar a, :root.photon #notifications a {\ncolor: #FF6600;\n}\n\n/* Settings */\n:root.photon #fourchanx-settings fieldset {\nborder-color: #CCC;\n}\n\n/* Quote */\n:root.photon .backlink.deadlink {\ncolor: #F60 !important;\n}\n:root.photon .inline {\nborder-color: #CCC;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.photon #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #DDD;\nborder-color: #CCC;\n}\n:root.photon .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.photon #menu {\ncolor: #333;\n}\n:root.photon .entry {\nborder-bottom: 1px solid #CCC;\nfont-size: 10pt;\n}\n:root.photon .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.photon .watch-thread-link\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n"
+ css: "/* General */\n.dialog {\nbox-shadow: 0 1px 2px rgba(0, 0, 0, .15);\nborder: 1px solid;\ndisplay: block;\npadding: 0;\n}\n.captcha-img,\n.field {\nbackground-color: #FFF;\nborder: 1px solid #CCC;\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\ncolor: #333;\nfont: 13px sans-serif;\noutline: none;\ntransition: color .25s, border-color .25s;\ntransition: color .25s, border-color .25s;\n}\n.field::-moz-placeholder,\n.field:hover::-moz-placeholder {\ncolor: #AAA !important;\nfont-size: 13px !important;\nopacity: 1.0 !important;\n}\n.captch-img:hover,\n.field:hover {\nborder-color: #999;\n}\n.field:hover, .field:focus {\ncolor: #000;\n}\n.field[disabled] {\nbackground-color: #F2F2F2;\ncolor: #888;\n}\n.move {\ncursor: move;\noverflow: hidden;\n}\nlabel,\n.watcher-toggler {\ncursor: pointer;\n}\na[href=\"javascript:;\"] {\ntext-decoration: none;\n}\n.warning {\ncolor: red;\n}\n#boardNavDesktop {\ndisplay: none !important;\n}\na {\noutline: none !important;\n}\n\n/* 4chan style fixes */\n.opContainer, .op {\ndisplay: block !important;\noverflow: visible !important;\n}\n[hidden] {\ndisplay: none !important;\n}\n\n/* fixed, z-index */\n#overlay,\n#fourchanx-settings,\n#qp, #ihover,\n#navlinks, .fixed #header-bar,\n:root.float #updater,\n:root.float #thread-stats,\n#qr {\nposition: fixed;\n}\n#fourchanx-settings {\nz-index: 999;\n}\n#overlay {\nz-index: 900;\n}\n#notifications {\nz-index: 70;\n}\n#qp, #ihover {\nz-index: 60;\n}\n#menu {\nz-index: 50;\n}\n#navlinks, #updater, #thread-stats {\nz-index: 40;\n}\n.fixed #header-bar.autohide {\nz-index: 35;\n}\n#qr {\nz-index: 30;\n}\n#thread-watcher {\nz-index: 8;\n}\n:root.fixed-watcher #thread-watcher {\nz-index: 20;\n}\n.fixed #header-bar {\nz-index: 10;\n}\n/* Header */\n.fixed.top body {\npadding-top: 2em;\n}\n.fixed.bottom body {\npadding-bottom: 2em;\n}\n.fixed #header-bar {\nright: 0;\nleft: 0;\npadding: 3px 4px 4px;\n}\n.fixed.top #header-bar {\ntop: 0;\n}\n.fixed.bottom #header-bar {\nbottom: 0;\n}\n#header-bar {\nborder-width: 0;\ntransition: all .1s .05s ease-in-out;\n}\n:root.centered-links #shortcuts {\nwidth: 300px;\ntext-align: right;\n}\n:root.centered-links #header-bar {\ntext-align: center;\n}\n:root.centered-links #custom-board-list {\nposition: relative;\nleft: 150px;\n}\n.fixed.top #header-bar {\nborder-bottom-width: 1px;\n}\n.fixed.bottom #header-bar {\nbox-shadow: 0 -1px 2px rgba(0, 0, 0, .15);\nborder-top-width: 1px;\n}\n.fixed.bottom #header-bar .menu-button i {\nborder-top: none;\nborder-bottom: 6px solid;\n}\n#board-list {\ntext-align: center;\n}\n.fixed #header-bar.autohide:not(:hover) {\nbox-shadow: none;\ntransition: all .8s .6s cubic-bezier(.55, .055, .675, .19);\n}\n.fixed.top #header-bar.autohide:not(:hover) {\nmargin-bottom: -1em;\n-webkit-transform: translateY(-100%);\ntransform: translateY(-100%);\n}\n.fixed.bottom #header-bar.autohide:not(:hover) {\n-webkit-transform: translateY(100%);\ntransform: translateY(100%);\n}\n#scroll-marker {\nleft: 0;\nright: 0;\nheight: 10px;\nposition: absolute;\n}\n:root:not(.autohide) #scroll-marker {\npointer-events: none;\n}\n#header-bar #scroll-marker {\ndisplay: none;\n}\n.fixed #header-bar #scroll-marker {\ndisplay: block;\n}\n.fixed.top #header-bar #scroll-marker {\ntop: 100%;\n}\n.fixed.bottom #header-bar #scroll-marker {\nbottom: 100%;\n}\n#header-bar a:not(.entry):not(.close) {\ntext-decoration: none;\npadding: 1px;\n}\n#header-bar input {\nmargin: 0;\nvertical-align: bottom;\n}\n#shortcuts:empty {\ndisplay: none;\n}\n.brackets-wrap::before {\ncontent: \"\\00a0[\";\n}\n.brackets-wrap::after {\ncontent: \"]\\00a0\";\n}\n.dead-thread,\n.disabled,\n.expand-all-shortcut {\nopacity: .45;\n}\n#shortcuts {\nfloat: right;\n}\n.shortcut {\nmargin-left: 3px;\n}\n#navbotright,\n#navtopright {\ndisplay: none;\n}\n#toggleMsgBtn {\ndisplay: none !important;\n}\n.current {\nfont-weight: bold;\n}\n/* 4chan X link brackets */\n.fourchanx-link::after {\ncontent: \"]\";\n}\n.fourchanx-link::before {\ncontent: \"[\";\n}\n/* Notifications */\n#notifications {\nposition: fixed;\ntop: 0;\nheight: 0;\ntext-align: center;\nright: 0;\nleft: 0;\ntransition: all .8s .6s cubic-bezier(.55, .055, .675, .19);\n}\n.fixed.top #header-bar #notifications {\nposition: absolute;\ntop: 100%;\n}\n.notification {\ncolor: #FFF;\nfont-weight: 700;\ntext-shadow: 0 1px 2px rgba(0, 0, 0, .5);\nbox-shadow: 0 1px 2px rgba(0, 0, 0, .15);\nborder-radius: 2px;\nmargin: 1px auto;\nwidth: 500px;\nmax-width: 100%;\nposition: relative;\ntransition: all .25s ease-in-out;\n}\n.notification.error {\nbackground-color: hsla(0, 100%, 38%, .9);\n}\n.notification.warning {\nbackground-color: hsla(36, 100%, 38%, .9);\n}\n.notification.info {\nbackground-color: hsla(200, 100%, 38%, .9);\n}\n.notification.success {\nbackground-color: hsla(104, 100%, 38%, .9);\n}\n.notification a {\ncolor: white;\n}\n.notification > .close {\npadding: 6px;\ntop: 0;\nright: 5px;\nposition: absolute;\n}\n.message {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\npadding: 6px 20px;\nmax-height: 200px;\nwidth: 100%;\noverflow: auto;\n}\n\n/* Settings */\n:root.fourchan-x body {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\n}\n#overlay {\nbackground-color: rgba(0, 0, 0, .5);\ntop: 0;\nleft: 0;\nheight: 100%;\nwidth: 100%;\n}\n#fourchanx-settings {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\nbox-shadow: 0 0 15px rgba(0, 0, 0, .15);\nheight: 600px;\nmax-height: 100%;\nwidth: 900px;\nmax-width: 100%;\nmargin: auto;\npadding: 3px;\ntop: 50%;\nleft: 50%;\n-moz-transform: translate(-50%, -50%);\n-webkit-transform: translate(-50%, -50%);\ntransform: translate(-50%, -50%);\n}\n#fourchanx-settings > nav {\npadding: 2px 2px 0;\nheight: 15px;\n}\n#fourchanx-settings > nav a {\ntext-decoration: underline;\n}\n#fourchanx-settings > nav a.close {\ntext-decoration: none;\npadding: 2px;\n}\n.section-container {\noverflow: auto;\nposition: absolute;\ntop: 2.1em;\nright: 5px;\nbottom: 5px;\nleft: 5px;\npadding-right: 5px;\n}\n.sections-list {\npadding: 0 3px;\nfloat: left;\n}\n.credits {\nfloat: right;\n}\n.tab-selected {\nfont-weight: 700;\n}\n.section-sauce ul,\n.section-advanced ul {\nlist-style: none;\nmargin: 0;\n}\n.section-sauce ul {\npadding: 8px;\n}\n.section-advanced ul {\npadding: 0px;\n}\n.section-sauce li,\n.section-advanced li {\npadding-left: 4px;\n}\n.section-main label {\ntext-decoration: underline;\n}\n.section-filter ul {\npadding: 0;\n}\n.section-filter li {\nmargin: 10px 40px;\n}\n.section-filter textarea {\nheight: 500px;\n}\n.section-sauce textarea {\nheight: 350px;\n}\n.section-advanced .field[name=\"boardnav\"] {\nwidth: 100%;\n}\n.section-advanced textarea {\nheight: 150px;\n}\n.section-advanced .archive-cell {\nmin-width: 160px;\ntext-align: center;\n}\n.section-advanced #archive-board-select {\nposition: absolute;\n}\n.section-advanced .note {\nfont-size: 0.8em;\nfont-style: italic;\nmargin-left: 10px;\n}\n.section-advanced .note code {\nfont-style: normal;\nfont-size: 11px;\n}\n.section-keybinds .field {\nfont-family: monospace;\n} \n#fourchanx-settings fieldset {\nborder: 1px solid;\nborder-radius: 3px;\n}\n#fourchanx-settings legend {\nfont-weight: 700;\n}\n#fourchanx-settings textarea {\nfont-family: monospace;\nmin-width: 100%;\nmax-width: 100%;\n}\n#fourchanx-settings code {\ncolor: #000;\nbackground-color: #FFF;\npadding: 0 2px;\n}\n.unscroll {\noverflow: hidden;\n}\n\n/* Announcement Hiding */\n:root.hide-announcement #globalMessage {\ndisplay: none;\n}\na.hide-announcement {\nfloat: left;\n}\n\n/* Unread */\n#unread-line {\nmargin: 0;\nborder-color: rgb(255,0,0);\n}\n\n/* Thread Updater */\n#updater {\nbackground: none;\nborder: none;\nbox-shadow: none;\n}\n#updater > .move {\npadding: 5px 3px 0px;\nmargin-bottom: -3px;\n}\n#updater > div:last-child {\ntext-align: center;\n}\n#updater input[type=number] {\nwidth: 4em;\n}\n:root.float #updater {\npadding: 0px 3px;\n}\n.new {\ncolor: limegreen;\n}\n#update-status.new {\nmargin-right: 5px;\n}\n#update-timer {\ncursor: pointer;\n}\n\n/* Thread Watcher */\n#thread-watcher {\nposition: absolute;\n}\n#thread-watcher {\npadding-bottom: 3px;\npadding-left: 3px;\noverflow: hidden;\nwhite-space: nowrap;\nmin-width: 136px;\nmax-height: 92%;\noverflow-y: auto;\n}\n#thread-watcher .menu-button {\nbottom: 1px;\n}\n:root.fixed-watcher #thread-watcher {\nposition: fixed;\n}\n:root:not(.fixed-watcher) #thread-watcher:not(:hover) {\nmax-height: 210px;\noverflow-y: hidden;\n}\n#thread-watcher > .move {\npadding-top: 3px;\n}\n#watched-threads > div {\nmax-width: 250px;\noverflow: hidden;\npadding-left: 3px;\npadding-right: 3px;\ntext-overflow: ellipsis;\n}\n#thread-watcher a {\ntext-decoration: none;\n}\n#thread-watcher .move>.close {\nposition: absolute;\nright: 0px;\ntop: 0px;\npadding: 0px 4px;\n}\n.watcher-toggler {\npadding-top: 18px;\nwidth: 18px;\nheight: 0px;\ndisplay: inline-block;\nbackground-repeat: no-repeat;\nopacity: 0.2;\nposition: relative;\ntop: 1px;\n}\n.watcher-toggler.watched {\nopacity: 1;\n}\n\n\n/* Thread Stats */\n#thread-stats {\nbackground: none;\nborder: none;\nbox-shadow: none;\n}\n:root.float #post-count, :root.float #file-count {\npointer-events: none;\n}\n:root.float #thread-stats {\npadding: 0px 3px;\n}\n\n/* Quote */\n.deadlink {\ntext-decoration: none !important;\n}\n.backlink.deadlink:not(.forwardlink),\n.quotelink.deadlink:not(.forwardlink) {\ntext-decoration: underline !important;\n}\n.inlined {\nopacity: .5;\n}\n#qp input, .forwarded {\ndisplay: none;\n}\n.quotelink.forwardlink,\n.backlink.forwardlink {\ntext-decoration: none;\nborder-bottom: 1px dashed;\n}\n.filtered {\ntext-decoration: underline line-through;\n}\n:root.hide-backlinks .backlink.filtered {\ndisplay: none;\n}\n.inline {\nborder: 1px solid;\ndisplay: table;\nmargin: 2px 0;\n}\n.inline .post {\nborder: 0 !important;\nbackground-color: transparent !important;\ndisplay: table !important;\nmargin: 0 !important;\npadding: 1px 2px !important;\n}\n#qp > .opContainer::after {\ncontent: '';\nclear: both;\ndisplay: table;\n}\n#qp .post {\nborder: none;\nmargin: 0;\npadding: 2px 2px 5px;\n}\n#qp img {\nmax-height: 80vh;\nmax-width: 50vw;\n}\n.qphl {\noutline: 2px solid rgba(216, 94, 49, .7);\n}\n:root.highlight-own .yourPost > .reply,\n:root.highlight-you .quotesYou > .reply {\nborder-left: 2px solid rgba(221,0,0,.5);\n}\n/* Quote Threading */\n.threadContainer {\nmargin-left: 20px;\nborder-left: 1px solid rgba(128,128,128,.3);\n}\n.threadOP {\nclear: both;\n} \n\n/* File */\n.fileText:hover .fntrunc,\n.fileText:not(:hover) .fnfull,\n.expanded-image > .post > .file > .fileThumb > img[data-md5],\n:not(.expanded-image) > .post > .file > .fileThumb > .full-image {\ndisplay: none;\n}\n.expanding {\nopacity: .5;\n}\n:root.fit-height .full-image {\nmax-height: 100vh;\n}\n:root.fit-width .full-image {\nmax-width: 100%;\n}\n:root.gecko.fit-width .full-image {\nwidth: 100%;\n}\n#ihover {\n-moz-box-sizing: border-box;\nbox-sizing: border-box;\nmax-height: 100%;\nmax-width: 75%;\npadding-bottom: 16px;\n}\n.fappeTyme .thread > .noFile,\n.fappeTyme .threadContainer > .noFile {\ndisplay: none;\n}\n\n/* Index/Reply Navigation */\n#navlinks {\nfont-size: 16px;\ntop: 25px;\nright: 10px;\n}\n\n/* Filter */\n.opContainer.filter-highlight {\nbox-shadow: inset 5px 0 rgba(255, 0, 0, .5);\n}\n.filter-highlight > .reply {\nbox-shadow: -5px 0 rgba(255, 0, 0, .5);\n}\n\n/* Spoiler text */\n:root.reveal-spoilers s {\ncolor: white !important;\n}\n\n/* Thread & Reply Hiding */\n.hide-thread-button,\n.hide-reply-button {\nfloat: left;\nmargin-right: 2px;\n}\n.stub ~ * {\ndisplay: none !important;\n}\n.stub input {\ndisplay: inline-block;\n}\n\n/* QR */\n:root.hide-original-post-form #postForm,\n:root.hide-original-post-form .postingMode,\n:root.hide-original-post-form #togglePostForm,\n#qr.autohide:not(.has-focus):not(:hover) > form,\n.postingMode ~ #qr select,\n#file-n-submit:not(.has-file) #qr-filerm {\ndisplay: none;\n}\n#qr select,\n#dump-button,\n.remove,\n.captcha-img {\ncursor: pointer;\n}\n#qr {\nz-index: 20;\nposition: fixed;\npadding: 1px;\nborder: 1px solid transparent;\nmin-width: 300px;\nborder-radius: 3px 3px 0 0;\n}\n#qrtab {\nborder-radius: 3px 3px 0 0;\n}\n#qrtab {\nmargin-bottom: 1px;\n}\n#qr .close {\nfloat: right;\npadding: 0 3px;\n}\n#qr .warning {\nmin-height: 1.6em;\nvertical-align: middle;\npadding: 0 1px;\nborder-width: 1px;\nborder-style: solid;\n}\n.qr-link-container {\ntext-align: center;\n}\n.persona {\nwidth: 248px;\nmax-width: 100%;\nmin-width: 100%;\n}\n#dump-button {\nwidth: 10%;\nmargin: 0;\nmargin-right: 4px;\nfont: 13px sans-serif;\npadding: 1px 0px 2px;\nopacity: 0.6;\n}\n.persona .field:not(#dump) {\nwidth: 95px;\nmin-width: 33.3%;\nmax-width: 33.3%;\n}\n#qr textarea.field {\nheight: 14.8em;\nmin-height: 9em;\n}\n#qr.has-captcha textarea.field {\nheight: 9em;\n}\ninput.field.tripped:not(:hover):not(:focus) {\ncolor: transparent !important;\ntext-shadow: none !important;\n}\n#qr textarea {\nresize: both;\n}\n.captcha-img {\nmargin: 0px;\ntext-align: center;\nbackground-image: #fff;\nfont-size: 0px;\nmin-height: 59px;\nmin-width: 302px;\n}\n.captcha-input {\nwidth: 100%;\nmargin: 1px 0 0;\n}\n.captcha-input.error:focus {\nborder-color: rgb(255,0,0) !important;\n}\n.field {\n-moz-box-sizing: border-box;\nmargin: 0px;\npadding: 2px 4px 3px;\n}\n#qr textarea {\nmin-width: 100%;\n}\n#qr [type='submit'] {\nwidth: 25%;\nvertical-align: top;\n}\n:root.webkit #qr [type='submit'] {\nheight: 24px;\n}\n/* Fake File Input */\n#qr-filename,\n.has-file #qr-no-file {\ndisplay: none;\n}\n#qr-no-file,\n.has-file #qr-filename {\ndisplay: inline-block;\npadding: 0px 4px;\nmargin-bottom: 2px;\noverflow: hidden;\ntext-overflow: ellipsis;\nmax-width: 88%;\n}\n#qr-no-file {\ncolor: #AAA;\n}\n#qr-filename-container {\n-moz-box-sizing: border-box;\ndisplay: inline-block;\nposition: relative;\nwidth: 100px;\nmin-width: 74.6%;\nmax-width: 74.6%;\nmargin-right: 0.4%;\nmargin-top: 1px;\noverflow: hidden;\npadding: 2px 1px 0;\nheight: 22px;\n}\n#qr-filename-container:hover {\ncursor: text;\n}\n#qr-extras-container {\nposition: absolute;\nright: 0px;\n}\n#qr-filerm {\nmargin-right: 2px;\nz-index: 2;\n}\n#file-n-submit {\nheight: 23px;\n}\n#qr input[type=file] {\nvisibility: hidden;\nposition: absolute;\n}\n/* Thread Select / Spoiler Label */\n#qr select {\nfloat: right;\n}\n#qr.has-spoiler .has-file #qr-spoiler-label {\nwidth: 6.7%;\nmin-width: 6.7%;\nmax-width: 6.7%;\ndisplay: inline-block;\ntext-align: center;\nvertical-align: top;\n}\n#qr.has-spoiler #file-n-submit:not(.has-file) #qr-spoiler-label {\ndisplay: none;\n}\n#qr.has-spoiler .has-file #qr-filename-container {\nmax-width: 67.9%;\nmin-width: 67.9%;\n}\n#qr-spoiler-label input {\nposition: relative;\ntop: 3px;\n}\n/* Dumping UI */\n.dump #dump-list-container {\ndisplay: block;\n}\n#dump-list-container {\ndisplay: none;\nposition: relative;\noverflow-y: hidden;\nmargin-top: 1px;\n}\n#dump-list {\noverflow-x: auto;\noverflow-y: hidden;\nwhite-space: nowrap;\nwidth: 248px;\nmax-width: 100%;\nmin-width: 100%;\n}\n#dump-list:hover {\noverflow-x: auto;\n}\n.qr-preview {\n-moz-box-sizing: border-box;\ncounter-increment: thumbnails;\ncursor: move;\ndisplay: inline-block;\nheight: 90px;\nwidth: 90px;\npadding: 2px;\nopacity: .5;\noverflow: hidden;\nposition: relative;\ntext-shadow: 0 1px 1px #000;\n-moz-transition: opacity .25s ease-in-out;\nvertical-align: top;\nbackground-size: cover;\n}\n.qr-preview:hover,\n.qr-preview:focus {\nopacity: .9;\n}\n.qr-preview::before {\ncontent: counter(thumbnails);\ncolor: #fff;\nposition: absolute;\ntop: 3px;\nright: 3px;\ntext-shadow: 0 0 3px #000, 0 0 8px #000;\n}\n.qr-preview#selected {\nopacity: 1;\n}\n.qr-preview.drag {\nbox-shadow: 0 0 10px rgba(0,0,0,.5);\n}\n.qr-preview.over {\nborder-color: #fff;\n}\n.qr-preview > span {\ncolor: #fff;\n}\n.remove {\nbackground: none;\ncolor: #e00;\nfont-weight: 700;\npadding: 3px;\n}\na:only-of-type > .remove {\ndisplay: none;\n}\n.remove:hover::after {\ncontent: \" Remove\";\n}\n.qr-preview > label {\nbackground: rgba(0,0,0,.5);\ncolor: #fff;\nright: 0;\nbottom: 0;\nleft: 0;\nposition: absolute;\ntext-align: center;\n}\n.qr-preview > label > input {\nmargin: 0;\n}\n#add-post {\ncursor: pointer;\nfont-size: 2em;\nposition: absolute;\ntop: 50%;\nright: 10px;\n-moz-transform: translateY(-50%);\n}\n.textarea {\nposition: relative;\n}\n:root.webkit .textarea {\nmargin-bottom: -2px;\n}\n#char-count {\ncolor: #000;\nbackground: hsla(0, 0%, 100%, .5);\nfont-size: 8pt;\nposition: absolute;\nbottom: 1px;\nright: 1px;\npointer-events: none;\n}\n\n/* Menu */\n.menu-button {\ndisplay: inline-block;\nposition: relative;\ncursor: pointer;\n}\n.menu-button i {\nborder-top: 6px solid;\nborder-right: 4px solid transparent;\nborder-left: 4px solid transparent;\ndisplay: inline-block;\nmargin: 2px;\nvertical-align: middle;\n}\n#menu {\nposition: fixed;\noutline: none;\n}\n.entry {\nborder-bottom: 1px solid rgba(0,0,0,.25);\ncursor: pointer;\ndisplay: block;\noutline: none;\npadding: 3px 7px;\nposition: relative;\ntext-decoration: none;\nwhite-space: nowrap;\n}\n.left>.entry.has-submenu {\npadding-right: 17px !important;\n}\n.entry:last-child {\nborder-bottom: 0;\n}\n.has-submenu::after {\ncontent: \"\";\nborder-left: .5em solid;\nborder-top: .3em solid transparent;\nborder-bottom: .3em solid transparent;\ndisplay: inline-block;\nmargin: .3em;\nposition: absolute;\nright: 3px;\n}\n.left .has-submenu::after {\nborder-left: 0;\nborder-right: .5em solid;\n}\n.submenu {\ndisplay: none;\nposition: absolute;\nleft: 100%;\ntop: -1px;\n}\n.focused .submenu {\ndisplay: block;\n}\n.imp-exp-result {\nposition: absolute;\ntext-align: center;\nmargin: auto;\nright: 0px;\nleft: 0px;\nwidth: 200px;\n}\n.export, .import {\ncursor: pointer;\ntext-decoration: none !important;\n}\n/* Link Title Favicons */\n.linkify.YouTube {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAMCAYAAABr5z2BAAABIklEQVQoz53LvUrDUBjG8bOoOammSf1IoBSvoCB4JeIqOHgBLt6AIMRBBQelWurQ2kERnMRBsBUcIp5FJSBI5oQsJVkkUHh8W0o5nhaFHvjBgef/Mq+Q46RJBMkI/vE+aOus956tnEswIZe1LV0QyJ5sE2GzgZfVMtRNIdiDpccEssdlB1mW4bvTwdvWJtRdErM7U+8S/FJykCRJX5qm+KpVce8UMNLRLbulz4iSjTAMh6Iowsd5BeNadp3nUF0VlxAEwZBotXC0Usa4ll3meZdA1iguwvf9vpvDA2wvmKgYGtSud8suDB4TyGr2PF49D/vra9jRZ1BVdknMzgwuCGSnZEObwu6sBnVTCHZiaC7BhFx2PKdxUidiAH/4lLo9Mv0DELVs9qsOHXwAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.Vimeo {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAASJJREFUOE9jYAAC7ln7/pODQXrBmq333PvPu/YaSRikB6QXbACpmmHqsRoAMll7+20UQ0H8tmuv/pdffPFfZtNNuByGASBFIPDh5x+4IV6HHoDFYGDJgw+YBoBMBUkgA5BtIKduuvvy//svX+FSB+88wTTAc+/t/83bj/0HScLA5BPXwc7lKJ36f+L6XXDxhUfOYxrAPWUnWKFp9UQUm3iWQxSDXAEDSX3zcIcB96wD/x+8eA1XDNKMHAYg20GW4Y0FkCIYAAUqzEBQOIBciRzlWKMxZelOlMCEcVxq+jHSC1YDJPs3YBgA8jey0/F6ARRwsFAHORukmat9NdbUijMpg/wKcrJodDFOzSBXwA3Alh9AToZFI7a8Asu98BxJbnYGAJb5vYLDANzSAAAAAElFTkSuQmCC') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.SoundCloud {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABsklEQVQ4y5WTy2pUQRCGv2rbzDjJeAlIBmOyipGIIJqFEBDElwh4yULGeRFXPoEIBl/AvQ/gC2RnxCAoxijiwks852S6+3dxzslcHJCpTXVX11/Xv0097gLPgVNMJxnQNfX4zsqleWbnpoMf/oa9d988MM9MC/rp+E0a+A0dsVobMNMCOO8B6McRoABJI+A6gJmN3D2A8jgEBCEkSEMBrcrsDAzDWWn3AjgKFaDMmgRqniGFgsaDp1jrLOngDf1XT1D+A1dFc4MKAkkiCVKjjVu7g9+4Rzx4i1u6hjXbuMWr0O5QPNvCu7IaCZwEKQukLGDrm5x8uI0tr6MkiGlkiv7yLfzN+6S5i6QsIMABkEfcxhbWWYMkVAOjxvYAjc3HNHrbKI9VBQBFwF25XQKSBjqIf1YBuAurEMrczgDygD6/x2LCpFLXLUyQ+PoldphhBhYfIX09XU1+Flaukz7uYqs3SHs7cG4BmTsmkBUF9mmXEwa28BNLPaQPLepuNcbGSWQquQC2/Kdcox1FUGkcB0ykck1nA2+wTzMs8stGnP4rbWGw74EuS/GFQWfK7/wF6P4F7fzIAYkdmdEAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.audio {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAitJREFUOE9jYCAWKJWwavr0KyXWb/FIbDtUFFyzJx6nVofE2Xo5nXsj0rqPNSR0nVkR2Hjmgmfd+U9Otdf+m5Vf/6+SfeU/R9ChVVgNYDRtlfJuuPA/rPfe/4QpD/6nznj0P27Kw/9unff/69Xf+69c/+C/SO7N/0z+OAxgMmmRCe++/r9i3ev/KWvf/vdY8PK/bt/9/wrNV3/IN5y/IVt1YqNg4pGTTP4HsbuA2bhZ2qvpyn+xjIObxAp3VwqlrgngLFyryVy5nhPmZJHANS2cwYexG8BmVC/pWn3hP4NZlzWuQDJI3dIiFnUUuwEsQAOcq87jNcC7fHeLUtJxHF4AGmBWeAavAWH1+1rUUk7giAWjOknllON4DXAs2NEiG4/DBQxAF/CFHfrPYI4jDFSLuJVjNrUJhB/B7gIGo1pJRt99GAZYJK7wLJ1z7Xzl4vu/7aqv/GRBj0bjqAX2qb0nJ7mXH17C4HcUxQA+hymWtSue/C5a9up/9Ozn/7Vr7v1nRY7GqMb91T3b3v6vWvPmf/S0p/9ZQk+DDLCBRSOz06Jqk+o7/21nvfqvsebDf7kZL/5zBaxphkezd+OFn7HzXvz3Wvjmv9a8N//5Ek//ZTBpVYUrMG2X5wjcdl68+uI/wa5Lr3hSNjczGFeywOVZ/bbcVGp//F9izfv/Ql03f3P4LC/HSEQquYwMFnUCDJ7dzBhyjGZNQpye89M5gpfnMvtNUyE2h4PUAQBovvT7lyNljwAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.LiveLeak {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAydJREFUOE9Nk1tIk2EYx79NyUNqTk0o6KYrnZeChodLDxfeZpCbJk4RXU5Nm7tYRYhiYXbQlaeGutyW2gxtpB1RIyKDEjKwA6Ti2dR5KNDn+fq/S6TBj/f93r3P732e53s/qfnkSdej4GB2SBLbwf+jmB+gUMgOheLg/z7EdCUnO6Ref392SpK8Hyh3I+gBwBo7lUp2xcbyQEoKD6alyQOpqd754/h4FjJXZCRJTl9ftmEzoK5/wdQJxPgkLY2WV1dpc2uLtnZ2eHNnhza3t2nd46GhjAzuValY6jx0iIfS03msoIDuQ9COQCtoUSjohU5HuwgaN5loeXycd3d3aW9vzwvW2K5SkdTi58fvzGb+3tdHFggA3QONEAzn59PvjQ1yqNX0zenkvX0B4ffWaGRraChJd/385JGqKvlzTw/fRqOaIGkEd1DjU52O/3g83BkTw5MOh7yJuUCUM2o0yi2hoSw1IIOhykr+YLNRHYKu4XQvyKA/N5c8yMCCDD7Z7bz26xcJ1rH2rKKCG0UJdRAMlJbyG6uVrkJQjWAB5tSbk0Nr2HwDgvcQiIYur6zQyvo6ucvLueHIEZKuQPBQr+dXra1kRuqXEOwFArtWSytra1QdFUVjNhvPLS3R3OIiLUDUD0F1WBhJJtwDW2Ehu5uaqBICI4IFlRB0QLCEzaboaHrd0cHzCBYsIIuesjK+LAQXkEFrXh676uupGCWcR6AeghLQptGQONUAwfOuLp6Zn6eZuTmaXVig7pISrhI90ENgQbdHhoep32JhFzLpu3WLio8epUYIfs7OUjF6UKJW88XERLqYkEBNej11oG8XhCAvMFAuOn5cNiclsTkhQTbhmpri4lgbEMANWi1DwC/xit3t7bK7rY0Fo4OD3G4wyEURESzloAdnceezlErK8vH5N4KzPj50PTOTfkxP0+THj/RlYoInJyZI8HVqim5qNFwQHk7SucBAPo2PKRMNPLM/4pnFszYkhJsNBu6uqWFHba1sr61lQSveQFZQkFx07BhJmhMnrLn4NLMPH/aSExR0QDbmWhwgyEapwDvXoDxdWBiXnjrV/Bdm2kYUxLwmEgAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.Vocaroo {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAw9JREFUOE9jYMABuMwYmCyTJKUCGlSnFSy02TTzeOyCiQcDViX26qVz2TAyYtWmEMwuoZ3M7V40LcB79pHkc0svpvzY8jD//87nxf+3Pyn8v/ZO8v+VNyP/2mZJumI1QCWSI8232Hjumitlfw5+qPp/9l8TCt76JP//xkdx/wsXWCzjtWFkwTCkbWFe9plPk/+ga4Txz/xt/D/hkN//gMXif21a+NbyWjIwoRiy6GDT5rP/mlFsPfyp5n/NpOj/22+0gMUXXIz/H7hC/L/bFKFbPDZMrHAD5H35OPt2J9zacDv/f3V7xv9FhwrBGubsT/1//Pjx/1GJ/mD+/nfl/1v3Ovy3KRJNQbHdOlXCvOO03/+pm1P/v3v37n90hhtYw9HPtf8Xb2v937cmHswHeWPRxYj/LvkK3igGKARwicTO07118H3V/5kbi/4vPZMJtK3s/6YH2f+Pfq1B8VbjWrdnMu5s4nAD9CNFhKwz5DTUvLl419zKvAcLtG1P84BRl/b/5M/6/6f/NPzf/qzo84yj0Uus0xUU4Zor54bm9+4OfZG02OCuoAMTb9ZkC9ull1Nvrr2Z+XvRpaRfc65H/68F+jl9svEhzyLFWoccWVc+eyTHq/twydjlKRln7jX9bNMkMJnbhoFRL1xCqmKx6/yi2fYXa/c5/e846PV/5fW0/7OPx/yfcjzop34ulxdGGvDuU8mMXaX507lBuiN6ueadmQeT/p/93vf/1O+G//sP5fw/eL3o/5JLif8zVxs+Tlir9S26UyeFQQvJGBE7FvaFZ9LfN+1y+WjbItSb3GmXvXd15v8zroH/HxgE/D+aGPx/18vi/z07PeZNPRKxe/Kh0Ae8toxscCO4zBkYXArk9C1SxJUYjBkYPPIVtbbuTftz3cz//2O9wP/75iSAXdO72/dt2HL5F6YlfBW4MiJYXMiBiW3t7azHBx+V/t89N+H/8a+1//e9K/9attDp5LQjYX8SuvVL8RoAkmxa65299Erq1FnHo0qrl7t4BddriIs4MrM3rfWcFd+pGwVSAwBZ0bKP8yrZPAAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.pastebin {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAtZJREFUOE+NU91LWmEc7sJtQew/2MUY7INg7CLY3W5GMHazyzEQo9UmfYxZTbAiVlgRqLMSZ+XnDC3z2+Y0+8JGakKZTtR0Tl2wtgtLLQh29cz3ZZ3h3Q68vOc95zzP73l+z+/U1f292O09DRxubxOH23P//1bvtQts3dPnry7LZnXJhcUl5Avf8dHtwY+fv2AyW5DOfIXFakMm+w0G4wISyRRm55TQG0y/Wzv6mikJ52Xf9TmVBoFAAD6fDwqFAqFQCJubmzCbzZiensbp6SmkUikikQi0Wi0kEgm6ewVaStDCfXPDandifn6egoaGhrCzswO1Wg2Hw4HBwUGk02kIBAL4/X4IhUJMTk6ii8dfYggy2RwymQzOz88Rj8dRLpexv7+PSqWCYDCIQqGAra0tJBIJrK2t0XdVAjNDEIl+wfj4OEqlEq2wt7dHrchkMmrBYDCAz+fTIjweD7FYrJbgIJOlgLOzM8jlcip1eXmZ2rFarVAqlRCLxcjlchCJRFRljYJYPAG32418Pg+n04lsNouVlRUcHh7C4/FQIOlHNBqlezgcJgQWxkIgGMbExASVNjY2hvX1dVo9mUzS5wREFLhcLrqTcw2B//M2RkdHodPp4PV6oVKpqH+SCom3v7+fNnF4eJiJusbCJ6+PviSyScakiaR5RIHRaKQpmEwmbAdCeD8zB6vdhebHT8SMhcUlC83bbrdTJRsbG3RwiCVCRNJJpDIoVeNNJJJQzKryV+rrmxiCtyNCCmaz2VhdXQWXy6XDpNfrodFoYLXZUTw+pk222Z3lW3ca26rgSwzBwqIZAwMDlITMAVEwNTVFR5fEJpK8Qyp1AJvDVbrTeLenCmxgfiZ22+urCtWHyu7uLp2wVCpFKx0dHaFYLOLk5KT6Y9kgk89kb95ubK0BX7A8a+1qannRLeW0daj/rU51S3tn9dypfvDw0QiLxbpX/Z7FVK7e/AEj4Wf24/2f5AAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.gist {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAk1JREFUeNqUkzuIE1EUhv955MnsbB6r4kYQLUQQFncV3SnCIqJsoWGDYOGjsIiCtY2Kla1sjLBIsFFcXJC1kaSwENQmXUQSRSUSjCQSTCbkbR4z47lXEgtBNwcu3DNzvvO8R8jlcj7LshKmaWqYQERRTAmCcEru9/sJr9er0QF92BJMAVGr1TQ6CeZAc7lcGAwGkyQAxpTLZU0eDoc8crfbRTgcRjAYRCQSYSmi1WpxY7fbjU6ng1gshmaziXg8zhnGIpVKWbquW9ls1mLZsaMoiqWq6lgnBxY55He/328Vi0XOMFZmqVMD4fF4QBAajcY48khY9JE4HA4enTGMFVkaTHmy+ZzD/5NSqYSNB484w1h55ODO3TVu4FXcWDywl24Cmp0e1WBhyuWELAtIf/qKUrWOONmev3Lpt4NRCXq1gplpBS/v3cDc0nGg9h1o1ZkfwO4Atu1B8cM7HLt8k37V/y5B2b4bJxf2Y+7oEbyJrkMvUjki0YYJ03LidfQxAt4dOHdCw5RdGZcgGobBlQtnV/BDr1GfDai7ZiHZZRi9PoY/e5SCCTUwC9gk1GmMh5YWOcNYkR4Sv1y9uAJbYB82N57h4OnDmN7phjQ0qUkWRJuB+TMaPn/5iFfvv+Ha7eucYey4iWw8q6tRJJNJ3Fp7ClUawEkViBTfkCR0YUNTVHD/4Tpm/P4/U2CeKpUKfD4fJDIMhUKEhP45St50XedZyLQY6Xw+v8AUemVb2oNqtYpCocCWKi2TLLfb7ReZTGZ+kmUi7i2VvfxLgAEAZChMriPcl+IAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.image {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAs5JREFUOE+lk/tvi1EYx98/xT8gW4REIpGFMEQWl2FiM9ZMZhm2xRAyOsmujFFmdFRHu0tWm87UypxStr69zPauN5e5rHVp3IYhbOvHy+wHEQlxkm+ek+d8nm9OznkeSfrfldmgJC7QyUlTymsJTfuTZ25z4HdWYwyLreYhtpgekGPw0+kKvo1Eo+IXRSIiEhkWZuc9tqnsJD9EqTUopCxjSGTpB0iueczSo1HyW8cpsExQ1DbxI2pt45j9cXpexul4FEd79RnZphAa/SD7WvuFtO6UItbU9LC+YQxNI2w0wwYT5LRAdhOU3oBTIXC9gXP3oUSGgz2vST3gYHejR0jptT1C332f8yrUEYHrz8CgxDnpm6DKCUfc0KnmXa/AEVPPwnDcD0cvetA2uYRk67Ive/lpjO7YBO1PPuF8Df3vwf4cbNE4tqdw7YVq8HYyHx6FvhE1hkMEg8HDUqvFkjT4aIjMqkqyqkswDSrcfBfH+Q561YLAZ/B+BLda6FXlU/cPv0AoEPhuoP1h4Av7Wbh9E/Py15NWWUjeSR3nZDfeN+N0DY9hG/7K1eGP3P0S5/EYRFUF/IOTBrUXHPm9fT6mr1xEwupkZqxbzLyiDJYUZ5NSnkdqdSHpxyrYdFpPgdmAsdfJwPMI/Yr65bf7tZLGGBQ7DNdJWFtIYvoOZmbuZE7OXpIKKli86zAr9p9gTVktWTVnKTI2U95uRWe3U2IJUDbVB5p6hVm5x5m9Vc/cnedZUNzC8lILaQesZBy6hEZ3maKzgvJWFzVWD9XtXvVGQbSWASFtMATVRlJIKbOTWtlJXaeXepuPM1f6MNp9GLt8mLvvYLmp0OhQ2Fwvk6m7xaqDTvY0eYWUVtcnllXfYlGpnfklVuraHHg8HjxuN+6fktUHlWWZPaZeUo/ILK0UKttBcbNbSB9GP0yLxWJJUxoZGUn80zD9C/vXQ/4NHY10h3M1zmQAAAAASUVORK5CYII=') center left no-repeat!important;\npadding-left: 18px;\n}\n.linkify.InstallGentoo {\nbackground: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAklJREFUOE9jYEAAASBTCorZkcSRmTjVCDLziCwG4hfM3EIvGNm44oC6WNEM4WXi5FsEkmfhFX3BxMmfAJSHW9Qr55Px3aZp3X/btq3/hQydPzKysMcCFbBBDeFj4uBdqBJR/gskb1W34j+PmulLoJwbzBJJoMm7dNO7/ntMP/XfpW/v//SKvk+7tl7fvXfTpx5pCdWVSiHFv1wnHQbLi9sE/Wdk5SwBauaCGQB3gUPb5v+7Lr/8/+fvr/9fv/z+f+Pyr/9bV735l9Wy/79Dx/b/Nk0bsLoAHgbeAVHv/v77/f8f0IB7N7+cu3DuecK54z9+7lzz639e9pK/7HwSWMMA5BJwCJeXtOm/fvVj1fcfv369f//92cN7X6ZcPvf9x6Htv//vXP3r/+T245UEYgpskPTNq08LgN749/PH7/93rv/6f/rw7//nj//4f+bU0zQcUQwWBkdVbGz62y+fv3wHeeXrlz//H9798//qpY//M3KqfzGxc8djiWKwZnBUuWQ2/fr46fv/P39+///x/ff/d69//z97+s7fyMb5/+y7d2GLYriDZikFF/1qXXXj/4Pbv/8/f/jn/5MH316/eP6jVlBAaIt6VO1/jxmn/zv27P7Pp2HxEajLD90ra9Sj6/979O37X73w0n+vqOL/0lJyMVBFq0EGgDSD0oKAlu1/oHg4ugGzVCKqfouYuL1Xj676Iajr8AnJFricGqYc3Bw+Zi6BVUxsXLHAdL6QiYMPFNrwpIxHDsUhgtAMAopKDjQn4pPDF7P45QC4hSmc1eX8WgAAAABJRU5ErkJggg==') center left no-repeat!important;\npadding-left: 18px;\n}\n\n/* General */\n:root.yotsuba .dialog {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.yotsuba .field:focus {\nborder-color: #EA8;\n}\n\n/* Header */\n:root.yotsuba #header-bar, :root.yotsuba #notifications {\nfont-size: 9pt;\ncolor: #B86;\n}\n:root.yotsuba #header-bar a, :root.yotsuba #notifications a {\ncolor: #800000;\n}\n\n/* Settings */\n:root.yotsuba #fourchanx-settings fieldset {\nborder-color: #D9BFB7;\n}\n\n/* Quote */\n:root.yotsuba .backlink.deadlink {\ncolor: #00E !important;\n}\n:root.yotsuba .inline {\nborder-color: #D9BFB7;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.yotsuba #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.yotsuba .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.yotsuba #menu {\ncolor: #800000;\n}\n:root.yotsuba .entry {\nborder-bottom: 1px solid #D9BFB7;\nfont-size: 10pt;\n}\n:root.yotsuba .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.yotsuba .watcher-toggler\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.yotsuba-b .dialog {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.yotsuba-b .field:focus {\nborder-color: #98E;\n}\n\n/* Header */\n:root.yotsuba-b #header-bar, :root.yotsuba-b #notifications {\nfont-size: 9pt;\ncolor: #89A;\n}\n:root.yotsuba-b #header-bar a, :root.yotsuba-b #notifications a {\ncolor: #34345C;\n}\n\n/* Settings */\n:root.yotsuba-b #fourchanx-settings fieldset {\nborder-color: #B7C5D9;\n}\n\n/* Quote */\n:root.yotsuba-b .backlink.deadlink {\ncolor: #34345C !important;\n}\n:root.yotsuba-b .inline {\nborder-color: #B7C5D9;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.yotsuba-b #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.yotsuba-b .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.yotsuba-b #menu {\ncolor: #000;\n}\n:root.yotsuba-b .entry {\nborder-bottom: 1px solid #B7C5D9;\nfont-size: 10pt;\n}\n:root.yotsuba-b .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.yotsuba-b .watcher-toggler\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.futaba .dialog {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.futaba .field:focus {\nborder-color: #EA8;\n}\n\n/* Header */\n:root.futaba #header-bar, :root.futaba #notifications {\nfont-size: 11pt;\ncolor: #B86;\n}\n:root.futaba #header-bar a, :root.futaba #notifications a {\ncolor: #800000;\n}\n\n/* Settings */\n:root.futaba #fourchanx-settings fieldset {\nborder-color: #D9BFB7;\n}\n\n/* Quote */\n:root.futaba .backlink.deadlink {\ncolor: #00E !important;\n}\n:root.futaba .inline {\nborder-color: #D9BFB7;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.futaba #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #F0E0D6;\nborder-color: #D9BFB7;\n}\n:root.futaba .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.futaba #menu {\ncolor: #800000;\n}\n:root.futaba .entry {\nborder-bottom: 1px solid #D9BFB7;\nfont-size: 12pt;\n}\n:root.futaba .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.futaba .watcher-toggler\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.burichan .dialog {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.burichan .field:focus {\nborder-color: #98E;\n}\n\n/* Header */\n:root.burichan #header-bar, :root.burichan #header-bar #notifications {\nfont-size: 11pt;\ncolor: #89A;\n}\n:root.burichan #header-bar a, :root.burichan #header-bar #notifications a {\ncolor: #34345C;\n}\n\n/* Settings */\n:root.burichan #fourchanx-settings fieldset {\nborder-color: #B7C5D9;\n}\n\n/* Quote */\n:root.burichan .backlink.deadlink {\ncolor: #34345C !important;\n}\n:root.burichan .inline {\nborder-color: #B7C5D9;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.burichan #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #D6DAF0;\nborder-color: #B7C5D9;\n}\n:root.burichan .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.burichan #menu {\ncolor: #000000;\n}\n:root.burichan .entry {\nborder-bottom: 1px solid #B7C5D9;\nfont-size: 12pt;\n}\n:root.burichan .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.burichan .watcher-toggler\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.tomorrow .dialog {\nbackground-color: #282A2E;\nborder-color: #111;\n}\n\n/* Header */\n:root.tomorrow #header-bar, :root.tomorrow #notifications {\nfont-size: 9pt;\ncolor: #C5C8C6;\n}\n:root.tomorrow #header-bar a, :root.tomorrow #notifications a {\ncolor: #81A2BE;\n}\n\n/* Settings */\n:root.tomorrow #fourchanx-settings fieldset {\nborder-color: #111;\n}\n\n/* Quote */\n:root.tomorrow .backlink.deadlink {\ncolor: #81A2BE !important;\n}\n:root.tomorrow .inline {\nborder-color: #111;\nbackground-color: rgba(0, 0, 0, .14);\n}\n\n/* QR */\n.tomorrow #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #282A2E;\nborder-color: #111;\n}\n:root.tomorrow .qr-preview {\nbackground-color: rgba(255, 255, 255, .15);\n}\n:root.tomorrow #qr .field {\nbackground-color: rgb(26, 27, 29);\ncolor: rgb(197,200,198);\nborder-color: rgb(40, 41, 42);\n}\n:root.tomorrow #qr .field:focus {\nborder-color: rgb(129, 162, 190) !important;\nbackground-color: rgb(30,32,36);\n}\n\n/* Menu */\n:root.tomorrow #menu {\ncolor: #C5C8C6;\n}\n:root.tomorrow .entry {\nborder-bottom: 1px solid #111;\nfont-size: 10pt;\n}\n:root.tomorrow .focused.entry {\nbackground: rgba(0, 0, 0, .33);\n}\n\n/* Watcher Favicon */\n:root.tomorrow .watcher-toggler\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n\n/* General */\n:root.photon .dialog {\nbackground-color: #DDD;\nborder-color: #CCC;\n}\n:root.photon .field:focus {\nborder-color: #EA8;\n}\n\n/* Header */\n:root.photon #header-bar, :root.photon #notifications {\nfont-size: 9pt;\ncolor: #333;\n}\n:root.photon #header-bar a, :root.photon #notifications a {\ncolor: #FF6600;\n}\n\n/* Settings */\n:root.photon #fourchanx-settings fieldset {\nborder-color: #CCC;\n}\n\n/* Quote */\n:root.photon .backlink.deadlink {\ncolor: #F60 !important;\n}\n:root.photon .inline {\nborder-color: #CCC;\nbackground-color: rgba(255, 255, 255, .14);\n}\n\n/* QR */\n.photon #dump-list::-webkit-scrollbar-thumb {\nbackground-color: #DDD;\nborder-color: #CCC;\n}\n:root.photon .qr-preview {\nbackground-color: rgba(0, 0, 0, .15);\n}\n\n/* Menu */\n:root.photon #menu {\ncolor: #333;\n}\n:root.photon .entry {\nborder-bottom: 1px solid #CCC;\nfont-size: 10pt;\n}\n:root.photon .focused.entry {\nbackground: rgba(255, 255, 255, .33);\n}\n\n/* Watcher Favicon */\n:root.photon .watcher-toggler\n{\nbackground-image: url(\"data:image/svg+xml, \");\n}\n"
};
Main.init();
diff --git a/src/Archive/Redirect.coffee b/src/Archive/Redirect.coffee
index 3f3904287..9eaa101c0 100755
--- a/src/Archive/Redirect.coffee
+++ b/src/Archive/Redirect.coffee
@@ -50,8 +50,8 @@ Redirect =
http: true
https: true
software: 'foolfuuka'
- boards: ['adv', 'asp', 'cm', 'i', 'lgbt', 'n', 'o', 'p', 's4s', 't', 'trv']
- files: ['adv', 'asp', 'cm', 'i', 'lgbt', 'n', 'o', 'p', 's4s', 't', 'trv']
+ boards: ['adv', 'asp', 'cm', 'd', 'e', 'i', 'lgbt', 'n', 'o', 'p', 'pol', 's', 's4s', 't', 'trv', 'y']
+ files: ['cm', 'd', 'e', 'i', 'n', 'o', 'p', 's', 'trv', 'y']
'Foolz Beta':
domain: 'beta.foolz.us'
diff --git a/src/General/Build.coffee b/src/General/Build.coffee
index cd4f73e01..6a1683a38 100755
--- a/src/General/Build.coffee
+++ b/src/General/Build.coffee
@@ -27,7 +27,7 @@ Build =
date: data.now
dateUTC: data.time
comment: data.com
- capReps: data.capcode_replies
+ capcodeReplies: data.capcode_replies
# thread status
isSticky: !!data.sticky
isClosed: !!data.closed
@@ -59,7 +59,7 @@ Build =
postID, threadID, boardID
name, capcode, tripcode, uniqueID, email, subject, flagCode, flagName, date, dateUTC
isSticky, isClosed
- comment, capReps
+ comment, capcodeReplies
file
} = o
isOP = postID is threadID
@@ -191,26 +191,6 @@ Build =
else
''
- capcodeReplies = ''
- if capReps
- generateCapcodeReplies = (capcodeType, array) ->
- "#{
- switch capcodeType
- when 'admin'
- 'Administrator'
- when 'mod'
- 'Moderator'
- when 'developer'
- 'Developer'
- } Repl#{if array.length > 1 then 'ies' else 'y'}: #{
- array.map (ID) ->
- ">>#{ID} "
- .join ' '
- } "
- for capcodeType, array of capReps
- capcodeReplies += generateCapcodeReplies capcodeType, array
- capcodeReplies = "#{capcodeReplies} "
-
container = $.el 'div',
id: "pc#{postID}"
className: "postContainer #{if isOP then 'op' else 'reply'}Container"
@@ -221,4 +201,36 @@ Build =
continue if href[0] is '/' # Cross-board quote, or board link
quote.href = "/#{boardID}/res/#{href}" # Fix pathnames
+ Build.capcodeReplies {boardID, threadID, root: container, capcodeReplies}
+
container
+
+ capcodeReplies: ({boardID, threadID, bq, root, capcodeReplies}) ->
+ return unless capcodeReplies
+
+ generateCapcodeReplies = (capcodeType, array) ->
+ "#{
+ switch capcodeType
+ when 'admin'
+ 'Administrator'
+ when 'mod'
+ 'Moderator'
+ when 'developer'
+ 'Developer'
+ } Repl#{if array.length > 1 then 'ies' else 'y'}: #{
+ array.map (ID) ->
+ ">>#{ID} "
+ .join ' '
+ } "
+ html = []
+ for capcodeType, array of capcodeReplies
+ html.push generateCapcodeReplies capcodeType, array
+
+ bq or= $ 'blockquote', root
+ $.add bq, [
+ $.el 'br'
+ $.el 'br'
+ $.el 'span',
+ className: 'capcodeReplies'
+ innerHTML: html.join ''
+ ]
diff --git a/src/General/Config.coffee b/src/General/Config.coffee
index 819779b89..83c2b3df9 100755
--- a/src/General/Config.coffee
+++ b/src/General/Config.coffee
@@ -57,12 +57,6 @@ Config =
true
'Show dice that were entered into the email field.'
]
- <% if (type !== 'crx') { %>
- 'Check for Updates': [
- true
- 'Check for updated versions of <%= meta.name %>.'
- ]
- <% } %>
'Show Updated Notifications': [
true
'Show notifications when 4chan X is successfully updated.'
@@ -255,14 +249,6 @@ Config =
true
'Adds a shortcut for the thread watcher, hides the watcher by default, and makes it scroll with the page.'
]
- 'Auto Watch': [
- true
- 'Automatically watch threads you start.'
- ]
- 'Auto Watch Reply': [
- false
- 'Automatically watch threads you reply to.'
- ]
'Posting':
'Quick Reply': [
@@ -399,7 +385,25 @@ Config =
false
'Advance to next post when contracting an expanded image.'
]
-
+
+ threadWatcher:
+ 'Current Board': [
+ false
+ 'Only show watched threads from the current board.'
+ ]
+ 'Auto Watch': [
+ true
+ 'Automatically watch threads you start.'
+ ]
+ 'Auto Watch Reply': [
+ false
+ 'Automatically watch threads you reply to.'
+ ]
+ 'Auto Prune': [
+ false
+ 'Automatically prune 404\'d threads.'
+ ]
+
filter:
name: """
# Filter any namefags:
diff --git a/src/General/Header.coffee b/src/General/Header.coffee
index d08b8cd99..947f084e4 100755
--- a/src/General/Header.coffee
+++ b/src/General/Header.coffee
@@ -109,7 +109,6 @@ Header =
fourchannav = $.id 'boardNavDesktop'
if a = $ "a[href*='/#{g.BOARD}/']", fourchannav
a.className = 'current'
-
boardList = $.el 'span',
id: 'board-list'
innerHTML: " - #{fourchannav.innerHTML} "
diff --git a/src/General/Main.coffee b/src/General/Main.coffee
index 86b92e391..f79be109b 100755
--- a/src/General/Main.coffee
+++ b/src/General/Main.coffee
@@ -126,6 +126,7 @@ Main =
'Thread Stats': ThreadStats
'Thread Updater': ThreadUpdater
'Thread Watcher': ThreadWatcher
+ 'Thread Watcher (Menu)': ThreadWatcher.menu
'Index Navigation': Nav
'Keybinds': Keybinds
'Show Dice Roll': Dice
@@ -205,9 +206,6 @@ Main =
Main.callbackNodes Thread, threads
Main.callbackNodesDB Post, posts, ->
$.event '4chanXInitFinished'
- <% if (type !== 'crx') { %>
- Main.checkUpdate()
- <% } %>
if styleSelector = $.id 'styleSelector'
passLink = $.el 'a',
@@ -227,9 +225,6 @@ Main =
new Notification 'warning', 'Cookies need to be enabled on 4chan for <%= meta.name %> to properly function.', 30
$.event '4chanXInitFinished'
- <% if (type !== 'crx') { %>
- Main.checkUpdate()
- <% } %>
callbackNodes: (klass, nodes) ->
# get the nodes' length only once
@@ -303,27 +298,6 @@ Main =
obj.callback.isAddon = true
Klass::callbacks.push obj.callback
- <% if (type !== 'crx') { %>
- message: (e) ->
- {version} = e.data
- if version and version isnt g.VERSION
- el = $.el 'span',
- innerHTML: "Update: <%= meta.name %> v#{version} is out, get it target=_blank>here ."
- new Notification 'info', el, 120
-
- checkUpdate: ->
- return unless Conf['Check for Updates'] and Main.isThisPageLegit()
- now = Date.now()
- $.get 'lastchecked', 0, ({lastchecked}) ->
- if (lastchecked > now - $.DAY)
- return
- $.ready ->
- $.on window, 'message', Main.message
- $.set 'lastchecked', now
- $.add d.head, $.el 'script',
- src: '<%= meta.repo %>raw/<%= meta.mainBranch %>/latest.js'
- <% } %>
-
handleErrors: (errors) ->
unless errors instanceof Array
error = errors
diff --git a/src/General/Settings.coffee b/src/General/Settings.coffee
index 8af3c568f..eaa4e908a 100755
--- a/src/General/Settings.coffee
+++ b/src/General/Settings.coffee
@@ -21,7 +21,8 @@ Settings =
else
$.on d, '4chanXInitFinished', Settings.open
$.set
- lastchecked: Date.now()
+ archives: Conf['archives']
+ lastarchivecheck: now
previousversion: g.VERSION
Settings.addSection 'Main', Settings.main
@@ -153,7 +154,6 @@ Settings =
data =
version: g.VERSION
date: now
- Conf['WatchedThreads'] = {}
for db in DataBoards
Conf[db] = boards: {}
# Make sure to export the most recent data.
@@ -265,13 +265,10 @@ Settings =
for key, val of Config.hotkeys when key of data.Conf
data.Conf[key] = data.Conf[key].replace(/ctrl|alt|meta/g, (s) -> "#{s[0].toUpperCase()}#{s[1..]}").replace /(^|.+\+)[A-Z]$/g, (s) ->
"Shift+#{s[0...-1]}#{s[-1..].toLowerCase()}"
- data.Conf.WatchedThreads = data.WatchedThreads
- else if version[0] is '3'
- data = Settings.convertSettings data,
- 'Reply Hiding': 'Reply Hiding Buttons'
- 'Thread Hiding': 'Thread Hiding Buttons'
- 'Bottom header': 'Bottom Header'
- 'Unread Tab Icon': 'Unread Favicon'
+ data.Conf['WatchedThreads'] = data.WatchedThreads
+ if data.Conf['WatchedThreads']
+ data.Conf['watchedThreads'] = boards: ThreadWatcher.convert data.Conf['WatchedThreads']
+ delete data.Conf['WatchedThreads']
$.set data.Conf
convertSettings: (data, map) ->
for prevKey, newKey of map
diff --git a/src/General/css/burichan.css b/src/General/css/burichan.css
index 6476a5539..917dea36c 100755
--- a/src/General/css/burichan.css
+++ b/src/General/css/burichan.css
@@ -52,7 +52,7 @@
}
/* Watcher Favicon */
-:root.burichan .watch-thread-link
+:root.burichan .watcher-toggler
{
background-image: url("data:image/svg+xml, ");
}
diff --git a/src/General/css/futaba.css b/src/General/css/futaba.css
index 9b56af61a..3a090155c 100755
--- a/src/General/css/futaba.css
+++ b/src/General/css/futaba.css
@@ -52,7 +52,7 @@
}
/* Watcher Favicon */
-:root.futaba .watch-thread-link
+:root.futaba .watcher-toggler
{
background-image: url("data:image/svg+xml, ");
}
diff --git a/src/General/css/photon.css b/src/General/css/photon.css
index 7f2370192..8eb680e14 100755
--- a/src/General/css/photon.css
+++ b/src/General/css/photon.css
@@ -52,7 +52,7 @@
}
/* Watcher Favicon */
-:root.photon .watch-thread-link
+:root.photon .watcher-toggler
{
background-image: url("data:image/svg+xml, ");
}
diff --git a/src/General/css/style.css b/src/General/css/style.css
index dbed7eeb0..07884666f 100755
--- a/src/General/css/style.css
+++ b/src/General/css/style.css
@@ -38,7 +38,8 @@
cursor: move;
overflow: hidden;
}
-label, .favicon {
+label,
+.watcher-toggler {
cursor: pointer;
}
a[href="javascript:;"] {
@@ -97,10 +98,10 @@ a {
#qr {
z-index: 30;
}
-#watcher {
+#thread-watcher {
z-index: 8;
}
-:root.fixed-watcher #watcher {
+:root.fixed-watcher #thread-watcher {
z-index: 20;
}
.fixed #header-bar {
@@ -204,6 +205,7 @@ a {
.brackets-wrap::after {
content: "]\\00a0";
}
+.dead-thread,
.disabled,
.expand-all-shortcut {
opacity: .45;
@@ -465,44 +467,48 @@ a.hide-announcement {
}
/* Thread Watcher */
-#watcher {
+#thread-watcher {
position: absolute;
}
-#watcher {
+#thread-watcher {
padding-bottom: 3px;
+ padding-left: 3px;
overflow: hidden;
white-space: nowrap;
- min-width: 120px;
+ min-width: 136px;
max-height: 92%;
overflow-y: auto;
}
-:root.fixed-watcher #watcher {
+#thread-watcher .menu-button {
+ bottom: 1px;
+}
+:root.fixed-watcher #thread-watcher {
position: fixed;
}
-:root:not(.fixed-watcher) #watcher:not(:hover) {
+:root:not(.fixed-watcher) #thread-watcher:not(:hover) {
max-height: 210px;
overflow-y: hidden;
}
-#watcher > .move {
+#thread-watcher > .move {
padding-top: 3px;
}
-#watcher > div {
+#watched-threads > div {
max-width: 250px;
overflow: hidden;
padding-left: 3px;
padding-right: 3px;
text-overflow: ellipsis;
}
-#watcher a {
+#thread-watcher a {
text-decoration: none;
}
-#watcher .move>.close {
+#thread-watcher .move>.close {
position: absolute;
right: 0px;
top: 0px;
padding: 0px 4px;
}
-.watch-thread-link {
+.watcher-toggler {
padding-top: 18px;
width: 18px;
height: 0px;
@@ -512,10 +518,11 @@ a.hide-announcement {
position: relative;
top: 1px;
}
-.watch-thread-link.watched {
+.watcher-toggler.watched {
opacity: 1;
}
+
/* Thread Stats */
#thread-stats {
background: none;
diff --git a/src/General/css/tomorrow.css b/src/General/css/tomorrow.css
index 6f8d64b49..343b62c60 100755
--- a/src/General/css/tomorrow.css
+++ b/src/General/css/tomorrow.css
@@ -58,7 +58,7 @@
}
/* Watcher Favicon */
-:root.tomorrow .watch-thread-link
+:root.tomorrow .watcher-toggler
{
background-image: url("data:image/svg+xml, ");
}
diff --git a/src/General/css/yotsuba-b.css b/src/General/css/yotsuba-b.css
index d3bdd0234..486554f35 100755
--- a/src/General/css/yotsuba-b.css
+++ b/src/General/css/yotsuba-b.css
@@ -52,7 +52,7 @@
}
/* Watcher Favicon */
-:root.yotsuba-b .watch-thread-link
+:root.yotsuba-b .watcher-toggler
{
background-image: url("data:image/svg+xml, ");
}
diff --git a/src/General/css/yotsuba.css b/src/General/css/yotsuba.css
index a06ab02fb..0cc6f5533 100755
--- a/src/General/css/yotsuba.css
+++ b/src/General/css/yotsuba.css
@@ -52,7 +52,7 @@
}
/* Watcher Favicon */
-:root.yotsuba .watch-thread-link
+:root.yotsuba .watcher-toggler
{
background-image: url("data:image/svg+xml, ");
}
diff --git a/src/General/html/Build/post.html b/src/General/html/Build/post.html
index cf833ebdd..239dec4f7 100755
--- a/src/General/html/Build/post.html
+++ b/src/General/html/Build/post.html
@@ -54,6 +54,6 @@
#{if isOP then '' else fileHTML}
- #{comment or ''}#{capcodeReplies} #{" "}
+ #{comment or ''} #{" "}
"""
\ No newline at end of file
diff --git a/src/General/html/Monitoring/ThreadWatcher.html b/src/General/html/Monitoring/ThreadWatcher.html
new file mode 100644
index 000000000..7debb0041
--- /dev/null
+++ b/src/General/html/Monitoring/ThreadWatcher.html
@@ -0,0 +1,2 @@
+
+
diff --git a/src/General/lib/$.coffee b/src/General/lib/$.coffee
index 238c79a0b..295bc41cc 100755
--- a/src/General/lib/$.coffee
+++ b/src/General/lib/$.coffee
@@ -57,18 +57,23 @@ $.extend = (object, properties) ->
object[key] = val
return
-$.ajax = (url, options, extra={}) ->
- {type, headers, upCallbacks, form, sync} = extra
- r = new XMLHttpRequest()
- r.overrideMimeType 'text/html'
- type or= form and 'post' or 'get'
- r.open type, url, !sync
- for key, val of headers
- r.setRequestHeader key, val
- $.extend r, options
- $.extend r.upload, upCallbacks
- r.send form
- r
+$.ajax = do ->
+ # Status Code 304: Not modified
+ # With the `If-Modified-Since` header we only receive the HTTP headers and no body for 304 responses.
+ # This saves a lot of bandwidth and CPU time for both the users and the servers.
+ lastModified = {}
+ (url, options, extra={}) ->
+ {type, whenModified, upCallbacks, form, sync} = extra
+ r = new XMLHttpRequest()
+ type or= form and 'post' or 'get'
+ r.open type, url, !sync
+ if whenModified
+ r.setRequestHeader 'If-Modified-Since', lastModified[url] or '0'
+ $.on r, 'load', -> lastModified[url] = r.getResponseHeader 'Last-Modified'
+ $.extend r, options
+ $.extend r.upload, upCallbacks
+ r.send form
+ r
$.cache = do ->
reqs = {}
diff --git a/src/General/lib/databoard.class b/src/General/lib/databoard.class
index 80c190f17..e1f58ed47 100755
--- a/src/General/lib/databoard.class
+++ b/src/General/lib/databoard.class
@@ -1,10 +1,10 @@
-DataBoards = ['hiddenThreads', 'hiddenPosts', 'lastReadPosts', 'yourPosts']
+DataBoards = ['hiddenThreads', 'hiddenPosts', 'lastReadPosts', 'yourPosts', 'watchedThreads']
class DataBoard
- constructor: (@key, sync) ->
+ constructor: (@key, sync, dontClean) ->
@data = Conf[key]
$.sync key, @onSync.bind @
- @clean()
+ @clean() unless dontClean
return unless sync
# Chrome also fires the onChanged callback on the current tab,
# so we only start syncing when we're ready.
@@ -13,6 +13,9 @@ class DataBoard
@sync = sync
$.on d, '4chanXInitFinished', init
+ save: ->
+ $.set @key, @data
+
delete: ({boardID, threadID, postID}) ->
if postID
delete @data.boards[boardID][threadID][postID]
@@ -22,7 +25,7 @@ class DataBoard
@deleteIfEmpty {boardID}
else
delete @data.boards[boardID]
- $.set @key, @data
+ @save()
deleteIfEmpty: ({boardID, threadID}) ->
if threadID
@@ -39,7 +42,7 @@ class DataBoard
(@data.boards[boardID] or= {})[threadID] = val
else
@data.boards[boardID] = val
- $.set @key, @data
+ @save()
get: ({boardID, threadID, postID, defaultValue}) ->
if board = @data.boards[boardID]
@@ -67,8 +70,7 @@ class DataBoard
@data.lastChecked = now
for boardID of @data.boards
@ajaxClean boardID
-
- $.set @key, @data
+ @save()
ajaxClean: (boardID) ->
$.cache "//api.4chan.org/#{boardID}/threads.json", (e) =>
@@ -84,7 +86,7 @@ class DataBoard
threads[thread.no] = board[thread.no]
@data.boards[boardID] = threads
@deleteIfEmpty {boardID}
- $.set @key, @data
+ @save()
onSync: (data) ->
@data = data or boards: {}
diff --git a/src/General/lib/polyfill.coffee b/src/General/lib/polyfill.coffee
index 5d9ddc124..3cec1905a 100755
--- a/src/General/lib/polyfill.coffee
+++ b/src/General/lib/polyfill.coffee
@@ -1,6 +1,16 @@
Polyfill =
init: ->
+ Polyfill.toBlob()
Polyfill.visibility()
+ toBlob: ->
+ HTMLCanvasElement::toBlob or= (cb) ->
+ data = atob @toDataURL()[22..]
+ # DataUrl to Binary code from Aeosynth's 4chan X repo
+ l = data.length
+ ui8a = new Uint8Array l
+ for i in [0...l]
+ ui8a[i] = data.charCodeAt i
+ cb new Blob [ui8a], type: 'image/png'
visibility: ->
# page visibility API
return unless 'webkitHidden' of document
diff --git a/src/Images/ImageExpand.coffee b/src/Images/ImageExpand.coffee
index a02e5ec31..3d7751853 100755
--- a/src/Images/ImageExpand.coffee
+++ b/src/Images/ImageExpand.coffee
@@ -169,8 +169,8 @@ ImageExpand =
{createSubEntry} = ImageExpand.menu
subEntries = []
- for key, conf of Config.imageExpansion
- subEntries.push createSubEntry key, conf
+ for name, conf of Config.imageExpansion
+ subEntries.push createSubEntry name, conf[1]
$.event 'AddMenuEntry',
type: 'header'
@@ -178,17 +178,16 @@ ImageExpand =
order: 105
subEntries: subEntries
- createSubEntry: (type, config) ->
+ createSubEntry: (name, desc) ->
label = $.el 'label',
- innerHTML: " #{type}"
+ innerHTML: " #{name}"
+ title: desc
input = label.firstElementChild
- if type in ['Fit width', 'Fit height']
+ if name in ['Fit width', '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
+ input.checked = Conf[name]
+ $.event 'change', null, input
+ $.on input, 'change', $.cb.checked
el: label
menuToggle: (e) ->
diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee
index 74dca4b22..ef1684dce 100755
--- a/src/Linkification/Linkify.coffee
+++ b/src/Linkification/Linkify.coffee
@@ -4,23 +4,20 @@ Linkify =
@regString = if Conf['Allow False Positives']
///(
- \b(
- [-a-z]+://
- |
- [a-z]{3,}\.[-a-z0-9]+\.[a-z]
- |
- [-a-z0-9]+\.[a-z]
- |
- [\d]+\.[\d]+\.[\d]+\.[\d]+/
- |
- [a-z]{3,}:[a-z0-9?]
- |
- [^\s@]+@[a-z0-9.-]+\.[a-z0-9]
- )
- [^\s'"]+
- )///gi
+ [-a-z]+://
+ |
+ [a-z]{3,}\.[-a-z0-9]+\.[a-z]
+ |
+ [-a-z0-9]+\.[a-z]
+ |
+ [\d]+\.[\d]+\.[\d]+\.[\d]+/
+ |
+ [a-z]{3,}:[a-z0-9?]
+ |
+ [^\s@]+@[a-z0-9.-]+\.[a-z0-9]
+ )///i
else
- /(((magnet|mailto)\:|(www\.)|(news|(ht|f)tp(s?))\:\/\/){1}\S+)/gi
+ /(((magnet|mailto)\:|(www\.)|(news|(ht|f)tp(s?))\:\/\/){1})/i
if Conf['Comment Expansion']
ExpandComment.callbacks.push @node
@@ -43,16 +40,44 @@ Linkify =
return
+ test = /[^\s'"]+/g
+ space = /[\s'"]/
+
snapshot = $.X './/br|.//text()', @nodes.comment
i = 0
while node = snapshot.snapshotItem i++
+ links = []
+ {data} = node
+ continue if node.parentElement.nodeName is "A" or not data
- continue if node.parentElement.nodeName is "A"
- links = []
+ while result = test.exec data
+ {index} = result
+ endNode = node
+ if (length = index + result[0].length) is data.length
- if Linkify.regString.test node.data
- Linkify.regString.lastIndex = 0
- Linkify.gatherLinks snapshot, @, node, links, i
+ while (saved = snapshot.snapshotItem i++)
+ break if saved.nodeName is 'BR'
+
+ endNode = saved
+ {length} = saved.data
+
+ if end = space.exec saved.data
+ length = end.index
+ i--
+ break
+
+ if length is endNode.data.length then test.lastIndex = 0
+ range = Linkify.makeRange node, endNode, index, length
+ if link = Linkify.regString.exec text = range.toString()
+ if lIndex = link.index
+ range.setStart node, lIndex + index
+ links.push [range, text]
+ break
+
+ else
+ if link = Linkify.regString.exec result[0]
+ range = Linkify.makeRange node, node, link.index, link.length
+ links.push [range, link]
for range in links.reverse()
@nodes.links.push Linkify.makeLink range, @
@@ -68,66 +93,29 @@ Linkify =
return
- gatherLinks: (snapshot, post, node, links, i) ->
- {data} = node
- len = data.length
-
- while (match = Linkify.regString.exec data)
- {index} = match
- link = match[0]
- len2 = index + link.length
-
- break if len is len2
-
- range = document.createRange();
- range.setStart node, index
- range.setEnd node, len2
- links.push range
-
- Linkify.regString.lastIndex = 0
-
- if match
- links.push Linkify.seek snapshot, post, node, links, match, i
-
- return
-
- seek: (snapshot, post, node, links, match, i) ->
- link = match[0]
- range = document.createRange()
- range.setStart node, match.index
-
- while (next = snapshot.snapshotItem i++) and next.nodeName isnt 'BR'
- node = next
- data = node.data
- if result = /[\s'"]/.exec data
- {index} = result
- range.setEnd node, index
- Linkify.regString.lastIndex = index
- Linkify.gatherLinks snapshot, post, node, links, i
- return range
-
- if range.collapsed
- range.setEndAfter node
-
+ makeRange: (startNode, endNode, startOffset, endOffset) ->
+ range = document.createRange();
+ range.setStart startNode, startOffset
+ range.setEnd endNode, endOffset
range
- makeLink: (range) ->
- link = range.toString()
- link =
- if link.contains ':'
- link
+ makeLink: ([range, text]) ->
+ text
+ text =
+ if text.contains ':'
+ text
else (
- if link.contains '@'
+ if text.contains '@'
'mailto:'
else
'http://'
- ) + link
+ ) + text
a = $.el 'a',
className: 'linkify'
rel: 'nofollow noreferrer'
target: '_blank'
- href: link
+ href: text
$.add a, range.extractContents()
range.insertNode a
a
diff --git a/src/Miscellaneous/ExpandComment.coffee b/src/Miscellaneous/ExpandComment.coffee
index d3499eaea..ee7451dde 100755
--- a/src/Miscellaneous/ExpandComment.coffee
+++ b/src/Miscellaneous/ExpandComment.coffee
@@ -16,8 +16,7 @@ ExpandComment =
callbacks: []
cb: (e) ->
e.preventDefault()
- post = Get.postFromNode @
- ExpandComment.expand post
+ ExpandComment.expand Get.postFromNode @
expand: (post) ->
if post.nodes.longComment and !post.nodes.longComment.parentNode
$.replace post.nodes.shortComment, post.nodes.longComment
@@ -55,6 +54,11 @@ ExpandComment =
href = quote.getAttribute 'href'
continue if href[0] is '/' # Cross-board quote, or board link
quote.href = "/#{post.board}/res/#{href}" # Fix pathnames
+ Build.capcodeReplies
+ boardID: post.board.ID
+ threadID: post.thread.ID
+ bq: clone
+ capcodeReplies: postObj.capcode_replies
post.nodes.shortComment = comment
$.replace comment, clone
post.nodes.comment = post.nodes.longComment = clone
diff --git a/src/Monitoring/ThreadStats.coffee b/src/Monitoring/ThreadStats.coffee
index a8002a575..452caf4cd 100755
--- a/src/Monitoring/ThreadStats.coffee
+++ b/src/Monitoring/ThreadStats.coffee
@@ -18,7 +18,6 @@ ThreadStats =
@postCountEl = $ '#post-count', sc
@fileCountEl = $ '#file-count', sc
@pageCountEl = $ '#page-count', sc
- @lastModified = '0'
Thread::callbacks.push
name: 'Thread Stats'
@@ -55,12 +54,10 @@ ThreadStats =
return
setTimeout ThreadStats.fetchPage, 2 * $.MINUTE
$.ajax "//api.4chan.org/#{ThreadStats.thread.board}/threads.json", onload: ThreadStats.onThreadsLoad,
- headers: 'If-Modified-Since': ThreadStats.lastModified
+ whenModified: true
onThreadsLoad: ->
- return if !Conf["Page Count in Stats"]
- ThreadStats.lastModified = @getResponseHeader 'Last-Modified'
- return if @status isnt 200
+ return unless Conf["Page Count in Stats"] and @status is 200
pages = JSON.parse @response
for page in pages
for thread in page.threads
diff --git a/src/Monitoring/ThreadUpdater.coffee b/src/Monitoring/ThreadUpdater.coffee
index ed4255104..2c245cba3 100755
--- a/src/Monitoring/ThreadUpdater.coffee
+++ b/src/Monitoring/ThreadUpdater.coffee
@@ -64,7 +64,6 @@ ThreadUpdater =
ThreadUpdater.root = @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']
@@ -136,9 +135,7 @@ ThreadUpdater =
when 200
g.DEAD = false
ThreadUpdater.parse JSON.parse(req.response).posts
- ThreadUpdater.lastModified = req.getResponseHeader 'Last-Modified'
- if Conf['Auto Update']
- ThreadUpdater.set 'timer', ThreadUpdater.getInterval()
+ ThreadUpdater.set 'timer', ThreadUpdater.getInterval()
when 404
g.DEAD = true
ThreadUpdater.set 'timer', null
@@ -149,14 +146,8 @@ ThreadUpdater =
404: true
thread: ThreadUpdater.thread
else
- if Conf['Auto Update']
- 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.
- ###
+ ThreadUpdater.outdateCount++
+ ThreadUpdater.set 'timer', ThreadUpdater.getInterval()
[text, klass] = if req.status is 304
[null, null]
else
@@ -218,7 +209,7 @@ ThreadUpdater =
ThreadUpdater.req.abort()
url = "//api.4chan.org/#{ThreadUpdater.thread.board}/res/#{ThreadUpdater.thread}.json"
ThreadUpdater.req = $.ajax url, onloadend: ThreadUpdater.cb.load,
- headers: 'If-Modified-Since': ThreadUpdater.lastModified
+ whenModified: true
updateThreadStatus: (title, OP) ->
titleLC = title.toLowerCase()
diff --git a/src/Monitoring/ThreadWatcher.coffee b/src/Monitoring/ThreadWatcher.coffee
index f92eff25a..9a48fa021 100755
--- a/src/Monitoring/ThreadWatcher.coffee
+++ b/src/Monitoring/ThreadWatcher.coffee
@@ -1,116 +1,299 @@
ThreadWatcher =
init: ->
- return unless Conf['Thread Watcher']
+ return if !Conf['Thread Watcher']
+
@shortcut = sc = $.el 'a',
textContent: 'Watcher'
id: 'watcher-link'
href: 'javascript:;'
className: 'disabled'
- @dialog = UI.dialog 'watcher', 'top: 50px; left: 0px;',
- ''
+ @db = new DataBoard 'watchedThreads', @refresh, true
+ @dialog = UI.dialog 'thread-watcher', 'top: 50px; left: 0px;', """
+ <%= grunt.file.read('src/General/html/Monitoring/ThreadWatcher.html').replace(/>\s+<').trim() %>
+ """
+ @status = $ '#watcher-status', @dialog
+ @list = @dialog.lastElementChild
$.on d, 'QRPostSuccessful', @cb.post
- $.sync 'WatchedThreads', @refresh
+ $.on d, 'ThreadUpdate', @cb.threadUpdate if g.VIEW is 'thread'
$.on sc, 'click', @toggleWatcher
$.on $('.move>.close', ThreadWatcher.dialog), 'click', @toggleWatcher
+ $.on d, '4chanXInitFinished', @ready
if Conf['Toggleable Thread Watcher']
Header.addShortcut sc
$.addClass doc, 'fixed-watcher'
- $.ready ->
- ThreadWatcher.refresh()
- $.add d.body, ThreadWatcher.dialog
- if Conf['Toggleable Thread Watcher']
- ThreadWatcher.dialog.hidden = true
+ now = Date.now()
+ if (@db.data.lastChecked or 0) < now - 2 * $.HOUR
+ @db.data.lastChecked = now
+ ThreadWatcher.fetchAllStatus()
+ @db.save()
+
+ # XXX tmp conversion from old to new format
+ $.get 'WatchedThreads', null, ({WatchedThreads}) ->
+ return unless WatchedThreads
+ for boardID, threads of ThreadWatcher.convert WatchedThreads
+ for threadID, data of threads
+ ThreadWatcher.db.set {boardID, threadID, val: data}
+ $.delete 'WatchedThreads'
Thread::callbacks.push
name: 'Thread Watcher'
cb: @node
node: ->
- favicon = $.el 'a',
- className: 'watch-thread-link'
- href: 'javascript:;'
- $.on favicon, 'click', ThreadWatcher.cb.toggle
- $.before $('input', @OP.nodes.post), favicon
- return if g.VIEW isnt 'thread'
- $.get 'AutoWatch', 0, (item) =>
- return if item['AutoWatch'] isnt @ID
- ThreadWatcher.watch @
+ toggler = $.el 'img',
+ className: 'watcher-toggler'
+ $.on toggler, 'click', ThreadWatcher.cb.toggle
+ $.before $('input', @OP.nodes.post), toggler
+
+ ready: ->
+ $.off d, '4chanXInitFinished', ThreadWatcher.ready
+ return unless Main.isThisPageLegit()
+ ThreadWatcher.refresh()
+ $.add d.body, ThreadWatcher.dialog
+
+ if Conf['Toggleable Thread Watcher']
+ ThreadWatcher.dialog.hidden = true
+
+ return unless Conf['Auto Watch']
+ $.get 'AutoWatch', 0, ({AutoWatch}) ->
+ return unless thread = g.BOARD.threads[AutoWatch]
+ ThreadWatcher.add thread
$.delete 'AutoWatch'
- refresh: (watched) ->
- unless watched
- $.get 'WatchedThreads', {}, (item) ->
- ThreadWatcher.refresh item['WatchedThreads']
- return
- nodes = [$('.move', ThreadWatcher.dialog)]
- for board of watched
- for id, props of watched[board]
- x = $.el 'a',
- textContent: '×'
- className: 'close'
- 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] or {}
- for ID, thread of g.BOARD.threads
- favicon = $ '.watch-thread-link', thread.OP.nodes.post
- if ID of watched
- $.addClass favicon, 'watched'
- else
- $.rmClass favicon, 'watched'
- return
-
toggleWatcher: ->
$.toggleClass ThreadWatcher.shortcut, 'disabled'
ThreadWatcher.dialog.hidden = !ThreadWatcher.dialog.hidden
cb:
+ openAll: ->
+ return if $.hasClass @, 'disabled'
+ for a in $$ 'a[title]', ThreadWatcher.list
+ $.open a.href
+ $.event 'CloseMenu'
+ checkThreads: ->
+ return if $.hasClass @, 'disabled'
+ ThreadWatcher.fetchAllStatus()
+ pruneDeads: ->
+ return if $.hasClass @, 'disabled'
+ for {boardID, threadID, data} in ThreadWatcher.getAll() when data.isDead
+ delete ThreadWatcher.db.data.boards[boardID][threadID]
+ ThreadWatcher.db.deleteIfEmpty {boardID}
+ ThreadWatcher.db.save()
+ ThreadWatcher.refresh()
+ $.event 'CloseMenu'
toggle: ->
ThreadWatcher.toggle Get.postFromNode(@).thread
- x: ->
- thread = @nextElementSibling.pathname.split '/'
- ThreadWatcher.unwatch thread[1], thread[3]
+ rm: ->
+ [boardID, threadID] = @parentNode.dataset.fullID.split '.'
+ ThreadWatcher.rm boardID, +threadID
post: (e) ->
{board, postID, threadID} = e.detail
if postID is threadID
if Conf['Auto Watch']
$.set 'AutoWatch', threadID
else if Conf['Auto Watch Reply']
- ThreadWatcher.watch board.threads[threadID]
+ ThreadWatcher.add board.threads[threadID]
+ threadUpdate: (e) ->
+ {thread} = e.detail
+ return unless e.detail[404] and ThreadWatcher.db.get {boardID: thread.board.ID, threadID: thread.ID}
+ # Update 404 status.
+ ThreadWatcher.add thread
+
+ fetchCount:
+ fetched: 0
+ fetching: 0
+ fetchAllStatus: ->
+ ThreadWatcher.status.textContent = '...'
+ for thread in ThreadWatcher.getAll()
+ ThreadWatcher.fetchStatus thread
+ return
+ fetchStatus: ({boardID, threadID, data}) ->
+ return if data.isDead
+ {fetchCount} = ThreadWatcher
+ fetchCount.fetching++
+ $.ajax "//api.4chan.org/#{boardID}/res/#{threadID}.json",
+ onloadend: ->
+ fetchCount.fetched++
+ if fetchCount.fetched is fetchCount.fetching
+ fetchCount.fetched = 0
+ fetchCount.fetching = 0
+ status = ''
+ else
+ status = "#{Math.round fetchCount.fetched / fetchCount.fetching * 100}%"
+ ThreadWatcher.status.textContent = status
+ return if @status isnt 404
+ if Conf['Auto Prune']
+ ThreadWatcher.rm boardID, threadID
+ else
+ data.isDead = true
+ ThreadWatcher.db.set {boardID, threadID, val: data}
+ ThreadWatcher.refresh()
+ ,
+ type: 'head'
+
+ getAll: ->
+ all = []
+ for boardID, threads of ThreadWatcher.db.data.boards
+ if Conf['Current Board'] and boardID isnt g.BOARD.ID
+ continue
+ for threadID, data of threads
+ all.push {boardID, threadID, data}
+ all
+
+ makeLine: (boardID, threadID, data) ->
+ x = $.el 'a',
+ textContent: '×'
+ href: 'javascript:;'
+ $.on x, 'click', ThreadWatcher.cb.rm
+
+ if data.isDead
+ href = Redirect.to 'thread', {boardID, threadID}
+ link = $.el 'a',
+ href: href or "/#{boardID}/res/#{threadID}"
+ textContent: data.excerpt
+ title: data.excerpt
+
+ div = $.el 'div'
+ fullID = "#{boardID}.#{threadID}"
+ div.dataset.fullID = fullID
+ $.addClass div, 'current' if g.VIEW is 'thread' and fullID is "#{g.BOARD}.#{g.THREADID}"
+ $.addClass div, 'dead-thread' if data.isDead
+ $.add div, [x, $.tn(' '), link]
+ div
+ refresh: ->
+ nodes = []
+ for {boardID, threadID, data} in ThreadWatcher.getAll()
+ nodes.push ThreadWatcher.makeLine boardID, threadID, data
+
+ {list} = ThreadWatcher
+ $.rmAll list
+ $.add list, nodes
+
+ for threadID, thread of g.BOARD.threads
+ toggler = $ '.watcher-toggler', thread.OP.nodes.post
+ watched = ThreadWatcher.db.get {boardID: thread.board.ID, threadID}
+ $[if watched then 'addClass' else 'rmClass'] toggler, 'watched'
+
+ for refresher in ThreadWatcher.menu.refreshers
+ refresher()
+ return
toggle: (thread) ->
- unless $.hasClass $('.watch-thread-link', thread.OP.nodes.post), 'watched'
- ThreadWatcher.watch thread
+ boardID = thread.board.ID
+ threadID = thread.ID
+ if ThreadWatcher.db.get {boardID, threadID}
+ ThreadWatcher.rm boardID, threadID
else
- ThreadWatcher.unwatch thread.board, thread.ID
+ ThreadWatcher.add thread
+ add: (thread) ->
+ data = {}
+ boardID = thread.board.ID
+ threadID = thread.ID
+ if thread.isDead
+ if Conf['Auto Prune'] and ThreadWatcher.db.get {boardID, threadID}
+ ThreadWatcher.rm boardID, threadID
+ return
+ data.isDead = true
+ data.excerpt = Get.threadExcerpt thread
+ ThreadWatcher.db.set {boardID, threadID, val: data}
+ ThreadWatcher.refresh()
+ rm: (boardID, threadID) ->
+ ThreadWatcher.db.delete {boardID, threadID}
+ ThreadWatcher.refresh()
- unwatch: (board, threadID) ->
- $.get 'WatchedThreads', {}, (item) ->
- watched = item['WatchedThreads']
- delete watched[board][threadID]
- delete watched[board] unless Object.keys(watched[board]).length
- ThreadWatcher.refresh watched
- $.set 'WatchedThreads', watched
+ convert: (oldFormat) ->
+ newFormat = {}
+ for boardID, threads of oldFormat
+ for threadID, data of threads
+ (newFormat[boardID] or= {})[threadID] = excerpt: data.textContent
+ newFormat
- watch: (thread) ->
- $.get 'WatchedThreads', {}, (item) ->
- watched = item['WatchedThreads']
- watched[thread.board] or= {}
- watched[thread.board][thread] =
- href: "/#{thread.board}/res/#{thread}"
- textContent: Get.threadExcerpt thread
- ThreadWatcher.refresh watched
- $.set 'WatchedThreads', watched
\ No newline at end of file
+ menu:
+ refreshers: []
+ init: ->
+ return if !Conf['Thread Watcher']
+ menu = new UI.Menu 'thread watcher'
+ $.on $('.menu-button', ThreadWatcher.dialog), 'click', (e) ->
+ menu.toggle e, @, ThreadWatcher
+ @addHeaderMenuEntry()
+ @addMenuEntries()
+
+ addHeaderMenuEntry: ->
+ return if g.VIEW isnt 'thread'
+ entryEl = $.el 'a',
+ href: 'javascript:;'
+ $.event 'AddMenuEntry',
+ type: 'header'
+ el: entryEl
+ order: 60
+ $.on entryEl, 'click', -> ThreadWatcher.toggle g.threads["#{g.BOARD}.#{g.THREADID}"]
+ @refreshers.push ->
+ [addClass, rmClass, text] = if $ '.current', ThreadWatcher.list
+ ['unwatch-thread', 'watch-thread', 'Unwatch thread']
+ else
+ ['watch-thread', 'unwatch-thread', 'Watch thread']
+ $.addClass entryEl, addClass
+ $.rmClass entryEl, rmClass
+ entryEl.textContent = text
+
+ addMenuEntries: ->
+ entries = []
+
+ # `Open all` entry
+ entries.push
+ cb: ThreadWatcher.cb.openAll
+ entry:
+ type: 'thread watcher'
+ el: $.el 'a',
+ textContent: 'Open all threads'
+ refresh: -> (if ThreadWatcher.list.firstElementChild then $.rmClass else $.addClass) @el, 'disabled'
+
+ # `Check 404'd threads` entry
+ entries.push
+ cb: ThreadWatcher.cb.checkThreads
+ entry:
+ type: 'thread watcher'
+ el: $.el 'a',
+ textContent: 'Check 404\'d threads'
+ refresh: -> (if $('div:not(.dead-thread)', ThreadWatcher.list) then $.rmClass else $.addClass) @el, 'disabled'
+
+ # `Prune 404'd threads` entry
+ entries.push
+ cb: ThreadWatcher.cb.pruneDeads
+ entry:
+ type: 'thread watcher'
+ el: $.el 'a',
+ textContent: 'Prune 404\'d threads'
+ refresh: -> (if $('.dead-thread', ThreadWatcher.list) then $.rmClass else $.addClass) @el, 'disabled'
+
+ # `Settings` entries:
+ subEntries = []
+ for name, conf of Config.threadWatcher
+ subEntries.push @createSubEntry name, conf[1]
+ entries.push
+ entry:
+ type: 'thread watcher'
+ el: $.el 'span',
+ textContent: 'Settings'
+ subEntries: subEntries
+
+ for {entry, cb, refresh} in entries
+ entry.el.href = 'javascript:;' if entry.el.nodeName is 'A'
+ $.on entry.el, 'click', cb if cb
+ @refreshers.push refresh.bind entry if refresh
+ $.event 'AddMenuEntry', entry
+ createSubEntry: (name, desc) ->
+ entry =
+ type: 'thread watcher'
+ el: $.el 'label',
+ innerHTML: " #{name}"
+ title: desc
+ input = entry.el.firstElementChild
+ input.checked = Conf[name]
+ $.on input, 'change', $.cb.checked
+ $.on input, 'change', ThreadWatcher.refresh if name is 'Current Board'
+ entry
diff --git a/src/Posting/QuickReply.coffee b/src/Posting/QuickReply.coffee
index 9e83b6779..bb8231e0f 100755
--- a/src/Posting/QuickReply.coffee
+++ b/src/Posting/QuickReply.coffee
@@ -660,21 +660,9 @@ QR =
cv.width = img.width = width
cv.getContext('2d').drawImage img, 0, 0, width, height
URL.revokeObjectURL fileURL
- applyBlob = (blob) =>
+ cv.toBlob (blob) =>
@URL = URL.createObjectURL blob
@nodes.el.style.backgroundImage = "url(#{@URL})"
- if cv.toBlob
- cv.toBlob applyBlob
- return
- data = atob cv.toDataURL().split(',')[1]
-
- # DataUrl to Binary code from Aeosynth's 4chan X repo
- l = data.length
- ui8a = new Uint8Array l
- for i in [0...l]
- ui8a[i] = data.charCodeAt i
-
- applyBlob new Blob [ui8a], type: 'image/png'
fileURL = URL.createObjectURL @file
img.src = fileURL
diff --git a/src/Quotelinks/QuoteYou.coffee b/src/Quotelinks/QuoteYou.coffee
index b5b9e4a60..b66eb96da 100755
--- a/src/Quotelinks/QuoteYou.coffee
+++ b/src/Quotelinks/QuoteYou.coffee
@@ -16,7 +16,6 @@ QuoteYou =
cb: @node
node: ->
- # Stop there if it's a clone.
return if @isClone
if @info.yours