Title: imgur script Author: Anonymous Pastebin link: http://pastebin.com/nZLG36hv First Edit: Thursday 24th of April 2014 04:13:04 AM CDT Last Edit: Thursday 24th of April 2014 04:13:04 AM CDT // ==UserScript== // @name            4chan imgur thumbnail // @version         0.7.3 // @namespace       anon.4chan.org // @description     Scans for 4chan posts that contain a specific link but no file and embeds an image as a thumbnail. Supports Imgur, Derpibooru and YouTube links as well as direct image links (jpg, png, gif). // @include         http*://boards.4chan.org/* // @grant           GM_xmlhttprequest // @updateURL       http://murkeli.kapsi.fi/userscripts/4chanimgur.user.js // @downloadURL     http://murkeli.kapsi.fi/userscripts/4chanimgur.user.js // ==/UserScript==   (function() {       var namespace = '4chanimgur.';     var version = '0.7.3';     var d = document;       var $ = function(selector, context, forceArray) {         if ($.null(context)) {             context = d.body;         }         if ($.null(context.querySelectorAll)) return null;         var nodes = context.querySelectorAll(selector);         if (!forceArray) {             if (nodes.length == 1) {                 return nodes[0];             } else if (nodes.length == 0) {                 return null;             }         }         return nodes;     };       $.extend = function(object, properties) {         var key, val;         for (key in properties) {             val = properties[key];             object[key] = val;         }     };       $.extend($, {         null: function(value) {             return (value === undefined || value === null);         },         notnull: function(value) {             return !$.null(value);         },         json: function(url, data, callback) {             if (typeof GM_xmlhttpRequest != 'function') {                 throw "Not supported";                 return false;             }             GM_xmlhttpRequest({                 method: 'GET',                 url:    url,                 onload: function(req) {                     try {                         var info = JSON.parse(req.responseText);                         callback.call(self, data, info);                     } catch(ex) {                         console.log('JSON data from ' + url + ' could not be parsed: ' + ex + '\nHTTP: ' + req.status + '\nResponse: ' + req.responseText);                     }                 },                 onerror: function() {                     console.log('Request to ' + url + ' failed.');                 }             });         },         on: function(el, events, handler) {             var event, _i, _len, _ref;             _ref = events.split(' ');             for (_i = 0, _len = _ref.length; _i < _len; _i++) {                 event = _ref[_i];                 el.addEventListener(event, handler, false);             }         },         off: function(el, events, handler) {             var event, _i, _len, _ref;             _ref = events.split(' ');             for (_i = 0, _len = _ref.length; _i < _len; _i++) {                 event = _ref[_i];                 el.removeEventListener(event, handler, false);             }         },         sibling: function(n, elem) {             var r = [];             for ( ; n; n = n.nextSibling ) {                 if (n.nodeType === 1 && n !== elem) {                     r.push(n);                 }             }             return r;         },         siblings: function(elem) {             return this.sibling((elem.parentNode || {}).firstChild, elem);         },         each: function(list, callback) {             if ($.null(list)) return;             for (var i = 0, c = list.length; i < c; i++) {                 if (callback.call(list[i], list[i], i) === false) {                     break;                 }             }         },         attr: function(elem, attr, value) {             if (!elem.getAttribute) return '';             if (!value) {                 return elem.getAttribute(attr);             } else {                 return elem.setAttribute(attr, value);             }         },         data: function(elem, key, value) {             if ($.null(value)) {                 return elem.getAttribute('data-' + key);             } else {                 return elem.setAttribute('data-' + key, value);             }         },         strip: function(elem) {             if (elem.innerHTML) {                 return elem.innerHTML.replace(//g, '').replace(/&/g, '&').replace(/
/g, ' ');             }             return '';         },         nodes: function(nodes) {             var frag, node, _i, _len;             if (!(nodes instanceof Array)) {                 return nodes;             }             frag = d.createDocumentFragment();             for (_i = 0, _len = nodes.length; _i < _len; _i++) {                 node = nodes[_i];                 frag.appendChild(node);             }             return frag;         },         append: function(parent, elem) {             return parent.appendChild($.nodes(elem));         },         prepend: function(parent, children) {             return parent.insertBefore($.nodes(children), parent.firstChild);         },         after: function(root, elem) {             return root.parentNode.insertBefore($.nodes(elem), root.nextSibling);         },         before: function(root, elem) {             return root.parentNode.insertBefore($.nodes(elem), root);         },         remove: function(elem) {             return elem.parentNode.removeChild($.nodes(elem));         },         replace: function(root, elem) {             return root.parentNode.replaceChild($.nodes(elem), root);         },         create: function(tag, properties) {             var elem = d.createElement(tag);             if (properties) {                 $.extend(elem, properties);             }             return elem;         },         tn: function(text) {             return d.createTextNode(text);         },         id: function(id) {             return d.getElementById(id);         },         hasClass: function(elem, className) {             return (' ' + elem.className + ' ').replace(/[\n\t]/g, ' ').indexOf(className) > -1;         },         addClass: function(elem, className) {             return elem.classList.add(className);         },         rmClass: function(elem, className) {             return elem.classList.remove(className);         },         addStyle: function(css) {             var style = $.create('style', {                 type: 'text/css',                 textContent: css             });             var f = function() {                 var root;                 if (root = d.head || d.documentElement) {                     return $.append(root, style);                 } else {                     return setTimeout(f, 20);                 }             };             f();             return style;         },         inArray: function(arr, obj) {             return arr.indexOf(obj) > -1;         },     });         var Hover = {         limit: 20,         elapsed: function() {             var now = Date.now();             if (!Hover.lastTimestamp || now - Hover.lastTimestamp >= Hover.limit) {                 Hover.lastTimestamp = now;                 return true;             }             return false;         },         set: function(src) {             var img = $('#imgur-thumbnail-hover');             if ($.null(img)) {                 img = $.create('img', { id: 'imgur-thumbnail-hover' });                 $.append(d.body, img);             }             img.style.display = 'block';             img.src = src;         },         update: function(e) {             if (!Hover.elapsed()) return;             var img = $('#imgur-thumbnail-hover');             if ($.notnull(img)) {                 var style = img.style;                 var clientX, clientY, top, height;                 height = img.offsetHeight;                 clientX = e.clientX, clientY = e.clientY;                 _ref = d.documentElement, clientHeight = _ref.clientHeight, clientWidth = _ref.clientWidth;                 top = clientY - 120;                 style.top = clientHeight <= height || top <= 0 ? '0px' : top + height >= clientHeight ? clientHeight - height + 'px' : top + 'px';                 if (clientX <= clientWidth - 400) {                     style.left = clientX + 45 + 'px';                     style.right = null;                 } else {                     style.left = null;                     style.right = clientWidth - clientX + 45 + 'px';                 }             }         },         hide: function() {             var img = $('#imgur-thumbnail-hover');             if ($.notnull(img)) {                 img.style.display = 'none';                 img.src = '';             }         },         init: function(img) {             $.on(img, 'mouseover', function() {                 Hover.set($.data(img, 'image-url'));             });             $.on(img, 'mousemove', function(e) {                 Hover.update(e);             });             $.on(img, 'mouseout', function() {                 Hover.hide();             });         }     };         var Resources = {         placeholderThumb: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAH0AAAB9CAMAAAC4XpwXAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADBQTFRFtbW1/v7+19fX6+vrv7+/yMjI0tLS9PT04eHh7+/vurq6zc3NxMTE3Nzc+fn55ubmQouatgAAA35JREFUeNrsmYlunDAQhn3gE7Df/207F2AIG7VkV22l+aUIBx8fHh9rzxijUqlUKpVKpVKpVKoHmiwohfFVsDZ/LeisDd7a6a6R2zxoxuETmr8UvdBP+d/QX3XhNu836R7fADFNc0Iw0QMmKz16hTolS/+gfLfeRNscNz/kYWk/SSVoZi3QEtIXTxlS9EyPRLd2ITtkpFdKeraM/LfRUfidluhjXhkrBc6oSKeMtBW963sxMzRXbEO6JOExNWqvu6Pv8LUxwWQh+jlvdTZJJczml4j1K/Wu3417o5Yil0e6JCM1lKBQ/oa+53lbFmOk0kCXLkYpeqXPG50sc9BNdcm+oIvlxzwDHfSLVDrTUbd0v03QyNNooIOt8n3f4W/9SjfV2yaVLn03R9F7Og52577LuKMRE9W+jvu+pMa8hONupdJl3Dmjv6bznMRqmW3VeSzSec4Tnafk3ZxvcW8GZfY5L2vqFd2EguNG631uuGYrLFjoxmW9Iz3zSJ7XOy7rNEulQOZzRJ86Znxd709Vu5W9TKVSqVQqlUqlUqn+Nc1wtSrByGXwcL1ETvEt7KMOLWvr2R/l9ivUZ+nIOW6PyZBXqTpykESme/iAmsnphqXxwrmb5uf0ONDFHQRve2mV6OT4WOkxIRedNu/CbyMsdHZoFHjb2KO33+Ut3uXRJug7gXT/DJ0v7FvvDh9OYHowmdL+A5Yf6euZbge6/Rw92wRviy1n+u4EfY9vYpzzi9DZq4T+n1xoCR7jvmx9h3EP7T19ZzdPMYfrSSzsVlryQuc5H4nOcz6/Z69Df++073XoSso0Ho6m9eY9W8mHw86w2Mi9rFKpfrTXn8Wb6asY1U8UT7zv6J8QebEnT2EGoWdyMVPwwpkpWXf0nU4YDnbX2WCdskDhgvutnDke9Z1d7ZXpvJUGdrzLfwe94akCN2T6rdvCIEHOHE/oWxSJ6XJ8WG1a5HdnpGMMYUn0MxA7vaH4h1R6Qt8CZUyX40Mmes5s752ej/jJSJdKb6ObBQ8WL+lQ1ts9Xhj2qNWb6I7iUK/p8LsO5p7ARJ3pT1fc7bhnjo1dx320fOZ5JuO+POg7zRWyWztOVxhS4ke+zvmBLpGnvu5z/o/P1hW+OiyF1i7TMQTUZrM0XOj5ut53y8NC75Tkpbb+lbgRfjjuTSqVSqVSqVQqlUqlUqn+d/0SYAC96h0S3W1cMQAAAABJRU5ErkJggg==',         errorThumb: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAH0AAAB9CAMAAAC4XpwXAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAwBQTFRF/3p7l4qKlhoahxoa7+7uxMTEZgEB/6e2/ikp/mBgtKKi/3Nz6+vr/42U2+bn5VdXaUFBpCcnxkxMmCUmzNPTyCQk/4KEtxUVpJmZ6YWFxaWljImJ5NjYq2ho19fXrays0tLS/zAwsbGx8yMjuTIyeiQkxRUV+OfnrqmpiiMjjIWFdklJ/VpaygcH/VNTZT09tn19+fj41SQkrKOj5zg40bu711NT5Hd3YUdHnJyc4uzs18bGmVJSrgcHXDU24xsb5EpK/5OT+UpKmGVl+SQkWAIC/4iI09vc1qeneRsb81tb/4WPvElJk0dHrlNT/6yu0EFB04CAwz096R4e/pqb/m1t89XV20RE5ubm3BgY1AkJ8vLy0hUVzDIy+f//sSsr0EpKy5mZgwEBhoSEyFpa2mho/52iiwMDqhMTvSIi9FRUhn5+kwIC4aur/paaoh0d/2pq2RISvCkpwzU1qEVF2Do6bBoa7CIikwgIxpycfAICycXF/6Gm5GNjcgEB/5Gg7GFh4sTEwcHCSgEBnAsLs25uztzc19ra4uTkugICrE1NaygozXR0zc3NclhYYFlZrR0d4Corw9HRsiIiusXG4xIS2d/ftbW14uLiqqiowYiIoRER2ExM/zg4tLOz/f39VyQkPAgIXRAQ/36B92Fh7tHRrzo61BwczMvL3yEhu2xs7PHx8pma1HR0kpOTbA0N6W1t9HFx0dbWmAUFhA0Ns2Fh5MzM0n5+upWV2XV1cj8/oU5OSRsb2n9/+vj4SCoqyb6+x5WV39XVhzw88vX1eQ4OvLq7xK6vsr29Rjg4/v7+jkFB4eHhv7+/////9PT0yMjIurq63NzctLS03Nvb/f///v//1dTUvbu8xMnK6c7Osre3//7++vv7xMfH1tbW5N/f9/z8xLW1wb+/+fn5+/z8/3Bw+Hl5/3Z38mpr/mdnjhAQr11dr66vmHBw//39jGhoim9wyTg4xsTF5g8PtLW1fnl67TU137+//6Swr7Cw5XBxvjAw+Pf3+W9v8SAgfetMUwAACIFJREFUeNrsmAtcU9cdx4EkFCUKAWKAQIhBaIM8ilow8hak1clEkIcUC4MKBMEQRMCsZlYBeQjloVwpLipSBPugRW2rVq1tme0tBAJrbWt1rUupg7LPps2wyubOufcmkI5ScLlx+/T+PnzCufeec77nf8/rd64J8jBlQtEpOkWn6BSdov9v0QUuSx/TU5OLwGj0waVv77h06Tc6Xbq04+2lCiPRBfYvvvLchq0ZGRnPQWVkbMhY98qL9gKj0AX2JxzWrfvhh0cIrcPkcOJB8LOmK+xLHbaGzZs373eEtm4NCwvbsMHB2V5BOn3UtNQ/LPLYsQULfkUoEmhBZFiYf6npKLl0zWOm392LNLG8aWJyDLQAtIEQuAh7/TvTJlLpo6aV/guG8uKGLG8CmYBGaAWuIu9VmrqQSFd4BG62zJszJ2/Yc3hoKG5oaMgSU9zwkGVc3M1vN5/zUJBGH/UI9HujNdtzTnZCTGp23jBQHlDcmtS1h1rjhlv/9a1foMcoOXSNi+n7Nn+xys7O9k4oCD+Xmj2HkGfqufDKQ62ta3btesPmfa4LKXTFlqq1Vlahodkr2ZWOzIDTYm9vT29PT0/v/NMBTMfKTWvWWFnt3LnWLV1BAn00fXHbodCEhNDt7IIddOXXT5weX+YNtGz89BNff0kH+AQrPz8rv7bF6S6Gp4tqog5F39q+fdmmSke6Uql8JsB529jKlWPbnAOeAZdPO/46JjQhNdXPr6BGpDE4nVtTEDM+vu0W28bxghLq8FfODWNj+c5fHcYuL1x+dlN0dEyMTdtiruFj5y62bUtZND4ufvYlJa5v3juRlXXivW+Iy5c2s2/F3IqJYZFCtxayWKyUlIaY8/EETxlQWhrwCZ78Mv58dP628UWLFknOkkE/KxQKbW1ZrKzaffH4y1ZeYzKvaeFnxJz8/BQgcujWQjc32ACJRLL+UeWnh4FQIPj/U+Wj58VicUNDA0vCIonuVlVVCPlmzay3AN7X11d97Zra1/efnwB4PofTUCuRCG2FZiTQB7nWhe8cKSxcTaOZmZ1seCve94OnCX1wIf68OKi2tlZiZkajudHIiN0D0N9pIfAlzfvefJlOZ2J/L7+5jwPgkmYIX11IO+th8Pmu8bBuOXr0aEtLZ2f3qZHikyOPlzOZiUDg9/GRkubm5pGRkVPdnS0t3aT0uw+g79mzZ5W5uVwmkwVeZh4s7zl4sKe8PPHGuVOZxcWZaTK5+apVezqtPTRk0CF7FaCby7sD311R/kdC5SveDTwlS5MBOE4nZcx34mS5XCYP7G9svML7Eybelcae3wbK0kDocsA3J4OuAXSIlgGMPOpyI4/P57dfmT+/qx0k9j55OQrch+HL5d2kxO7TKYNo0L0fz32yq7q9vd9ur5PTXrv+9vbqrrK5H8vScjJBC9K6fciIfXlnJlTOSNRcO7vbt28zrjfeWb/+TuN1Brjg18+NGskBQy8zh5zYl7udBNUX5xTc+Px67+7dn+0uc3o1KOhVpzKQ3P3n65/fKICPi0/SlnMNP+ZFL1SZlRSXlOS0PTW/XvGZYn+Z0xlORYX7Gaey/Yo/KOrnP9WW01xSUmJW9YLI8LG7pC8vBGtKc0mWTS5//90P7Z73d69w96o47v+83Yd39/NzbThBWVlZZoU+6aOGj10j2HLRrTYrixMUFJ3bdbX+zr0kL2lycrJX0ut36q925SZUVHA4HInbxfRBUvy8C/fiajEguHul5q74YqdUmrwRSCqV7vxiRW6ClzuQmBbMddGQQtcI0oNp7OPu7l7JoQ67OpI2hmA6kNSxyyFUmpScfJxNC04n6TSBWfpgW3bI8SVSacj30lidDnwfckDasTGEbRu8hbyTFDxLHbGtC+noCAmJLSq6P6HY2KLY2CWsIx6zPEPP8vzexA2m1bkWFRW5urpG6OR6/75rRJ1ZMJfcEzSC3OVa0+osIiIsIiwmK8KijmbNJfnrARx7r/nY1i20WKgni4V1tj6vDSLk0wWij4RjC3+vr2XCj0TG+GqEIAJRjVtKQ4OYzV6CiS0WjwtrRMb5YoYgV0X/+PvfwsOdtQoP/+sWkQYxEh0ZFDRB6b6TNjUJBhGj0akv5BSdolN0ik7R/6/ovSiK9vSDH/4U2XpQtA9L8EGG/umrhBXxfuIZqAc1KB0WMyQdpgaYqBpQ+H0oqubh9GoUTVThdNUAzNw7ic5g6pg4XdWjzcIDCXo1goDyPTOkQ/VhBbG6eohbPJzehz9XgWKQCij4Y+YEHc+iViGJ+KN+FVHFTOg8GB2iBglQmo7RVTo6iALtVeOx4nSQW80ACYaWDrMwYBYGkRiACVjZjOg8gsfHuhz70dHhs94+or+xNw9q7eslxoyuOJalf3KC3zMLOlYf1tz/pKPoZDpzejqInTl7OhgydPS/oyOIiqdGf5aOTEGHvaeemt6rN+OmoQ/gdTwAXa2dJFPQmTOLHQ42OG8fgK4r8OB07aj7OToINBGbKHp0npb+oxnHAANigCiGvd6fmHEQyoD06WecdmlhInpvXtfvmKrx1YaOLyVY3/dph5TeaqNSE6sNAyX6ffrVBiyFxGo5Qe9Xo0weQadXw2AnrbSJDLwUrBqphg0aUE2sdYxEIgsoz2NiWaZbaSl3QdEpOkWf0g7+oug6X10NF3Em2seYMLwq6H9xIzvJ6xo8du1eAzcW+oThHdAa3slelxS6Gm5VAzw9w8uE2512W9V6XVLomMfgw50O0RlerbXg6XldI9Axt6BHR1Hj0HWG96HQdYZX/82TNt/16TrDC+kMHZ1pvH7HbutmnJHpuOFVgbEHu4Gv53XJf/N4v2tPA3w9r0syXWd44ZKDHVn0vK6xdlhios18gTXs/o4dUgd6kYdDp5wVRafoFJ2iU3SK/iP9W4ABALeyhvlMe5fjAAAAAElFTkSuQmCC',         externalImage: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAahJREFUeNpUks9LFVEUxz933sy8nok/HolGpGIgIghCO3XpJty4ENwUImTLaCEh7foDFNqJiJBb2whi6FoUJAoR1FoomlhI8ohX+qZ5b27fmWcNXvie++t8zz3ne67h2TaQFzoEI/DQGNat1apCOuIrh4IbW7i4PmmHyPF9l/z8OHQ2Q/matPcNJhbx3Oo2I/wQAvFatoKg4d30mhl5/wJa6qoet7MyljAmjBFGWaxecH6CdxlR7vGKJZ/fQZrRVVidXbHmultr/PpchlLZ8unzXbrbfVYVvU2lfS3ISVnXZv8RIvvr7XhbvudeLaOzULrPf+dTOQ9OQ9aHV4+UeAaT1HBL9vUKLG/B/kwaeegNfDkJV3C90pMFRqLqY4qq/J4OQJdEmlyCnVNFFnH3UDXldpdwC6NSq19SDyaEQNJ13IG1STiQfL1T8KBJDek6k65/ajDfI4zdlOt2Qsh5yURrI2y8hKlh1fEcGnJSrhJLXhSOEl1d9cv7eHJJWLEJydf94z74cAznxSjuq5P2KVbJMecTi8ch1t78BvHW0cJzrtLmXvBXgAEAaJaDi8YtYjEAAAAASUVORK5CYII=',     };             var Thumb = function(props) {         var self = this;                 $.extend(self, props);                         self.buildFile = function(fileId) {             var container = $.create('div', { id: fileId, className: 'file imgur-container' });             var div = $.create('div', { className: 'fileInfo' });             var span = $.create('span', { className: 'fileText', innerHTML: 'Link: ' });             var fia = $.create('a', { target: '_BLANK', href: self.link, innerHTML: self.name + ' ' });             var extImg = $.create('img', { src: Resources.externalImage });             var fa = $.create('a', { target: '_BLANK', href: self.link, className: 'fileThumb' });             var img = $.create('img', { className: 'imgur-thumbnail' });             //$.data(img, 'processor', self.processor);             //$.data(img, 'thumb-url', self.thumbUrl);             $.data(img, 'image-url', self.imageUrl);             $.append(fia, extImg);             $.append(span, fia);             $.append(div, span);             $.append(container, div);             $.append(fa, img);             $.append(container, fa);             return container;         };                 self.loadImage = function(callback) {             var image = new Image();             image.onload = function() {                 callback.call(self, true);             };             image.onerror = function() {                 console.log("Could not load image: " + self.imageUrl);                 callback.call(self, false);             };             image.src = self.imageUrl;         };                 self.placehold = function(post, file) {             var fileId = 'f' + (/m(\d+)/.exec(post.id))[1];             var file = file || self.buildFile(fileId);             var img = $('img.imgur-thumbnail', file)             img.src = Resources.placeholderThumb;             var handler = function(e) {                 e.preventDefault();                 Thumb.preloaded.push(fileId);                 $.off(img, 'click', handler);                 self.loadImage(function(loaded) {                     if (loaded) {                         img.src = self.thumbUrl;                         if (self.configValue('hoverExpand') === true) {                             Hover.init(img);                             Hover.set(self.imageUrl);                         }                     } else {                         img.src = Resources.errorThumb;                     }                 });             };             $.on(img, 'click', handler);             $.before(post, file);         };                 self.plant = function(post, file) {             var fileId = 'f' + (/m(\d+)/.exec(post.id))[1];             if (self.configValue('preload') === false && !Thumb.isPreloaded(fileId)) {                 return self.placehold(post, file);             }             var file = file || self.buildFile(fileId);             var img = $('img.imgur-thumbnail', file)             $.before(post, file);             self.loadImage(function(loaded) {                 if (loaded) {                     img.src = self.thumbUrl;                     if (self.configValue('hoverExpand') === true) {                         Hover.init(img);                     }                 } else {                     img.src = Resources.errorThumb;                 }             });         };                 self.configValue = function(key) {             return Config.get([self.processor, key], Options.processors[self.processor][key][0]);         };     };         $.extend(Thumb, {         preloaded: [],         isPreloaded: function(id) {             return $.inArray(Thumb.preloaded, id);         },     });       var Main = {         processors: [],         getFile: function(post) {             var siblings = $.siblings(post);             var res;             $.each(siblings, function(sibling) {                 if ($.hasClass(sibling, 'file')) {                     res = sibling;                     return false;                 }             });             return res;         },         qualify: function(post, qualifier) {             return post.innerHTML.indexOf(qualifier) >= 0;         },         sortProcessors: function() {             Main.processors.sort(function(a, b) {                 if (a.priority < b.priority)                     return -1;                 else if (a.priority > b.priority)                     return 1;                 return 0;             });         },         attach: function(processor) {             var exists = false;             $.each(Main.processors, function(proc) {                 if (proc.name == processor.name) {                     exists = true;                     return false;                 }             });             if (!exists) {                 //console.log("attaching " + processor.name);                 Main.processors.push(new processor);                 Main.sortProcessors();             }         },         detach: function(type) {             $.each(Main.processors, function(proc, index) {                 if (proc.name == type) {                     //console.log("detaching " + type);                     Main.processors.splice(index, 1);                     Main.sortProcessors();                     return false;                 }             });         },         process: function(target) {             if (Main.processors.length == 0) return;             var posts = $('blockquote', target, true);             $.each(posts, function(post) {                 var file = Main.getFile(post);                 if ($.null(file) || $.hasClass(file, 'imgur-container')) {                     $.each(Main.processors, function(processor) {                         if (Main.qualify(post, processor.qualifier)) {                             return !processor.process(post, file);                         }                     });                 }             });         },         init: function() {             Main.process(d.body);                         d.addEventListener('DOMNodeInserted', function(e) {                 Main.process(e.target);             });         },     };         var Processors = {         'Imgur': function() {             var self = this;                         self.priority = 1;             self.name = 'Imgur';             self.regex = /((?:i\.)?imgur.com\/)(\w{4,7})(\.?(?:jpg|png|gif))?/i;             self.qualifier = 'imgur.com/';             self.imageBase = 'http://i.imgur.com/';                         self.process = function(post, file) {                 self.regex.lastIndex = 0;                 var match = self.regex.exec($.strip(post));                 if (match && $.notnull(match[2])) {                     var base = match[1];                     var filename = match[2];                     var extension = '';                     if (match.length >= 3 && $.notnull(match[3])) {                         extension = match[3];                     }                     var name = base + filename + extension;                     var link = '//' + base + filename + extension;                     var imageUrl = self.imageBase + filename + (extension.length > 0 ? extension : '.jpg');                     var thumbUrl;                     var tinyThumb = Config.get([self.name, 'tinyThumb'], Options.processors[self.name]['tinyThumb'][0]);                     var autoGif = Config.get([self.name, 'autoGif'], Options.processors[self.name]['autoGif'][0]);                     if (!tinyThumb && autoGif && extension.length && extension == '.gif') {                         thumbUrl = self.imageBase + filename + extension;                     } else {                         thumbUrl = self.imageBase + filename + (tinyThumb ? 's.jpg' : 'm.jpg');                     }                     var thumb = new Thumb({                         processor: self.name,                         name: name,                         link: link,                         imageUrl: imageUrl,                         thumbUrl: thumbUrl                     });                     thumb.plant(post, file);                     return true;                 }                 return false;             };         },         'Fourchan': function() {             var self = this;                         self.priority = 2;             self.name = 'Fourchan';             self.regex = /images\.4chan\.org\/(?:a|b|c|d|e|f|g|gif|h|hr|k|m|o|p|r|s|t|u|v|vg|w|wg|i|ic|r9k|cm|hm|y|3|adv|an|cgl|ck|co|diy|fa|fit|hc|int|jp|lit|mlp|mu|n|po|pol|sci|soc|sp|tg|toy|trv|tv|vp|wsg|x|rs|q)\/src\/(\d+?)\.(?:jpg|png|gif)/i;             self.qualifier = 'images.4chan.org';             self.url = 'http://thumbs.4chan.org/mlp/thumb/{stamp}s.jpg';                         self.process = function(post, file) {                 self.regex.lastIndex = 0;                 var match = self.regex.exec($.strip(post));                 if (match && $.notnull(match[0])) {                     var name = match[0];                     var stamp = match[1];                     var link = '//' + name;                     var thumbUrl = self.url.replace('{stamp}', stamp);                     var thumb = new Thumb({                         processor: self.name,                         name: name,                         link: link,                         imageUrl: link,                         thumbUrl: thumbUrl                     });                     thumb.plant(post, file);                     return true;                 }                 return false;             };         },         'YouTube': function() {             var self = this;                         self.priority = 3;             self.name = 'YouTube';             //self.regex = /(?:youtube(?:-nocookie)?\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/ ]{11})/i;             self.regex = /(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube(?:-nocookie)?\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w]*(?:['"][^<>]*>|<\/a>))[?=&#+%\w-]*/i;             self.qualifier = 'youtu';             self.url = '//i.ytimg.com/vi/{id}/0.jpg';                         self.process = function(post, file) {                 self.regex.lastIndex = 0;                 var match = self.regex.exec($.strip(post));                 if (match && $.notnull(match[1])) {                     var id = match[1];                     var name = match[0];                     var link = '//' + match[0];                     var imageUrl = self.url.replace('{id}', id);                     var thumb = new Thumb({                         processor: self.name,                         name: name,                         link: link,                         imageUrl: imageUrl,                         thumbUrl: imageUrl                     });                     thumb.plant(post, file);                     return true;                 }                 return false;             };         },         'Derpibooru': function() {             var self = this;                         self.priority = 5;             self.name = 'Derpibooru';             self.regex = /(derpiboo(?:\.ru|ru\.org)\/)(\d+)/i;             self.qualifier = 'derpiboo';             self.cache = {};                         self.processJSON = function(data, info) {                 if ($.notnull(info)) {                     self.cache[data.id] = info;                 } else {                     info = self.cache[data.id];                 }                 var name = data.base + info.id_number;                 var link = data.url;                 var imageUrl = info.image;                 var thumbUrl = info.image;                 var thumb = new Thumb({                     processor: self.name,                     name: name,                     link: link,                     imageUrl: imageUrl,                     thumbUrl: thumbUrl                 });                 thumb.plant(data.post, data.file);             };                         self.process = function(post, file) {                 self.regex.lastIndex = 0;                 var match = self.regex.exec($.strip(post));                 if (match && $.notnull(match[1]) && $.notnull(match[2])) {                     var data = {                         post: post,                         file: file,                         base: match[1],                         id: match[2],                     };                     data.url = '//' + data.base + data.id;                     if (self.cache[data.id]) {                         self.processJSON(data);                     } else {                         $.json(data.url + '.json', data, self.processJSON);                     }                     return true;                 }                 return false;             };         },         'Generic': function() {             var self = this;                         self.priority = 10;             self.name = 'Generic';             //self.regex = /https?:\/\/[\-A-Z0-9+&@#\/%?=~_|!:,.;]*[\-A-Z0-9+&@#\/%=~_|]?(?:\.(?:jpe?g|png|gif))/i;             self.regex = /https?:\/\/([\-A-Z0-9.]+)\/[\-A-Z0-9+&@#\/%=~_|]+\.(?:jpe?g|png|gif)/i;             self.qualifier = 'http';                         self.isAllowedDomain = function(domain) {                 var disallowed = Config.get([self.name, 'disallowedDomains'], Options.processors[self.name]['disallowedDomains'][0]).split(',');                 for (var i = 0, c = disallowed.length; i < c; i++) {                     var dom = disallowed[i].trim();                     if (dom.length > 0 && domain.indexOf(dom) > -1) return false;                 }                 if (!Config.get([self.name, 'whitelistOnly'], Options.processors[self.name]['whitelistOnly'][0])) {                     return true;                 }                 var allowed = Config.get([self.name, 'allowedDomains'], Options.processors[self.name]['allowedDomains'][0]).split(',');                 for (var i = 0, c = allowed.length; i < c; i++) {                     var dom = allowed[i].trim();                     if (dom.length > 0 && domain.indexOf(dom) > -1) return true;                 }                 return false;             };                         self.process = function(post, file) {                 self.regex.lastIndex = 0;                 var match = self.regex.exec($.strip(post));                 if (match && $.notnull(match[0])) {                     var imageUrl = match[0];                     var domain = match[1];                     if (self.isAllowedDomain(domain)) {                         var thumb = new Thumb({                             processor: self.name,                             name: imageUrl,                             link: imageUrl,                             imageUrl: imageUrl,                             thumbUrl: imageUrl                         });                         thumb.plant(post, file);                         return true;                     }                 }                 return false;             };         },     };         var Options = {         processors: {             'Imgur': {                 enabled: [true, 'Enabled', 'Enable imgur.com link thumbnails'],                 preload: [true, 'Preload', 'Preload images'],                 hoverExpand: [true, 'Hover Expand', 'Enable image hover expansion'],                 autoGif: [true, 'Auto-Gif', 'Use animated gifs instead of non-animated thumbnails'],                 tinyThumb: [false, 'Tiny Thumb', 'Use smallest available thumbnail (overrides auto-gif)'],             },             'Fourchan': {                 enabled: [true, 'Enabled', 'Enable 4chan link thumbnails'],                 preload: [true, 'Preload', 'Preload images'],                 hoverExpand: [true, 'Hover Expand', 'Enable image hover expansion'],             },             'YouTube': {                 enabled: [true, 'Enabled', 'Enable YouTube link thumbnails'],                 preload: [true, 'Preload', 'Preload images'],                 hoverExpand: [true, 'Hover Expand', 'Enable image hover expansion'],             },             'Derpibooru': {                 enabled: [false, 'Enabled', 'Enable derpibooru.org link thumbnails (probably doesn\'t work on Opera)'],                 preload: [false, 'Preload', 'Preload images'],                 hoverExpand: [true, 'Hover Expand', 'Enable image hover expansion'],             },             'Generic': {                 enabled: [false, 'Enabled', 'Enable other image link thumbnails'],                 whitelistOnly: [false, 'Allowed Only', 'Only enable for whitelisted domains (comma-separated, match-based)'],                 allowedDomains: ['tumblr.com,derpicdn.net', 'Allowed Domains'],                 disallowedDomains: ['', 'Disallowed Domains'],                 preload: [false, 'Preload', 'Preload images (not recommended)'],                 hoverExpand: [true, 'Hover Expand', 'Enable image hover expansion'],             },         },     };         var Config = {         get: function(key, def) {             if (key instanceof Array) {                 key = key.join('.');             }             var val = JSON.parse(localStorage.getItem(namespace + key));             if ($.null(val)) return def;             return val;         },         set: function(key, value) {             return localStorage.setItem(namespace + key, JSON.stringify(value));         },         remove: function(key) {             return localStorage.removeItem(namespace + key);         },         checkbox: {             change: function() {                 Config.set(this.name, this.checked);                 var opt = this.name.split('.');                 if (opt[1] == 'enabled') {                     if (this.checked)                         Main.attach(Processors[opt[0]]);                     else                         Main.detach(opt[0]);                 }                 return this.checked;             },         },         textbox: {             change: function() {                 Config.set(this.name, this.value);                 return this.value;             },         },     };         var Menu = {         init: function() {             var ref = ['boardNavDesktop', 'boardNavDesktopFoot'];             for (var i = 0; i < ref.length; i++) {                 var elem = $.id(ref[i]);                 if ($.null(elem)) continue;                                 var a = $.create('span', {                     className: 'imgur-settings-link',                     innerHTML: '[Imgur Settings]',                 });                 $.on(a, 'click', Menu.dialog);                 //$.replace(elem.previousSibling, [$.tn('] ['), a, $.tn('] [')]);                 $.append(elem, a);             }             if (!Config.get('firstrun')) {                 Config.set('firstrun', true);                 return Menu.dialog();             }         },         dialog: function() {             var menu = $.create('div', {                 id: 'imgur-menu',                 innerHTML: '\                    
\                        

4chan imgur thumbnail v' + version + '

\                    
\                    
\                        
\                    
\                 ',             });             var label, key, ref, opt, procs, content;             ref = Options.processors;             procs = $('.processors', menu);             content = $('.content', menu);             for (label in ref) {                 var ul = $.create('ul', { innerHTML: '' + label + '' });                 opt = ref[label];                 for (key in opt) {                     var arr = opt[key];                     var confKey = [label, key].join('.');                     var def = arr[0];                     var text = arr[1];                     switch (typeof def) {                         case 'boolean':                             var checked = Config.get(confKey, arr[0]) ? true : false;                             var description = arr[2];                             var li = $.create('li', {                                 innerHTML: ': ' + description + '',                             });                             $.on($('input', li), 'change', Config.checkbox.change);                             break;                         case 'string':                             var value = Config.get(confKey, arr[0]);                             var li = $.create('li', {                                 innerHTML: ': ',                             });                             $.on($('input', li), 'change', Config.textbox.change);                             break;                     }                     $.append(ul, li);                 }                 $.append(procs, ul);             }                         overlay = $.create('div', {                 id: 'imgur-overlay'             });             $.on(overlay, 'click', Menu.close);             $.on(menu, 'click', function(e) {                 return e.stopPropagation();             });             $.append(overlay, menu);             $.append(d.body, overlay);         },         close: function() {             $.remove(this);         },     };         $.addStyle('\         #imgur-overlay {\             position: fixed;\             top: 0;\             left: 0;\             width: 100%;\             height: 100%;\             text-align: center;\             background: rgba(0,0,0,.5);\             z-index: 1;\         }\         #imgur-overlay:after {\             content: "";\             display: inline-block;\             height: 100%;\             vertical-align: middle;\         }\         #imgur-menu {\             background: #D6DAF0;\             border: 1px solid rgba(0, 0, 0, 0.25);\             display: inline-block;\             padding: 5px;\             position: relative;\             text-align: left;\             vertical-align: middle;\             max-width: 100%;\             max-height: 100%;\         }\         #imgur-menu .info {\             font-size: 10px;\         }\         #imgur-menu .warning {\             font-weight: bold;\             color: #f00;\         }\         #imgur-menu p {\             line-height: 0;\             margin-bottom: 0;\         }\         #imgur-menu .bar {\             font-size: 16px;\             font-weight: bold;\             margin-left: 5px;\         }\         #imgur-menu .content {\             overflow: auto;\             padding: 10px;\         }\         #imgur-menu ul {\             padding: 0;\             list-style: none;\         }\         #imgur-menu label {\             text-decoration: underline;\         }\         #imgur-menu input[type="text"] {\             width: 320px;\             margin-top: 3px;\         }\         .imgur-settings-link {\             float: right;\             margin-right: .25em;\         }\         .imgur-thumbnail {\             border: 1px solid #00a !important;\             padding: 3px;\             max-height: 125px !important;\             max-width: 125px !important;\         }\         #imgur-thumbnail-hover {\             position: fixed;\             max-height: 97%;\             max-width: 75%;\             padding-bottom: 18px;\         }\     ');         Menu.init();       for (label in Options.processors) {         var opt = Options.processors[label];         if (Config.get([label, 'enabled'], opt.enabled[0])) {             Main.attach(Processors[label]);         }     }         Main.init();     })();