User:Alexis Jazz/GUS2Wiki.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
//<nowiki>
/*
GUS2Wiki (Gadget Usage Statistics to Wiki) is public domain, irrevocably released as WTFPL Version 2[www.wtfpl.net/about/] by its author, Alexis Jazz. If you don\'t like that or think it\'s invalid where you live you may use this under CC BY-SA 3.0, CC BY 2.5 or CC BY 4.0 instead. Your choice.';
GUS2Wiki automatically posts Special:GadgetUsage to some on-wiki page.
Only SOME users should run this. Not everyone
To load, add this to https://meta.wikimedia.org/wiki/Special:MyPage/global.js or your common.js on any project:
if ( window.localStorage && ( ! window.localStorage.GUS2Wcheck || Number(window.localStorage.GUS2Wcheck) < new Date().getTime()-64800000 ) ) {
	mw.loader.load('//en.wikipedia.org/w/index.php?title=User:Alexis_Jazz/GUS2Wiki.js&action=raw&ctype=text/javascript');
}
This will prevent the script from being loaded at all if it already ran in the past 18 hours.
You can optionally specificy some variables BEFORE the mw.loader.load line:
window.GUS2Walt = true; // to try and post the report to userspace if GUS2W.pageTitle doesn't exist on this wiki
window.GUS2WpageTitle = 'Project:Gadget stats'; //customize default page title. Don't put that in your global.js, this should be project-specific so common.js
window.GUS2WaltTitle = 'User:Example/Gadget stats'; //customize alternative page title
window.GUS2WikiDomains = [ 'en.wikipedia.org','de.wiktionary.org','es.wikipedia.org']; //domains to process. if omitted only the current domain
window.GUS2WmetaJSON = 'Project:GUS2Wiki.json'; // post JSON with everything to meta
window.GUS2WmetaJSONMinAmount = 100; //only post JSON if window.GUS2WikiDomains contains at least # of entries (prevents updating the JSON on small test runs)
window.GUS2WBlacklist = [ 'lang.project.org' ]; //never post to these projects (but do collect info for JSON)
Reset your localStorage:
window.localStorage.removeItem('GUS2Wcheck');window.localStorage.removeItem('GUS2Wresume');window.localStorage.removeItem('GUS2WresumeDate');window.localStorage.removeItem('GUS2Wrunning');
/*globals $:false,mw:false,OO:false*/
window.GUS2W = {};
var GUS2W = window.GUS2W;
GUS2W.metaJSON = {}; //format: domain>timestamp>key>u:val + domain>timestamp>key>a:val (users/active)
GUS2W.debug = function(msg) {
	if ( window.GUS2Wdebug == true ) {
		if ( typeof msg == 'string' ) {
			console.log('GUS2W: '+msg);
		} else {
			console.log(msg);
		}
	}
};
var AutoReload1 = setInterval(function(){
	clearInterval(AutoReload1);
	window.location.reload();
},86400000); //24 hour reload
GUS2W.lineScroll = function(currDomainNoDot) {
	GUS2W.debug('scroll to '+currDomainNoDot)
	if ( ! window.GUS2Wnoscroll ) {
		$('#'+currDomainNoDot+'-status')[0].scrollIntoView({behavior: 'smooth',block: 'center',inline: 'nearest'});
	}
};

