// ==UserScript== // @name Chess.com Favicon Alerts // @description Add number of games waiting to favicon // @version 0.8 // @author Jim Farrand // @author Peter Wooley (Original GMail Favicon script) // @license MIT // @namespace http://xyxyx.org/ // @include https://www.chess.com/* // @include http://www.chess.com/* // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @downloadURL https://update.greasyfork.icu/scripts/257/Chesscom%20Favicon%20Alerts.user.js // @updateURL https://update.greasyfork.icu/scripts/257/Chesscom%20Favicon%20Alerts.meta.js // ==/UserScript== if(typeof GM_getValue === "undefined") { function GM_getValue(name, fallback) { return fallback; } } var titleNotificationConfigKey = 'titleNotificationEnabled'; var debuggingConfigKey = 'debuggingEnabled'; var autoReloadConfigKey = 'autoReloadEnabled'; var lastCountKey = 'lastCount'; var lastCountUpdateTimeKey = 'lastCountUpdateTime'; var lastCountChangeTimeKey = 'lastCountChangeTime'; var flashIconForNewKey = 'flashIconEnabled'; // Register GM Commands and Methods if(typeof GM_registerMenuCommand !== "undefined") { var setTitleNotification = function(state) { console.log("Setting title notifications: " + state); GM_setValue(titleNotificationConfigKey, state); }; var setDebugging = function(state) { console.log("Setting debugging: " + state); GM_setValue(debuggingConfigKey, state); }; var setAutoReload = function(state) { console.log("Setting auto-reload: " + state); GM_setValue(autoReloadConfigKey, state); } var setFlashIcon = function(state) { console.log("Setting flash icon: " + state); GM_setValue(flashIconForNewKey, state); } GM_registerMenuCommand( "Chess.com Favicon Alerts > Set Title Notifications On", function() { setTitleNotification(true) }); GM_registerMenuCommand( "Chess.com Favicon Alerts > Set Title Notifications Off", function() { setTitleNotification(false) }); GM_registerMenuCommand( "Chess.com Favicon Alerts > Set Debugging On", function() { setDebugging(true) }); GM_registerMenuCommand( "Chess.com Favicon Alerts > Set Debugging Off", function() { setDebugging(false) }); GM_registerMenuCommand( "Chess.com Favicon Alerts > Set Auto Reload On", function() { setAutoReload(true) }); GM_registerMenuCommand( "Chess.com Favicon Alerts > Set Auto Reload Off", function() { setAutoReload(false) }); GM_registerMenuCommand( "Chess.com Favicon Alerts > Set Flash Icon After Change On", function() { setFlashIcon(true) }); GM_registerMenuCommand( "Chess.com Favicon Alerts > Set Flash Icon After Change Off", function() { setFlashIcon(false) }); } if(!window.frameElement) { new ChessDotComFavIconAlerts(); } function ChessDotComFavIconAlerts() { var self = this; // PRIVATE VARIABLES AND METHODS // The URL attached to the little hand icon, with the link containing the number of games var gotoReadyGameURL = "http://www.chess.com/echess/goto_ready_game"; // Min time to wait after suspected suspend before refreshing var reloadRandomizationMin = 20 * 1000; // Random time to wait after suspected suspend before refreshing, in addition to reloadAfterSuspendMinimum var reloadRandomizationMax = 40 * 1000; var searchElement; var iconCanvas; var isDebugging = function() { return false || GM_getValue(debuggingConfigKey, false); } var getLastCount = function() { return GM_getValue(lastCountKey); } var getLastCountUpdateTime = function() { return GM_getValue(lastCountUpdateTimeKey); } var getLastCountChangeTime = function() { return GM_getValue(lastCountChangeTimeKey); } var setLastCount = function(value) { GM_setValue(lastCountKey, value); } var setLastCountUpdateTime = function(value) { GM_setValue(lastCountUpdateTimeKey, value); } var setLastCountChangeTime = function(value) { GM_setValue(lastCountChangeTimeKey, value); } var isAutoReloadEnabled = function() { return false || GM_getValue(autoReloadConfigKey, false); } var isFlashIconEnabled = function() { return false || GM_getValue(flashIconForNewKey, false); } var isTitleUpdatedEnabled = function() { return false || GM_getValue(titleNotificationConfigKey, false); } var head = window.document.getElementsByTagName('head')[0]; // Element that contains the count var findSearchElement = function() { var searchElement = document.getElementById("topright");; if (isDebugging()) { console.log("findSearchElement: " + searchElement); } return searchElement; } var setIcon = function(icon) { var links = head.getElementsByTagName("link"); for (var i = 0; i < links.length; i++) { if ((links[i].rel == "shortcut icon" || links[i].rel=="icon") && links[i].href != icon) { head.removeChild(links[i]); } else if(links[i].href == icon) { return; } } var newIcon = document.createElement("link"); newIcon.type = "image/png"; newIcon.rel = "shortcut icon"; newIcon.href = icon; head.appendChild(newIcon); setTimeout(function() { if (isDebugging()) { console.log("Timeout function"); } var shim = document.createElement('iframe'); shim.width = shim.height = 0; document.body.appendChild(shim); shim.src = "icon"; document.body.removeChild(shim); if (isDebugging()) { console.log("Timeout function done"); } }, 1000); } var getIconCanvas = function() { if(!iconCanvas) { iconCanvas = document.createElement('canvas'); iconCanvas.height = iconCanvas.width = 16; var ctx = iconCanvas.getContext('2d'); for (var y = 0; y < iconCanvas.width; y++) { for (var x = 0; x < iconCanvas.height; x++) { if (self.pixelMaps.icons.unread[y][x]) { ctx.fillStyle = self.pixelMaps.icons.unread[y][x]; ctx.fillRect(x, y, 1, 1); } } } } return iconCanvas; } var showCount = function() { // We could decide here whether to show the count or the other icon return true; } // TODO: This could be made abstract so that that this class can be more easily reused var getCount = function() { // Return the number of things if(searchElement) { var center; var topRightChildren = searchElement.childNodes; for (var i = 0; i < topRightChildren.length; i++) { var topRightChild = topRightChildren.item(i); if (topRightChild.tagName == "LI" && topRightChild.hasAttribute("class") && topRightChild.getAttribute("class") == "center") { var centerChildren = topRightChild.childNodes; for (var i = 0; i < centerChildren.length; i++) { var centerChild = centerChildren.item(i); if (centerChild.tagName == "A" && centerChild.hasAttribute("href") && centerChild.getAttribute("href") == gotoReadyGameURL) { var result = centerChild.textContent; if (isDebugging()) { console.log("getCount: " + result); } return result; } } } } if (isDebugging()) { console.log("getCount: 0"); } return 0; } } this.construct = function() { if (isDebugging()) { console.log("Creating ChessDotComFavIconAlerts"); } // PUBLIC VARIABLES AND METHODS this.backgroundFillColour = "#ff0000"; this.backgroundBorderColour = "#990000"; this.digitColour = "#ffffff"; // How long must have passed without user input in this window before we reload the page? this.inactivityTimeout = 15 * 60 * 1000; // 15 minutes // How old must the data be before we reload the page? this.dataTimeout = 3 * 60 * 1000; // 3 minutes // Note that we might have received data from another tab/window, which is why there are seperate data/inactivity timeouts // How long to flash the icon for after it changes this.flashPeriod = 15 * 1000; // TODO: More things could be private this.icons = { // TODO: These are the same, and incorrectly named. read: 'data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAARCwAAEQsAAAAAAAAAAAAA////AP///wD///8AO4ZcPDuKYMw7i2HsN3xR8jZ2S/83d0z/N3dM9zd3TN83d0ytN3dMIP///wD///8A////AP///wD///8A////AD+SaP4+k2r/PpNq/zqEWv84d03/OHhN/zZ3S/83d0z/N3dM/zd3TO////8A////AP///wD///8A////AP///wA7iV7hPpNq/z6Tav8+jWT/N3hM/zh4Tf83d0z/N3dM/zh3Tf42dkvL////AP///wD///8A////AP///wD///8AO4heuj6Tav8+k2r/PpJq/zmAVv83d0z/N3dM/zh3Tf83d0z/NnZLm////wD///8A////AP///wD///8A////ADuGXCo7jGLhPpNq/z6Tav87hVv/OHdN/zd3TP84d037N3dMqjd3TBX///8A////AP///wD///8A////AP///wAAAAAAAAAAADuGXFw9kGf7PIlg/zh4Tf82dkvfNnZLGwAAAAAAAAAA////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAPYphzjyOZP83d0z/N3dMjwAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAADuIX6I/kmj/N3dL/zZ3S2UAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAA8h1+AP5Rq/zh5T/82d0tLAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAO4ddZT6Tav83fFH/NnZLOQAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AAAAAAAAAAAAPYphzjyPZvg+k2r/PI5k/zd5Ttk4d02PAAAAAAAAAAD///8A////AP///wD///8A////AP///wAAAAAAAAAAADuIX9o9kGf8PpNq/z2NZP84eE7kN3dMnQAAAAAAAAAA////AP///wD///8A////AP///wD///8AAAAAAAAAAAA7hlxFPpNq/z+Uav8+k2r/On9U/jZ3SyUAAAAAAAAAAP///wD///8A////AP///wD///8A////AAAAAAAAAAAAO4leij6Sav8+k2r/PpNq/zuHXv82d0tSAAAAAAAAAAD///8A////AP///wD///8A////AP///wAAAAAAAAAAADuGXEFyr5L/wNzO/0mZc/87h13/N3dMIwAAAAAAAAAA////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAP4tifF2ee/9Vn3v+OYJYZQAAAAAAAAAAAAAAAP///wD///8A////AOAHAADgBwAA4AcAAOAHAADgBwAA+B8AAPw/AAD8PwAA/D8AAPw/AAD4HwAA+B8AAPgfAAD4HwAA+B8AAPw/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAARCwAAEQsAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8AAAAAAAAAAAA7hVsCO4ddaDuGXKk5f1W+N3dN0jd3Teo3d03+N3dN/zd3Tf83d03+N3dN6jd3TdI3d02sN3dNejd3TTs3d00BAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wA7hVsKPIlftj2QZvw+k2n/PpNp/z6Taf88iF7/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3TeE3d013N3dNBf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AD2MYuY+k2n/PpNp/z6Taf8+k2n/PpNp/z6SaP83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d02v////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8APpJo/z6Taf8+k2n/PpNp/z6Taf8+k2n/PY9l/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3TfT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wA7iF6WPpJo/z6Taf8+k2n/PpNp/z6Taf89kWf/OH5U/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d032N3dNW////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAA7hlxVPpJo/z6Taf8+k2n/PpNp/z6Taf8+kmj/OHpQ/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN9jd3TS0AAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAD2MYuY+k2n/PpNp/z6Taf8+k2n/PpNp/z6Taf87hVv/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dNpwAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAPI5k9D6Taf8+k2n/PpNp/z6Taf8+k2n/PpNp/z2MYv83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03LAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAA7h12BPpJo/z6Taf8+k2n/PpNp/z6Taf8+k2n/PZBm/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN9Dd3TU4AAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAA7hlwwPIpgwj2QZvw+k2n/PpNp/z6Taf8+k2n/N3hO/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN4zd3TYI3d00ZAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAO4VbCDuIXpM+kmj+PpNp/z6Taf84fVP/N3dN/zd3Tf83d03/N3dN8Dd3TVo3d00DAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADyJX7U+k2n/PpNp/zmBV/83d03/N3dN/zd3Tf83d012AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO4ZcSz6Taf8+k2n/OoVb/zd3Tf83d03/N3dN/zd3TSkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7hVsCPpJo/z6Taf88iV//N3dN/zd3Tf83d031N3dNAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9j2X3PpNp/zyNY/83d03/N3dN/zd3TdIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2MYuY+k2n/PZFn/zd3Tf83d03/N3dNrwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPIth1D6Taf8+k2n/N3lP/zd3Tf83d02WAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8imDFPpNp/z6Taf84fFL/N3dN/zd3TYUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADyJX7I+k2n/PpNp/zl/Vf83d03/N3dNcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPIhenT6Taf8+k2n/OoJY/zd3Tf83d01gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAA7hVslPIhenDyKYM08jmTxPpNp/z6Taf88jWP/OYFX/zd3TcQ3d02ON3dNYDd3TRMAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAAAAAADyOZPM+k2n/PpNp/z6Taf8+k2n/PpNp/z6Taf8+k2n/OX9V/zd3Tf83d03/N3dNxgAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAPIlfuj6SaP4+k2n/PpNp/z6Taf8+k2n/PpNp/zyNY/84elD/N3dN/zd3TfI3d016AAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAO4VbBjyJX7o+k2n/PpNp/z6Taf8+kmj/OYBW/zd3Tf83d015N3dNAwAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAA7hVslPZFn/j6Taf8+k2n/PpNp/z6Taf8+k2n/OH5U/zd3Te83d00TAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAADyJX6s+k2n/PpNp/z6Taf8+k2n/PpNp/z6Taf88jmT/N3dN/zd3TW0AAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAPIth2T6Taf8+k2n/PpNp/z6Taf8+k2n/PpNp/z6Taf83e1H/N3dNmwAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAA9i2HcPpNp/z6Taf8+k2n/PpNp/z6Taf8+k2n/PpNp/zh+VP83d02fAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAADyJX7E+k2n/rdG//7TVxP9OnHX/PpNp/z6Taf8+k2n/OH1T/zd3TXIAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAO4ZcLj6SaP6Twqv///////D28/9nqoj/PpNp/z6SaP84eU/0N3dNFwAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO4hekEaXbv/I4NT/+/38/5TDqv8+k2n/PIpg/jd3TVcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO4ddbTyNY+8+kmj/PpJo/zyNY+45gFZSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP8AAP/8AAA//AAAP/wAAD/8AAA//gAAf/4AAH/+AAB//gAAf/8AAP//wAP///AP///wD///8A////gf///4H///+B////gf///4H///+B///8AD///AA///wAP//+AH///gB///4Af//+AH///gB///4Af//+AH///wD///+B//', unread: 'data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAARCwAAEQsAAAAAAAAAAAAA////AP///wD///8AO4ZcPDuKYMw7i2HsN3xR8jZ2S/83d0z/N3dM9zd3TN83d0ytN3dMIP///wD///8A////AP///wD///8A////AD+SaP4+k2r/PpNq/zqEWv84d03/OHhN/zZ3S/83d0z/N3dM/zd3TO////8A////AP///wD///8A////AP///wA7iV7hPpNq/z6Tav8+jWT/N3hM/zh4Tf83d0z/N3dM/zh3Tf42dkvL////AP///wD///8A////AP///wD///8AO4heuj6Tav8+k2r/PpJq/zmAVv83d0z/N3dM/zh3Tf83d0z/NnZLm////wD///8A////AP///wD///8A////ADuGXCo7jGLhPpNq/z6Tav87hVv/OHdN/zd3TP84d037N3dMqjd3TBX///8A////AP///wD///8A////AP///wAAAAAAAAAAADuGXFw9kGf7PIlg/zh4Tf82dkvfNnZLGwAAAAAAAAAA////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAPYphzjyOZP83d0z/N3dMjwAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAADuIX6I/kmj/N3dL/zZ3S2UAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAA8h1+AP5Rq/zh5T/82d0tLAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAO4ddZT6Tav83fFH/NnZLOQAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AAAAAAAAAAAAPYphzjyPZvg+k2r/PI5k/zd5Ttk4d02PAAAAAAAAAAD///8A////AP///wD///8A////AP///wAAAAAAAAAAADuIX9o9kGf8PpNq/z2NZP84eE7kN3dMnQAAAAAAAAAA////AP///wD///8A////AP///wD///8AAAAAAAAAAAA7hlxFPpNq/z+Uav8+k2r/On9U/jZ3SyUAAAAAAAAAAP///wD///8A////AP///wD///8A////AAAAAAAAAAAAO4leij6Sav8+k2r/PpNq/zuHXv82d0tSAAAAAAAAAAD///8A////AP///wD///8A////AP///wAAAAAAAAAAADuGXEFyr5L/wNzO/0mZc/87h13/N3dMIwAAAAAAAAAA////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAP4tifF2ee/9Vn3v+OYJYZQAAAAAAAAAAAAAAAP///wD///8A////AOAHAADgBwAA4AcAAOAHAADgBwAA+B8AAPw/AAD8PwAA/D8AAPw/AAD4HwAA+B8AAPgfAAD4HwAA+B8AAPw/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAARCwAAEQsAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8AAAAAAAAAAAA7hVsCO4ddaDuGXKk5f1W+N3dN0jd3Teo3d03+N3dN/zd3Tf83d03+N3dN6jd3TdI3d02sN3dNejd3TTs3d00BAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wA7hVsKPIlftj2QZvw+k2n/PpNp/z6Taf88iF7/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3TeE3d013N3dNBf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AD2MYuY+k2n/PpNp/z6Taf8+k2n/PpNp/z6SaP83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d02v////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8APpJo/z6Taf8+k2n/PpNp/z6Taf8+k2n/PY9l/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3TfT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wA7iF6WPpJo/z6Taf8+k2n/PpNp/z6Taf89kWf/OH5U/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d032N3dNW////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAA7hlxVPpJo/z6Taf8+k2n/PpNp/z6Taf8+kmj/OHpQ/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN9jd3TS0AAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAD2MYuY+k2n/PpNp/z6Taf8+k2n/PpNp/z6Taf87hVv/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dNpwAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAPI5k9D6Taf8+k2n/PpNp/z6Taf8+k2n/PpNp/z2MYv83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03LAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAA7h12BPpJo/z6Taf8+k2n/PpNp/z6Taf8+k2n/PZBm/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN9Dd3TU4AAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAA7hlwwPIpgwj2QZvw+k2n/PpNp/z6Taf8+k2n/N3hO/zd3Tf83d03/N3dN/zd3Tf83d03/N3dN4zd3TYI3d00ZAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAO4VbCDuIXpM+kmj+PpNp/z6Taf84fVP/N3dN/zd3Tf83d03/N3dN8Dd3TVo3d00DAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADyJX7U+k2n/PpNp/zmBV/83d03/N3dN/zd3Tf83d012AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO4ZcSz6Taf8+k2n/OoVb/zd3Tf83d03/N3dN/zd3TSkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7hVsCPpJo/z6Taf88iV//N3dN/zd3Tf83d031N3dNAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9j2X3PpNp/zyNY/83d03/N3dN/zd3TdIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2MYuY+k2n/PZFn/zd3Tf83d03/N3dNrwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPIth1D6Taf8+k2n/N3lP/zd3Tf83d02WAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8imDFPpNp/z6Taf84fFL/N3dN/zd3TYUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADyJX7I+k2n/PpNp/zl/Vf83d03/N3dNcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPIhenT6Taf8+k2n/OoJY/zd3Tf83d01gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAA7hVslPIhenDyKYM08jmTxPpNp/z6Taf88jWP/OYFX/zd3TcQ3d02ON3dNYDd3TRMAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAAAAAADyOZPM+k2n/PpNp/z6Taf8+k2n/PpNp/z6Taf8+k2n/OX9V/zd3Tf83d03/N3dNxgAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAPIlfuj6SaP4+k2n/PpNp/z6Taf8+k2n/PpNp/zyNY/84elD/N3dN/zd3TfI3d016AAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAO4VbBjyJX7o+k2n/PpNp/z6Taf8+kmj/OYBW/zd3Tf83d015N3dNAwAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAA7hVslPZFn/j6Taf8+k2n/PpNp/z6Taf8+k2n/OH5U/zd3Te83d00TAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAADyJX6s+k2n/PpNp/z6Taf8+k2n/PpNp/z6Taf88jmT/N3dN/zd3TW0AAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAPIth2T6Taf8+k2n/PpNp/z6Taf8+k2n/PpNp/z6Taf83e1H/N3dNmwAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAA9i2HcPpNp/z6Taf8+k2n/PpNp/z6Taf8+k2n/PpNp/zh+VP83d02fAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAADyJX7E+k2n/rdG//7TVxP9OnHX/PpNp/z6Taf8+k2n/OH1T/zd3TXIAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAO4ZcLj6SaP6Twqv///////D28/9nqoj/PpNp/z6SaP84eU/0N3dNFwAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO4hekEaXbv/I4NT/+/38/5TDqv8+k2n/PIpg/jd3TVcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO4ddbTyNY+8+kmj/PpJo/zyNY+45gFZSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP8AAP/8AAA//AAAP/wAAD/8AAA//gAAf/4AAH/+AAB//gAAf/8AAP//wAP///AP///wD///8A////gf///4H///+B////gf///4H///+B///8AD///AA///wAP//+AH///gB///4Af//+AH///gB///4Af//+AH///wD///+B//', }; this.pixelMaps = { icons: { // TODO: Transparency 'unread': [["#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#afc59b","#aac193","#6d9645","#c6d4bc","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff"],["#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#e1e8dc","#7ea159","#eef3e9","#67923a","#407119","#f5f8f7","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff"],["#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#b4c8a4","#59882a","#5c8a2e","#69933d","#507d29","#c7d4c1","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff"],["#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#f1f4f0","#598729","#69933e","#6c963e","#406f23","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff"],["#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#bcceac","#6a9342","#68933c","#608b39","#5b8149","#c1cfb9","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff"],["#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#7b9f5b","#5f8b35","#68933c","#638e39","#5b8247","#84a176","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff"],["#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#dce5d7","#5f8d2e","#3c6a23","#f6f8f5","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff"],["#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#c2d2b5","#618e30","#3b6924","#d8e1d3","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff"],["#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#b8cba7","#608d31","#3b6826","#c2d1bb","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff"],["#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#a9c192","#5d8932","#3f6c2a","#a2b897","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff"],["#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#fefeff","#608c35","#5e8939","#477232","#567e41","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff","#ffffff"],["#ffffff","#ffffff","#ffffff","#f7f9f7","#7da05c","#548324","#69943c","#5b853a","#4b7536","#497332","#38671f","#819f72","#ffffff","#ffffff","#ffffff","#ffffff"],["#ffffff","#ffffff","#ffffff","#b0c59e","#5a882a","#69933d","#6c963e","#557f39","#4b7536","#4d7737","#4c7636","#36651d","#beceb7","#ffffff","#ffffff","#ffffff"],["#ffffff","#ffffff","#ffffff","#bcceae","#5f8c31","#69933e","#66903d","#4a7436","#4c7636","#4d7737","#4c7636","#416e2a","#cdd8c7","#ffffff","#ffffff","#ffffff"],["#ffffff","#ffffff","#ffffff","#40750c","#618d33","#68933b","#588238","#4b7536","#4c7636","#4b7535","#487331","#406d28","#2d5f14","#ffffff","#ffffff","#ffffff"],["#ffffff","#ffffff","#ffffff","#f3f6f2","#a8bf90","#799e58","#5b8346","#4b7535","#4c7636","#587f43","#759564","#a8bc9d","#ffffff","#ffffff","#ffffff","#ffffff"]] }, numbers: [ [ [0,1,1,0], [1,0,0,1], [1,0,0,1], [1,0,0,1], [0,1,1,0] ], [ [0,1,0], [1,1,0], [0,1,0], [0,1,0], [1,1,1] ], [ [1,1,1,0], [0,0,0,1], [0,1,1,0], [1,0,0,0], [1,1,1,1] ], [ [1,1,1,0], [0,0,0,1], [0,1,1,0], [0,0,0,1], [1,1,1,0] ], [ [0,0,1,0], [0,1,1,0], [1,0,1,0], [1,1,1,1], [0,0,1,0] ], [ [1,1,1,1], [1,0,0,0], [1,1,1,0], [0,0,0,1], [1,1,1,0] ], [ [0,1,1,0], [1,0,0,0], [1,1,1,0], [1,0,0,1], [0,1,1,0] ], [ [1,1,1,1], [0,0,0,1], [0,0,1,0], [0,1,0,0], [0,1,0,0] ], [ [0,1,1,0], [1,0,0,1], [0,1,1,0], [1,0,0,1], [0,1,1,0] ], [ [0,1,1,0], [1,0,0,1], [0,1,1,1], [0,0,0,1], [0,1,1,0] ], ] }; this.timer = setInterval(this.poll, 100); this.poll(); return true; } // This breaks unless the parameter is a string this.drawNumberedIcon = function(number) { if (! (number instanceof String) ) { number = number.toString(); } if(!self.textedCanvas) { self.textedCanvas = []; } if(!self.textedCanvas[number]) { if (isDebugging()) { console.log("drawNumberedIcon(" + number + ")"); } var iconCanvas = getIconCanvas(); var textedCanvas = document.createElement('canvas'); textedCanvas.height = textedCanvas.width = iconCanvas.width; var ctx = textedCanvas.getContext('2d'); ctx.drawImage(iconCanvas, 0, 0); ctx.fillStyle = this.backgroundFillColour; ctx.strokeStyle = this.backgroundBorderColour; ctx.strokeWidth = 1; var count = number.length; var bgHeight = self.pixelMaps.numbers[0].length; var bgWidth = 0; var padding = count > 2 ? 0 : 1; for(var index = 0; index < count; index++) { bgWidth += self.pixelMaps.numbers[number[index]][0].length; if(index < count-1) { bgWidth += padding; } } bgWidth = bgWidth > textedCanvas.width-4 ? textedCanvas.width-4 : bgWidth; ctx.fillRect(textedCanvas.width-bgWidth-4,2,bgWidth+4,bgHeight+4); var digit; var digitsWidth = bgWidth; for(var index = 0; index < count; index++) { digit = number[index]; if (self.pixelMaps.numbers[digit]) { var map = self.pixelMaps.numbers[digit]; var height = map.length; var width = map[0].length; ctx.fillStyle = this.digitColour; for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { if(map[y][x]) { ctx.fillRect(14- digitsWidth + x, y+4, 1, 1); } } } digitsWidth -= width + padding; } } ctx.strokeRect(textedCanvas.width-bgWidth-3.5,2.5,bgWidth+3,bgHeight+3); self.textedCanvas[number] = textedCanvas; if (isDebugging()) { console.log("drawNumberedIcon: Done making icon"); } } return self.textedCanvas[number]; } var resetTimer = function(init) { var time = new Date().getTime(); self.lastActivity = time; } this.poll = function() { var lastCount = getLastCount(); var time = new Date().getTime(); var count; if (self.foundCountAlready) { count = lastCount; if (isAutoReloadEnabled()) { // TODO: Maybe we shouldn't do this on explorer, analysis board, and a few other places var lastCountUpdateTime = getLastCountUpdateTime(); var refreshTime = lastCountUpdateTime + self.dataTimeout; if (self.lastActivity) { var inactivityRefreshTime = self.lastActivity + self.inactivityTimeout; if (inactivityRefreshTime > refreshTime) { refreshTime = inactivityRefreshTime; } } if (self.noReloadBefore) { if (self.noReloadBefore > refreshTime) { refreshTime = self.noReloadBefore; } else { // Some activity happened since this was set, so clear it and pick a new one next time self.noReloadBefore = undefined; } } var time = new Date().getTime(); if (isDebugging()) { var d = new Date(refreshTime); var formattedTime = d.getUTCHours() + ":" + (d.getUTCMinutes() < 10 ? "0" : "") + d.getUTCMinutes(); if (self.noReloadBefore) { formattedTime += ":" + (d.getUTCSeconds() < 10 ? "0" : "") + d.getUTCSeconds() } else { formattedTime += " (ish)"; } if (!self.lastDebugTime || self.lastDebugTime != formattedTime) { self.lastDebugTime = formattedTime; console.log("poll: Will reload page at " + formattedTime); } } if (time > refreshTime) { if (isDebugging()) { console.log("poll: Page reload timeout passed after " + ((self.pageLoadTime - time)/1000) + "sec"); } if ( self.noReloadBefore ) { // We already did a random period, and passed it, so we can reload now self.noReloadBefore = undefined; // Probably unneeded, we'll lose this after the reload location.reload(); } else { // If we massively overshot the refresh time, it's possible that this machine was suspended // (which is why we didn't get woken up) // That can be a problem - often the CPU becomes active several seconds before the network, and so if we // immediately reload, we will get an error // Also, we don't want tabs all piling up and reloading at the same moment // We therefore wait some extra random time before refreshing self.noReloadBefore = time + reloadRandomizationMin + Math.ceil((reloadRandomizationMax-reloadRandomizationMin)*Math.random()); } } } } else { searchElement = findSearchElement(); if(!searchElement) { if (isDebugging()) { console.log("poll: Search element not found, using last value"); } count = lastCount; } else { if (isDebugging()) { console.log("poll: Found search element"); } var lastCountUpdateTime = getLastCountUpdateTime(); if (lastCountUpdateTime && lastCountUpdateTime > time) { if (isDebugging()) { console.log("poll: Stored count more recent"); } // Some other page got a more up to date value count = lastCount; } else { count = getCount(); if (count !== lastCount) { if (isDebugging()) { console.log("Count updated to: " + count); } setLastCount(count); setLastCountChangeTime(time); } setLastCountUpdateTime(time); } self.foundCountAlready = true; } } var displayCountIcon; if (count == 0 || !showCount()) { displayCountIcon = false; } else { var lastCountChangeTime = getLastCountChangeTime(); if (isFlashIconEnabled() && (time - lastCountChangeTime) < self.flashPeriod && (!self.lastActivity || self.lastActivity < lastCountTime)) { displayCountIcon = (0 == (Math.floor(time / 1000) % 2)); } else { displayCountIcon = true; } } if(displayCountIcon) { setIcon(self.drawNumberedIcon(count).toDataURL('image/png')); } else { setIcon(self.icons.read); } if (isTitleUpdatedEnabled()) { if (count === 0) { document.title = self.pageTitle; } else { document.title = "(" + count + ") " + self.pageTitle; } } } this.toString = function() { return '[object ChessDotComFavIconAlerts]'; } this.pageLoadTime = new Date().getTime(); this.pageTitle = document.title; window.addEventListener('mousemove', resetTimer); window.addEventListener('click', resetTimer); window.addEventListener('onkeypress', resetTimer); if (isDebugging()) { console.log("Done creating ChessDotComFavIconAlerts"); } ; return this.construct(); }