Chess.com Favicon Alerts

Add number of games waiting to favicon

// ==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
// ==/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();
}