GUS2W.processNext = function() {
	GUS2W.domainInt++;
	GUS2W.percentComplete=(100 / GUS2W.domains.length);
	GUS2W.percentComplete=(GUS2W.domainInt * GUS2W.percentComplete);
	$('#GUS2Wpercent')[0].innerText = GUS2W.percentComplete.toString().slice(0,6);
	if ( GUS2W.domains[GUS2W.domainInt] ) {
		GUS2W.debug('proceed to update '+GUS2W.domains[GUS2W.domainInt]);
		//var DelayHammer = setInterval(function(){
		//	clearInterval(DelayHammer);
			GUS2W.run(GUS2W.domains[GUS2W.domainInt]);
		//},150); // Hammertime!

	} else {
		window.localStorage.removeItem('GUS2Wresume');
		window.localStorage.removeItem('GUS2WresumeDate');
		window.localStorage.removeItem('GUS2Wrunning');
		window.localStorage.setItem('GUS2Wcheck',new Date().getTime());
		$('#GUS2WikiFinished').append('Finished at '+new Date().toString());
	}
};
GUS2W.getPage = function (domain,domaindata) {
	domaindata.api = new mw.ForeignApi('https://'+domain+mw.config.get('wgScriptPath')+'/api.php');
	domaindata.api.get( {format:'json',action:'query',list:'querypage',qppage:'GadgetUsage',qplimit:'max' } ).then( function ( data ) {
		GUS2W.debug('obtained gadget stats for '+GUS2W.domains[domaindata.domainInt]);
		domaindata.gadgetInfo = data;
		GUS2W.processNext(); //start processing next site while posting stats to this one continues in the background
		domaindata.api.get( {format:'json',action:'query',list:'gadgets' } ).then( function ( data ) {
			GUS2W.debug('obtained gadget default status for '+GUS2W.domains[domaindata.domainInt]);
			domaindata.defaultInfo = data;
			$('#'+domaindata.currDomainNoDot+'-status')[0].innerHTML = 'downloaded';
			GUS2W.lineScroll(domaindata.currDomainNoDot);
			$('#'+domaindata.currDomainNoDot+'-downloaded')[0].style.background = 'lightgreen';
			domaindata.defaultGadgets = [];
			if ( domaindata.defaultInfo.query.gadgets.length == 0 ) {
				GUS2W.debug(''+domain+' has no gadgets');
				$('#'+domaindata.currDomainNoDot+'-note')[0].innerHTML = 'no gadgets';
				return;
			}
			for ( domaindata.gDefaultInt=0;domaindata.gDefaultInt<domaindata.defaultInfo.query.gadgets.length;domaindata.gDefaultInt++) {
				if ( domaindata.defaultInfo.query.gadgets[domaindata.gDefaultInt].metadata.settings && typeof domaindata.defaultInfo.query.gadgets[domaindata.gDefaultInt].metadata.settings.default == 'string' ) {
					domaindata.defaultGadgets.push(domaindata.defaultInfo.query.gadgets[domaindata.gDefaultInt].id.replace(/_/g,' '));
				}
			}
			GUS2W.metaJSON[domain][domaindata.gadgetInfo.query.querypage.cachedtimestamp] = {};
			domaindata.wikiText = '{{#ifexist:Project:GUS2Wiki/top|{{/top}}|This page provides a historical record of [[Special:GadgetUsage]] through its page history. To get the data in CSV format, see wikitext. To customize this message or add categories, create [[/top]].}}\n{{subst:int:Perfcachedts|'+domaindata.gadgetInfo.query.querypage.cachedtimestamp+'|'+domaindata.gadgetInfo.query.querypage.cachedtimestamp.replace(/T.*/,'')+'|'+domaindata.gadgetInfo.query.querypage.cachedtimestamp.replace(/.*T/,'')+'|5000}}\n{| class="sortable wikitable"\n! {{subst:int:gadgetusage-gadget}} !! data-sort-type="number" | {{subst:int:gadgetusage-usercount}}';
			if ( domain != 'en.wikipedia.org' ) {
				domaindata.wikiText = domaindata.wikiText + ' !! data-sort-type="number" | {{subst:int:gadgetusage-activeusers}}'; // no idea what's going on here. The value for 'ns' on enwiki is always <s>2300</s> 8 and the column for active users is missing. Seems to work for other wikis. See T313336
			}
			domaindata.gadgetsPlusGarbage = {}; //For titles we rely on the second query (list:gadgets) because the first query (list:querypage, https://en.wikipedia.org/w/api.php?action=query&list=querypage&qppage=GadgetUsage&qplimit=max ) also contains decommissioned gadgets which we skip
			for ( domaindata.gInt=0;domaindata.gInt<domaindata.gadgetInfo.query.querypage.results.length;domaindata.gInt++) {
				domaindata.garbage = domaindata.gadgetInfo.query.querypage.results[domaindata.gInt];
				domaindata.gadgetsPlusGarbage[domaindata.garbage.title.replace(/.*gadget\-/,'').replace(/_/g,' ')] = { users: domaindata.garbage.value, active:domaindata.garbage.ns };
			}
			domaindata.gadgetStats = {};
			for ( domaindata.gInt=0;domaindata.gInt<domaindata.defaultInfo.query.gadgets.length;domaindata.gInt++) { 
				domaindata.gadgetNameKey = domaindata.defaultInfo.query.gadgets[domaindata.gInt].id.replace(/.*:gadget\-/,'').replace(/_/g,' ');
				GUS2W.debug('push '+domaindata.gadgetNameKey);
				domaindata.gadgetStats[domaindata.gadgetNameKey] = domaindata.gadgetsPlusGarbage[domaindata.gadgetNameKey];
			}
			domaindata.gadgetKeys = Object.keys(domaindata.gadgetStats).sort(); //We sort the gadgets alphabetically. This way the diffs make more sense
			for ( domaindata.gInt=0;domaindata.gInt<domaindata.gadgetKeys.length;domaindata.gInt++) {
				domaindata.defaultGadget = false;
				if ( domaindata.gadgetStats[domaindata.gadgetKeys[domaindata.gInt]] == undefined ) { //hidden gadget
					GUS2W.debug('hidden gadget: '+domaindata.gadgetKeys[domaindata.gInt]);
					continue;
				}
				domaindata.gadgetObj = domaindata.gadgetStats[domaindata.gadgetKeys[domaindata.gInt]];
				domaindata.gadgetName = domaindata.gadgetKeys[domaindata.gInt];
				if ( domaindata.defaultGadgets.indexOf(domaindata.gadgetName) == -1 ) {
					domaindata.gadgetUse = '| '+domaindata.gadgetObj.users;
				} else {
					domaindata.defaultGadget = true;
					domaindata.gadgetStats[domaindata.gadgetKeys[domaindata.gInt]] = { users: 'default', active:'default' };
					domaindata.gadgetUse = '| data-sort-value="Infinity" | {{subst:int:gadgetusage-default}}';
				}
				if ( domain != 'en.wikipedia.org' && ! domaindata.defaultGadget ) {
					domaindata.gadgetUse = domaindata.gadgetUse + ' || '+domaindata.gadgetObj.active;
				} else if ( domain != 'en.wikipedia.org' ) {
					domaindata.gadgetUse = domaindata.gadgetUse + ' || data-sort-value="Infinity" | {{subst:int:gadgetusage-default}}';
				}
				domaindata.wikiText = domaindata.wikiText + '\n|-\n|'+domaindata.gadgetName+' |'+domaindata.gadgetUse;
			}
			domaindata.wikiText = domaindata.wikiText+'\n|}\n* [[{{subst:#special:GadgetUsage}}]]\n* [[m:Meta:GUS2Wiki/Script|GUS2Wiki]]';
			domaindata.CSV = '';
			for ( domaindata.gInt=0;domaindata.gInt<domaindata.gadgetKeys.length;domaindata.gInt++) {
				if ( domaindata.gadgetStats[domaindata.gadgetKeys[domaindata.gInt]] != undefined ) {
					domaindata.CSV = domaindata.CSV + domaindata.gadgetKeys[domaindata.gInt]+','+domaindata.gadgetStats[domaindata.gadgetKeys[domaindata.gInt]].users+','+domaindata.gadgetStats[domaindata.gadgetKeys[domaindata.gInt]].active+'\n';
					if ( domaindata.gadgetStats[domaindata.gadgetKeys[domaindata.gInt]].users.match(/^[0-9]*$/) ) {
						domaindata.gadgetUsers = Number(domaindata.gadgetStats[domaindata.gadgetKeys[domaindata.gInt]].users);
					} else {
						domaindata.gadgetUsers = domaindata.gadgetStats[domaindata.gadgetKeys[domaindata.gInt]].users;
					}
					GUS2W.metaJSON[domain][domaindata.gadgetInfo.query.querypage.cachedtimestamp][domaindata.gadgetKeys[domaindata.gInt]] = {u:domaindata.gadgetUsers,a:domaindata.gadgetStats[domaindata.gadgetKeys[domaindata.gInt]].active};
				}
			}
			if ( typeof window.GUS2WmetaJSON == 'string' && ( domain == window.GUS2WikiDomains[window.GUS2WikiDomains.length-1] && ( window.GUS2WikiDomains && window.GUS2WikiDomains.length > window.GUS2WmetaJSONMinAmount ) ) ) {
				GUS2W.api = new mw.ForeignApi('https://meta.wikimedia.org/w/api.php');
				GUS2W.api.postWithEditToken( {format:'json',action:'edit',assert:'user',nocreate:false,title:window.GUS2WmetaJSON,text:JSON.stringify(GUS2W.metaJSON),watchlist:'unwatch',summary:GUS2W.summary } ).then( function ( data ) {
					$('#GUS2WikiFinished').append(' (JSON posted)');
				});
			}
			if ( domain == 'en.wikipedia.org' ) {
				domaindata.CSV = domaindata.CSV.replace(/\,(default|8)\n/g,'\n');
			}
			domaindata.wikiText = domaindata.wikiText + '\n<!-- data in CSV format:\n'+domaindata.CSV+'-->';
			if ( typeof window.GUS2WBlacklist != 'object' || window.GUS2WBlacklist.indexOf(domain) == -1 ) {
				domaindata.postTableToWiki();
			} else if ( window.GUS2WBlacklist.indexOf(domain) != -1 ) {
				$('#'+domaindata.currDomainNoDot+'-note')[0].innerHTML = 'blacklisted';
			}
		});
	}, function ( code, data ) {
		//error
	});
};
GUS2W.run = function(domain,domaindata) {
	domaindata = {};
	domaindata.currDomain = domain;
	GUS2W.metaJSON[domain] = {};
	domaindata.currDomainNoDot = domaindata.currDomain.replace(/\./g,'_');
	GUS2W.debug('initiating');
	domaindata.summary = 'Updating gadget usage statistics from [[Special:GadgetUsage]] ([[phab:T121049]])';
	domaindata.postTableToWiki = function() {
		if ( window.GUS2WpageTitle ) {
			domaindata.pageTitle = window.GUS2WpageTitle;
		} else {
			domaindata.pageTitle = 'Project:GUS2Wiki'; //Project: is a universal redirect to Wikidata:, Wikipedia:, Wiktionary:, etc.
		}
		domaindata.api = new mw.ForeignApi('https://'+domain+mw.config.get('wgScriptPath')+'/api.php');
		if ( window.GUS2Wcreate && domain.match(new RegExp(window.GUS2Wcreate)) ) { // when adding a new domain instead of manually creating you can define window.GUS2Wcreate as ^(fa|fi)\.
			domaindata.nocreate = false;
		} else {
			domaindata.nocreate = true;
		}
		//get old wikitext to check for redirects
		domaindata.api.get( {action: 'query', prop: 'revisions', redirects:true, format: 'json', titles: domaindata.pageTitle, rvlimit: 1, rvprop: 'timestamp|comment', rvslots: '*' } ).then( function ( data ) {
			if ( ! data.query.pages[-1] ) {
				domaindata.pageTitle = data.query.pages[Object.keys(data.query.pages)[0]].title;
				domaindata.oldRevDate = data.query.pages[Object.keys(data.query.pages)[0]].revisions[0].timestamp;
				domaindata.oldRevDate = new Date(domaindata.oldRevDate).getTime();
				domaindata.oldEditSummary = data.query.pages[Object.keys(data.query.pages)[0]].revisions[0].comment;
			}
			if ( new Date().getTime() < domaindata.oldRevDate+583200000 && domaindata.oldEditSummary == domaindata.summary && ! mw.util.getParamValue('force') ) { // last edit was less than 6 days and 18 hours ago and edit summary matches GUS2Wiki
				GUS2W.debug('page was last updated <6d18h ago, skipping today');
				$('#'+domaindata.currDomainNoDot+'-note')[0].innerHTML = 'skip today';
				return;
			}
			domaindata.api.postWithEditToken( {format:'json',action:'edit',assert:'user',nocreate:domaindata.nocreate,title:domaindata.pageTitle,text:domaindata.wikiText,watchlist:'unwatch',summary:domaindata.summary } ).then( function ( data ) {
				GUS2W.debug('posted gadget stats to '+GUS2W.domains[domaindata.domainInt]);
				$('#'+domaindata.currDomainNoDot+'-status')[0].innerHTML = 'done';
				if ( data.edit.nochange == '' ) {
					$('#'+domaindata.currDomainNoDot+'-note')[0].innerHTML = 'null edit';
				} else if ( data.edit.newrevid ) {
					$('#'+domaindata.currDomainNoDot+'-note')[0].innerHTML = '<a href="https://'+domain+mw.config.get('wgArticlePath').replace('$1','Special:Diff/'+data.edit.newrevid+'">diff</a>');
				}
				GUS2W.lineScroll(domaindata.currDomainNoDot);
				window.localStorage.setItem('GUS2Wresume',domain);
				window.localStorage.setItem('GUS2WresumeDate',new Date().getTime());
				$('#'+domaindata.currDomainNoDot+'-posted')[0].style.background = 'lightgreen';
			}, function ( code, data ) {
				if ( ( mw.util.getParamValue('GUS2Walt') || window.GUS2Walt ) && data.error.code == 'missingtitle' ) { //page does not exist on this wiki. if alternative is enabled (put it in common.js/global.js before the load line), post to the other location
					if ( window.GUS2WaltTitle ) {
						domaindata.pageTitleAlt = window.GUS2WaltTitle;
					} else {
						//domaindata.pageTitleAlt = 'User:'+mw.config.get('wgUserName')+'/GUS2Wiki';
						domaindata.pageTitleAlt = 'User:GUS2Wiki/GUS2Wiki'; // will ONLY be used if domaindata.pageTitle doesn't exist and window.GUS2Walt is set
					}
					domaindata.api.postWithEditToken( {format:'json',action:'edit',assert:'user',nocreate:domaindata.nocreate,title:domaindata.pageTitleAlt,text:domaindata.wikiText,watchlist:'unwatch',summary:domaindata.summary } ).then( function ( data ) {
						GUS2W.debug('posted gadget stats to '+GUS2W.domains[domaindata.domainInt]+' (alternative page title)');
						$('#'+domaindata.currDomainNoDot+'-status')[0].innerHTML = 'done';
						GUS2W.lineScroll(domaindata.currDomainNoDot);
						if ( data.edit.nochange == '' ) {
							$('#'+domaindata.currDomainNoDot+'-note')[0].innerHTML = 'null edit';
						} else {
							$('#'+domaindata.currDomainNoDot+'-note')[0].innerHTML = '<a href="https://'+domain+mw.config.get('wgArticlePath').replace('$1','Special:Diff/'+data.edit.newrevid+'">diff</a>');
						}
						window.localStorage.setItem('GUS2Wresume',domain);
						window.localStorage.setItem('GUS2WresumeDate',new Date().getTime());
						$('#'+domaindata.currDomainNoDot+'-posted')[0].style.background = 'lightgreen';
					}, function ( code, data ) {
						GUS2W.debug('failed to post gadget stats to '+GUS2W.domains[domaindata.domainInt]+' (alternative page title)');
						$('#'+domaindata.currDomainNoDot+'-status')[0].innerHTML = 'failed: '+data.error.code;
						$('#'+domaindata.currDomainNoDot+'-posted')[0].style.background = 'red';
						GUS2W.lineScroll(domaindata.currDomainNoDot);
					});
				} else {
					$('#'+domaindata.currDomainNoDot+'-status')[0].innerHTML = 'failed: '+data.error.code;
					$('#'+domaindata.currDomainNoDot+'-posted')[0].style.background = 'red';
					GUS2W.lineScroll(domaindata.currDomainNoDot);
				}
			});
		});//get old wikitext to check for redirects
	};
	GUS2W.getPage(domain,domaindata);
};
if ( window.GUS2Winterval ) {
	GUS2W.interval = window.GUS2Winterval;
} else {
	GUS2W.interval = 172800000;
}
GUS2W.checkLongAgo = ( window.localStorage && ( ! window.localStorage.GUS2Wcheck || Number(window.localStorage.GUS2Wcheck) < new Date().getTime()-GUS2W.interval ) );
if ( ( window.localStorage.GUS2WresumeDate && Number(window.localStorage.GUS2WresumeDate) < new Date().getTime()-20000 ) || GUS2W.checkLongAgo ) { // last checked >18 hours ago or an aborted operation was last active > 20s ago (so the tab that ran it is unlikely to be active anymore)
		if ( typeof window.GUS2WikiDomains == 'object' ) {
			GUS2W.domains = window.GUS2WikiDomains;
		} else {
			GUS2W.domains = [ mw.config.get('wgServerName') ];
		}
		//if ( window.localStorage.GUS2Wresume ) {
		//	while ( GUS2W.domains[0] && GUS2W.domains[0] != window.localStorage.GUS2Wresume ) { //to resume an incomplete run
		//		GUS2W.domains.shift();
		//	}
		//}
		GUS2W.domainHTML = document.createElement('table');
		GUS2W.domainHTML.classList = 'wikitable';
		GUS2W.domainHTML.style.width = '100%';
		GUS2W.domainInnerHTML = '<tr><th>Domain</th><th style="width:12em;">Status</th><th style="width:2.5em;">DL</th><th style="width:4.5em;">Post</th><th>Diff/failed</th></tr>';
		for (GUS2W.int=0;GUS2W.int<GUS2W.domains.length;GUS2W.int++){
			GUS2W.currentDomain = GUS2W.domains[GUS2W.int];
			GUS2W.currentDomainNoDot = GUS2W.currentDomain.replace(/\./g,'_');
			GUS2W.domainInnerHTML = GUS2W.domainInnerHTML+'<tr><td>'+GUS2W.currentDomain+'</td><td id="'+GUS2W.currentDomainNoDot+'-status">PENDING</td><td id="'+GUS2W.currentDomainNoDot+'-downloaded"></td><td id="'+GUS2W.currentDomainNoDot+'-posted"></td><td id="'+GUS2W.currentDomainNoDot+'-note"></td></tr>';
		}
		GUS2W.domainHTML.innerHTML = GUS2W.domainInnerHTML;
		mw.loader.using(['mediawiki.ForeignApi'], function(){
			GUS2W.domainInt = 0;
			mw.loader.using(['oojs-ui-core','oojs-ui-windows']).then(function(){
				GUS2W.debug('okay try to update');
				GUS2W.bottomStatus = document.createElement('div');
				GUS2W.bottomStatus.style = 'position:fixed;bottom:5%;right:5%;padding:0.3em;text-align:center;background-color:lightblue';
				GUS2W.bottomStatus.id = 'GUS2Wbottom';
				GUS2W.bottomStatus.innerHTML = '<div id="GUS2WstatusSmall" style="text-align:end;text-decoration:underline;cursor:pointer">GUS2W <span id="GUS2Wpercent">0</span>%</div>';
				GUS2W.fullStatus = document.createElement('div');
				GUS2W.fullStatus.innerHTML = '<div id="GUS2Wstatus" style="display:block;position:fixed;bottom:5%;left:20%;padding:1em;background-color:lightblue;overflow-y:scroll;max-height:80%"><div style="position:sticky;background:#eee;top: 0;width: 100%;left: 0;text-align: center;"><b>GUS2Wiki 1.0<br>'+new Date().toString()+'</b></div><br>'+GUS2W.domainHTML.outerHTML+'<div id="GUS2WikiFinished"></div></div>';
				document.body.append(GUS2W.bottomStatus);
				document.body.append(GUS2W.fullStatus);
				$('#GUS2WstatusSmall')[0].addEventListener('click',function(){
					if ( $('#GUS2Wstatus')[0].style.display == 'none' ) {
						$('#GUS2Wstatus')[0].style.display = 'block';
					} else {
						$('#GUS2Wstatus')[0].style.display = 'none';
					}
				});
				if ( ! window.localStorage.GUS2Wrunning || Number(window.localStorage.GUS2Wrunning) < new Date().getTime()-3600000 ) { //prevent multiple simultaneous instances. GUS2Wrunning is cleared when the script finishes successfully, GUS2Wcheck isn't
					GUS2W.debug('start running');
					window.localStorage.setItem('GUS2Wrunning',new Date().getTime());
					//window.localStorage.setItem('GUS2Wcheck',new Date().getTime());
					//Prevent leaving the page before script is finished
					window.onbeforeunload = function() {
						mw.loader.using(['oojs-ui-core','oojs-ui-windows']).then(function(){
							OO.ui.alert('Please check if GUS2Wiki is still running');
						});
						return '';
					};
					GUS2W.run(GUS2W.domains[GUS2W.domainInt]);
				} else {
					GUS2W.debug('is GUS2Wiki already running?');
				}
			});
	});
} else {
	GUS2W.debug('too soon (or you have no localStorage)');
}
//</nowiki>