Kartom

GR-Tools 3.07 Beautified

Aug 5th, 2013
370
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name          GR-Tools - Pimp your GayRomeo! :-)
  3. // @namespace     http://gr-tools.justlep.net/
  4. // @description   Thumbnail-Zoom, BMI-Filter, opens Profiles without Popups, etc. etc.
  5. // @version v3.07
  6. // @date    27.05.2013 19:12
  7. // @author LeP <gr-tools@justlep.net> (GR: noscript / GR-Club: GR-Tools)
  8. // @downloadURL http://userscripts.org/scripts/source/33184.user.js
  9. // @include http*://www.gayromeo.com*/pix/popup.php*
  10. // @include http*://www.gayromeo.com*mainpage.php?set=*
  11. // @include http*://www.gayromeo.com*auswertung/album/*
  12. // @include http*://www.gayromeo.com/*mitglieder/administration/pictures/overview.php*
  13. // @include http*://www.gayromeo.com/*mitglieder/administration/pictures/edit.php?id=*
  14. // @include http*://www.gayromeo.com/*mitglieder/administration/pictures/navigation.php
  15. // @include http*://www.gayromeo.com/*main/top.php*
  16. // @include http*://www.gayromeo.com*auswertung/setcard/cluide/navigation.php*
  17. // @include http*://www.gayromeo.com/*/main/bottom.php
  18. // @include http*://www.gayromeo.com*auswertung/setcard/cluide/club_navigation.php?set=*
  19. // @include http*://www.gayromeo.com*/main/index.php*
  20. // @include http*://www.gayromeo.com*/search/index.php*
  21. // @include http*://www.gayromeo.com*myuser/*page=club
  22. // @include http*://www.gayromeo.com*myuser/*page=club*subPage=forum*
  23. // @include http*://www.gayromeo.com*search/*action=execute*
  24. // @include http*://www.gayromeo.com*search/*action=showPage*
  25. // @include http*://www.gayromeo.com*/search/*execute*searchType=*
  26. // @include http*://www.gayromeo.com*main/personalList/PersonalListPage.php?show*
  27. // @include http*://www.gayromeo.com*0/main/
  28. // @include http*://www.gayromeo.com*/settings/*
  29. // @include http*://www.gayromeo.com*/mitglieder/messages/*
  30. // @include http*://www.gayromeo.com*/myuser/*
  31. // @include http*://www.gayromeo.com*auswertung/setcard/cluide/club_profile.php*
  32. // @include http*://www.gayromeo.com/*auswertung/setcard/*set=*
  33. // @include http*://www.gayromeo.com*msg/history.php*
  34. // @include http*://www.gayromeo.com*/auswertung/setcard/romeo/footprint.php?receiverId=*
  35. // @include http*://www.gayromeo.com*/auswertung/setcard/romeo/saveFootprint.php*
  36. // @include http*://www.planetromeo.com*/pix/popup.php*
  37. // @include http*://www.planetromeo.com*mainpage.php?set=*
  38. // @include http*://www.planetromeo.com*auswertung/album/*
  39. // @include http*://www.planetromeo.com/*mitglieder/administration/pictures/overview.php*
  40. // @include http*://www.planetromeo.com/*mitglieder/administration/pictures/edit.php?id=*
  41. // @include http*://www.planetromeo.com/*mitglieder/administration/pictures/navigation.php
  42. // @include http*://www.planetromeo.com/*main/top.php*
  43. // @include http*://www.planetromeo.com*auswertung/setcard/cluide/navigation.php*
  44. // @include http*://www.planetromeo.com/*/main/bottom.php
  45. // @include http*://www.planetromeo.com*auswertung/setcard/cluide/club_navigation.php?set=*
  46. // @include http*://www.planetromeo.com*/main/index.php*
  47. // @include http*://www.planetromeo.com*/search/index.php*
  48. // @include http*://www.planetromeo.com*myuser/*page=club
  49. // @include http*://www.planetromeo.com*myuser/*page=club*subPage=forum*
  50. // @include http*://www.planetromeo.com*search/*action=execute*
  51. // @include http*://www.planetromeo.com*search/*action=showPage*
  52. // @include http*://www.planetromeo.com*/search/*execute*searchType=*
  53. // @include http*://www.planetromeo.com*main/personalList/PersonalListPage.php?show*
  54. // @include http*://www.planetromeo.com*0/main/
  55. // @include http*://www.planetromeo.com*/settings/*
  56. // @include http*://www.planetromeo.com*/mitglieder/messages/*
  57. // @include http*://www.planetromeo.com*/myuser/*
  58. // @include http*://www.planetromeo.com*auswertung/setcard/cluide/club_profile.php*
  59. // @include http*://www.planetromeo.com/*auswertung/setcard/*set=*
  60. // @include http*://www.planetromeo.com*msg/history.php*
  61. // @include http*://www.planetromeo.com*/auswertung/setcard/romeo/footprint.php?receiverId=*
  62. // @include http*://www.planetromeo.com*/auswertung/setcard/romeo/saveFootprint.php*
  63. // @include http*://83.98.143.20*/pix/popup.php*
  64. // @include http*://83.98.143.20*mainpage.php?set=*
  65. // @include http*://83.98.143.20*auswertung/album/*
  66. // @include http*://83.98.143.20/*mitglieder/administration/pictures/overview.php*
  67. // @include http*://83.98.143.20/*mitglieder/administration/pictures/edit.php?id=*
  68. // @include http*://83.98.143.20/*mitglieder/administration/pictures/navigation.php
  69. // @include http*://83.98.143.20/*main/top.php*
  70. // @include http*://83.98.143.20*auswertung/setcard/cluide/navigation.php*
  71. // @include http*://83.98.143.20/*/main/bottom.php
  72. // @include http*://83.98.143.20*auswertung/setcard/cluide/club_navigation.php?set=*
  73. // @include http*://83.98.143.20*/main/index.php*
  74. // @include http*://83.98.143.20*/search/index.php*
  75. // @include http*://83.98.143.20*myuser/*page=club
  76. // @include http*://83.98.143.20*myuser/*page=club*subPage=forum*
  77. // @include http*://83.98.143.20*search/*action=execute*
  78. // @include http*://83.98.143.20*search/*action=showPage*
  79. // @include http*://83.98.143.20*/search/*execute*searchType=*
  80. // @include http*://83.98.143.20*main/personalList/PersonalListPage.php?show*
  81. // @include http*://83.98.143.20*0/main/
  82. // @include http*://83.98.143.20*/settings/*
  83. // @include http*://83.98.143.20*/mitglieder/messages/*
  84. // @include http*://83.98.143.20*/myuser/*
  85. // @include http*://83.98.143.20*auswertung/setcard/cluide/club_profile.php*
  86. // @include http*://83.98.143.20/*auswertung/setcard/*set=*
  87. // @include http*://83.98.143.20*msg/history.php*
  88. // @include http*://83.98.143.20*/auswertung/setcard/romeo/footprint.php?receiverId=*
  89. // @include http*://83.98.143.20*/auswertung/setcard/romeo/saveFootprint.php*
  90. // @icon data:image/gif;base64,R0lGODlhHgAeAOYAAOUvLPn6+rWQZDxjttqus2JOJehbCpbI6eWGWvOGPYiHixCY0Hl5d7S0tUNswCdauvBSQwVPhxQnbUy4SfGsdDFfulHDTSRGmNhJD12HsDygQHGs16wsDPyOIOhwLZ+jpNPLugwWVM00CS1Xr0V6vOxoWPDmsIRsN6x1NQYGBgp0sehiDUFtcec+N/vjjz6zQ6WogytaWMhcXoBuVzhaqdWldh45hiVJcKxnSEqOz2x3hVovF01VjgEpXTJpwc9rNJiBYv6lG/N8HkOHO7FZLEiqReLi4/XOk4+ZntSOT5mvwlVql4tCLaI3UolWefJlCeuTbDJjmuNhG9VhFOIaIwhAbkJZpAZfmV45Sqh2cM4MGHNoYHi44yU6WX5HcwmBvFezVytOouEkKNtuc+NvG8EmHPoaFvAjHuRJQs9/Ts6HP6jeot/AI0hMUE6bWEuVY+tgU+GqMYV1Ivi9e8ZBCi03cFSrWEyySFqe3GafzNebYepvDvRvIS49OkBouzFctiH5BAAAAAAALAAAAAAeAB4AAAf/gA4OA2EDfjQ0Aw5+fgOIiIyRjImRJH4XISESI5khYRUVNp02oKUVPhI2Pn9/hiGqf5x/rz4+FZwjYZojmJupoheDIX+YmJmhm7O6FzYSIRcS0b0jjK8Vr88hvDaxnsOiIcipf9GCxtkV0aW44GHtv5qLt2F/FQ8PVvlW9yP1YSOg/t0akasCI1b2rDiRUaIhHBlO9oFiVa8CxXp/Dj4Y4QUNBAhwQn6EgMbLg4soKTKqEKZJixYjSZJ8CaDJA4spVTpoCQDAy5dofrboecZmTpUDWIg507OpmKdPqUg1Y3JiSj9WXpygAlXMmDFQEJAhI4QMESZYIlwIcw+lHxYW/+6UkQqAwIG7B0ywkdOnR4S/VarEWDKgbcY3Fiyc0EKFABc8GTJA7hKix40IKlT87YIiDhAaJ/3YmUCaA5oDOXLMIBKlR4guAlhc+fLlSoQqWISwUQPaDxjSFoaM4UKCBBMRRNIkSZBlduYvmkP0IRIEhxXfpCe8gLHBxxcmBp4YCM9k9oLztXuoxyEEhx832cFYOKAiyorx41eI4KBjwwEueZDwVwRY8MHHEixkR9oaeZwgHn4GSEEBCEjooMMHSggYwQ8ddIBgEXcoCAMRBqxwX3hQgKADAw00wAADGUaAQhBBZBHGECBm94IcBuwxHgYeHAHEBwEYYUQACiigxOYVOHSYwAA3aJDjHTs+cR8dHGSBBAMBIElkAFsgocAPQnSQxE4xSFmEdkw84SMHHOixRQNGMNBHHwoEUGENBnYggB/ExDCElBoU4KYBdNABBQpENtDGnEjqUIMQUgTBAKAs3SBooSWORwcCeszQJRINFDlDAwgkkIAQSwDKCi+a9kHHgwZ4QAEQDBxZZBs71EDBER3gYNBFFoVxwQ4YdGpAArdukeQWO6SwgwsmJMDDAAOkZFEdZWCwgrfLUlCDAAJQQEEBKRQwhwCtWCJJJBVgUQYd3UohhQcJhIXAHC7Ika4SOTgQCAA7
  91. // ==/UserScript==
  92.  
  93. /**
  94.  * Each & every line:
  95.  * Copyright(c) by LeP <gr-tools@justlep.net> (GR: noscript / GR-Club: GR-Tools)
  96.  *
  97.  * Modifications and/or reuse of the GR-Tools code require my explicit consent.
  98.  * You are NOT allowed to publish any changed version of the GR-Tools!
  99.  *
  100.  * All code has been tested with a recent Firefox and Chrome browser.
  101.  * However, the use of this script is at your own risk.
  102.  *
  103.  * ** Privacy **
  104.  * The GR-Tools do NOT and never will include any code to identify you
  105.  * or spy on your data. There is no commercial interest, no backdoors,
  106.  * no line of code intended to harm you and/or your privacy.
  107.  *
  108.  * The latest version of the GR-Tools are always available on userscripts.org:
  109.  * http://userscripts.org/scripts/show/33184
  110.  */
  111.  
  112. // #####################################################################################################################
  113. // ################################################ BEGIN OF USERSCRIPT ################################################
  114. // #####################################################################################################################
  115.  
  116.  
  117. GRT = (function(grtVersion) {
  118.     var DEBUG = false,
  119.         win = (typeof unsafeWindow != 'undefined') ? unsafeWindow : self,
  120.         doc = (win.document.unsafeObject || win.document),
  121.         version = grtVersion,
  122.         PAGE_URL = location.href || '',
  123.         ALLOWED_URLS_REGEX = /^https?:\/\/(?:www\.)?(?:planetromeo\.com|gayromeo\.com|83\.98\.143\.20|(?:gr-tools|ref)\.justlep\.net)/,
  124.         ANON_URL_HASH = '#GRT_ANON_PROFILE',
  125.         BASE_URL_REGEX = /(https?:\/\/[^\/]*)/,
  126.         useSSL = location.protocol.indexOf('https') >= 0,
  127.         CONFIG_COOKIE_NAME = 'grt',
  128.         CONFIG_COOKIE_TTL = 14,
  129.         config = {
  130.             keep: 0,
  131.             de: 1,
  132.             rc: 1,
  133.             pica: 1,
  134.             dim: 0,
  135.             tit: 0,
  136.             lt: 1,
  137.             sb: 1,
  138.             bmi: 1,
  139.             bmin: 17,
  140.             bmax: 27,
  141.             age: 1,
  142.             amin: 18,
  143.             amax: 88,
  144.             secr: 1,
  145.             popa: 1,
  146.             popt: 1,
  147.             z: 1,
  148.             pl: 1,
  149.             lm: 1,
  150.             yth: 1,
  151.             ytp: 1,
  152.             ytpr: 1,
  153.             taps: 1
  154.         },
  155.         processors = {},
  156.         processorIdInitOrder = [],
  157.         moreAllowed = true,
  158.         modulesNeedDispatcher = false,
  159.         finalized = false,
  160.         NOP = function() {},
  161.         configHtmlProviderFn = null,
  162.         dispatcher = null,
  163.         cssQueue = [],
  164.         cssInjector = null,
  165.         console = win.console,
  166.         bodyClass = doc.body.className || '',
  167.         LOG_ENABLED = DEBUG && typeof console != 'undefined' && typeof console.log == 'function' && typeof console.log.apply == 'function',
  168.         DOMAIN = {
  169.             GR: 'www.gayromeo.com',
  170.             PR: 'www.planetromeo.com',
  171.             IP: '83.98.143.20'
  172.         },
  173.         log = (!LOG_ENABLED) ? NOP : function() {
  174.             console.log.apply(console, arguments);
  175.         },
  176.         assertTrue = function(expr, errorMsg) {
  177.             if (expr) return;
  178.             arguments[1] = '(!) ' + arguments[1];
  179.             log.apply(this, Array.prototype.slice.call(arguments, 1));
  180.             throw 'GRT assertion error.';
  181.         },
  182.         assertIsAllowedUrl = function(url) {
  183.             var isValidUrl = url.indexOf('/') === 0 || url.match(ALLOWED_URLS_REGEX);
  184.             assertTrue(isValidUrl, 'The given URL seems to link outside GR or the GR-Tools page: ', url);
  185.         },
  186.         MIN_AGE = 18,
  187.         MAX_AGE = 123,
  188.         MIN_BMI = 10,
  189.         MAX_BMI = 70,
  190.         setConfig = function(o) {
  191.             o = o || {};
  192.             for (var key in o) {
  193.                 var k = '' + key,
  194.                     val = parseInt('' + o[k], 10) || 0;
  195.                 if (typeof config[k] == 'undefined') continue;
  196.                 if (k == 'amin') val = Math.max(Math.min(MAX_AGE, val), MIN_AGE);
  197.                 else
  198.                 if (k == 'amax') val = Math.max(Math.min(MAX_AGE, val), MIN_AGE);
  199.                 else
  200.                 if (k == 'bmin') val = Math.max(Math.min(MAX_BMI, val), MIN_BMI);
  201.                 else
  202.                 if (k == 'bmax') val = Math.max(Math.min(MAX_BMI, val), MIN_BMI);
  203.                 config[k] = val;
  204.             }
  205.             var tmp = [config.amin, config.amax];
  206.             config.amin = Math.min(tmp[0], tmp[1]);
  207.             config.amax = Math.max(tmp[0], tmp[1]);
  208.             tmp = [config.bmin, config.bmax];
  209.             config.bmin = Math.min(tmp[0], tmp[1]);
  210.             config.bmax = Math.max(tmp[0], tmp[1]);
  211.         },
  212.         serializeConfig = function() {
  213.             var s = [];
  214.             for (var k in config) {
  215.                 s[s.length] = k + ':' + config[k];
  216.             }
  217.             return s.join('|');
  218.         },
  219.         deserializeConfig = function(s) {
  220.             var cfg = {},
  221.                 pairs = s.split('|');
  222.             for (var i = 0; i < pairs.length; i++) {
  223.                 var keyVal = pairs[i].split(':');
  224.                 cfg[keyVal[0]] = keyVal[1];
  225.             }
  226.             return cfg;
  227.         },
  228.         loadConfigFromCookie = function() {
  229.             var cookies = (document.cookie || '').split(';');
  230.             for (var i = 0; i < cookies.length; i++) {
  231.                 var cookie = cookies[i].trim();
  232.                 if (cookie.substring(0, CONFIG_COOKIE_NAME.length + 1) == (CONFIG_COOKIE_NAME + '=')) {
  233.                     var serializedConfig = decodeURIComponent(cookie.substring(CONFIG_COOKIE_NAME.length + 1)),
  234.                         newConfig = deserializeConfig(serializedConfig);
  235.                     setConfig(newConfig);
  236.                     return;
  237.                 }
  238.             }
  239.         },
  240.         saveConfigCookie = function() {
  241.             var expiryDateString = '';
  242.             if (config.keep) {
  243.                 var newExpiryDate = new Date();
  244.                 newExpiryDate.setTime(newExpiryDate.getTime() + CONFIG_COOKIE_TTL * 24 * 60 * 60 * 1000);
  245.                 expiryDateString = newExpiryDate.toUTCString();
  246.             }
  247.             var cookieData = [CONFIG_COOKIE_NAME, '=', encodeURIComponent(serializeConfig()), '; expires=', expiryDateString, '; path=/'];
  248.             document.cookie = cookieData.join('');
  249.         },
  250.         getVersion = function() {
  251.             return version;
  252.         },
  253.         urlContainsAll = function() {
  254.             for (var i = arguments.length - 1; i >= 0; i--) {
  255.                 if (PAGE_URL.indexOf(arguments[i]) < 0) return false;
  256.             }
  257.             return true;
  258.         },
  259.         urlContainsAny = function() {
  260.             for (var i = arguments.length - 1; i >= 0; i--) {
  261.                 if (PAGE_URL.indexOf(arguments[i]) >= 0) return true;
  262.             }
  263.             return false;
  264.         },
  265.         hasProcessor = function(processorID) {
  266.             return !!processors[processorID];
  267.         },
  268.         addProcessor = function(processor) {
  269.             assertTrue(!finalized, 'Cannot add processor after finalize() called.');
  270.             var id = (processor || {}).ID;
  271.             try {
  272.                 assertTrue( !! processor && typeof processor == 'object', 'Invalid processor: ', processor);
  273.                 assertTrue(moreAllowed, 'No more page processors allowed');
  274.                 assertTrue(!processor.EXCLUSIVE || !processorIdInitOrder.length, 'Processor <%s> cannot be added alongside other processors. It is exclusive.', id);
  275.                 assertTrue( !! id, 'Invalid processor id <%s>', id);
  276.                 assertTrue(!processors[id], 'Processor <%s> already registered', id);
  277.                 assertTrue(typeof processor.init == 'function', 'Invalid or missing init-method for processor <%s>', id);
  278.                 processors[id] = processor;
  279.                 moreAllowed &= !processor.EXCLUSIVE;
  280.                 modulesNeedDispatcher |= processor.NEEDS_DISPATCHER;
  281.                 processorIdInitOrder.push(id);
  282.                 if (processor.CSS) {
  283.                     for (var i = 0; i < processor.CSS.length; i++) {
  284.                         cssQueue[cssQueue.length] = processor.CSS[i];
  285.                     }
  286.                 }
  287.             } catch (e) {}
  288.         },
  289.         supportsUrl = function(matcherFn) {
  290.             assertTrue(!finalized, 'supportsUrl() not available after finalize() called.');
  291.             return matcherFn(PAGE_URL, bodyClass);
  292.         },
  293.         addClass = function(elem, cls) {
  294.             if (!elem) return;
  295.             var oldClass = elem.className || '';
  296.             elem.className = oldClass + ' ' + cls;
  297.         },
  298.         stopEvent = function(e) {
  299.             if (!e) return;
  300.             e.cancelBubble = true;
  301.             if (e.preventDefault) e.preventDefault();
  302.             if (e.stopPropagation) e.stopPropagation();
  303.         },
  304.         initProcessors = function() {
  305.             for (var i = 0; i < processorIdInitOrder.length; i++) {
  306.                 try {
  307.                     var processorId = processorIdInitOrder[i],
  308.                         processor = processors[processorId],
  309.                         now = +new Date();
  310.                     processor.init(GRT_PUBLIC, HELPERS_FOR_PROCESSORS);
  311.                     var dur = (+new Date()) - now;
  312.                 } catch (e) {}
  313.             }
  314.         },
  315.         setDispatcher = function(_dispatcher) {
  316.             assertTrue(!finalized, 'Cannot set dispatcher after finalize() called.');
  317.             dispatcher = _dispatcher;
  318.             dispatcher.init(GRT_PUBLIC, HELPERS_FOR_PROCESSORS);
  319.         },
  320.         setCssInjector = function(_injector) {
  321.             assertTrue(!finalized, 'Cannot set CSSInjector after finalize() called.');
  322.             cssInjector = _injector;
  323.         },
  324.         needsDispatcher = function() {
  325.             return modulesNeedDispatcher;
  326.         },
  327.         needsCssInjector = function() {
  328.             return !!cssQueue.length;
  329.         },
  330.         anonymousBaseUrl = null,
  331.         getAnonymousBaseUrl = function() {
  332.             if (!anonymousBaseUrl) {
  333.                 anonymousBaseUrl = top.location.protocol + '//';
  334.                 if (useSSL) {
  335.                     anonymousBaseUrl += ((top.location.host == DOMAIN.PR) ? DOMAIN.GR : DOMAIN.PR);
  336.                 } else {
  337.                     anonymousBaseUrl += ((top.location.host == DOMAIN.IP) ? DOMAIN.PR : DOMAIN.IP);
  338.                 }
  339.             }
  340.             return anonymousBaseUrl;
  341.         },
  342.         anonymizeUrl = function(url) {
  343.             return url.replace(BASE_URL_REGEX, getAnonymousBaseUrl()) + ANON_URL_HASH + location.host;
  344.         },
  345.         unanonymizeUrl = function(url, newDomainIndex) {
  346.             var urlToUse = url,
  347.                 targetHost = DOMAIN['' + newDomainIndex] || '';
  348.             if (!targetHost) return url;
  349.             targetHost = location.protocol + '//' + targetHost;
  350.             if (urlToUse.indexOf('..') === 0) {
  351.                 urlToUse = urlToUse.replace(/^(?:\.\.\/)+/, '/');
  352.             }
  353.             return urlToUse.replace(BASE_URL_REGEX, targetHost);
  354.         },
  355.         xpath = function(xpath, refNode) {
  356.             var n = [],
  357.                 res = (doc).evaluate(xpath, refNode || doc, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null),
  358.                 r = res.iterateNext();
  359.             while (r) {
  360.                 n[n.length] = r;
  361.                 r = res.iterateNext();
  362.             }
  363.             return n;
  364.         },
  365.         bodyClassContainsAny = function() {
  366.             var cls = doc.body.className || '';
  367.             for (var i = arguments.length - 1; i >= 0; i--) {
  368.                 if (cls.indexOf(arguments[i]) >= 0) return true;
  369.             }
  370.             return false;
  371.         },
  372.         finalize = function(customConfig) {
  373.             assertTrue(!finalized, 'Cannot run finalize() twice!');
  374.             if (customConfig) {
  375.                 setConfig(customConfig);
  376.             }
  377.             loadConfigFromCookie();
  378.             initProcessors();
  379.             finalized = true;
  380.             if (dispatcher) {
  381.                 dispatcher.finalize();
  382.             }
  383.             if (cssInjector) {
  384.                 cssInjector.init(GRT_PUBLIC, HELPERS_FOR_PROCESSORS, cssQueue);
  385.             }
  386.         },
  387.         isAnonymousUrl = function(url) {
  388.             return url && url.indexOf(ANON_URL_HASH) > 0;
  389.         },
  390.         setConfigHtmlProviderFunction = function(fn) {
  391.             assertTrue(typeof fn == 'function', "The given ConfigHtmlProvider is NOT a function!");
  392.             configHtmlProviderFn = fn;
  393.         },
  394.         getConfigHtml = function() {
  395.             return configHtmlProviderFn ? configHtmlProviderFn() : 'No ConfigHtmlProvider registered!';
  396.         },
  397.         addExternalRetriggerHandler = function(fn) {
  398.             doc.addEventListener('GRT_RETRIGGER', fn, false);
  399.         },
  400.         hashContains = function(s) {
  401.             return (location.hash || '').indexOf(s) > 0;
  402.         },
  403.         HELPERS_FOR_PROCESSORS = {
  404.             setConfig: setConfig,
  405.             anonymizeUrl: anonymizeUrl,
  406.             config: config,
  407.             unanonymizeUrl: unanonymizeUrl,
  408.             getAnonymousBaseUrl: getAnonymousBaseUrl,
  409.             ANON_URL_HASH: ANON_URL_HASH,
  410.             log: log,
  411.             assertTrue: assertTrue,
  412.             xpath: xpath,
  413.             getVersion: getVersion,
  414.             doc: doc,
  415.             win: win,
  416.             useSSL: useSSL,
  417.             assertIsAllowedUrl: assertIsAllowedUrl,
  418.             addClass: addClass,
  419.             stopEvent: stopEvent,
  420.             isAnonymousUrl: isAnonymousUrl,
  421.             urlContainsAny: urlContainsAny,
  422.             urlContainsAll: urlContainsAll,
  423.             hashContains: hashContains,
  424.             bodyClassContainsAny: bodyClassContainsAny,
  425.             saveConfigCookie: saveConfigCookie,
  426.             setConfigHtmlProviderFunction: setConfigHtmlProviderFunction,
  427.             getConfigHtml: getConfigHtml,
  428.             refreshConfig: loadConfigFromCookie,
  429.             addExternalRetriggerHandler: addExternalRetriggerHandler
  430.         },
  431.         GRT_PUBLIC = {
  432.             supportsUrl: supportsUrl,
  433.             addProcessor: addProcessor,
  434.             needsDispatcher: needsDispatcher,
  435.             needsCssInjector: needsCssInjector,
  436.             setDispatcher: setDispatcher,
  437.             setCssInjector: setCssInjector,
  438.             getVersion: getVersion,
  439.             hasProcessor: hasProcessor,
  440.             finalize: finalize,
  441.             urlContainsAny: urlContainsAny,
  442.             urlContainsAll: urlContainsAll,
  443.             hashContains: hashContains,
  444.             bodyClassContainsAny: bodyClassContainsAny
  445.         };
  446.     return GRT_PUBLIC;
  447. })('3.07');
  448.  
  449.  
  450. // #####################################################################################################################
  451. // ################################################ BEGIN: ADD PROCESSORS ##############################################
  452. // #####################################################################################################################
  453.  
  454.  
  455.  
  456. // -------------------- BEGIN PROCESSOR: Rightclick ----------------------
  457.  
  458. if (GRT.urlContainsAny('/pix/popup.php', 'mainpage.php?set=', 'auswertung/album/')) {
  459.     GRT.addProcessor((function(PROCESSOR_ID) {
  460.         var log = null,
  461.             init = function(grt, helpers) {
  462.                 log = helpers.log;
  463.                 if (!helpers.config.rc) return;
  464.                 var doc = helpers.doc,
  465.                     fuckedObjects = [doc],
  466.                     img = doc.getElementById('picture');
  467.                 if (img) fuckedObjects.push(img);
  468.                 for (var i = fuckedObjects.length - 1; i >= 0; i--) {
  469.                     var o = fuckedObjects[i];
  470.                     o.onmousedown = null;
  471.                     o.ondragstart = null;
  472.                     o.oncontextmenu = null;
  473.                 }
  474.             };
  475.         return {
  476.             ID: PROCESSOR_ID,
  477.             EXCLUSIVE: true,
  478.             NEEDS_DISPATCHER: false,
  479.             init: init
  480.         };
  481.     })('Rightclick'));
  482. }
  483.  
  484. // -------------------- END PROCESSOR: Rightclick ------------------------
  485.  
  486.  
  487. // -------------------- BEGIN PROCESSOR: PictureAdministration ----------------------
  488.  
  489. if (GRT.urlContainsAny('mitglieder/administration/pictures/overview.php', 'mitglieder/administration/pictures/edit.php?id=')) {
  490.     GRT.addProcessor((function(PROCESSOR_ID) {
  491.         var log = null,
  492.             assertTrue = null,
  493.             grt = null,
  494.             doc = null,
  495.             assertIsAllowedUrl = null,
  496.             handleImagePage = function(url, imageParam) {
  497.                 grt.registerAction('restorePicHTML', function(args) {
  498.                     var html = args.html,
  499.                         isMoreThanOne = (html.match(/<img/g) || []).length > 1;
  500.                     if (isMoreThanOne) {
  501.                         var h1 = doc.getElementsByTagName('h1')[0],
  502.                             div = doc.createElement('div');
  503.                         div.id = 'grtimageblablubs';
  504.                         div.innerHTML = html;
  505.                         h1.parentNode.insertBefore(div, h1);
  506.                     }
  507.                     var as = doc.getElementById('grtimageblablubs').getElementsByTagName('a'),
  508.                         currentFound = false,
  509.                         nextImageUrl = '';
  510.                     for (var i = 0; i < as.length; i++) {
  511.                         var a = as[i],
  512.                             isCurrent = a.href.indexOf(imageParam) >= 0;
  513.                         if (!isCurrent && !currentFound) continue;
  514.                         if (!isCurrent && currentFound) {
  515.                             nextImageUrl = a.href;
  516.                             break;
  517.                         }
  518.                         as[i].className = 'blubs';
  519.                         currentFound = true;
  520.                     }
  521.                     grt.callAction('cacheSaveNextImageUrl', {
  522.                         url: nextImageUrl
  523.                     });
  524.                 });
  525.                 grt.callAction('cacheRestorePicHTML');
  526.             },
  527.             handleImageOverviewAfterComment = function() {
  528.                 grt.registerAction('restoreNextImageOrGalleryUrl', function(args) {
  529.                     var url = args.url;
  530.                     assertIsAllowedUrl(url);
  531.                     self.location.href = url;
  532.                 });
  533.                 grt.callAction('cacheRestoreNextImageOrGalleryUrl');
  534.             },
  535.             handleGalleryPage = function(url) {
  536.                 var picHTML = [],
  537.                     pics = doc.getElementsByClassName('thumb');
  538.                 for (var i = 0; i < pics.length; i++) {
  539.                     var html = pics[i].parentNode.parentNode.innerHTML;
  540.                     picHTML.push(html);
  541.                 }
  542.                 grt.callAction('cacheSetPicHTML', {
  543.                     html: picHTML.join('&nbsp;'),
  544.                     galleryUrl: url
  545.                 });
  546.             },
  547.             init = function(_grt, helpers) {
  548.                 grt = _grt;
  549.                 if (!helpers.config.pica) return;
  550.                 log = helpers.log;
  551.                 assertIsAllowedUrl = helpers.assertIsAllowedUrl;
  552.                 assertTrue = helpers.assertTrue;
  553.                 doc = helpers.doc;
  554.                 var url = location.href,
  555.                     isGallery = /folder=-?\d+/.test(url),
  556.                     isOverviewAfterComment = /action=comment&id=\d+/.test(url),
  557.                     imageParam = (url.match(/(id=\d+)/) || [])[0],
  558.                     isImage = !! imageParam;
  559.                 if (isOverviewAfterComment) {
  560.                     handleImageOverviewAfterComment(url);
  561.                 } else if (isGallery) {
  562.                     handleGalleryPage(url);
  563.                 } else if (isImage) {
  564.                     handleImagePage(url, imageParam);
  565.                 }
  566.             };
  567.         return {
  568.             ID: PROCESSOR_ID,
  569.             EXCLUSIVE: false,
  570.             NEEDS_DISPATCHER: true,
  571.             CSS: ['pictureAdmin'],
  572.             init: init
  573.         };
  574.     })('PictureAdministration'));
  575. }
  576.  
  577. // -------------------- END PROCESSOR: PictureAdministration ------------------------
  578.  
  579.  
  580. // -------------------- BEGIN PROCESSOR: PictureAdministrationCache ----------------------
  581.  
  582. if (GRT.urlContainsAny('mitglieder/administration/pictures/navigation.php')) {
  583.     GRT.addProcessor((function(PROCESSOR_ID) {
  584.         var log = null,
  585.             assertTrue = null,
  586.             assertIsAllowedUrl = null,
  587.             grt = null,
  588.             doc = null,
  589.             url = location.href,
  590.             picHTML = null,
  591.             lastGalleryUrl = null,
  592.             nextImageUrl = null,
  593.             init = function(_grt, helpers) {
  594.                 grt = _grt;
  595.                 log = helpers.log;
  596.                 if (!helpers.config.pica) return;
  597.                 assertTrue = helpers.assertTrue;
  598.                 assertIsAllowedUrl = helpers.assertIsAllowedUrl;
  599.                 doc = helpers.doc;
  600.                 grt.registerAction('cacheSaveNextImageUrl', function(args) {
  601.                     var url = args.url;
  602.                     if (!url) {
  603.                         nextImageUrl = null;
  604.                     } else {
  605.                         assertIsAllowedUrl(url);
  606.                         nextImageUrl = url;
  607.                     }
  608.                 });
  609.                 grt.registerAction('cacheRestoreNextImageOrGalleryUrl', function() {
  610.                     var url = nextImageUrl || lastGalleryUrl;
  611.                     if (!url) return;
  612.                     grt.callAction('restoreNextImageOrGalleryUrl', {
  613.                         url: url
  614.                     });
  615.                 });
  616.                 grt.registerAction('cacheSetPicHTML', function(args) {
  617.                     assertIsAllowedUrl(args.galleryUrl);
  618.                     lastGalleryUrl = args.galleryUrl;
  619.                     picHTML = args.html;
  620.                 });
  621.                 grt.registerAction('cacheRestorePicHTML', function() {
  622.                     if (!picHTML) return;
  623.                     grt.callAction('restorePicHTML', {
  624.                         html: picHTML
  625.                     });
  626.                 });
  627.             };
  628.         return {
  629.             ID: PROCESSOR_ID,
  630.             EXCLUSIVE: false,
  631.             NEEDS_DISPATCHER: true,
  632.             CSS: false,
  633.             init: init
  634.         };
  635.     })('PictureAdministrationCache'));
  636. }
  637.  
  638. // -------------------- END PROCESSOR: PictureAdministrationCache ------------------------
  639.  
  640.  
  641. // -------------------- BEGIN PROCESSOR: Header ----------------------
  642.  
  643. if (GRT.urlContainsAny('/main/top.php', 'auswertung/setcard/cluide/navigation.php')) {
  644.     GRT.addProcessor((function(PROCESSOR_ID) {
  645.         var log = null,
  646.             doc = null,
  647.             grt = null,
  648.             helpers = null,
  649.             addClass = null,
  650.             assertTrue = null,
  651.             version = null,
  652.             liveVersionInfo = null,
  653.             UPDATE_INFO_URL = 'http://gr-tools.justlep.net/v3/builds/updateInfo.php?v=',
  654.             ALTERNATIVE_TITLE = 'R..',
  655.             lastHotlinkFilterSoothTime = 0,
  656.             HOTLINK_FILTER_REFRESH_TIME = 60,
  657.             HANDLERS = {
  658.                 CLUB_CLICK: function() {
  659.                     grt.callAction('openClub');
  660.                 },
  661.                 CONFIG_CLICK: function() {
  662.                     grt.callAction('openConfig');
  663.                 },
  664.                 UPDATE_CLICK: function() {
  665.                     if (!liveVersionInfo) return;
  666.                     if (!liveVersionInfo.needsUpdate) {
  667.                         return;
  668.                     }
  669.                     helpers.refreshConfig();
  670.                     var updateInfoUrl = UPDATE_INFO_URL + encodeURIComponent(liveVersionInfo.currentVersion) + '&lang=' + (helpers.config.de ? 'de' : 'en');
  671.                     grt.callAction('loadInOverlay', {
  672.                         url: updateInfoUrl
  673.                     });
  674.                 },
  675.                 RECEIVE_LIVE_VERSION: function(newVersionInfo) {
  676.                     if (liveVersionInfo) return;
  677.                     liveVersionInfo = newVersionInfo;
  678.                     if (liveVersionInfo.needsUpdate) {
  679.                         addClass(doc.getElementById('grtDiv'), 'grtUpdateAvailable');
  680.                     }
  681.                 }
  682.             },
  683.             sootheHotlinkFilter = function() {
  684.                 var allowedAfter = lastHotlinkFilterSoothTime + (HOTLINK_FILTER_REFRESH_TIME * 1000),
  685.                     now = (+new Date);
  686.                 if (now < allowedAfter) return;
  687.                 lastHotlinkFilterSoothTime = now;
  688.                 var img = doc.createElement('img');
  689.                 img.id = 'grtHLS';
  690.                 img.style.display = 'none';
  691.                 doc.body.appendChild(img);
  692.                 img.src = helpers.getAnonymousBaseUrl() + '/';
  693.             },
  694.             addElements = function() {
  695.                 var div = doc.createElement('div');
  696.                 div.innerHTML = '<div id="grtDiv"><div id="grtPimp"><i title="v' + version + '">pimped by<b>GR-Tools v' + helpers.getVersion() + '</b></i></div>' + '<span id="grtClub" title="GR-Tools Club"></span>' + '<span id="grtCfg" title="GR-Tools Setup"></span>' + '<span id="grtUpd" title="GR-Tools Update"></span>' + '</div>';
  697.                 doc.body.appendChild(div.childNodes[0]);
  698.                 doc.getElementById('grtClub').addEventListener('click', HANDLERS.CLUB_CLICK, false);
  699.                 doc.getElementById('grtCfg').addEventListener('click', HANDLERS.CONFIG_CLICK, false);
  700.                 doc.getElementById('grtUpd').addEventListener('click', HANDLERS.UPDATE_CLICK, false);
  701.             },
  702.             recheckDimFeature = function() {
  703.                 helpers.refreshConfig();
  704.                 var DIM_CHECK_REGEX = /\s?grtDimLogo/,
  705.                     bodyHasDimClass = DIM_CHECK_REGEX.test(doc.body.className || '');
  706.                 if (helpers.config.dim && !bodyHasDimClass) {
  707.                     doc.body.className += ' grtDimLogo';
  708.                 } else if (!helpers.config.dim && bodyHasDimClass) {
  709.                     doc.body.className = doc.body.className.replace(DIM_CHECK_REGEX, '');
  710.                 }
  711.             },
  712.             originalTitle = null,
  713.             recheckTitleFeature = function() {
  714.                 try {
  715.                     if (!helpers.config.tit && originalTitle) {
  716.                         top.document.title = originalTitle;
  717.                     } else if (helpers.config.tit) {
  718.                         if (!originalTitle) {
  719.                             originalTitle = top.document.title;
  720.                         }
  721.                         top.document.title = ALTERNATIVE_TITLE;
  722.                     }
  723.                 } catch (e) {}
  724.             },
  725.             refreshHeaderConfig = function(dontReloadConfig) {
  726.                 if (dontReloadConfig !== true) {
  727.                     helpers.refreshConfig();
  728.                 }
  729.                 recheckDimFeature();
  730.                 recheckTitleFeature();
  731.             },
  732.             init = function(_grt, _helpers) {
  733.                 log = _helpers.log;
  734.                 doc = _helpers.doc;
  735.                 grt = _grt;
  736.                 helpers = _helpers;
  737.                 addClass = _helpers.addClass;
  738.                 version = _helpers.getVersion();
  739.                 assertTrue = _helpers.assertTrue;
  740.                 var isClub = !! doc.getElementsByClassName('clubBack').length,
  741.                     isGuide = !isClub && !! doc.getElementsByClassName('cluideBack').length;
  742.                 if (isClub) {
  743.                     _helpers.addClass(doc.body, 'grtClub');
  744.                 } else if (isGuide) {
  745.                     _helpers.addClass(doc.body, 'grtGuideClub');
  746.                 }
  747.                 grt.registerAction('setLatestGRTVersion', HANDLERS.RECEIVE_LIVE_VERSION);
  748.                 grt.registerAction('sootheHotlinkFilter', sootheHotlinkFilter);
  749.                 grt.registerAction('refreshHeaderConfig', refreshHeaderConfig);
  750.                 addElements();
  751.                 refreshHeaderConfig(true);
  752.                 _helpers.saveConfigCookie();
  753.             };
  754.         return {
  755.             ID: PROCESSOR_ID,
  756.             EXCLUSIVE: false,
  757.             NEEDS_DISPATCHER: true,
  758.             CSS: ['header'],
  759.             init: init
  760.         };
  761.     })('Header'));
  762. }
  763.  
  764. // -------------------- END PROCESSOR: Header ------------------------
  765.  
  766.  
  767. // -------------------- BEGIN PROCESSOR: Version ----------------------
  768.  
  769. if (GRT.hasProcessor('Header')) {
  770.     GRT.addProcessor((function(PROCESSOR_ID) {
  771.         var log = null,
  772.             doc = null,
  773.             grt = null,
  774.             helpers = null,
  775.             VERSION_IMG_URL = {
  776.                 HTTP: 'http://gr-tools.justlep.net/v3/builds/version.php',
  777.                 HTTPS: 'https://ssl-account.com/gr-tools.justlep.net/v3/builds/version.php'
  778.             },
  779.             assertTrue = null,
  780.             versionImg = null,
  781.             latestVersion = null,
  782.             HANDLERS = {
  783.                 VERSION_IMG_LOAD: function(e) {
  784.                     assertTrue( !! versionImg, 'Version image seems null although it should be loaded.');
  785.                     var latestMajor = (versionImg.width || 1) - 1,
  786.                         latestMinor = (versionImg.height || 1) - 1,
  787.                         versionString = latestMajor + '.' + latestMinor,
  788.                         currentVersion = grt.getVersion(),
  789.                         currSplit = currentVersion.split('.'),
  790.                         currentMajor = parseInt(currSplit[0], 10),
  791.                         currentMinor = parseInt(currSplit[1], 10),
  792.                         needsUpdate = currentMajor < latestMajor || currentMinor < latestMinor;
  793.                     latestVersion = {
  794.                         latestMajor: latestMajor,
  795.                         latestMinor: latestMinor,
  796.                         latestVersion: versionString,
  797.                         currentMajor: currentMajor,
  798.                         currentMinor: currentMinor,
  799.                         currentVersion: grt.getVersion(),
  800.                         needsUpdate: needsUpdate
  801.                     };
  802.                     checkLatestGRTVersion();
  803.                     versionImg.removeEventListener('load', HANDLERS.VERSION_IMG_LOAD);
  804.                 }
  805.             },
  806.             checkLatestGRTVersion = function() {
  807.                 if (!latestVersion && versionImg) {
  808.                     return;
  809.                 }
  810.                 if (latestVersion) {
  811.                     grt.callAction('setLatestGRTVersion', latestVersion);
  812.                     return;
  813.                 }
  814.                 versionImg = doc.createElement('img');
  815.                 versionImg.addEventListener('load', HANDLERS.VERSION_IMG_LOAD, false);
  816.                 var imgUrl = (helpers.useSSL) ? VERSION_IMG_URL.HTTPS : VERSION_IMG_URL.HTTP;
  817.                 versionImg.src = imgUrl + '?' + (+new Date());
  818.             },
  819.             init = function(_grt, _helpers) {
  820.                 log = _helpers.log;
  821.                 doc = _helpers.doc;
  822.                 helpers = _helpers;
  823.                 grt = _grt;
  824.                 assertTrue = _helpers.assertTrue;
  825.                 grt.registerAction('checkLatestGRTVersion', checkLatestGRTVersion);
  826.                 checkLatestGRTVersion();
  827.             };
  828.         return {
  829.             ID: PROCESSOR_ID,
  830.             EXCLUSIVE: false,
  831.             NEEDS_DISPATCHER: true,
  832.             CSS: false,
  833.             init: init
  834.         };
  835.     })('Version'));
  836. }
  837.  
  838. // -------------------- END PROCESSOR: Version ------------------------
  839.  
  840.  
  841. // -------------------- BEGIN PROCESSOR: ClubOpener ----------------------
  842.  
  843. if (GRT.urlContainsAny('/main/bottom.php', 'auswertung/setcard/cluide/club_navigation.php?set=', '/main/index.php', '/search/index.php')) {
  844.     GRT.addProcessor((function(PROCESSOR_ID) {
  845.         var CLUB_URL = '/auswertung/setcard/index.php?set=3053381&t=3&page=club',
  846.             log = null,
  847.             win = null,
  848.             init = function(grt, helpers) {
  849.                 log = helpers.log;
  850.                 win = helpers.win;
  851.                 if (typeof win.openUrl == 'function') {
  852.                     grt.registerAction('openClub', function() {
  853.                         win.openUrl(CLUB_URL);
  854.                     });
  855.                 }
  856.             };
  857.         return {
  858.             ID: PROCESSOR_ID,
  859.             EXCLUSIVE: false,
  860.             NEEDS_DISPATCHER: true,
  861.             CSS: false,
  862.             init: init
  863.         };
  864.     })('ClubOpener'));
  865. }
  866.  
  867. // -------------------- END PROCESSOR: ClubOpener ------------------------
  868.  
  869.  
  870. // -------------------- BEGIN PROCESSOR: ForumLatestThreads ----------------------
  871.  
  872. if (GRT.urlContainsAll('/myuser/', 'page=club')) {
  873.     GRT.addProcessor((function(PROCESSOR_ID) {
  874.         var log = null,
  875.             MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
  876.             today = new Date(),
  877.             DEFAULT_DAY_REGEX = /\d{1,2}\.[a-z]{3}\.\d{4}/i,
  878.             getDayRegex = function(date) {
  879.                 if (!date) return DEFAULT_DAY_REGEX;
  880.                 var day = date.getDate(),
  881.                     dayPrefix = (day < 10) ? '0' : '',
  882.                     year = date.getFullYear(),
  883.                     monthName = MONTHS[date.getMonth()];
  884.                 return new RegExp(dayPrefix + day + '\\.' + monthName + '\\.' + year);
  885.             },
  886.             regexes = {},
  887.             init = function(grt, helpers) {
  888.                 log = helpers.log;
  889.                 if (!helpers.config.lt) return;
  890.                 regexes['today exact'] = getDayRegex(today);
  891.                 today.setDate(today.getDate() - 1);
  892.                 regexes['today minus1'] = getDayRegex(today);
  893.                 today.setDate(today.getDate() - 1);
  894.                 regexes['today minus2'] = getDayRegex(today);
  895.                 regexes['today older'] = getDayRegex();
  896.                 var tds = helpers.doc.getElementById('content').getElementsByTagName('td');
  897.                 for (var i = tds.length - 1; i >= 0; i--) {
  898.                     var td = tds[i];
  899.                     if (td.align != 'right') continue;
  900.                     for (var k in regexes) {
  901.                         if (!regexes[k].test(td.innerHTML || '')) continue;
  902.                         td.parentNode.className = (td.parentNode.className || '') + k;
  903.                         break;
  904.                     }
  905.                 }
  906.             };
  907.         return {
  908.             ID: PROCESSOR_ID,
  909.             EXCLUSIVE: false,
  910.             NEEDS_DISPATCHER: false,
  911.             CSS: ['forumLatestThreads'],
  912.             init: init
  913.         };
  914.     })('ForumLatestThreads'));
  915. }
  916.  
  917. // -------------------- END PROCESSOR: ForumLatestThreads ------------------------
  918.  
  919.  
  920. // -------------------- BEGIN PROCESSOR: BMIAgeFilter ----------------------
  921.  
  922. if (GRT.bodyClassContainsAny('searchResults')) {
  923.     GRT.addProcessor((function(PROCESSOR_ID) {
  924.         var log = null,
  925.             doc = null,
  926.             stopEvent = null,
  927.             grt = null,
  928.             helpers = null,
  929.             liveHandlerBound = false,
  930.             DONE_MARKER_CLASS = 'grtBMIDone',
  931.             AGE_FILTER_CLASS = ' grtOffAge',
  932.             BMI_FILTER_CLASS = ' grtOffBmi',
  933.             bmiElemPrototype = null,
  934.             HANDLERS = {
  935.                 BMI_CLICK: function(e) {
  936.                     if (!e.target || e.button == 2 || e.target.className != 'grtBMI') return;
  937.                     stopEvent(e);
  938.                     var profileUrl = getUrlFromBMILink(e.target);
  939.                     grt.callAction('loadInOverlay', {
  940.                         url: profileUrl,
  941.                         anonymize: helpers.config.secr
  942.                     });
  943.                 }
  944.             },
  945.             getUrlFromBMILink = function(bmiElement) {
  946.                 if (!bmiElement) return '#';
  947.                 return bmiElement.parentNode.parentNode.getElementsByTagName('a')[0].href;
  948.             },
  949.             BMI_REGEX = /(\d{2,3}),\s+(\d{2,3}) cm,\s+(?:<[^>]+>)?(\d{1,3}) kg/,
  950.             determineBMIAndAge = function(td) {
  951.                 var txt = (td.textContent || '').replace(/[\r\n]/g, '');
  952.                 if (!BMI_REGEX.exec(txt)) return '?';
  953.                 var age = parseInt(RegExp.$1, 10),
  954.                     size = parseInt(RegExp.$2, 10) / 100.0,
  955.                     weight = parseInt(RegExp.$3, 10),
  956.                     bmi = Math.round(weight / (size * size));
  957.                 return {
  958.                     bmi: bmi,
  959.                     age: age
  960.                 };
  961.             },
  962.             getBMIElementForTD = function(td) {
  963.                 if (!bmiElemPrototype) {
  964.                     bmiElemPrototype = doc.createElement('i');
  965.                     bmiElemPrototype.className = 'grtBMI';
  966.                 }
  967.                 var bmiElem = null,
  968.                     bmiAndAge = determineBMIAndAge(td.nextElementSibling),
  969.                     config = helpers.config;
  970.                 try {
  971.                     var offAge = config.age && (bmiAndAge.age < config.amin || bmiAndAge.age > config.amax),
  972.                         offBmi = config.bmi && (bmiAndAge.bmi < config.bmin || bmiAndAge.bmi > config.bmax);
  973.                     if (offAge || offBmi) {
  974.                         markParentTrFiltered(offAge, offBmi, td);
  975.                     }
  976.                 } catch (e) {}
  977.                 if (config.sb) {
  978.                     bmiElem = bmiElemPrototype.cloneNode(false);
  979.                     bmiElem.textContent = '(' + bmiAndAge.bmi + ')';
  980.                 }
  981.                 return bmiElem;
  982.             },
  983.             markParentTablesDone = function(td) {
  984.                 var table = td.parentNode;
  985.                 while (table) {
  986.                     if (table.nodeName.toLowerCase() == 'table') {
  987.                         table.className += ' ' + DONE_MARKER_CLASS;
  988.                     }
  989.                     table = table.parentNode;
  990.                 }
  991.             },
  992.             markParentTrFiltered = function(offAge, offBmi, td) {
  993.                 var tr = td.parentNode,
  994.                     cls = (offAge ? AGE_FILTER_CLASS : '') + (offBmi ? BMI_FILTER_CLASS : '');
  995.                 tr.className += cls;
  996.                 tr.nextElementSibling.className += cls;
  997.             },
  998.             decorateResultList = function() {
  999.                 if ((doc.body.className || '').indexOf('searchResults') < 0) return;
  1000.                 var userLinks = helpers.xpath('//table[not(contains(@class,"' + DONE_MARKER_CLASS + '"))]//td[contains(@class,"resHeadline")]/a[contains(@href,"setcard")]'),
  1001.                     td = null;
  1002.                 for (var i = 0; i < userLinks.length; i++) {
  1003.                     var link = userLinks[i],
  1004.                         username = link.textContent;
  1005.                     td = link.parentNode;
  1006.                     td.parentNode.setAttribute('username', username);
  1007.                     var bmiElem = getBMIElementForTD(td);
  1008.                     if (bmiElem) {
  1009.                         td.appendChild(bmiElem);
  1010.                     }
  1011.                     td.className += ' ' + DONE_MARKER_CLASS;
  1012.                 }
  1013.                 if (td) {
  1014.                     markParentTablesDone(td);
  1015.                     if (!liveHandlerBound && helpers.config.sb) {
  1016.                         doc.addEventListener('click', HANDLERS.BMI_CLICK, true);
  1017.                         liveHandlerBound = true;
  1018.                         grt.callAction('sootheHotlinkFilter');
  1019.                     }
  1020.                 }
  1021.             },
  1022.             init = function(_grt, _helpers) {
  1023.                 log = _helpers.log;
  1024.                 doc = _helpers.doc;
  1025.                 stopEvent = _helpers.stopEvent;
  1026.                 grt = _grt;
  1027.                 helpers = _helpers;
  1028.                 decorateResultList();
  1029.                 _helpers.addExternalRetriggerHandler(decorateResultList);
  1030.             };
  1031.         return {
  1032.             ID: PROCESSOR_ID,
  1033.             EXCLUSIVE: false,
  1034.             NEEDS_DISPATCHER: false,
  1035.             CSS: ['bmi'],
  1036.             init: init
  1037.         };
  1038.     })('BMIAgeFilter'));
  1039. }
  1040.  
  1041. // -------------------- END PROCESSOR: BMIAgeFilter ------------------------
  1042.  
  1043.  
  1044. // -------------------- BEGIN PROCESSOR: HistoryLink ----------------------
  1045.  
  1046. if (GRT.hasProcessor('BMIAgeFilter') || GRT.urlContainsAny('main/personalList/PersonalListPage.php?show')) {
  1047.     GRT.addProcessor((function(PROCESSOR_ID) {
  1048.         var log = null,
  1049.             doc = null,
  1050.             xpath = null,
  1051.             stopEvent = null,
  1052.             assertTrue = null,
  1053.             grt = null,
  1054.             histLinkPrototype = null,
  1055.             randNo = 0,
  1056.             liveHandlerBound = false,
  1057.             DONE_MARKER_CLASS = 'grtHistDone',
  1058.             HANDLERS = {
  1059.                 HISTORY_ICON_CLICK: function(e) {
  1060.                     if (!e.target || e.target.className != 'grtHist') return;
  1061.                     stopEvent(e);
  1062.                     var historyUrl = getUrlFromIcon(e.target);
  1063.                     grt.callAction('loadInOverlay', {
  1064.                         url: historyUrl
  1065.                     });
  1066.                 }
  1067.             },
  1068.             createIcon = function(userId) {
  1069.                 if (!histLinkPrototype) {
  1070.                     histLinkPrototype = doc.createElement('i');
  1071.                     histLinkPrototype.className = 'grtHist';
  1072.                 }
  1073.                 var icon = histLinkPrototype.cloneNode(false);
  1074.                 icon.id = 'grtHist_' + userId + '_' + (++randNo);
  1075.                 return icon;
  1076.             },
  1077.             getUrlFromIcon = function(icon) {
  1078.                 if (!icon) return '#';
  1079.                 var userId = icon.id.match(/grtHist_(\d*)/)[1];
  1080.                 return '/msg/history.php?uid=' + userId;
  1081.             },
  1082.             decorateMessageList = function() {
  1083.                 var msgList = doc.getElementById('newMessageList'),
  1084.                     msgLinks = xpath('//a[contains(@href,"\/msg\/\?id=")]', msgList);
  1085.                 for (var i = msgLinks.length - 1; i >= 0; i--) {
  1086.                     var a = msgLinks[i],
  1087.                         userId = a.parentNode.id.match(/row(\d*)_msg/)[1],
  1088.                         icon = createIcon(userId);
  1089.                     a.parentNode.className += ' grtHistActive';
  1090.                     a.appendChild(icon);
  1091.                 }
  1092.                 if (msgLinks.length) {
  1093.                     msgList.addEventListener('click', HANDLERS.HISTORY_ICON_CLICK, true);
  1094.                 }
  1095.             },
  1096.             decorateResultList = function() {
  1097.                 if ((doc.body.className || '').indexOf('searchResults') < 0) return;
  1098.                 var userLinks = xpath('//table//td[contains(@class,"resHeadline") and not(contains(@class,"' + DONE_MARKER_CLASS + '"))]/a[contains(@href,"setcard")]'),
  1099.                     ID_REGEX = /set=(\d*)/;
  1100.                 for (var i = 0; i < userLinks.length; i++) {
  1101.                     var link = userLinks[i],
  1102.                         td = link.parentNode,
  1103.                         alreadyDecorated = td.className.indexOf(DONE_MARKER_CLASS) >= 0;
  1104.                     if (alreadyDecorated) continue;
  1105.                     var userId = link.href.match(ID_REGEX)[1],
  1106.                         icon = createIcon(userId);
  1107.                     td.appendChild(icon);
  1108.                     td.className += ' ' + DONE_MARKER_CLASS;
  1109.                 }
  1110.                 if (userLinks.length && !liveHandlerBound) {
  1111.                     doc.addEventListener('click', HANDLERS.HISTORY_ICON_CLICK, true);
  1112.                     liveHandlerBound = true;
  1113.                 }
  1114.             },
  1115.             init = function(_grt, helpers) {
  1116.                 log = helpers.log;
  1117.                 doc = helpers.doc;
  1118.                 grt = _grt;
  1119.                 stopEvent = helpers.stopEvent;
  1120.                 xpath = helpers.xpath;
  1121.                 assertTrue = helpers.assertTrue;
  1122.                 var url = location.href,
  1123.                     isLatestMessagePage = url.indexOf('main/personalList/PersonalListPage') >= 0,
  1124.                     isResultList = !isLatestMessagePage && url.indexOf('/search/') > 0;
  1125.                 if (isLatestMessagePage) {
  1126.                     decorateMessageList();
  1127.                 } else if (isResultList) {
  1128.                     decorateResultList();
  1129.                     helpers.addExternalRetriggerHandler(decorateResultList);
  1130.                 }
  1131.             };
  1132.         return {
  1133.             ID: PROCESSOR_ID,
  1134.             EXCLUSIVE: false,
  1135.             NEEDS_DISPATCHER: true,
  1136.             CSS: ['historyLink'],
  1137.             init: init
  1138.         };
  1139.     })('HistoryLink'));
  1140. }
  1141.  
  1142. // -------------------- END PROCESSOR: HistoryLink ------------------------
  1143.  
  1144.  
  1145. // -------------------- BEGIN PROCESSOR: Overlay ----------------------
  1146.  
  1147. if (((location.href.indexOf('/search/') >= 0 && GRT.urlContainsAny('action=execute', 'action=showPage', 'searchType=advert', 'searchType=myVisits', 'searchType=newWithin')) || GRT.urlContainsAny('searchType=picture', '/settings/', '/mitglieder/messages/', '/setcard/cluide/club_profile.php') || GRT.bodyClassContainsAny('mainPage', 'pUsCe') || document.getElementById('startpageContainerCollection')) && location.href.indexOf('club_profile.php') < 0) {
  1148.     GRT.addProcessor((function(PROCESSOR_ID) {
  1149.         var PROFILE_URL_REGEX = /auswertung\/setcard\/(?:index\.php)?\?set=/,
  1150.             NO_OVERLAY_HASH = '#NO_OVERLAY',
  1151.             HTML = '<div id="grtGray"></div>' + '<div id="grtOverlay">' + '<iframe id="grtIframe" src="about:blank"></iframe>' + '<div id="grtHtmlContent"></div>' + '<img id="grtImage" alt="" src="/v18/gemeinsam/skins/allSkins/logo/mainlogo/planetromeoGold.png">' + '<div id="grtUsername"></div>' + '<div id="grtClose"></div>' + '<div id="grtAnon"></div>' + '<div id="grtWait"></div>' + '</div>',
  1152.             CLASSID = {
  1153.                 GRAY: 'grtGray',
  1154.                 IFRAME: 'grtIframe',
  1155.                 HTMLCONTENT: 'grtHtmlContent',
  1156.                 IMAGE: 'grtImage',
  1157.                 USERNAME: 'grtUsername',
  1158.                 WAIT: 'grtWait',
  1159.                 CLOSE: 'grtClose',
  1160.                 ANON: ' grtAnon'
  1161.             },
  1162.             DEFAULT_URL = 'about:blank',
  1163.             doc = null,
  1164.             docElem = null,
  1165.             win = null,
  1166.             log = null,
  1167.             grt = null,
  1168.             assertTrue = null,
  1169.             helpers = null,
  1170.             pendingLoadType = null,
  1171.             imageHovered = false,
  1172.             elems = {
  1173.                 gray: null,
  1174.                 overlay: null,
  1175.                 iframe: null,
  1176.                 htmlContent: null,
  1177.                 image: null,
  1178.                 username: null,
  1179.                 close: null
  1180.             },
  1181.             boundHandlers = {},
  1182.             HANDLERS = {
  1183.                 DISPATCHED_OPEN_CONFIG: function() {
  1184.                     loadHtml(helpers.getConfigHtml());
  1185.                     grt.callAction('initConfigForm');
  1186.                 },
  1187.                 DISPATCHED_LOAD_IN_OVERLAY: function(args) {
  1188.                     pendingLoadType = null;
  1189.                     hideAll();
  1190.                     assertTrue(args.url, 'Received dispatched loadInOverlay() call without a URL!');
  1191.                     var url = (args.anonymize) ? helpers.anonymizeUrl(args.url) : args.url;
  1192.                     loadUrl(url);
  1193.                 },
  1194.                 DISPATCHED_LOAD_IMAGE_IN_OVERLAY: function(args) {
  1195.                     elems.image.src = DEFAULT_URL;
  1196.                     hideAll();
  1197.                     assertTrue(args.url, 'Received dispatched loadImageInOverlay() call without image URL!');
  1198.                     loadImage(args.url, args.username);
  1199.                 },
  1200.                 DISPATCHED_CLOSE_IMAGE: function(args) {
  1201.                     if (args.ifNotHovered && imageHovered) return;
  1202.                     if (pendingLoadType != CLASSID.IMAGE) return;
  1203.                     hideAll();
  1204.                 },
  1205.                 IFRAME_LOADED: function() {
  1206.                     if (pendingLoadType != CLASSID.IFRAME || elems.iframe.src == DEFAULT_URL) return;
  1207.                     elems.overlay.className = CLASSID.IFRAME;
  1208.                     if (helpers.isAnonymousUrl(elems.iframe.src)) {
  1209.                         markAnonymous();
  1210.                     }
  1211.                 },
  1212.                 IMAGE_LOADED: function() {
  1213.                     if (pendingLoadType != CLASSID.IMAGE || elems.image.src == DEFAULT_URL) return;
  1214.                     imageHovered = false;
  1215.                     var username = elems.image.getAttribute('username'),
  1216.                         overlayClass = CLASSID.IMAGE;
  1217.                     if (username) {
  1218.                         elems.username.textContent = username;
  1219.                     } else {
  1220.                         overlayClass += ' grtNoUser';
  1221.                     }
  1222.                     elems.overlay.className = overlayClass;
  1223.                 },
  1224.                 IMAGE_OVER: function() {
  1225.                     imageHovered = true;
  1226.                 },
  1227.                 IMAGE_ERROR: function() {
  1228.                     hideAll();
  1229.                 },
  1230.                 CLICK_TO_CLOSE: function(e) {
  1231.                     var o = e.target;
  1232.                     if (!o || [CLASSID.CLOSE, CLASSID.IMAGE, CLASSID.GRAY].indexOf(o.id || '') < 0) return;
  1233.                     hideAll();
  1234.                 },
  1235.                 PROFILE_LINK_CLICK: function(e) {
  1236.                     if (!e.target) return;
  1237.                     if (e.button == 2 || e.target.nodeName == 'IMG' && !helpers.config.popt) return;
  1238.                     var o = e.target,
  1239.                         href = o.href,
  1240.                         i = 0;
  1241.                     while (!href && (++i) < 5 && o) {
  1242.                         href = o.href;
  1243.                         o = o.parentNode;
  1244.                     }
  1245.                     if (!PROFILE_URL_REGEX.test(href || '') || href.indexOf(NO_OVERLAY_HASH) > 0 || href.indexOf('page=club') > 0) return;
  1246.                     e.target.onclick = null;
  1247.                     e.cancelBubble = true;
  1248.                     e.preventDefault();
  1249.                     grt.callAction('loadInOverlay', {
  1250.                         url: href
  1251.                     });
  1252.                 }
  1253.             },
  1254.             DEFAULT_OVERLAY_WIDTH = 500,
  1255.             DEFAULT_IMAGE_WIDTH = 450,
  1256.             lastHeight = null,
  1257.             updateDimensions = function() {
  1258.                 var winWidth = self.innerWidth || 680,
  1259.                     availabelWidth = winWidth - 180,
  1260.                     w = Math.min(availabelWidth, DEFAULT_OVERLAY_WIDTH),
  1261.                     h = self.innerHeight - 28,
  1262.                     wPx = w + 'px',
  1263.                     hPx = h + 'px';
  1264.                 if (lastHeight == h) return;
  1265.                 lastHeight = h;
  1266.                 elems.iframe.style.width = wPx;
  1267.                 elems.iframe.style.height = hPx;
  1268.                 elems.htmlContent.style.width = wPx;
  1269.                 elems.htmlContent.style.height = hPx;
  1270.                 elems.close.style.height = hPx;
  1271.                 elems.image.style.maxWidth = Math.min(availabelWidth, DEFAULT_IMAGE_WIDTH) + 'px';
  1272.                 elems.image.style.maxHeight = hPx;
  1273.             },
  1274.             initElements = function() {
  1275.                 var tmp = doc.createElement('div');
  1276.                 tmp.innerHTML = HTML;
  1277.                 doc.body.appendChild(tmp.childNodes[1]);
  1278.                 doc.body.appendChild(tmp.childNodes[0]);
  1279.                 elems = {
  1280.                     gray: doc.getElementById('grtGray'),
  1281.                     overlay: doc.getElementById('grtOverlay'),
  1282.                     iframe: doc.getElementById(CLASSID.IFRAME),
  1283.                     htmlContent: doc.getElementById(CLASSID.HTMLCONTENT),
  1284.                     image: doc.getElementById(CLASSID.IMAGE),
  1285.                     username: doc.getElementById(CLASSID.USERNAME),
  1286.                     close: doc.getElementById(CLASSID.CLOSE)
  1287.                 };
  1288.                 updateDimensions();
  1289.                 elems.overlay.addEventListener('click', HANDLERS.CLICK_TO_CLOSE, false);
  1290.             },
  1291.             hideAll = function() {
  1292.                 elems.gray.style.display = 'none';
  1293.                 doc.body.style.paddingRight = 0;
  1294.                 elems.overlay.className = '';
  1295.                 doc.body.style.overflow = 'auto';
  1296.                 pendingLoadType = null;
  1297.                 elems.iframe.src = DEFAULT_URL;
  1298.             },
  1299.             showWait = function() {
  1300.                 elems.overlay.className = CLASSID.WAIT;
  1301.             },
  1302.             showGray = function() {
  1303.                 if (!boundHandlers[CLASSID.GRAY]) {
  1304.                     boundHandlers[CLASSID.GRAY] = elems.gray.addEventListener('click', HANDLERS.CLICK_TO_CLOSE, false) || 1;
  1305.                 }
  1306.                 updateDimensions();
  1307.                 elems.gray.style.display = 'block';
  1308.                 var widthBefore = doc.body.clientWidth;
  1309.                 doc.body.style.overflow = 'hidden';
  1310.                 var widthDiff = doc.body.clientWidth - widthBefore;
  1311.                 doc.body.style.paddingRight = widthDiff + 'px';
  1312.             },
  1313.             loadUrl = function(url) {
  1314.                 helpers.assertIsAllowedUrl(url);
  1315.                 if (!boundHandlers[CLASSID.IFRAME]) {
  1316.                     boundHandlers[CLASSID.IFRAME] = elems.iframe.addEventListener('load', HANDLERS.IFRAME_LOADED, false) || 1;
  1317.                     elems.iframe.addEventListener('error', function() {
  1318.                         alert('iframe error!');
  1319.                     }, false);
  1320.                 }
  1321.                 showGray();
  1322.                 showWait();
  1323.                 elems.iframe.src = url;
  1324.                 pendingLoadType = CLASSID.IFRAME;
  1325.             },
  1326.             loadHtml = function(html) {
  1327.                 showGray();
  1328.                 elems.htmlContent.innerHTML = html;
  1329.                 elems.overlay.className = CLASSID.HTMLCONTENT;
  1330.                 pendingLoadType = CLASSID.HTMLCONTENT;
  1331.             },
  1332.             loadImage = function(imageUrl, username) {
  1333.                 if (!boundHandlers[CLASSID.IMAGE]) {
  1334.                     elems.image.addEventListener('load', HANDLERS.IMAGE_LOADED, false);
  1335.                     elems.image.addEventListener('error', HANDLERS.IMAGE_ERROR, false);
  1336.                     elems.image.addEventListener('mouseover', HANDLERS.IMAGE_OVER, false);
  1337.                     boundHandlers[CLASSID.IMAGE] = 1;
  1338.                 }
  1339.                 showWait();
  1340.                 if (elems.image.src == imageUrl) {
  1341.                     elems.image.src += '?1';
  1342.                 } else {
  1343.                     elems.image.src = imageUrl;
  1344.                 }
  1345.                 elems.image.setAttribute('username', username ? ('User: ' + username) : '');
  1346.                 pendingLoadType = CLASSID.IMAGE;
  1347.             },
  1348.             markAnonymous = function() {
  1349.                 if (elems.overlay.className != CLASSID.IFRAME) return;
  1350.                 elems.overlay.className += ' ' + CLASSID.ANON;
  1351.             },
  1352.             bindGenericProfileClickHandler = function() {
  1353.                 var isClubsPage = grt.urlContainsAll('/myuser/', 'page=club'),
  1354.                     isLinkingPage = grt.urlContainsAny('page=linking');
  1355.                 if (!isClubsPage && !isLinkingPage) {
  1356.                     doc.addEventListener('click', HANDLERS.PROFILE_LINK_CLICK, true);
  1357.                 }
  1358.             },
  1359.             init = function(_grt, _helpers) {
  1360.                 log = _helpers.log;
  1361.                 doc = _helpers.doc;
  1362.                 docElem = doc.documentElement || doc;
  1363.                 win = _helpers.win;
  1364.                 grt = _grt;
  1365.                 assertTrue = _helpers.assertTrue;
  1366.                 helpers = _helpers;
  1367.                 initElements();
  1368.                 _grt.registerAction('closeOverlay', hideAll);
  1369.                 _grt.registerAction('loadInOverlay', HANDLERS.DISPATCHED_LOAD_IN_OVERLAY);
  1370.                 _grt.registerAction('loadImageInOverlay', HANDLERS.DISPATCHED_LOAD_IMAGE_IN_OVERLAY);
  1371.                 _grt.registerAction('closeImageOverlay', HANDLERS.DISPATCHED_CLOSE_IMAGE);
  1372.                 _grt.registerAction('markAnonymous', markAnonymous);
  1373.                 _grt.registerAction('openConfig', HANDLERS.DISPATCHED_OPEN_CONFIG);
  1374.                 if (_helpers.config.popa) {
  1375.                     bindGenericProfileClickHandler();
  1376.                 }
  1377.             };
  1378.         return {
  1379.             ID: PROCESSOR_ID,
  1380.             EXCLUSIVE: false,
  1381.             NEEDS_DISPATCHER: true,
  1382.             CSS: ['overlay'],
  1383.             init: init
  1384.         };
  1385.     })('Overlay'));
  1386. }
  1387.  
  1388. // -------------------- END PROCESSOR: Overlay ------------------------
  1389.  
  1390.  
  1391. // -------------------- BEGIN PROCESSOR: Config ----------------------
  1392.  
  1393. if (GRT.hasProcessor('Overlay')) {
  1394.     GRT.addProcessor((function(PROCESSOR_ID) {
  1395.         var log = null,
  1396.             doc = null,
  1397.             helpers = null,
  1398.             grt = null,
  1399.             handlersBound = false,
  1400.             HANDLERS = {
  1401.                 INPUT_CHANGE: function(e) {
  1402.                     if (!e.target) return;
  1403.                     var input = e.target,
  1404.                         cfgKey = (input.id || 'grt_').match(/^grt_(.*)/)[1];
  1405.                     if (!cfgKey) return;
  1406.                     var o = {};
  1407.                     o[cfgKey] = (input.type == 'checkbox') ? (input.checked ? 1 : 0) : input.value || '0';
  1408.                     helpers.setConfig(o);
  1409.                     helpers.saveConfigCookie();
  1410.                     if (cfgKey == 'de') {
  1411.                         grt.callAction('openConfig');
  1412.                     } else {
  1413.                         initForm();
  1414.                         if (cfgKey == 'dim' || cfgKey == 'tit') {
  1415.                             grt.callAction('refreshHeaderConfig');
  1416.                         }
  1417.                     }
  1418.                 }
  1419.             },
  1420.             initForm = function() {
  1421.                 for (var k in helpers.config) {
  1422.                     var input = doc.getElementById('grt_' + k),
  1423.                         cfgVal = helpers.config[k];
  1424.                     if (!input) continue;
  1425.                     if (input.type == 'checkbox') {
  1426.                         input.checked = cfgVal ? 'checked' : '';
  1427.                     } else {
  1428.                         input.value = cfgVal;
  1429.                     }
  1430.                 }
  1431.             },
  1432.             getConfigHtml = function() {
  1433.                 if (!handlersBound) {
  1434.                     doc.addEventListener('change', HANDLERS.INPUT_CHANGE, true);
  1435.                     handlersBound = true;
  1436.                 }
  1437.                 var BASE_URL = helpers.useSSL ? 'https://ssl-account.com/gr-tools.justlep.net' : 'http://gr-tools.justlep.net',
  1438.                     styles = '<style type="text/css"> #grtcfg2 {padding:10px;color:#D1DEF1;font-family:Tahoma,Arial,Verdana,Helvetica;} #grtcfg2 table {width:auto;margin:10px 0 0;border-collapse:collapse;border-spacing:0} #grtcfg2 input {cursor:pointer} #grtcfg2 h3 {padding:0 4px 5px 0;margin:0;font-size:14px;border-bottom:1px solid #ccc;text-align:right;color:#D1DEF1 !important} #grtcfg2 h4, #grtcfg2 p {padding:0;margin:0} #grtcfg2 td {vertical-align:top;padding:7px 5px 0;color:#D1DEF1;width:auto !important} #grtcfg2 label { cursor:pointer; display:block; padding:2px 0; position:relative; float:left; } #grtcfg2 label.ex b { padding-right:20px; background:transparent url(' + BASE_URL + '/img/cfg/show.png) right center no-repeat; } #grtcfg2 label b {color:#fff} #grtcfg2 label img:hover {display:none !important} #grtcfg2 label img { vertical-align:middle; border:1px solid yellow; margin-top:4px; display:none; position:absolute; z-index:2 } #grtcfg2 label.ex:hover img {display:block} #grtcfg2 .grtwarn b {color:#ffb400} #grtcfg2 .bg2, #grtcfg2 .grtwarn {background-color:#2A509F} #bmiDiv, #ageDiv {padding-bottom:5px} #bmiDiv label, #ageDiv label {display:inline} #ageDiv input, #bmiDiv input {border:1px solid #fff;width:30px;margin:0 5px 0 2px;background-color:#85E854;cursor:default;font-size:11px;text-align:center} #grtopts p {opacity:0.9;padding-top:2px;padding-bottom:10px;clear:both} #grtopts td:hover p {opacity:1} #grtSaveConfig { font-size:11px; font-family:Verdana; } #grtcfg2 tr.ind td:last-child {padding-left:26px !important} #grtcfg2 tr.ind2 td {padding-top:0 !important} #grt_de {margin:0 0 0 10px} #grtCookieInfo {padding:0;border:1px solid #ccc;border-radius:5px;margin-top:10px;overflow:hidden} #grtCookieInfo p {padding:5px 0 10px} </style>';
  1439.                 if (helpers.config.de) {
  1440.                     return styles + '<div id="grtcfg2"> <h3> GR-Tools - Einstellungen <select id="grt_de"><option value="1">Deutsch</option><option value="0">English</option></select> </h3> <table cellspacing="5" id="grtopts"> <tr class="bg2"> <td><input type="checkbox" id="grt_z"/></td> <td> <label for="grt_z" class="ex"> <b>Vorschaubild-Lupe</b><img src="' + BASE_URL + '/img/cfg/lupe.png" alt="" class="ex" /> </label> <p>Zeigt das <img src="' + BASE_URL + '/img/lupe2.png" alt="Lupe"/>-Symbol in Vorschaubildern an, um beim Herüberfahren mit der Maus das Originalbild zu sehen.</p> </td> </tr> <tr> <td><input type="checkbox" id="grt_popa"/></td> <td> <label for="grt_popa" class="ex"> <b>Popups vermeiden</b><img src="' + BASE_URL + '/img/cfg/iframe.jpg" alt="" class="ex" /> </label> <p>Nutzerprofile werden in vielen (aber nicht allen!) Bereichen statt in Popups direkt in der Seite geöffnet.</p> </td> </tr> <tr class="ind ind2"> <td><input type="checkbox" id="grt_popt"/></td> <td> <label for="grt_popt"> <b>... auch bei Vorschaubild-Klick</b> </label> <p>Durch Deaktivieren dieser Option bleibt hartnäckigen Popup-Fetischisten ein Weg, trotz aktivierter "Popup-Vermeidung" noch Profil-Popups zu öffnen - per Klick aufs Vorschaubild ;-).</p> </td> </tr> <tr class="bg2"> <td><input type="checkbox" id="grt_sb"/></td> <td> <label for="grt_sb" class="ex"> <b>BMI-Wert anzeigen</b><img src="' + BASE_URL + '/img/cfg/bmi-wert.png" alt="" class="ex" /> </label> <p>Zeigt in Suchergebnissen den BMI-Wert jedes Nutzers hinter seinem Nickname in Klammern an.<br/>Der Body-Mass-Index (BMI) gibt Aufschluss über das Verhältnis von Körpergröße zu Gewicht - je höher der BMI, desto voluminöser der Mensch. BMIs von 20 bis 25 gelten allgemein als "gesund". <u>Kaum Aussagekraft</u> hat der BMI allerdings bei muskulösen oder durchtrainierten Kerlen. Und überhaupt: den BMI bitte nicht überbewerten!</p> </td> </tr> <tr> <td><input type="checkbox" id="grt_bmi"/></td> <td> <label for="grt_bmi" class="ex"> <b>... und nach BMI filtern</b><img src="' + BASE_URL + '/img/cfg/bmi-filter.png" alt="" class="ex" /> </label> <p>Wenn aktiviert, werden Nutzer, die nicht deinem eingestellten "BMI-Wunschraster" entsprechen, in Suchergebislisten halbtransparent dargestellt.</p> <div id="bmiDiv">Dein Traum-BMI: &nbsp; <input type="text" id="grt_bmin"/> - <input type="text" id="grt_bmax"/></div> </td> </tr> <tr class="bg2"> <td><input type="checkbox" id="grt_age"/></td> <td> <label for="grt_age" class="ex"> <b>Alters-Filter</b><img src="' + BASE_URL + '/img/cfg/age-filter.png" alt="" class="ex" /> </label> <p>Wenn aktiviert, werden Nutzername, Alters- und Gewichtsangaben der Nutzer, die nicht in deinem Alters-Wunschbereich liegen, grau bzw. abgeschwächt dargestellt.</p> <div id="ageDiv">Dein Wunschalter: &nbsp; <input type="text" id="grt_amin"/> - <input type="text" id="grt_amax"/></div> </td> </tr> <tr> <td><input type="checkbox" id="grt_pica"/></td> <td> <label for="grt_pica" class="ex"> <b>Bilderverwaltung erleichtern</b><img src="' + BASE_URL + '/img/cfg/picadmin.jpg" alt="" class="ex" /> </label> <p>Zeigt beim Bearbeiten eines Bildes in der Bilderverwaltung die anderen Bilder der aktuellen Galerie klickbar über dem derzeitigen Bild an. Außerdem springst du nach Speichern des Kommentartextes automatisch gleich zum nächsten.</p> </td> </tr> <tr class="bg2"> <td><input type="checkbox" id="grt_taps"/></td> <td> <label for="grt_taps"> <b>Fußtapsen zum Klicken</b> </label> <p>Ein Klick auf eine erhaltene Tapse öffnet das Tapsen-Popup, so dass du direkt eine Antwort-Tapse geben kannst.</p> </td> </tr> <tr> <td><input type="checkbox" id="grt_pl"/></td> <td> <label for="grt_pl" class="ex"> <b>Größere Blätter-Links unter Ergebnissen</b><img src="' + BASE_URL + '/img/cfg/paging.png" alt="" class="ex" /> </label> <p>Die futzeligen "Nächste-/Zurück"-Links in Suchergebnisseiten werden durch große, nicht zu verfehlende Monster-Buttons ersetzt. Nicht nur für Grobmotoriker :).</p> </td> </tr> <tr class="bg2"> <td><input type="checkbox" id="grt_dim"/></td> <td> <label for="grt_dim" class="ex"> <b>Gayromeo/Planetromeo-Logo abdimmen</b><img src="' + BASE_URL + '/img/cfg/logodim.jpg" alt="" class="ex" /> </label> <p>Macht das Gayromeo/Planetromeo-Logo stark durchsichtig, damit nicht jeder Nicht-Kenner schon aus 50 Metern erkennt, wo du gerade surfst ;-).</p> </td> </tr> <tr> <td><input type="checkbox" id="grt_tit"/></td> <td> <label for="grt_tit"> <b>Seitentitel verharmlosen</b> </label> <p>Ändert den Seitentitel in &apos;R..&apos;, so dass in deiner Taskleiste kein &apos;Gayromeo&apos; mehr auftaucht ;-).</p> </td> </tr> <tr class="bg2"> <td><input type="checkbox" id="grt_lm"/></td> <td> <label for="grt_lm" class="ex"> <b>Messageverlauf: letzte Nachricht hervorheben</b><img src="' + BASE_URL + '/img/cfg/lastmsg.jpg" alt="" class="ex" /> </label> <p>Springt im Messageverlauf automatisch zur letzten Nachricht und hebt sie optisch hervor.</p> </td> </tr> <tr> <td><input type="checkbox" id="grt_yth"/></td> <td> <label for="grt_yth" class="ex"> <b>YouTube-Links in Headlines</b><img src="' + BASE_URL + '/img/cfg/yt-list.png" alt="" class="ex" /> </label> <p>YouTube-URLs innerhalb von Nutzer-Headlines in Suchergebnissen werden zu direkt klickbaren Links - denn Copy&Paste sucks ;-).</p> </td> </tr> <tr class="ind2"> <td><input type="checkbox" id="grt_ytp"/></td> <td> <label for="grt_ytp"> <b>YouTube-Links in Profilen</b> </label> <p>YouTube-URLs innerhalb von Nutzer-Profiltexten werden zu direkt klickbaren Links.</p> </td> </tr> <tr class="ind ind2"> <td><input type="checkbox" id="grt_ytpr"/></td> <td> <label for="grt_ytpr" class="ex"> <b>... und Video-Vorschaubild einblenden</b><img src="' + BASE_URL + '/img/cfg/ytpreview.jpg" alt="" class="ex" /> </label> <p>Beim Überfahren von YouTube-Links mit der Maus wird das Vorschaubild des entsprechenden Videos neben dem Cursor eingeblendet.</p> </td> </tr> <tr class="bg2"> <td><input type="checkbox" id="grt_lt"/></td> <td> <label for="grt_lt" class="ex"> <b>Aktuelle Forum-Threads hervorherben</b><img src="' + BASE_URL + '/img/cfg/lthreads.jpg" alt="" class="ex" /> </label> <p>Auf der Forum-Unterseite des Club-Centers werden die Threads der letzten 3 Tage farblich abgestuft hervorgehoben.</p> </td> </tr> <tr> <td><input type="checkbox" id="grt_secr"/></td> <td> <label for="grt_secr" class="ex"> <b>"Geheim"-Klick auf BMI</b><img src="' + BASE_URL + '/img/cfg/bmiclick.jpg" alt="" class="ex" /> </label> <p>Ein Klick auf den BMI-Wert eines Nutzers öffnet sein Profil so, dass du nicht in seiner Besucherliste auftauchst (funktioniert <u>nur</u>, falls er sein Profil für jedermann sichtbar eingestellt hat).<br/> <b>Achtung:</b> falls du gleichzeitig mit mehreren Profilen bei gayromeo.com, planetromeo.com und/oder 83.98.143.20 eingeloggt bist, kann es passieren, dass dein Zweit-/Drittprofil in der Besucherliste des anderen auftaucht! Pech gehabt!</p> </td> </tr> <tr class="ind2"> <td><input type="checkbox" id="grt_rc"/></td> <td> <label for="grt_rc"> <b>Rechtsklicks auf Bilder erlauben</b> </label> <p>Macht es wieder möglich, per Rechtsklick Bilder zu speichern. Alternative <a target="_blank" href="/jump.php?jump=http%3A%2F%2Fwww.com-magazin.de%2Ftipps%2Fuebersicht%2Ftipp-id%2Ffirefox-kontextmenue-reaktivieren.html">hier</a>.</p> </td> </tr> </table> <div id="grtCookieInfo"> <table cellspacing="5" border="0" style="margin:0"> <tr class="grtWarn"> <td><input type="checkbox" id="grt_keep"/></td> <td> <label for="grt_keep"><b>GR-Tools-Cookie auch nach dem Logout behalten</b></label> <p style="clear:both"> <img src="' + BASE_URL + '/img/cfg/warn.png" alt="" style="vertical-align:top" /> Wichtig: Die Lebenszeit des Gayromeo-Cookie&apos;s endet normalerweise mit dem Logout (Session-Cookie). Die GR-Tools verwenden ebenfalls einen Cookie, um deine Einstellungen zu speichern. Diesen kannst du auch über den Logout hinaus behalten, um die Einstellungen nicht bei jedem Login erneut treffen zu müssen. <br/> Aber: falls du nicht an deinem Privat-PC sitzt, lässt ein dauerhafterer Cookie bei anderen Nutzern deines Computer&apos;s Rückschlüsse darauf zu, dass du bei GR unterwegs warst. Bevor du hier den Haken setzt, entscheide deshalb bitte sehr bewusst, ob dir durch einen GayRomeo-Cookie eventuell Probleme entstehen könnten. </p> </td> </tr> </table></div> </div>';
  1441.                 }
  1442.                 return styles + '<div id="grtcfg2"> <h3> GR-Tools - Settings <select id="grt_de"><option value="1">Deutsch</option><option value="0">English</option></select> </h3> <table cellspacing="5" id="grtopts"> <tr class="bg2"> <td><input type="checkbox" id="grt_z"/></td> <td> <label for="grt_z" class="ex"> <b>Preview Image Zoom</b><img src="' + BASE_URL + '/img/cfg/lupe.png" alt="" class="ex" /> </label> <p>Adds a <img src="' + BASE_URL + '/img/lupe2.png" alt="Zoom"/> icon to preview images. Moving the mouse on it will show the original image.</p> </td> </tr> <tr> <td><input type="checkbox" id="grt_popa"/></td> <td> <label for="grt_popa" class="ex"> <b>Popup Avoidance</b><img src="' + BASE_URL + '/img/cfg/iframe.jpg" alt="" class="ex" /> </label> <p>In many (but not all) areas of GR, user profiles will be opened directly within the site instead of nasty popup windows.</p> </td> </tr> <tr class="ind ind2"> <td><input type="checkbox" id="grt_popt"/></td> <td> <label for="grt_popt"> <b>... even on thumbnail clicks</b> </label> <p>With activated popup avoidance, <u>de</u>activating this option allows the popup fetishists among you to still open profile popups by clicking the user&apos;s thumbnail ;-).</p> </td> </tr> <tr class="bg2"> <td><input type="checkbox" id="grt_age"/></td> <td> <label for="grt_age" class="ex"> <b>Age Filter</b><img src="' + BASE_URL + '/img/cfg/age-filter.png" alt="" class="ex" /> </label> <p>If activated and a user is below or beyond your prefered age, his nickname, age and weight data will be displayed semitransparently / grayed out.</p> <div id="ageDiv">Your prefered age: &nbsp; <input type="text" id="grt_amin"/> - <input type="text" id="grt_amax"/></div> </td> </tr> <tr> <td><input type="checkbox" id="grt_sb"/></td> <td> <label for="grt_sb" class="ex"> <b>Show BMI values</b><img src="' + BASE_URL + '/img/cfg/bmi-wert.png" alt="" class="ex" /> </label> <p>In result pages, each user&apos;s BMI value will be displayed behind his nickname.<br/>The Body-Mass-Index (BMI) is the relation between body size and weight - the higher the value, the more "voluminous" the guy. Values from 20 to 25 are considered "healthy", though this may vary with age and origin. Moreover, the BMI is quite <u>pointless</u> regarding trained or muscle guys. Just generally: Do not overrate the BMI, please!</p> </td> </tr> <tr class="bg2"> <td><input type="checkbox" id="grt_bmi"/></td> <td> <label for="grt_bmi" class="ex"> <b>BMI Filter</b><img src="' + BASE_URL + '/img/cfg/bmi-filter.png" alt="" class="ex" /> </label> <p>If activated, all users outside your prefered BMI range will be displayed semi-<wbr/>transparently in the result lists.</p> <div id="bmiDiv">Your prefered BMI range: &nbsp; <input type="text" id="grt_bmin"/> - <input type="text" id="grt_bmax"/></div> </td> </tr> <tr> <td><input type="checkbox" id="grt_pica"/></td> <td> <label for="grt_pica" class="ex"> <b>Easier Picture Management</b><img src="' + BASE_URL + '/img/cfg/picadmin.jpg" alt="" class="ex" /> </label> <p>While editing the text of one of your pictures, you will see all the other pictures of the same gallery just above the current image.Also, after saving the changes, you will be automatically redirected to the next picture.</p> </td> </tr> <tr class="bg2"> <td><input type="checkbox" id="grt_taps"/></td> <td> <label for="grt_taps"> <b>Footprints clickable</b> </label> <p>A click on a footprint you&apos;ve been given opens the footprint popup, so you can give a reply footprint right away.</p> </td> </tr> <tr> <td><input type="checkbox" id="grt_pl"/></td> <td> <label for="grt_pl" class="ex"> <b>Bigger Paging Links under Result Lists</b><img src="' + BASE_URL + '/img/cfg/paging.png" alt="" class="ex" /> </label> <p>The tiny "Next/Back" links of result pages will be replaced with huge, non-missable monster arrow buttons :-).</p> </td> </tr> <tr class="bg2"> <td><input type="checkbox" id="grt_dim"/></td> <td> <label for="grt_dim" class="ex"> <b>Dim the Gayromeo/Planetromeo logo</b><img src="' + BASE_URL + '/img/cfg/logodim.jpg" alt="" class="ex" /> </label> <p>Makes the Gayromeo/Planetromeo logo *almost* invisible, so not everyone who doesn&apos;t know GR can recognize from the distance what website you&apos;re surfing ;-).</p> </td> </tr> <tr> <td><input type="checkbox" id="grt_tit"/></td> <td> <label for="grt_tit"> <b>Harmless page title</b> </label> <p>Changes the page title into simple &apos;R..&apos;, so there is no &apos;Gayromeo&apos; in your task bar anymore ;-).</p> </td> </tr> <tr class="bg2"> <td><input type="checkbox" id="grt_lm"/></td> <td> <label for="grt_lm" class="ex"> <b>Message history: Highlight last message</b><img src="' + BASE_URL + '/img/cfg/lastmsg.jpg" alt="" class="ex" /> </label> <p>Jumps automatically to the last message in the message history and highlights it.</p> </td> </tr> <tr> <td><input type="checkbox" id="grt_yth"/></td> <td> <label for="grt_yth" class="ex"> <b>YouTube-Links in Headlines</b><img src="' + BASE_URL + '/img/cfg/yt-list.png" alt="" class="ex" /> </label> <p>YouTube URLs within online-headlines will be turned into real, clickable links -<br/>&apos;coz Copy&Paste sucks ;-).</p> </td> </tr> <tr class="ind2"> <td><input type="checkbox" id="grt_ytp"/></td> <td> <label for="grt_ytp"> <b>YouTube-Links in Profiles</b> </label> <p>YouTube-URLs within user profiles wil be turned into clickable links.</p> </td> </tr> <tr class="ind ind2"> <td><input type="checkbox" id="grt_ytpr"/></td> <td> <label for="grt_ytpr" class="ex"> <b>... Video Preview on mouseover</b><img src="' + BASE_URL + '/img/cfg/ytpreview.jpg" alt="" class="ex" /> </label> <p>When you hold the mouse over a YouTube-Link, the video&apos;s preview image will be displayed next to the mouse cursor.</p> </td> </tr> <tr class="bg2"> <td><input type="checkbox" id="grt_lt"/></td> <td> <label for="grt_lt" class="ex"> <b>Highlight latest Threads on Forum page</b><img src="' + BASE_URL + '/img/cfg/lthreads.jpg" alt="" class="ex" /> </label> <p>On the Forum-subpage of the Club-Center all threads of the recent 3 days will be highlighted.</p> </td> </tr> <tr> <td><input type="checkbox" id="grt_secr"/></td> <td> <label for="grt_secr" class="ex"> <b>"Secret" Click on BMI value</b><img src="' + BASE_URL + '/img/cfg/bmiclick.jpg" alt="" class="ex" /> </label> <p>Clicking a BMI value opens that user&apos;s public profile through a different GayRomeo domain, so the user won&apos;t notice your visit (works <u>only</u>, if his is profile is set public for everyone).<br/> <b>Attention:</b> if you are surfing with multiple profiles simultaneously on gayromeo.com, planetromeo.com and/or 83.98.143.20, it may happen that your second/third profile ends up in the visitor list of the viewed person! Bad luck!</p> </td> </tr> <tr class="ind2"> <td><input type="checkbox" id="grt_rc"/></td> <td> <label for="grt_rc"> <b>Allow Rightclicks on images</b> </label> <p>Re-enables the rightclick on images which GR normally prevents.. just in case you do not want to change JavaScript settings of your browser.</p> </td> </tr> </table> <div id="grtCookieInfo"> <table cellspacing="5" border="0" style="margin:0"> <tr class="grtWarn"> <td><input type="checkbox" id="grt_keep"/></td> <td> <label for="grt_keep"><b>Keep the GR-Tools cookie after logout</b></label> <p style="clear:both"> <img src="' + BASE_URL + '/img/cfg/warn.png" alt="" style="vertical-align:top" /> NOTE: Lifetime of the Gayromeo cookie is normally limited to the period you are logged in (Session Cookie). The GR-Tools use a cookie to save your settings, too. You can keep that cookie even after logout if you want to, just to not have to re-configure your GR-Tools on each login.<br/> But: if you are not working at your private PC, that longer-lasting cookie may reveal to other users of that computer that you&apos;ve been surfing GR lately. Thus, before you make the cross for this option, please decide carefully for yourself whether or not a GayRomeo cookie might get you into trouble! </p> </td> </tr> </table></div> </div>';
  1443.             },
  1444.             init = function(_grt, _helpers) {
  1445.                 grt = _grt;
  1446.                 helpers = _helpers;
  1447.                 log = _helpers.log;
  1448.                 doc = _helpers.doc;
  1449.                 _grt.registerAction('initConfigForm', initForm);
  1450.                 _helpers.setConfigHtmlProviderFunction(getConfigHtml);
  1451.             };
  1452.         return {
  1453.             ID: PROCESSOR_ID,
  1454.             EXCLUSIVE: false,
  1455.             NEEDS_DISPATCHER: true,
  1456.             init: init
  1457.         };
  1458.     })('Config'));
  1459. }
  1460.  
  1461. // -------------------- END PROCESSOR: Config ------------------------
  1462.  
  1463.  
  1464. // -------------------- BEGIN PROCESSOR: ImageZoom ----------------------
  1465.  
  1466. if (GRT.hasProcessor('Overlay')) {
  1467.     GRT.addProcessor((function(PROCESSOR_ID) {
  1468.         var IMG_POPUP_URL_PREFIX = '/auswertung/pix/popup.php/',
  1469.             IMG_POPUP_IMG_REGEX = /<img src="([^"]*\/img\/usr\/[^\.]*\.jpg)"/,
  1470.             HIDE_DELAY = 150,
  1471.             log = null,
  1472.             doc = null,
  1473.             grt = null,
  1474.             assertTrue = null,
  1475.             zoomIconProtoype = null,
  1476.             xpath = null,
  1477.             xhr = null,
  1478.             urlCache = {},
  1479.             currentThumbId = null,
  1480.             currentUsername = null,
  1481.             visible = 0,
  1482.             urlContainsAll = null,
  1483.             HANDLERS = {
  1484.                 ZOOM_ICON_OVER: function(e) {
  1485.                     var o = e.target;
  1486.                     if (!o || !/^grtZoom/.test(o.className || '') || !o.id) return;
  1487.                     e.cancelBubble = true;
  1488.                     currentThumbId = o.id.substring(3);
  1489.                     currentUsername = e.target.parentNode.parentNode.parentNode.getAttribute('username') || '';
  1490.                     visible = true;
  1491.                     findAndLoadFullsizeImge(currentThumbId);
  1492.                 },
  1493.                 ZOOM_ICON_OUT: function(e) {
  1494.                     if (!/^grtZoom/.test(e.target.className || '')) return;
  1495.                     currentThumbId = null;
  1496.                     e.cancelBubble = true;
  1497.                     visible = false;
  1498.                     setTimeout(closeOverlayDelayed, HIDE_DELAY);
  1499.                 },
  1500.                 XHR_SUCCESS: function(e) {
  1501.                     if (xhr.readyState != 4 || xhr.status != 200) {
  1502.                         return;
  1503.                     }
  1504.                     var html = xhr.responseText || '',
  1505.                         imageUrl = extractImageUrlFromImagePopup(html);
  1506.                     if (imageUrl) {
  1507.                         if (currentThumbId) urlCache[currentThumbId] = imageUrl;
  1508.                         showOverlay(imageUrl);
  1509.                     } else {
  1510.                         hideOverlay();
  1511.                     }
  1512.                 },
  1513.                 XHR_ERROR: function() {
  1514.                     currentThumbId = null;
  1515.                     hideOverlay();
  1516.                 }
  1517.             },
  1518.             closeOverlayDelayed = function() {
  1519.                 if (visible) return;
  1520.                 grt.callAction('closeImageOverlay', {
  1521.                     ifNotHovered: true
  1522.                 });
  1523.             },
  1524.             closeOverlay = function(force) {
  1525.                 grt.callAction('closeImageOverlay');
  1526.             },
  1527.             showOverlay = function(fullsizeImgUrl) {
  1528.                 grt.callAction('loadImageInOverlay', {
  1529.                     url: fullsizeImgUrl,
  1530.                     username: currentUsername
  1531.                 });
  1532.             },
  1533.             extractImageUrlFromImagePopup = function(html) {
  1534.                 return (html.match(IMG_POPUP_IMG_REGEX) || [])[1];
  1535.             },
  1536.             findAndLoadFullsizeImge = function(thumbId) {
  1537.                 if (urlCache[thumbId]) {
  1538.                     currentThumbId = null;
  1539.                     showOverlay(urlCache[thumbId]);
  1540.                     return;
  1541.                 }
  1542.                 if (!xhr) {
  1543.                     xhr = new XMLHttpRequest();
  1544.                     xhr.addEventListener('load', HANDLERS.XHR_SUCCESS, false);
  1545.                     xhr.addEventListener('error', HANDLERS.XHR_ERROR, false);
  1546.                 }
  1547.                 currentThumbId = thumbId;
  1548.                 var imagePopupUrl = IMG_POPUP_URL_PREFIX + thumbId;
  1549.                 xhr.open('GET', imagePopupUrl, true);
  1550.                 xhr.send();
  1551.             },
  1552.             addZoomIcons = function() {
  1553.                 if (!zoomIconProtoype) {
  1554.                     zoomIconProtoype = doc.createElement('i');
  1555.                     zoomIconProtoype.className = 'grtZoom';
  1556.                 }
  1557.                 var thumbs = doc.getElementsByClassName('thumb'),
  1558.                     isClubCenterPage = urlContainsAll('page=club');
  1559.                 if (!thumbs || !thumbs.length) return;
  1560.                 for (var i = 0; i < thumbs.length; i++) {
  1561.                     var img = thumbs[i],
  1562.                         imgParent = img.parentNode,
  1563.                         thumbId = null;
  1564.                     if (/grtZoomParent/.test(imgParent.className || '')) continue;
  1565.                     if (/\/img\/usr\/([0-9a-f]*\.jpg)$/.exec(img.src || '') || /popup\.php\/([0-9a-z\.]+)\.jpg/.exec(imgParent.href || '')) {
  1566.                         thumbId = RegExp.$1;
  1567.                     }
  1568.                     if (!thumbId) return;
  1569.                     var icon = zoomIconProtoype.cloneNode(false);
  1570.                     icon.id = 'gz_' + thumbId;
  1571.                     imgParent.className += ' grtZoomParent';
  1572.                     if (isClubCenterPage && imgParent.className.indexOf('pop') >= 0) {
  1573.                         icon.className += ' pop';
  1574.                     }
  1575.                     imgParent.appendChild(icon);
  1576.                 }
  1577.                 doc.body.addEventListener('mouseover', HANDLERS.ZOOM_ICON_OVER, true);
  1578.                 doc.body.addEventListener('mouseout', HANDLERS.ZOOM_ICON_OUT, true);
  1579.             },
  1580.             init = function(_grt, helpers) {
  1581.                 if (!helpers.config.z) return;
  1582.                 grt = _grt;
  1583.                 log = helpers.log;
  1584.                 doc = helpers.doc;
  1585.                 urlContainsAll = helpers.urlContainsAll;
  1586.                 xpath = helpers.xpath;
  1587.                 assertTrue = helpers.assertTrue;
  1588.                 addZoomIcons();
  1589.                 helpers.addExternalRetriggerHandler(addZoomIcons);
  1590.             };
  1591.         return {
  1592.             ID: PROCESSOR_ID,
  1593.             EXCLUSIVE: false,
  1594.             NEEDS_DISPATCHER: true,
  1595.             CSS: ['imageZoom'],
  1596.             init: init
  1597.         };
  1598.     })('ImageZoom'));
  1599. }
  1600.  
  1601. // -------------------- END PROCESSOR: ImageZoom ------------------------
  1602.  
  1603.  
  1604. // -------------------- BEGIN PROCESSOR: Profile ----------------------
  1605.  
  1606. if (GRT.urlContainsAll('auswertung/setcard/', 'set=')) {
  1607.     var circ = document.getElementById('jsCircle');
  1608.     if (circ) {
  1609.         circ.style.width = '18px';
  1610.     }
  1611.     GRT.addProcessor((function(PROCESSOR_ID) {
  1612.         var log = null,
  1613.             assertTrue = null,
  1614.             doc = null,
  1615.             win = null,
  1616.             grt = null,
  1617.             helpers = null,
  1618.             isOpenedAnonymously = false,
  1619.             sanitizeAnonymousProfile = function() {
  1620.                 var sidebar = doc.getElementById('sidebar'),
  1621.                     picbar = doc.getElementById('picbar'),
  1622.                     topbar = doc.getElementById('tabse'),
  1623.                     targetDomain = (location.hash || '').replace(helpers.ANON_URL_HASH, ''),
  1624.                     domainIndex = (targetDomain.indexOf('gayromeo') > 0) ? 'GR' : (targetDomain.indexOf('planetromeo') > 0) ? 'PR' : 'IP',
  1625.                     replaceLinks = function(links) {
  1626.                         if (!links) return;
  1627.                         for (var i = links.length - 1; i >= 0; i--) {
  1628.                             var a = links[i],
  1629.                                 url = a.href || '',
  1630.                                 isPartnerLink = url.indexOf('auswertung/setcard/index.php') >= 0,
  1631.                                 isXXXPic = !isPartnerLink && url.indexOf('page=status') > 0;
  1632.                             if (url && !isPartnerLink && !isXXXPic) {
  1633.                                 a.href = helpers.unanonymizeUrl(url, domainIndex);
  1634.                             }
  1635.                         }
  1636.                     };
  1637.                 replaceLinks((sidebar) ? sidebar.getElementsByTagName('a') : 0);
  1638.                 replaceLinks((picbar) ? picbar.getElementsByTagName('a') : 0);
  1639.                 replaceLinks((topbar) ? topbar.getElementsByTagName('a') : 0);
  1640.             },
  1641.             fixHideVisitClose = function() {
  1642.                 win.close = function() {
  1643.                     (function($) {
  1644.                         $('#cancelButton').trigger('click');
  1645.                         grt.callAction('markAnonymous');
  1646.                     })(win.jQuery);
  1647.                 };
  1648.             },
  1649.             init = function(_grt, _helpers) {
  1650.                 log = _helpers.log;
  1651.                 doc = _helpers.doc;
  1652.                 win = _helpers.win;
  1653.                 helpers = _helpers;
  1654.                 grt = _grt;
  1655.                 assertTrue = _helpers.assertTrue;
  1656.                 isOpenedAnonymously = (location.hash || '').indexOf(_helpers.ANON_URL_HASH) >= 0;
  1657.                 if (isOpenedAnonymously) {
  1658.                     sanitizeAnonymousProfile();
  1659.                 } else {
  1660.                     fixHideVisitClose();
  1661.                 }
  1662.             };
  1663.         return {
  1664.             ID: PROCESSOR_ID,
  1665.             EXCLUSIVE: false,
  1666.             NEEDS_DISPATCHER: true,
  1667.             CSS: 0,
  1668.             init: init
  1669.         };
  1670.     })('Profile'));
  1671. }
  1672.  
  1673. // -------------------- END PROCESSOR: Profile ------------------------
  1674.  
  1675.  
  1676. // -------------------- BEGIN PROCESSOR: PagingLinks ----------------------
  1677.  
  1678. if (GRT.hasProcessor('Overlay')) {
  1679.     GRT.addProcessor((function(PROCESSOR_ID) {
  1680.         var helpers = null,
  1681.             decoratePaging = function() {
  1682.                 var prevLink = helpers.xpath('//a[contains(@href,"resultPage")][contains(./strong,"\xab")]')[0],
  1683.                     nextLink = helpers.xpath('//a[contains(@href,"resultPage")][contains(./strong,"\xbb")]')[0];
  1684.                 if (prevLink) {
  1685.                     prevLink.id = 'grtPrev';
  1686.                     prevLink.innerHTML = '&nbsp;';
  1687.                 }
  1688.                 if (nextLink) {
  1689.                     nextLink.id = 'grtNext';
  1690.                     nextLink.innerHTML = '&nbsp;';
  1691.                 }
  1692.             },
  1693.             init = function(grt, _helpers) {
  1694.                 helpers = _helpers;
  1695.                 if (!_helpers.config.pl) return;
  1696.                 decoratePaging();
  1697.             };
  1698.         return {
  1699.             ID: PROCESSOR_ID,
  1700.             EXCLUSIVE: false,
  1701.             NEEDS_DISPATCHER: false,
  1702.             CSS: ['pagingLinks'],
  1703.             init: init
  1704.         };
  1705.     })('PagingLinks'));
  1706. }
  1707.  
  1708. // -------------------- END PROCESSOR: PagingLinks ------------------------
  1709.  
  1710.  
  1711. // -------------------- BEGIN PROCESSOR: LatestMessage ----------------------
  1712.  
  1713. if (GRT.urlContainsAny('/msg/history.php')) {
  1714.     GRT.addProcessor((function(PROCESSOR_ID) {
  1715.         var log = null,
  1716.             assertTrue = null,
  1717.             helpers = null,
  1718.             doc = null,
  1719.             attemptsLeft = 3,
  1720.             REATTEMPT_DELAY = 250,
  1721.             scrollToBottom = function() {
  1722.                 helpers.doc.body.scrollTop = 9999999;
  1723.                 var now = helpers.doc.body.scrollTop || 0;
  1724.                 if (!now && --attemptsLeft) {
  1725.                     setTimeout(scrollToBottom, REATTEMPT_DELAY);
  1726.                 }
  1727.             },
  1728.             highlightLastMessage = function() {
  1729.                 var lastMsgA = helpers.xpath('//a[contains(@name,"lastmessage")]');
  1730.                 if (!lastMsgA.length) return;
  1731.                 var tds = helpers.xpath('//tr/td[contains(@class,"body")]');
  1732.                 if (!tds.length) return;
  1733.                 var td = tds[tds.length - 1];
  1734.                 td.id = 'grtLastMessage';
  1735.                 td.parentNode.parentNode.parentNode.style.borderCollapse = 'separate';
  1736.                 setTimeout(scrollToBottom, 50);
  1737.             },
  1738.             init = function(grt, _helpers) {
  1739.                 log = _helpers.log;
  1740.                 assertTrue = _helpers.assertTrue;
  1741.                 helpers = _helpers;
  1742.                 if (!helpers.config.lm) return;
  1743.                 highlightLastMessage();
  1744.             };
  1745.         return {
  1746.             ID: PROCESSOR_ID,
  1747.             EXCLUSIVE: false,
  1748.             NEEDS_DISPATCHER: false,
  1749.             CSS: ['latestMessage'],
  1750.             init: init
  1751.         };
  1752.     })('LatestMessage'));
  1753. }
  1754.  
  1755. // -------------------- END PROCESSOR: LatestMessage ------------------------
  1756.  
  1757.  
  1758. // -------------------- BEGIN PROCESSOR: Youtube ----------------------
  1759.  
  1760. if (GRT.hasProcessor('Profile') || GRT.bodyClassContainsAny('searchResults')) {
  1761.     GRT.addProcessor((function(PROCESSOR_ID) {
  1762.        
  1763.         var log = null,
  1764.             doc = null,
  1765.             helpers = null,
  1766.             assertTrue = null,
  1767.             DONE_MARKER_CLASS = 'grtYTDone',
  1768.             /*REGEX = /(">)?http:\/\/(?:<wbr>)?(?:[a-z]+\.)?(?:<wbr>)?youtube.(<wbr>)?com\/[^\s\t\n\r\]\)"']+/ig,*/
  1769.             REGEX = /http:\/\/(?:<wbr>)?(?:\w+\.)?(?:<wbr>)?youtube\.(?:<wbr>)?com\/[^\s\]\)"']+/ig,
  1770.  
  1771.  
  1772.             /*
  1773.              /(">)?http:\/\/
  1774.                     (?:<wbr>)?
  1775.                 (?:[a-z]+\.)?
  1776.                     (?:<wbr>)?
  1777.                 youtube.
  1778.                 (<wbr>)?
  1779.                 com\/
  1780.                 [^\s\t\n\r\]\)"']+/
  1781.              */
  1782.             THUMB_LOAD_BASE_URL = 'http://ref.justlep.net/ytimg',
  1783.             div = 0,
  1784.             currentA = null,
  1785.            
  1786.             HANDLERS = {
  1787.                
  1788.                 YT_OVER: function(e) {
  1789.                     var a = e.target;
  1790.                     if (!(/%3Fv%3D([a-z0-9_\-]*)/i).exec(a.href)) return;
  1791.                     div.style.display = 'none';
  1792.                     div.childNodes[0].src = THUMB_LOAD_BASE_URL + RegExp.$1;
  1793.                     a.style.cursor = 'wait';
  1794.                     div.on = 1;
  1795.                     currentA = a;
  1796.                 },
  1797.                
  1798.                 YT_OUT: function(e) {
  1799.                     div.style.display = 'none';
  1800.                     div.on = 0;
  1801.                 },
  1802.                
  1803.                 YT_MOVE: function(e) {
  1804.                     div.style.left = 20 + e.clientX + 'px';
  1805.                     div.style.top = 15 + e.clientY + 'px';
  1806.                 },
  1807.                
  1808.                 YT_IMG_LOAD: function(e) {
  1809.                     if (!div.on) return;
  1810.                     div.style.display = 'block';
  1811.                     if (currentA) {
  1812.                         currentA.style.cursor = 'pointer';
  1813.                     }
  1814.                 },
  1815.                
  1816.                 YT_IMG_ERROR: function(e) {}
  1817.             },
  1818.            
  1819.             REPLACE_CALLBACK = function(s) {
  1820.                 if (!s.indexOf('">')) return s;
  1821.                 var url = s.replace(/(<wbr>| |<br>?)/g, '').replace('&amp;', '&'),
  1822.                     jumpURL = '/jump.php?jump=' + encodeURIComponent(url);
  1823.                 return '<a class="ytlink" href="' + jumpURL + '" target="_blank">' + s + '</a>';
  1824.             },
  1825.            
  1826.             markParentTablesDone = function(td) {
  1827.                 var table = td.parentNode;
  1828.                 while (table) {
  1829.                     if (table.nodeName.toLowerCase() == 'table') {
  1830.                         table.className += ' ' + DONE_MARKER_CLASS;
  1831.                     }
  1832.                     table = table.parentNode;
  1833.                 }
  1834.             },
  1835.            
  1836.             processHeadlines = function() {
  1837.                
  1838.              // enable Youtube links in headlines (0|1)
  1839.                 if (!helpers.config.yth) return;
  1840.                
  1841.                 var ytSpans = helpers.xpath('//table[not(contains(@class,"' + DONE_MARKER_CLASS + '"))]//span[contains(.,"http:")][contains(.,"youtube")]'),
  1842.                     lastSpan = null;
  1843.                
  1844.                 for (var i = ytSpans.length - 1; i >= 0; i--) {
  1845.                     lastSpan = ytSpans[i];
  1846.                     lastSpan.innerHTML = lastSpan.innerHTML.replace(REGEX, REPLACE_CALLBACK);
  1847.                 }
  1848.                 if (lastSpan) {
  1849.                     markParentTablesDone(lastSpan);
  1850.                 }
  1851.                 addYTPreview();
  1852.             },
  1853.            
  1854.             processProfile = function() {
  1855.                
  1856.              // enable Youtube links in user profiles (0|1)
  1857.                 if (!helpers.config.ytp) return;
  1858.                
  1859.                 var PROFILE_XPATH = '//table     [contains(@class, "prfl"   )]  \
  1860.                                      /tbody/tr/td[contains(.     , "http:"  )]       \
  1861.                                                  [contains(.     , "youtube")]';
  1862.                 try {
  1863.                     var tds = helpers.xpath(PROFILE_XPATH);
  1864.                     debugger;
  1865.                     for (var i = tds.length - 1; i >= 0; i--) {
  1866.                         var lenBefore =   tds[i].innerHTML.length ;
  1867.                            
  1868.                         var sDone = tds[i].innerHTML.replace(REGEX, REPLACE_CALLBACK) ;
  1869.                        
  1870.                         var ReplaceDone = (sDone.length == lenBefore);
  1871.                         if (ReplaceDone) continue;
  1872.                        
  1873.                         tds[i].innerHTML = sDone;
  1874.                     }
  1875.                    
  1876.                     addYTPreview();
  1877.                    
  1878.                 } catch (e) {}
  1879.             },
  1880.            
  1881.             addYTPreview = function() {
  1882.                
  1883.              // enable Youtube video preview image (0|1)
  1884.                 if (!helpers.config.ytpr) return;
  1885.                
  1886.                 var ytAs = doc.getElementsByClassName('ytlink');
  1887.                 if (!ytAs.length) return;
  1888.                 if (!div) {
  1889.                     var tmp = doc.createElement('div');
  1890.                     tmp.innerHTML = '<div id="grtYT" style="position:fixed;display:none"><img /></div>';
  1891.                     div = tmp.childNodes[0];
  1892.                     doc.body.appendChild(div);
  1893.                     div.childNodes[0].addEventListener('load', HANDLERS.YT_IMG_LOAD, false);
  1894.                     div.childNodes[0].addEventListener('error', HANDLERS.YT_IMG_ERROR, false);
  1895.                     div.childNodes[0].style.marginTop = '-33px';
  1896.                 }
  1897.                 for (var i = 0; i < ytAs.length; i++) {
  1898.                     var a = ytAs[i];
  1899.                     a.ytdiv = div;
  1900.                     a.addEventListener('mouseover', HANDLERS.YT_OVER, false);
  1901.                     a.addEventListener('mouseout', HANDLERS.YT_OUT, false);
  1902.                     a.addEventListener('mousemove', HANDLERS.YT_MOVE, false);
  1903.                 }
  1904.             },
  1905.            
  1906.             init = function(grt, _helpers) {
  1907.                 log = _helpers.log;
  1908.                 doc = _helpers.doc;
  1909.                 helpers = _helpers;
  1910.                 assertTrue = _helpers.assertTrue;
  1911.                 var isResultList = _helpers.bodyClassContainsAny('searchResults');
  1912.                 if (isResultList) {
  1913.                     processHeadlines();
  1914.                 } else {
  1915.                     processProfile();
  1916.                 }
  1917.             };
  1918.         return {
  1919.             ID: PROCESSOR_ID,
  1920.             EXCLUSIVE: false,
  1921.             NEEDS_DISPATCHER: true,
  1922.             init: init
  1923.         };
  1924.     })('Youtube'));
  1925. }
  1926.  
  1927. // -------------------- END PROCESSOR: Youtube ------------------------
  1928.  
  1929.  
  1930. // -------------------- BEGIN PROCESSOR: Tapse ----------------------
  1931.  
  1932. if (GRT.hasProcessor('BMIAgeFilter') || GRT.hashContains('grt_taps_id__')) {
  1933.     GRT.addProcessor((function(PROCESSOR_ID) {
  1934.         var doc = null,
  1935.             log = null,
  1936.             helpers = null,
  1937.             grt = null,
  1938.             TAPSE_CLASS = 'grtTaps',
  1939.             TAPSE_ATTRIB = 'grttaps',
  1940.             handlerBound = false,
  1941.             TAPSE_USER_ID_HASH = 'grt_taps_id__',
  1942.             PROFILE_URL_BASE = '/auswertung/setcard/index.php?set=',
  1943.             HANDLERS = {
  1944.                 TAPSE_CLICK: function(e) {
  1945.                     if (!e.target || !e.target.getAttribute(TAPSE_ATTRIB)) return;
  1946.                     var tr = e.target.parentNode.parentNode,
  1947.                         userId = 0;
  1948.                     while (!userId && tr) {
  1949.                         if (tr.getAttribute) userId = findUserIdInTR(tr);
  1950.                         tr = tr.previousSibling;
  1951.                     }
  1952.                     if (!userId) {
  1953.                         return;
  1954.                     }
  1955.                     var hash = '#' + TAPSE_USER_ID_HASH + userId,
  1956.                         tapseUrl = '/auswertung/setcard/romeo/footprint.php?receiverId=' + userId + '&cameFrom=profile' + hash;
  1957.                     grt.callAction('loadInOverlay', {
  1958.                         url: tapseUrl
  1959.                     });
  1960.                 }
  1961.             },
  1962.             findUserIdInTR = function(tr) {
  1963.                 if (!tr) return 0;
  1964.                 var links = helpers.xpath('.//td[contains(@class,"resHeadline")]/a[contains(@href,"/setcard/")]', tr);
  1965.                 if (links.length) {
  1966.                     return (links[0].href.match(/set=(\d*)/) || [])[1] || 0;
  1967.                 }
  1968.                 return 0;
  1969.             },
  1970.             initTapsen = function() {
  1971.                 var fPrints = helpers.xpath('//img[contains(@src,"/img/footprints/") and not(contains(@class,"' + TAPSE_CLASS + '"))]');
  1972.                 for (var i = fPrints.length - 1; i >= 0; i--) {
  1973.                     var fp = fPrints[i];
  1974.                     fp.setAttribute(TAPSE_ATTRIB, 1);
  1975.                     fp.className += ' ' + TAPSE_CLASS;
  1976.                 }
  1977.                 if (fPrints.length && !handlerBound) {
  1978.                     doc.addEventListener('click', HANDLERS.TAPSE_CLICK, true);
  1979.                     handlerBound = true;
  1980.                 }
  1981.             },
  1982.             getUserIdFromHash = function() {
  1983.                 var url = location.href;
  1984.                 return userId = url.substring(url.indexOf(TAPSE_USER_ID_HASH) + TAPSE_USER_ID_HASH.length) || '';
  1985.             },
  1986.             initTapseSubmitPage = function() {
  1987.                 setTimeout(function() {
  1988.                     grt.callAction('closeOverlay');
  1989.                 }, 30);
  1990.             },
  1991.             initTapseSelectPage = function() {
  1992.                 var userId = getUserIdFromHash();
  1993.                 var as = helpers.doc.getElementsByTagName('a');
  1994.                 for (var i = 0; i < as.length; i++) {
  1995.                     var a = as[i],
  1996.                         url = a.href || '',
  1997.                         isTapseLink = url.indexOf('saveFootprint.php') >= 0;
  1998.                     if (!isTapseLink) continue;
  1999.                     a.href = url + '#' + TAPSE_USER_ID_HASH + userId;
  2000.                 }
  2001.             },
  2002.             init = function(_grt, _helpers) {
  2003.                 doc = _helpers.doc;
  2004.                 log = _helpers.log;
  2005.                 helpers = _helpers;
  2006.                 grt = _grt;
  2007.                 if (!_helpers.config.taps) return;
  2008.                 if (grt.hashContains(TAPSE_USER_ID_HASH)) {
  2009.                     var isTapseSubmitPage = grt.urlContainsAll('saveFootprint.php'),
  2010.                         isTapseSelectPage = !isTapseSubmitPage;
  2011.                     if (isTapseSelectPage) {
  2012.                         initTapseSelectPage();
  2013.                     } else if (isTapseSubmitPage) {
  2014.                         initTapseSubmitPage();
  2015.                     }
  2016.                     return;
  2017.                 }
  2018.                 initTapsen();
  2019.                 _helpers.addExternalRetriggerHandler(initTapsen);
  2020.             };
  2021.         return {
  2022.             ID: PROCESSOR_ID,
  2023.             EXCLUSIVE: false,
  2024.             NEEDS_DISPATCHER: true,
  2025.             CSS: ['tapse'],
  2026.             init: init
  2027.         };
  2028.     })('Tapse'));
  2029. }
  2030.  
  2031. // -------------------- END PROCESSOR: Tapse ------------------------
  2032.  
  2033.  
  2034.  
  2035. // #####################################################################################################################
  2036. // ################################################ END: ADD PROCESSORS ################################################
  2037. // #####################################################################################################################
  2038.  
  2039. // ----------------------- BEGIN: Dispatcher --------------------------------------------------
  2040.  
  2041. if (GRT.needsDispatcher()) {
  2042.     GRT.setDispatcher((function() {
  2043.         var log = null,
  2044.             doc = null,
  2045.             assertTrue = null,
  2046.             initDone = 0,
  2047.             actions = {},
  2048.             DISPATCH_MSG_NAME = 'GRT_DISPATCH',
  2049.             TARGET_ACTION = 'grtTargetAction',
  2050.             DOC_ACTIONS_ATTRIB = 'grtactions',
  2051.             finalized = false,
  2052.             HANDLERS = {
  2053.                 DISPATCH_MESSAGE_RECEIVED: function(e) {
  2054.                     var data = e.data || {},
  2055.                         targetAction = data[TARGET_ACTION];
  2056.                     assertTrue( !! targetAction, 'Invalid message received: missing action name.');
  2057.                     delete data[TARGET_ACTION];
  2058.                     callAction(targetAction, data, true);
  2059.                 }
  2060.             },
  2061.             cloneFlat = function(obj) {
  2062.                 var o = obj || {},
  2063.                     flatClone = {};
  2064.                 for (var k in o) {
  2065.                     flatClone[k] = '' + o[k];
  2066.                 }
  2067.                 return flatClone;
  2068.             },
  2069.             registeredActionsAttribVal = null,
  2070.             registerAction = function(actionName, fn) {
  2071.                 assertTrue(!finalized, 'Cannot add new action <%s> to finalized Dispatcher.', actionName);
  2072.                 assertTrue(actionName && fn, 'Invalid actionName or listener for event <%s>', actionName);
  2073.                 assertTrue(!actions[actionName], 'Action name <%s> already defined.', actionName);
  2074.                 actions[actionName] = fn;
  2075.                 registeredActionsAttribVal = (registeredActionsAttribVal || '#') + actionName + '#';
  2076.                 doc.head.setAttribute(DOC_ACTIONS_ATTRIB, registeredActionsAttribVal);
  2077.             },
  2078.             docSupportsAction = function(doc, actionName) {
  2079.                 if (!doc || !doc.head || !doc.head.getAttribute) return false;
  2080.                 var attrib = doc.head.getAttribute(DOC_ACTIONS_ATTRIB);
  2081.                 return attrib && attrib.indexOf('#' + actionName + '#') >= 0;
  2082.             },
  2083.             callAction = function(actionName, actionArgs, noDispatch) {
  2084.                 var action = actions[actionName];
  2085.                 if (action) {
  2086.                     action.apply(this, [actionArgs]);
  2087.                     return;
  2088.                 }
  2089.                 if (noDispatch) {
  2090.                     return;
  2091.                 }
  2092.                 var targetDoc = getDocumentForActionName(actionName, top.document);
  2093.                 if (!targetDoc) {
  2094.                     return;
  2095.                 }
  2096.                 dispatchAction(actionName, actionArgs, targetDoc);
  2097.             },
  2098.             getDocumentForActionName = function(actionName, startDoc) {
  2099.                 if (!startDoc) {
  2100.                     return null;
  2101.                 }
  2102.                 var MAX_DEPTH = 5,
  2103.                     docsToCheck = [startDoc],
  2104.                     depth = 0;
  2105.                 while (docsToCheck.length && depth < MAX_DEPTH) {
  2106.                     if (!depth) {
  2107.                         for (var i = 0; i < docsToCheck.length; i++) {
  2108.                             if (!docSupportsAction(docsToCheck[i], actionName)) continue;
  2109.                             return docsToCheck[i];
  2110.                         }
  2111.                     }
  2112.                     var newDocsToCheck = [];
  2113.                     for (var k = docsToCheck.length - 1; k >= 0; k--) {
  2114.                         var frames = docsToCheck[k].getElementsByTagName('frame');
  2115.                         for (var j = 0; j < frames.length; j++) {
  2116.                             var frame = frames[j],
  2117.                                 doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument;
  2118.                             if (docSupportsAction(doc, actionName)) {
  2119.                                 return doc;
  2120.                             }
  2121.                             newDocsToCheck[newDocsToCheck.length] = doc;
  2122.                         }
  2123.                     }
  2124.                     docsToCheck = newDocsToCheck;
  2125.                     depth++;
  2126.                 }
  2127.                 return null;
  2128.             },
  2129.             dispatchAction = function(actionName, actionArgs, targetDoc) {
  2130.                 assertTrue( !! targetDoc, 'Invalid target document argument');
  2131.                 var msgData = cloneFlat(actionArgs);
  2132.                 msgData[TARGET_ACTION] = actionName;
  2133.                 try {
  2134.                     var msgEvent = targetDoc.createEvent('MessageEvent');
  2135.                     msgEvent.initMessageEvent(DISPATCH_MSG_NAME, false, false, msgData, null, null, null, null);
  2136.                     targetDoc.dispatchEvent(msgEvent);
  2137.                 } catch (e) {}
  2138.             },
  2139.             finalize = function() {
  2140.                 finalized = true;
  2141.             },
  2142.             init = function(grt, helpers) {
  2143.                 if (initDone) return;
  2144.                 log = helpers.log;
  2145.                 doc = helpers.doc;
  2146.                 assertTrue = helpers.assertTrue;
  2147.                 doc.addEventListener(DISPATCH_MSG_NAME, HANDLERS.DISPATCH_MESSAGE_RECEIVED, false);
  2148.                 grt.callAction = callAction;
  2149.                 grt.registerAction = registerAction;
  2150.                 initDone = true;
  2151.             };
  2152.         return {
  2153.             init: init,
  2154.             finalize: finalize
  2155.         };
  2156.     })());
  2157. }
  2158.  
  2159. // ----------------------- END: Dispatcher --------------------------------------------------
  2160.  
  2161. // ----------------------- BEGIN: CSSInjector --------------------------------------------------
  2162.  
  2163. if (GRT.needsCssInjector()) {
  2164.     GRT.setCssInjector((function() {
  2165.         var initDone = false,
  2166.             log = null,
  2167.             init = function(grt, helpers, cssQueue) {
  2168.                 helpers.assertTrue(!initDone, 'Cannot initialize CSSInjector twice!');
  2169.                 log = helpers.log;
  2170.                 var usedIds = {},
  2171.                     distinctIdList = [],
  2172.                     doc = helpers.doc;
  2173.                 for (var i = 0; i < cssQueue.length; i++) {
  2174.                     var id = cssQueue[i];
  2175.                     if (usedIds[id]) continue;
  2176.                     usedIds[id] = 1;
  2177.                     distinctIdList[distinctIdList.length] = id;
  2178.                 }
  2179.                 var css = getCollectedCss(distinctIdList, helpers.useSSL),
  2180.                     styleElem = doc.createElement('style');
  2181.                 styleElem.setAttribute('type', 'text/css');
  2182.                 styleElem.innerHTML = css;
  2183.                 doc.getElementsByTagName('head')[0].appendChild(styleElem);
  2184.                 initDone = true;
  2185.             },
  2186.             getCollectedCss = function(cssIds, useSSL) {
  2187.                 var css = [];
  2188.                 var GRT_DOMAIN = useSSL ? 'https://ssl-account.com/gr-tools.justlep.net' : 'http://gr-tools.justlep.net';
  2189.                 if (cssIds.indexOf('pictureAdmin') >= 0) css[css.length] = '#grtimageblablubs img {max-height:40px;max-width:40px}#grtimageblablubs a.blubs img {border:2px solid #fc0}';
  2190.                 if (cssIds.indexOf('header') >= 0) css[css.length] = '#grtDiv {position: absolute;right: 315px;top: 0;overflow: visible;border: 1px solid #A2B3DE;border-top: none;padding: 1px 5px 2px 5px;z-index: 9999;color: #E1DEF1;font:normal 11px Tahoma, Arial, Verdana, Helvetica, sans-serif;line-height:14px;border-radius: 0 0 6px 6px;background:transparent url(' + GRT_DOMAIN + '/img/bg.jpg) 0 0 no-repeat;}#grtDiv:hover {border-color: #D1D8EB}#grtDiv.grtRomeo {right: 311px}body.grtClub #grtDiv {left: auto;right: 82px !important;}body.grtGuideClub #grtDiv {left: auto;right: 82px !important;}#grtDiv div, #grtDiv span {float: left;}#grtDiv span {cursor: pointer;vertical-align: middle;opacity: 0.7;margin: 1px 2px 0;width:24px;height:24px;background-repeat:no-repeat;background-position:0 0;display:none;}#grtDiv span:hover {opacity: 1;}#grtDiv #grtPimp {padding: 0 5px 0 2px;position: static;overflow: hidden;}#grtPimp b {display: block;color: #AEE451;font-style: normal}#grtDiv:hover span {display: block}body #grtDiv #grtCfg {display: block;}#grtDiv #grtUpd {/* opacity:0.2; */display:none;}#grtDiv.grtUpdateAvailable #grtUpd {display:block;opacity:0.8;}#grtDiv.grtUpdateAvailable #grtUpd:hover {display:block;opacity:1}body.grtClub #grtDiv #grtClub,body.grtGuideClub #grtDiv #grtClub {display: block;}#grtClub {background-image:url(' + GRT_DOMAIN + '/img/home.png)}#grtCfg {background-image:url(' + GRT_DOMAIN + '/img/tool.png)}#grtUpd {background-image:url(' + GRT_DOMAIN + '/img/flag.png)}body.grtDimLogo #logoblock {opacity: 0.05 !important;}';
  2191.                 if (cssIds.indexOf('forumLatestThreads') >= 0) css[css.length] = 'tr.today {font-weight:bold;}tr.today.exact {background:#B4FF7C !important;}tr.today.minus1 {background:#DEFFC6 !important;}tr.today.minus2 {background:#EEFFE2 !important}tr.today.older td, tr.today.older td * {color:#999 !important;font-weight:normal}';
  2192.                 if (cssIds.indexOf('bmi') >= 0) css[css.length] = '.grtBMI:hover {color:#FBBE00;}.grtBMI {color:#ddd;cursor:pointer;font-style:normal;margin-left:3px;margin-right:2px;}tr.grtOffAge td {opacity: 0.5;}tr.grtOffAge td:first-child {opacity:1}tr.grtOffAge td.optionLine:first-child {opacity:0.5}tr.grtOffBmi td {opacity: 0.4;}body tr.grtOffBmi td:first-child {opacity:0.4;}';
  2193.                 if (cssIds.indexOf('historyLink') >= 0) css[css.length] = '.grtHist {display:inline-block;width:10px;height:10px;overflow:hidden;background:transparent url(' + GRT_DOMAIN + '/img/hist.gif) left center no-repeat;cursor:pointer;opacity:0.6;vertical-align:top;}.grtHistActive img {display:none; /* hide letter icon */}.grtHist:hover {opacity:1}#newMessageList .grtHistActive {position:relative;}#newMessageList .grtHist {position:absolute;left:4px;top:3px;}.grtHistActive.read img {display:block}.grtHistActive.read .grtHist {display:none}td.resHeadline .grtHist {display:inline;vertical-align:top;display:inline;padding:0 8px;line-height:14px !important;background-position:0 2px;margin-left:2px;}';
  2194.                 if (cssIds.indexOf('overlay') >= 0) css[css.length] = '#grtGray {position: fixed;left: 0;top: 0;width: 100%;height: 100%;background: #000 none;opacity: 0.7;z-index: 5000;display: none;}div#grtOverlay {display: none;width: auto;height: auto;position: fixed;top: 10px;right: 6px;z-index: 6000;border: 1px solid #bbb;border-radius: 5px 0 0 5px;}div#grtWait {background:transparent url(' + GRT_DOMAIN + '/img/load.gif) center center no-repeat;width:100px;height:100px;overflow:hidden;}#grtOverlay > * {display:none}/* replaced by the above rule:#grtOverlay #grtIframe,#grtOverlay #grtHtmlContent,#grtOverlay #grtImage,#grtOverlay #grtUsername,#grtOverlay #grtWait,#grtOverlay #grtAnon,#grtOverlay #grtClose {display:none;}*/#grtOverlay.grtHtmlContent #grtClose, #grtOverlay.grtIframe #grtClose,#grtOverlay.grtIframe #grtIframe,#grtOverlay.grtHtmlContent #grtHtmlContent,#grtOverlay.grtImage #grtImage,#grtOverlay.grtWait #grtWait,#grtOverlay.grtAnon #grtAnon,#grtOverlay.grtImage #grtUsername {display:block;}#grtOverlay.grtIframe,#grtOverlay.grtHtmlContent {border-radius:0;border-left-color:#999;}#grtOverlay.grtHtmlContent {background-color:#305AB1;color:#ccc;}#grtOverlay iframe {border:none !important}#grtOverlay.grtImage {overflow:hidden;}#grtHtmlContent {overflow-y:auto;}#grtOverlay.grtHtmlContent,#grtOverlay.grtIframe,#grtOverlay.grtIframe,#grtOverlay.grtHtmlContent,#grtOverlay.grtImage,#grtOverlay.grtWait,#grtOverlay.grtImage {display:block;background-image:none;}#grtImage {cursor: url(' + GRT_DOMAIN + '/img/close.cur), default;}#grtClose {position: absolute;left: -51px;top: -1px;background: #236 url(' + GRT_DOMAIN + '/img/close.png) center center no-repeat;width: 50px;height: 300px;border:1px solid #bbb;border-right-width: 0;border-radius: 20px 0 0 20px;opacity: 0.6;cursor: pointer;}#grtClose:hover {opacity: 0.8}#grtUsername {color: yellow;background: #305AB1 none;border: 1px solid #bbb;border-width: 0 0 1px 1px;position: absolute;right: 0;top: 0;padding: 0px 5px 3px 9px;border-radius: 0 0 0 5px;opacity: 0.8;z-index: 6005;box-shadow: 0px 0px 7px #fff;}#grtOverlay.grtNoUser #grtUsername {display:none}#grtAnon {width: 26px;height: 26px;background: transparent url(' + GRT_DOMAIN + '/img/nogo.png) center center no-repeat;position: absolute;left: -38px;top: 10px;opacity: 0.3;z-index: 999;cursor: pointer;}';
  2195.                 if (cssIds.indexOf('imageZoom') >= 0) css[css.length] = '.grtZoom {width:17px;height:17px;overflow:hidden;position: absolute;right: 0px;bottom: 1px;cursor: pointer;z-index: 2000;opacity: 0.7;background:transparent url(' + GRT_DOMAIN + '/img/lupe2.png) 0 0 no-repeat;}.pUsCe .grtZoom {right:8px;bottom:5px;}.searchResults .grtZoom {bottom:3px;}.grtZoom:hover {opacity: 1;}.grtZoomParent {position:relative;}';
  2196.                 if (cssIds.indexOf('pagingLinks') >= 0) css[css.length] = '#grtNext, #grtPrev {text-decoration: none;outline: none;background: transparent url(' + GRT_DOMAIN + '/img/next.png) center center no-repeat;opacity: 0.6;padding: 8px 39px;margin: 0 5px;border: 1px dotted #6890E5}a#grtPrev {background-image: url(http://gr-tools.justlep.net/img/prev.png)}#grtPrev:hover, #grtNext:hover {opacity: 1;}';
  2197.                 if (cssIds.indexOf('latestMessage') >= 0) css[css.length] = 'td#grtLastMessage {border: 1px solid #738cbe;border-width: 1px 0;background: #203B71 url(' + GRT_DOMAIN + '/img/msgHighlight.gif) right top no-repeat;padding-top: 6px;}td#grtLastMessage > b {padding:0 0 0 15px;}td#grtLastMessage > div {padding:5px 0 0 15px;}';
  2198.                 if (cssIds.indexOf('tapse') >= 0) css[css.length] = '.grtTaps {cursor:pointer;}';
  2199.                 return css.join('');
  2200.             };
  2201.         return {
  2202.             init: init
  2203.         };
  2204.     })());
  2205. }
  2206.  
  2207. // ----------------------- END: CSSInjector --------------------------------------------------
  2208.  
  2209. GRT.finalize(false && {
  2210.     keep: 0,         // keep cookie 14 days after login (0|1)
  2211.     de: 1,           // use German (1) or English (0)
  2212.     rc: 1,           // enable rightclicks on images (0|1)
  2213.     pica: 1,         // enable enhanced image administration (0|1)
  2214.     dim: 0,          // dim GR/PR logo (0|1)
  2215.     tit: 0,          // make title harmless (0|1)
  2216.     lt: 1,           // enable thread highlighter (0|1)
  2217.     sb: 1,           // show BMI value (0|1)
  2218.     bmi: 1,          // enable BMI filter (0|1)
  2219.     bmin: 17,        // min. preferred BMI (10-70) (dunno sensible extremes)
  2220.     bmax: 27,        // max. preferred BMI (10-70)
  2221.     age: 1,          // enable age filter (0|1)
  2222.     amin: 18,        // min. preferred age (18-123)
  2223.     amax: 88,        // max. preferred age (18-123)
  2224.     secr: 1,         // enable secret click on BMI (0|1)
  2225.     popa: 1,         // enable popup avoidance (0|1)
  2226.     popt: 1,         // enable popup avoidance on thumbnail-click, too (0|1)
  2227.     z: 1,            // enable zoom icons (0|1)
  2228.     pl: 1,           // enable big paging links (0|1)
  2229.     lm: 1,           // enable last message highlighting (0|1)
  2230.     yth: 1,          // enable Youtube links in headlines (0|1)
  2231.     ytp: 1,          // enable Youtube links in user profiles (0|1)
  2232.     ytpr: 1,         // enable Youtube video preview image (0|1)
  2233.     taps: 1          // enable clickable footprints (0|1)
  2234. });
  2235.  
  2236. // #####################################################################################################################
  2237. // ################################################ END OF USERSCRIPT ##################################################
  2238. // #####################################################################################################################
Add Comment
Please, Sign In to add comment