Cookie Zapper

By slow Last update Mar 21, 2013 — Installed 1,761 times.

There are 46 previous versions of this script.

Add Syntax Highlighting (this will take a few seconds, probably freezing your browser while it works)

// ==UserScript==
// @name          Cookie Zapper
// @description	  Deletes site's cookies whenever page is unloaded/reloaded.  Invoke from Grease Monkey menu "User Script Commands."  The script also adds an icon at bottom left.
// @name          Cookie Zapper
// @version Cookie Zapper 
// @version Cookie Zapper 18th February 2010.  Option added to allow all cookies to be deleted on sites where auto-deletion has not otherwise been specified.  See GM status icon 'User Script Commands' menu option 'Zap Cookies by default.' 
// ==/UserScript==

log=GM_log;
log=function(){}

GM_platform_wrapper("Cookie Zapper"); // for Google Chrome.

log("cookie zapper "+(window.document.cookie?window.document.cookie.split(";"):""));

// GM_xmlhttpRequest({    method: "GET", url: window.document.URL, 
//     headers: {	    "User-Agent": "Mozilla/5.0",      "Accept": "text/xml", 'Cookie': document.cookie     },
//     onload: function(response) 
//     {
// 	log("respons");log('after Cookie: ' + document.cookie); 
// 	for (var i in response) log(" resp "+i+" val: "+response[i]);
// 	if (response.responseText.indexOf("TEST") > -1) 
// 	{
	    
//             log("Response confirmed..."+response.cookies); 
// 	}
//     }
// }); 

var widener="\n___________________________________\n\n"
var iframe="";
var light_green="#CEED91"
if (window.document.URL=="about:blank") { return;}
//var GM_log=log;
if ( ! window.document.body)    return;
var docloc;

try  { docloc=window.document.location.host } catch(e){docloc=getDomain(window.document.URL);};
if ( ! docloc) docloc=window.document.URL
if (/about:blank$/.test(docloc)) return;
var site=getDomain()
if ( self != top) {
    iframe="frame";
    try{ 
	var own_domain=getDomain(window.document.baseURI);
	var tabs_domain;
	if ( ! top )  tabs_domain=getDomain(window.document.referrer);  
	else tabs_domain=getDomain(top.location.host);
	if( own_domain == tabs_domain  &&  ( ! top && window.document.referrer ) )
	    return;
    } 
    catch(e) { 
	try { GM_log(own_domain+" Frames error, frame on other domain: l."+e.lineNumber+" "+e);  
	      GM_log("Was on "+window.document.URL+".  Top: "+top)
	    } 
	catch(e) { GM_log("Iframe error:"+e); }
    }
}
log(window.document.URL+" iframe? "+iframe);

var zap_list=eval(GM_getValue("zap_list", "")) || {}

var icon=zap_list["icon"];
var clear_all=zap_list["clear_all"];

if (icon==undefined)
    icon=true
var zap_obj=zap_list[site];

log("zap obj?");for(var i in zap_obj) log("zap_obj["+i+"]:"+zap_obj[i]);

insertCode("yesscript=true;");
var yeascript=unsafeWindow.yesscript;
var button = window.document.createElement("div");
button.id="CookieZapper";
var cookie_div = window.document.createElement("div")
var minimized_text = window.document.createTextNode(   (iframe ? "iframe cookies":"Cookie Zapper" )     );

var minimized=true;
var title="Click to toggle the showing of cookies"+(iframe?" within this Frame, which could be from another domain or is without a referrer":"")
    +".  Right click to "+ ( zap_obj && ! zap_obj.man ? "show log of recent cookie deletions." : "delete cookies on this site, right click a second time to see results.  ");
button.title=title;
var bgColor="WhiteSmoke"
if (zap_obj && ! zap_obj.auto) {
    bgColor="Wheat";
    if (zap_obj.onload) 
	bgColor="Sienna";
    if (zap_obj.unload) 
	bgColor="lightblue";
    if (zap_obj.man) 
	bgColor=light_green;
}

var temp_results, cookies_deleted;

if ( icon )
    renderButton();
if ( zap_obj && zap_obj.auto && clear_all)
    zapNow("Zapped by default");

if (zap_obj && ! iframe) {
    if (zap_obj.onload)
	listenForUnload(null, +1);
    else if ( ! zap_obj.man && ! zap_obj.auto ) listenForUnload();
}

GM_registerMenuCommand("____________________________________", function() {} )

GM_registerMenuCommand("Zap Cookies,  Setup for this site [toggle] ...", function() {
    zap_list=eval(GM_getValue("zap_list", "")) || {};
    var zap;
    try {
    var site_name = getDomain();
    zap=zap_list[site_name];} catch(e) {}

    if (zap || zap_obj) {
	var reply=confirm("Remove this site from auto cookie deletion or from the list of sites gathered for default cookie deletion ? "
			  +"\n\nCurrent setting is: delete cookies "+getSitesSetting(zap_list[site])+"");
	if (reply) {
	    delete zap_list[site]; delete zap_list[site_name];
	    zap_obj=undefined;
	    listenForUnload(-1);
	    if ( ! icon) renderButton(-1);
	    else renderButton();
            persist();
	}
    }
    else {
	prompt2("\nCookies will be automatically deleted at this site (domain) at the time of your choice.  "
		       +"Please enter a number below.  There are four choices:  The background color of the Zap Cookies icon will change"
		       +"as a result of this choice (to beige, red, blue or green respectively)"
		       +"\n\n1.  Automatically delete cookies only when a Tab or window, open onto this site, "
		       +"is closed.  (Allows logins & shopping baskets, etc. but cookies are deleted once the tab is closed)"
		       +"\n\n2.  On document unload.  Delete them whenever one browses away from a a page on "
		       +"this site--ie, the same tab has a new document loaded."
		       +"\n\n3.  On document load.  Delete cookies whenever a page on this site is visited."
		       +"\n\n4.  Manual.  Only delete cookies when requested by right click on icon or through GM menu."
		       +"\n\nOn all sites not set for automatic or manual deletion in the above ways AND where cookies have previously been deleted by "
		       +"right click on icon or via the GM menu, cookies will be cleared on those sites by default in future if the "
		       + "command 'Zap cookies by default' is chosen from the GM menu"
		       +"\n\nEnter a number between 1 and 4: "
		       ,1
		, function(choice){
		    if (choice==null) return;
		    zap_list[site]={}
		    zap_list[site].results=[];
		    if (choice==2) 
			zap_list[site].unload=true;
		    if (choice==3)
			zap_list[site].onload=true;
		    if (choice==4)
			zap_list[site].man=true;
		    zap_obj=zap_list[site];
		    if (zap_obj.onload) 
			listenForUnload(null, +1);
		    else if ( ! zap_obj.man && ! zap_obj.auto )   listenForUnload();
		    if (icon) renderButton();
		    
		    persist();
		    } );
    }
}, "", "" , "Z");

GM_registerMenuCommand("Zap Cookies: show recent results...", showResults, "", "" , "Z");

GM_registerMenuCommand("Zap this site's Cookies now", zapNow,"","","Z");

GM_registerMenuCommand("Zap Cookies, Remove Icon -- toggle", function() {
    zap_list=eval(GM_getValue("zap_list", "")) || {};
    if (zap_list["icon"]) renderButton(-1);
    else renderButton();
    zap_list["icon"]^=true;
    persist();
},"","","Z");

GM_registerMenuCommand("Zap cookies by default after first manual deletion ["+(clear_all ? "\u2714" : "\u2717")+"]-- toggle", 
		       function() {
			   if ( ! clear_all ) alert2("Any site where cookies get manually deleted by the user will be deleted automatically in future.  "
						    +"Manual deletion means by a right-click on the Zapper icon or via the GM menu.  "
						    +"The site must also not have been setup for auto-deletion in another way, see menu option above this one called, 'Setup for this site'."
						    +"\n\nSuch sites are gathered on an ongoing basis into a permanent list.  Their cookies are cleared upon "
						    +"visiting/loading a page from the site.  Select once more to toggle.  To remove a certain site "
						    +"from this list select GM menu option 'Zap Cookies, Setup for this site';  select it a second time to set deletion to manual deletion only (option 4).")
			   else alert("No longer deleting cookies by default");
			   zap_list=eval(GM_getValue("zap_list", "")) || {};
			   zap_list["clear_all"]^=true;
			   clear_all^=true;
			   persist();    
			   unsafeWindow.document.location.reload(false); 
		       }
		       , "", "" , "Z");

GM_registerMenuCommand("_________________", function(){});

function deleteCookies(stage) {
    GM_log("Deleting cookies: "+stage);
    if (window.document.cookie == "") return "";
    var cookies_list=window.document.cookie.split(";");
    var str="";
    for(var i in  cookies_list )   {
	var cookie_name = "", value="";
	if(cookies_list[i].indexOf("=") !=-1)  {
	    var splits = cookies_list[i].split("=");
	    cookie_name = splits[0].replace(/^\s+|\s+$/g,"")
	    value=get_cookie(cookie_name);
	    if ( ! value)
		value=splits[1];
	}
	else
	    cookie_name = cookies_list[i];
	var new_value=deleteCookie(cookie_name, value);
	value=(value != null ? decodeURIComponent(value) : value);
	cookie_name=decodeURIComponent(cookie_name)
	new_value=(new_value != null ? decodeURIComponent(new_value) : new_value);

	if (new_value != null)
	    str+="\nSession cookie named, "+cookie_name+", still has value: "+new_value;
	else {
	    if ( ! value)
		str+="\nCookie"+ cookie_name + " has empty value "+value
	    else
		str+="\nZapper successfully deleted cookie: "+cookie_name+" = "+value;
	}
	//	("decodeURIComponent "+decodeURIComponent(value));
	//	("utf "+ Utf8.decode(value)  );
	//(window.btoa(value)); //, window.btoa();
    }// end for.
    //if (document.cookie) alert("Still cooks "+document.cookie);
    if (str)
	str=stage+", "+Date()+", url: "+document.location.href+":\n"+str;
    return str;
}

function deleteCookie(name, value) {
    var domain = getDomain();
    var del_str = name+'='+value+';path=/;domain='+domain+';expires=Sat, 01-Jan-2000 00:00:01 GMT';
    window.document.cookie = del_str;
    var after = get_cookie(name);
    if (after != null) {
	del_str = name+'='+value+';path=/;domain=;expires=Sat, 01-Jan-2000 00:00:01 GMT';
	window.document.cookie = del_str;
	del_str = name+'='+value+';path=/;domain=.'+window.document.location.host+';expires=Sat, 01-Jan-2000 00:00:01 GMT';
	window.document.cookie = del_str;
	del_str = name+'='+value+';expires=Sat, 01-Jan-2000 00:00:01 GMT';
	window.document.cookie = del_str;
	after = get_cookie(name);
	if (after != null) {
	    var path;
	    try { path=window.document.location.pathname; } catch(e) { path="/"; };
	    var try_path; // try long path, then a short one, finally path itself.
	    if (path.length > 1 && path[path.length-1] != "/") try_path=path.substring(0, path.lastIndexOf("/") )
	    del_str = name+'='+value+';path='+try_path+';domain='+domain+';expires=Sat, 01-Jan-2000 00:00:01 GMT';
	    window.document.cookie = del_str;
	    del_str = name+'='+value+';path='+try_path+';domain=;expires=Sat, 01-Jan-2000 00:00:01 GMT';
	    window.document.cookie = del_str;
	    del_str = name+'='+value+';path='+try_path+'/;domain='+domain+';expires=Sat, 01-Jan-2000 00:00:01 GMT';
	    window.document.cookie = del_str;
	    del_str = name+'='+value+';path='+try_path+'/;domain=;expires=Sat, 01-Jan-2000 00:00:01 GMT';
	    window.document.cookie = del_str;
	    after = get_cookie(name);
	    if ( after && path.indexOf("/", 1) != -1 )   {
		try_path=path.substr( 0, path.indexOf("/", 1) )
		del_str = name+'='+value+';path='+try_path+';domain='+domain+';expires=Sat, 01-Jan-2000 00:00:01 GMT';
		window.document.cookie = del_str;
		del_str = name+'='+value+';path='+try_path+';domain=;expires=Sat, 01-Jan-2000 00:00:01 GMT';
		window.document.cookie = del_str;
		del_str = name+'='+value+';path='+try_path+'/;domain='+domain+';expires=Sat, 01-Jan-2000 00:00:01 GMT';
		window.document.cookie = del_str;
		del_str = name+'='+value+';path='+try_path+'/;domain=;expires=Sat, 01-Jan-2000 00:00:01 GMT';
		window.document.cookie = del_str;
		after=get_cookie(name);
	    }
	    if (after != null) {
		del_str = name+'='+value+';path='+path+';domain=;expires=Sat, 01-Jan-2000 00:00:01 GMT';
		window.document.cookie = del_str;
		del_str = name+'='+value+';path='+path+';domain='+domain+';expires=Sat, 01-Jan-2000 00:00:01 GMT';
		window.document.cookie = del_str;
		del_str = name+'='+value+';path='+path+'/;domain=;expires=Sat, 01-Jan-2000 00:00:01 GMT';
		window.document.cookie = del_str;
		del_str = name+'='+value+';path='+path+'/;domain='+domain+';expires=Sat, 01-Jan-2000 00:00:01 GMT';
		window.document.cookie = del_str;
		after=get_cookie(name);
	    }
	}
    }
    return after;
}

function get_cookie( name ) {
    var start = window.document.cookie.indexOf( name + "=" );
    if ( start == -1 ) return null;
    var value_index = start + name.length + 1;
    var value_end_index = window.document.cookie.indexOf( ';',  value_index );
    if ( value_end_index == -1 ) value_end_index = window.document.cookie.length;
    return  window.document.cookie.substring( value_index, value_end_index ); 
}

function Click(e)  {
    var name = "", name_value, value, cookies_list=window.document.cookie.split(";");
    var str="", str_ascii="", name_value;
    log("click ");
    if (minimized) {
	button.style.MozOpacity = 1;
	if (window.document.cookie == "")
	    str="<em style='color: black ! important;'>No cookies on "+site+"</em>"
	else {
	    if (cookies_deleted) {
		str="<em style='color: black ! important;'>Cookies deleted</em>";
		cookies_deleted=false;
	    }
	    else for(var i in  cookies_list )   {
		name_value = cookies_list[i].split("=");
		name = name_value[0];
		value=decodeURIComponent(get_cookie(name));
		var emphasis="<em style='color: black ! important; background-color: "+bgColor+" ! important;"
		    +"font-size: " +       ( iframe ? 12 : 16 )          +         "pt ! important;'>"
		str_ascii+=name + "="+(value?value:null)+".";
		str+=emphasis + name + "=</em>"+(value?value:null)+emphasis+".  </em>";
	    }
	}// end else.
	cookie_div.innerHTML=str;
	button.replaceChild(cookie_div, minimized_text);
	button.title=title;
	button.fontSize = "10pt";
	button.style.setProperty("background", "none"," important");
	cookie_div.style.setProperty("background-color", bgColor," important");
	cookie_div.style.setProperty("color", "midnightblue"," important");
    }
    else { // minimize.
	if ( ! cookies_deleted) minimized_text.textContent= (iframe ? "iframe cookies":"Cookie Zapper" );
	button.style.MozOpacity =  0.4;
	button.replaceChild(minimized_text, cookie_div);
	button.style.setProperty("background", "none"," important");
	button.style.setProperty("background-color", bgColor," important");
	button.style.setProperty("color", "midnightblue"," important");

    }
    minimized^=true;
    return true;
}

function persist() {
    if (zap_list[site]) {
	var results=zap_list[site].results
	if (results && results.length > 2) 
	    results.shift();
    }
    GM_setValue("zap_list", uneval(zap_list))
}

function showResults(from_click) {
    zap_list=eval(GM_getValue("zap_list", "")) || {};
    var site = getDomain();
    var zap_obj=zap_list[site];
    
    if ( ! zap_obj || ( zap_obj.man || zap_obj.auto) ) {
	if (temp_results) {
	    alert2(widener+temp_results);temp_results="";
	}
	else if (from_click) zapNow("Right Mouse click on icon");
	else { 
	    var str="No current results for this site.\n\nSites where cookies are deleted automatically or are reserved for only manual deletion:\n\n", twolines;
	    for(var i in zap_list) str+=( /^clear_all$/.test(i) || getSitesSetting(zap_list[i], true, true) == null ? "" :  i + 
					  ":\t\t\t"+getSitesSetting(zap_list[i], true, true) + ( twolines^=true,twolines ? "\t\t\t\t" : "\n" ) )
	    alert2(widener + str + "\n\nSet cookies: " + window.document.cookie + ".");
	}
	return;
    }
    var res="";
    if (/\w/.test(window.document.cookie)) {
	res+="\nCurrently set cookies for domain "+site+": \n\n"
	res+=decodeURIComponent(window.document.cookie.replace(/(;+)/g,"$1\n"))
    }
    if ( ! res) {
	if ( ! minimized) Click();
	res+="No cookies are currently set on domain "+site+".\n"
    }
    if (zap_obj && zap_obj.results && zap_obj.results.length)  { 
	if (zap_obj.results.length==2) {
	    res+="\n\n"+zap_obj.results[1]
	    res+="\n\nPrevious log of deletions:\n"
	}
	res+="\n"+zap_obj.results[0];
    }
    else 
	res+="\n\nNo cookie zapper results so far for domain: "+site

    if (zap_obj) 
	if (zap_obj.onload) res+="\n\nAll of this domain's cookies are being deleted when its pages are visited (loaded).";
        else if (zap_obj.unload) res+="\n\nAll of this domain's cookies are being deleted when its pages are browsed away from (unloaded).";
        else if ( ! ( zap_obj.man || zap_obj.auto) ) res+="\n\nAll of this domain's cookies are being deleted when its Tabs are closed.";
    
    alert2(widener+res);
    
    return true;
}

function renderButton(remove) {
    if (remove) {
	if (button.parentNode)
	    button.parentNode.removeChild(button)
	return;
    }
    bgColor="WhiteSmoke"
    if (zap_obj && ! zap_obj.auto) {
	bgColor="Wheat";
	if (zap_obj.onload ) 
	    bgColor="Sienna";
	if (zap_obj.unload) 
	    bgColor="lightblue";
	if (zap_obj.man) 
	    bgColor=light_green;

    }
    if (button.parentNode) {
	//button.style.backgroundColor=bgColor;
	button.style.setProperty("background", "none"," important");
	button.style.setProperty("background-color", bgColor," important");
	button.style.setProperty("color", "midnightblue"," important");
	return;
    }
    if ( ! zap_obj && ( unsafeWindow.document.cookie == '' ) ) { log("No Cookies, no policy");return; }
    function setStyle(elem) {
	elem.appendChild(minimized_text);
	minimized=true;
	with(elem.style) {	cursor="default"; position = "fixed";	iframe ? (left = "40px" , top = "0px") : (  bottom = "0px") ; overflow= "visible"; 
				//maxWidth=(window.innerWidth-40)+"px";
				border = "1px solid";	padding = "0px";   	fontSize = "8pt"; zIndex=99999;MozOpacity= 0.4;
				face="Verdana";fontFamily="verdana";
			 }
	elem.style.setProperty("font-size", (iframe?8:10)+"pt", "important");
	elem.style.setProperty("background", "none"," important");
	elem.style.setProperty("background-color", bgColor," important");
	elem.style.setProperty("color", "midnightblue"," important");
    }
    setStyle(button);// setStyle(cookie_div);
    window.document.body.appendChild(button);
    if (yeascript && ! iframe  ) {
	window.setTimeout( function() { if (minimized) Click(); }, 1000 );
	window.setTimeout( function() { if ( ! minimized) Click(); }, 5000 );
    }
    else if ( ! iframe ) { 
	Click(); 
    }
    window.document.addEventListener('mousemove', detectMove, false);
    window.document.addEventListener('keypress', detectMove, false);
    button.addEventListener("click", Click, false);
    button.addEventListener("contextmenu", nopopup, false);
}
 
function detectMove(e) {
    this.removeEventListener("mousemove", arguments.callee, false);
    this.removeEventListener("keypress", arguments.callee, false);
    if ( minimized) Click();
    Click();
}

function nopopup(e) { 
    log("click rt");
    showResults(true);
    e.preventDefault();    e.stopPropagation();    e.returnValue=false;    e.cancelBubble=true;    e.cancel=true;
    return true;
}

function listenForUnload(deaf, onload) {
    log("setting up listen for unload "+deaf+" "+onload);
    if ( ! deaf && ! onload)
	window.addEventListener("unload", loadOrUnload, false);
    else if (onload)  
	window.addEventListener("pageshow", loadOrUnload, false);
    else  if  (deaf) try { 
	window.removeEventListener("unload", loadOrUnload, false);
	window.removeEventListener("pageshow", loadOrUnload, false);} catch(e){}
}

function loadOrUnload(e){
    zap_list=eval(GM_getValue("zap_list", "")) || {};
    log("loadOrUnload");
    var res="";
    if (window.innerHeight == 0  && /unload/i.test(e.type))
	res=" Tab Close"; 
    else if (zap_list[site].unload && /unload/i.test(e.type))
	res=" Unload"
    else if (zap_list[site].onload && /pageshow/i.test(e.type))
	res="loaded" ;
    else
	return;
    GM_log("Deleting Cookies due to:"+res);
    res=deleteCookies("At "+(iframe ? "frame " : "page ") + res ) 
    GM_log(res);

    if (res) {
	zap_list[site].results.push(res);
	persist();
	if ( ! minimized) Click();
    }
    //alert(iframe+" "+/unload/i.test(e.type) +", unload. Load: "+ /^\s*load/i.test(e.type)+" cookies "+res+" win.he"+window.innerHeight)
}

function checkIfPopupsAllowed() {
    var pwin = window.open('','','width=1,height=10,left=-10,top=-10,scrollbars=no');
    if ( pwin) {
	//win.document.open(); 
	try { pwin.document.writeln("asafkokpjof");} catch(e) { GM_log("cant write "+e)}
	pwin.close();
    }
    return pwin;
}

function zapNow(quiet) {
    var res;
    res = deleteCookies((quiet ? quiet : "On GM command") )
    if (zap_obj && ! ( zap_obj.auto || zap_obj.man ) ) {
	zap_list[site].results.push(res);
	persist();
    }
    else if (clear_all && ! zap_obj) { 
	zap_list[site]={}	
	zap_list[site].auto=1;
	persist();
    }
	
    if (window.document.cookie)
	res+="\n\nLeft over: "+decodeURIComponent(window.document.cookie)
	+".\nThese cookies could not be deleted, but unless there is a scripting error, they are 'Session cookies'.  The browser itself always deletes these session cookies in any case when it quits."
    else
	res+="\n\nThere "+(quiet ? "were":"are") +" no document cookies"+(res? " left after deletion.":".");
    
    if ( ! quiet) alert2(widener+"\n"+res);
    else  { 
	temp_results=res; cookies_deleted=true; 
	cookie_div.textContent=minimized_text.textContent= "Cookies deleted"; 
	if ( ! zap_obj || zap_obj.auto  )
	    button.style.MozOpacity=1; 
    }
    if ( ! minimized) Click();
    if ( quiet ) button.style.MozOpacity=1;
}

function getSitesSetting(obj, give_color, in_effect) {
    var sites_setting=null;
    if (obj ) {
	sites_setting=        "on tab close (beige-1)                         ";
	if ( obj.auto )
	    if ( ( in_effect && clear_all ) || ! in_effect )
		sites_setting="by default action (previously deleted manually)";
	   else
	       sites_setting=null;
	if (obj.unload)
	    sites_setting=    "when site is browsed away from (light blue-2)  ";
	if (obj.onload)
	    sites_setting=    "when site is visited (red-3)                   ";
	if( obj.man)
	    sites_setting=    "only manually (green-4)                        ";
    }
    return sites_setting;
}

function getDomain(other_host) {
    var site, host;
    var domain_regexp = /((\.[\w-]+\.|^)[\w-]+.[\w-]*$)/; // removes name before first dot.
    var url_regexp="^(.+///?)?([^/]+)"
    try{ 
	if ( ! other_host) host=(""+unsafeWindow.location).match(url_regexp)[2]; //host=window.document.location.host;
        else host=other_host.match(url_regexp)[2];
	if (host) {
	    site=host.match(domain_regexp)[0];
	    if (site && site[0] != ".") site="."+site;
	} 
    }    catch(e){ }// GM_log("Zapper site, xss, iframe in other domain?  No host for: "+host+".  Other host "+other_host+".  Error: "+e); }
    if (site=="")
	site="localfile";
    else if ( ! site)
	try { site=window.document.title.subtring(0,30); } catch(e){ site="";}
    return site;
}

function insertCode(code) {
    var script = document.createElement("script");
    script.type = "application/javascript";
     script.textContent = code; 
    window.document.body.appendChild(script);
    window.document.body.removeChild(script);
    return;
}

function log(str) {
    if ( typeof dcount == "undefined" ) { dcount=1; }
    if ( ! log.win) {
	log.win=window.open(""); // need to allow site in noscript for this.
	log.doc=log.win.document; 
    }
    str=str.replace(/\n/g, "<p id=newnline;>");
    var style="style='margin-left : 100px; border-bottom: solid 1px; font-size: 14pt;line-height: 2em ' ondblclick='document.body.innerHTML=null'";
    try{  log.doc.writeln("<div "+style+">"+dcount+":   "+str+"</div>"); dcount++; log.doc.title=dcount;}
    catch(e){ window.setTimeout(function() {log(str)}, 0);	}
}

//WR/////////////////
/////////////////// ////////////WRAPPER for Google Chrome etc.///////////////////////////////////////////
///////////////////
// Notes: the this pointer on chrome may differ from ff.
//              keypress does not pass on altKey setting (charCode is not set for keypress but for keydown for both).
function GM_platform_wrapper(title) {
  var name=title.replace(/\W*/g,""), uwin=unsafeWindow, bg_color="#add8e6";
  String.prototype.parse = function (r, limit_str) {   var i=this.lastIndexOf(r); var end=this.lastIndexOf(limit_str);if (end==-1) end=this.length; if(i!=-1) return this.substring(i+r.length, end); };  //return string after "r" and before "limit_str" or end of string. 
  window.outerHTML = function (obj) { return new XMLSerializer().serializeToString(obj); };
  window.FireFox=false;     window.Chrome=false; //log=GM_log;
  window.confirm2=confirm2;  window.prompt2=prompt2;  window.alert2=alert2;
  //
  //Split, first firefox only, then chrome only exception for function definitions which of course apply to both:
    if (  !  /^Goo/.test (navigator.vendor) )  { /////////Firefox:
      window.FireFox=true;
      window.brversion=parseInt(navigator.userAgent.parse("Firefox/"));
      if (brversion >= 4) { 	  
	    window.countMembers=countMembers;	  
	    window.__defineSetter__ = {}.__defineSetter__;
	    window.__defineGetter__ = {}.__defineGetter__;
	    window.lpix={}; // !!! firefox4 beta.
	    initStatus();
	    bg_color="#f7f7f7";
	}
	else 	  window.countMembers=function(obj) {	    return obj.__count__;	}

	var old_set=GM_setValue, old_get=GM_getValue;
	GM_setValue=function(name, value) { return old_set( name, uneval(value));	}
	GM_getValue=function(name, defaulT) {	 var res=old_get ( name, uneval (defaulT) ); 
						 if (res!="") try { return eval  ( res ); } catch(e) {} ; return old_get ( name, defaulT  );	}
        window.pipe=uwin; try {
	  if (uwin.opener && uwin.opener.pipe)  { window.pipe=uwin.opener } } catch(e) { }
	window.pool=uwin;
	//useOwnMenu();
	return;
    }
    ///////////////////// Only Google Chrome!! :
    window.Chrome=true;
    window.brversion=parseInt(navigator.userAgent.parse("Chrome/"));
    Object.prototype.merge = function (obj)  { 		for (var i in obj) 	    if ( ! obj.hasOwnProperty(i))                              continue;             else if ( this[i] == undefined )  			    this[i] = obj[i];                    else if ( obj[i] && ! obj[i].substr)                        this[i].merge(obj[i] );	return this;         }
    function unsafeGlobal() {
	pool={}, pipe={}, shadow = local_getValue("global", {});
	var ggetter= function(pipe) {
	    if ( ! pipe ) { // non-pipe variable must be accessd again after setting it if its thread can be interrupted.
		var glob=GM_getValue("global", {})
		shadow.merge(glob);                    
	    }
	    local_setValue("global", shadow);
	    return shadow;
	}
	window.__defineGetter__("pool", ggetter);
	window.__defineGetter__("pipe", function() { return ggetter(true)} );
	addEventListener("unload", function() { local_setValue("global", null) }, 0);
    }
    GM_log = function(message) {
	console.log(message);
    };
    uneval=function(x) {
	return "("+JSON.stringify(x)+")";
    }
    function countMembers(obj, roll) { var cnt=0;     for(var i in obj) if ( ! obj.hasOwnProperty || obj.hasOwnProperty(i)) cnt++; 	return cnt;    }
    window.countMembers=countMembers;

    
    
    GM_addStyle = function(css) {
	var style = document.createElement('style');
	style.textContent = css;
	document.getElementsByTagName('head')[0].appendChild(style);
    }
    
    GM_setValue = local_setValue
    function local_setValue(name, value) {
	if ( ! value && value !=0 ) {
	    localStorage.removeItem(name);
	    return;
	}
	var str=JSON.stringify(value);
	localStorage.setItem(name,  str );
    }
    
    GM_getValue = local_getValue
    function local_getValue(name, defaultValue) {
	var value = localStorage.getItem(name);
	if (value==null) return defaultValue;
	value=JSON.parse(value);
	return value;
    }
    GM_deleteValue = function(name) {
	localStorage.removeItem(name);
    }
  unsafeGlobal();
  window.doGMmenu=doGMmenu;
  function doGMmenu() { 
    var right_pos=GM_getValue("GMmenuLeftRight", true), i=doGMmenu.count||0, lpix="40px";
      doGMmenu.colors=" background-color: #bbf ! important;	    color: #000 ! important;	  ";
      doGMmenu.divcss= doGMmenu.colors+" border: 3px outset #ccc;	position: fixed;	    opacity:  0.8;	    z-index: 100000;"
	+"top: 5px; padding: 0 0 0 0;   overflow: hidden ! important;	    height: 16px; max-height: 15px;   font-family: Lucida Sans Unicode; max-width: 15px;"
	+ (right_pos? "right: 5px;" : "left: "+lpix+";" );	   
      if ( ! pool["menu"+name].length ) { return; }
      var div = document.getElementById('GM_pseudo_menu'), bold, bold2, img, ul, li, par = document.body ? document.body : document.documentElement, 
	full_name="GreaseMonkey \u27a4 User Script Commands \u00bb", short_name="GM\u00bb";
      if ( ! div ) {
	  div = document.createElement('div');
	  div.id = 'GM_pseudo_menu';
	  par.appendChild(div);
	  div.style.cssText= doGMmenu.divcss;
	  //div.title="Click to open GreaseMonkey menu";
	  bold = document.createElement('b');
	  //bold.textContent=short_name;
	div.appendChild(bold);
	img=document.createElement('img');
	img.src="data:image/gif;base64,AAABAAEADxAAAAEAIAAoBAAAFgAAACgAAAAPAAAAIAAAAAEAIAAAAAAAAAAAABMLAAATCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAADgAAABAAAAAQAAAAEAAAAA4AAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAfw8ANGiHADx42wBAf/8AQH//AEB//wBAf/8AQH//ADx42wA0aIcAQH8PAAAAAAAAAAAAAAAAAEB/LwBAf98jZp//YKrX/4/b//+T3P//lNz//5Pc//+Q2///YarX/yNmn/8AQH/fAEB/LwAAAAAAAAAAAEB/vzR5r/+M2v//ktv//5jd//+c3///nt///53f//+Z3v//lNz//43a//80ea//AEB/vwAAAAAAQH8PAEB//4PQ9/9+v+D/L0Vj/x4qX/8qOIT/KjmY/yo4if8fKmX/L0Vn/4DA4P+D0Pf/AEB//wAAAAAAQH8PEVOP/43a//9Se5D/gbXS/6bi//+t5P//seX//67l//+o4v//grbT/1R8kv+O2v//AEB//wAAAAAAJElfCEJ6/4XR9/+W3f//oOD//2mVn/9wlZ//uuj//3GXn/9rlJ//o+H//5ne//+G0ff/CEJ6/wAkSV8TPmXfO3em/1CXx/+W3f//oOD//wAmAP8AHQD/uOf//wAmAP8AHQD/ouH//5ne//9Rl8f/Q3+s/xM+Zd87bZP/O3em/z6Dt/+U3P//nN///0BvQP8QPBD/ruT//0BvQP8QPBD/n9///5bd//8+g7f/Q3+s/zttk/8yaJP/S4ax/yNmn/+P2///l93//2Gon/9lop//peH//2apn/9iop//md7//5Hb//8jZp//S4ax/zJok/8JQ3vvMm2d/wBAf/+D0Pf/kNv//5bd//+a3v//dbff/5re//+X3f//ktv//4TQ9/8AQH//Mm2d/wlDe+8APn1PAD99rwA/fq8rcKf/g9D3/47a//9boc//AEB//1uhz/+O2v//g9D3/ytwp/8AP36vAD99rwA+fU8AAAAAAAAAAAAAAAAAQH/PAEB//xFTj/8ANGf/ADBf/wAyY/8AOnP/ADpz/wAqU/8AIEA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEB/jwBAf/8AQH//AC5b/wAgQP8AIED/AChP/wA6dL8AJEnfACBADwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAfx8AQH+PAEB/3wA2a/8AJEf/ACBA/wAgQH8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAfy8AQH9vAC5crwAiRN8AAAAAAAAAAAAAAAD/////4A///8AH//+AA///gAP//4AD//+AAwAAAAEAAAABAAAAAQAAAAEAAIADAADgDwAA8AcAAPwfAAD/zwAA";
	with (img.style) { border="none"; margin="0"; padding="0"; cssFloat="left"; }
	bold.appendChild(img);
	function minimize(p) {
	  var style=p;
	  if (p.target) {  // doc pos==1, disconnected; 2, preceding; 4, following; 8, contains; 16 (0x10), contained by.  Gives relation p.relatedTarget "is" to this. (0x0 means not related but is same elem)
	    var pos=this.compareDocumentPosition(p.relatedTarget);
	    var contained_by=pos & 0x10;
	      if (pos==2 || pos==10) 
		style=div.style;  
	    else return;
	  }
	  style.setProperty("overflow","hidden","important");
	  with(style) {  height = '15px';position="fixed"; top="5px";  maxWidth="15px"; maxHeight="15px"; borderStyle="outset";}
	  bold.textContent="";
	  bold.appendChild(img);
	}
	div.addEventListener("click",  function (e) {
	  if (e.button!=0) return;
	  if ( div.style.height[0] == 1 ) {
	    with (div.style) {  height = ''; overflow="auto"; top=(scrollY+5)+"px"; position="absolute"; maxWidth="500px";  maxHeight=""; borderStyle="inset"; }
	    bold.textContent=full_name;
	    div.addEventListener("mouseout", minimize, false);
	  }
	  else  	{
	    minimize(div.style);
	    div.removeEventListener("mouseout", minimize, false);
	  }
	  }, false);
	bold.style.cssText="cursor: move; font-size: 1em; border-style=outset;" ;
	bold.title="GreaseMonkey.  Click this icon to open GreaseMonkey scripts' menu.  Middle Click to move icon other side.  Right Click to remove icon.";
	bold.addEventListener("mousedown", function(){return false}, false);
	bold.style.cursor = "default";
	bold.addEventListener("mousedown", function (e) {
	    if (e.button==0) return;
	    if (e.button==1) {	    this.parentNode.style.left = this.parentNode.style.left ? '' : lpix;	    this.parentNode.style.right = this.parentNode.style.right ? '' : '10px';	    GM_setValue("GMmenuLeftRight", ( this.parentNode.style.right ? true : false ) ); }
	    else 
	      div.style.display="none"; //div.parentNode.removeChild(div);
	  }, false);
      } // end if ! div
      bold=div.firstElementChild;
      if (i==0) {
	div.appendChild(document.createElement('br'));
	div.appendChild(bold2 = document.createElement('div'));
	bold2.textContent="\u00ab "+name+" Commands \u00bb";
	bold2.style.cssText="font-weight: bold; font-size: 0.9em; text-align: center ! important;"+doGMmenu.colors+"background-color: #aad ! important;";
	div.appendChild(ul = document.createElement('ul'));
	ul.style.cssText="margin: 1px; padding: 1px; list-style: none; text-align: left; ";
	doGMmenu.ul=ul;	  doGMmenu.count=0;
      }
      for( ; pool["menu"+name][i]; i++ ) {
	var li = document.createElement('li'), a;
	li.appendChild(a = document.createElement('a'));				     //				     +'setTimeout(function() {div.style.cssText= doGMmenu.divcss;}, 100);'
	a.setUserData("i", i, null);
	function callfunc(e) { 
	  var i=parseInt(e.target.getUserData("i"));
	  div.style.position="fixed";div.style.top="5px"; 
	  div.style.cssText= doGMmenu.divcss;div.style.height="0.99em";
	  uwin["menu"+name][i][1]();
	}
	if (FireFox) 	a.addEventListener("click" , callfunc	, 0);
	else a.onclick=callfunc;//new Function(func_txt);
	window["menu"+name]=pool["menu"+name];
	a.addEventListener("mouseover", function (e) { this.style.textDecoration="underline"; }, false);
	a.addEventListener("mouseout", function (e) { this.style.textDecoration="none";}, false);
	a.textContent=pool["menu"+name][i][0];
	a.style.cssText="font-size: 0.9em; cursor: pointer; font-weight: bold; opacity: 1.0;background-color: #bbd;color:black ! important;";
	doGMmenu.ul.appendChild(li);	    doGMmenu.count++;
      }
    } // end of function doGMmenu.

  useOwnMenu();
  function useOwnMenu() {
    if (FireFox) uwin.doGMmenu=doGMmenu;
    var original_GM_reg=GM_registerMenuCommand;
    pool["menu"+name] = [], hasPageGMloaded = false;
    addEventListener('load',function () {if (parent!=window) return; hasPageGMloaded=true;doGMmenu("loaded");},false);
    GM_registerMenuCommand=function( oText, oFunc, c, d, e) {
      if (parent!=window || /{\s*}\s*$/.test( oFunc.toString() )) return;
      hasPageGMloaded=document.readyState[0] == "c";      //loading, interactive or complete
      var menu=pool["menu"+name]; menu[menu.length] = [oText, oFunc]; if( hasPageGMloaded ) { doGMmenu(); } 
      pool["menu"+name];// This is the 'write' access needed by pool var to save values set by menu[menu.lenth]=x
      original_GM_reg.call(unsafeWindow, oText, oFunc, c, d, e);
    }
  }

    function setStatus(s) {
      if (s)  s = s.toLowerCase ? s.toLowerCase() : s;
      setStatus.value = s;
      var div=document.getElementById("GMstatus");
      if ( div ) {	
	if ( s ) {	    div.textContent=s;	    div.style.display="block";	    setDivStyle();	    }
	else {     setDivStyle();	    div.style.display="none"; }
      } 
      else  if ( s ) { 
	div=document.createElement('div');
	div.textContent=s;
	div.setAttribute('id','GMstatus');
	document.body.appendChild(div);
	setDivStyle();
	div.addEventListener('mouseout', function(e){ setStatus(); },false);
      }
      if (s) setTimeout( function() {  if (s==setStatus.value) setStatus();    }, 5000);
      setTimeout(setDivStyle, 100);
      function setDivStyle() {
	  var div=document.getElementById("GMstatus");
	  if ( ! div ) return;
	  var display=div.style.display; 
	  div.style.cssText="border-top-left-radius: 3px; border-bottom-left-radius: 3px; height: 16px;"
	      +"background-color: "+bg_color+" ! important; color: black ! important; "
	      +"font-family: Nimbus Sans L; font-size: 11.5pt; z-index: 99; padding: 2px; padding-top:0px; border: 1px solid #82a2ad; "//Lucida Sans Unicode;
	      +"position: fixed ! important; bottom: 0px; " + (FireFox && brversion >= 4 ? "left: "+lpix : "" )
	      div.style.display=display;
      }
    }
    initStatus();
    function initStatus() {
	window.__defineSetter__("status", function(val){    setStatus(val); });
	window.__defineGetter__("status", function(){    return setStatus.value; });
    }
    var old_removeEventListener=Node.prototype.removeEventListener;
    Node.prototype.removeEventListener=function (a, b, c) {
      if (this.sfsint) { clearInterval(this.sfsint); this.sfsint=0; }
      else old_removeEventListener.call(this, a, b, c);
    }
    var old_addEventListener=Node.prototype.addEventListener;
    Node.prototype.addEventListener=function (a, b, c) {
      if (a[0] != "D") old_addEventListener.call(this, a, b, c);
      if (/^DOMAttrModified/.test(a)) {
	var dis=this; setInterval.unlocked=15; // lasts for 40 secs;
	dis.oldStyle=dis.style.cssText;
	setTimeout(checkForChanges, 200);
	dis.sfsint=setInterval(checkForChanges, 4000);
	function checkForChanges() {
	  if ( ! setInterval.unlocked) return;
	  if ( dis.style.cssText != dis.oldStyle ) {
	    var event={ target: dis, attrName: "style", prevValue: dis.oldStyle};
	    b.call(dis, event);
	  }
	  dis.oldStyle=dis.style.cssText;
	  setInterval.unlocked--;// !! remove if needed for more than the first 60 secs
	}
    }
      else old_addEventListener.call(this, a, b, c);
    }
    var original_addEventListener=window.addEventListener;
    window.addEventListener=function(a, b, c) {
    	if (/^load$/.test(a) && document.readyState == "complete") {
	    b();
	}
    	else original_addEventListener(a, b, c);
    }
    document.addEventListener=function(a, b, c) {
    	if (/^load$/.test(a) && document.readyState == "complete")
	    b();
    	else original_addEventListener(a, b, c);
    }
    Node.prototype.getUserData = function(a) { return this.a } 
    Node.prototype.setUserData = function(a, b ) { this.a=b }

  // The following version of alert, prompt and confirm are now asynchronous, 
  // so persistData() may need to be called at end of callback (reply_handler) for prompt2 and confirm2;
  // If alert2, confirm2 or prompt2 is called form within an alert2, confirm2 or prompt2 reply handler, take care because the same window gets reused.
function alert2 (info, width) {
      if ( Chrome) { alert(info); return;}
      var popup=window.open("","myWin","menubar=no,scrollbars,location=no,toolbar=no,status=no, "
			    +"left=30px,top=40px,height=400px,width="+(width?width:600)+"px");
      popup.document.body.innerHTML="<pre style='white-space: pre-wrap;'>"+info+"</pre>";
      return popup;
  }
  function prompt2 (str, fill_value, result_handler, mere_confirm) {
      if (Chrome) {  if (mere_confirm) result_handler(confirm(str));
		     else result_handler(prompt(str, fill_value));return; }
      log("setup prompt2 "+mere_confirm);
      var res, prompt_win;
      prompt_win=window.open("","myWin","dependent=no, menubar=no,scrollbars,location=no,toolbar=no, statusbar=no, left=30px,top=40px,width=600em");
      var body=prompt_win.document.body;
      body.innerHTML="<div><pre style='white-space: pre-wrap;'>"+str+"</pre>"
	  +( !mere_confirm ? "<textarea style='width:100%;  border: double;'>"+fill_value+"</textarea>":"")
	  +"<form><input type=button value='Cancel/Next' style='width:100; height:50;font-size: 12'>"
	  +"<input type=button value='OK' style='width:100; height:50;font-size: 24;' onClick='OKbutton()'></form></div>";
      var div=body.getElementsByTagName("div")[0];
      var ta=body.getElementsByTagName("textarea")[0];
      var form_inputs=body.getElementsByTagName("input");
      form_inputs[0].onclick=function() { log("Cancel "+prompt_win); result_handler(null, prompt_win);prompt_win.close();  };//cancel
      form_inputs[0].style.cssFloat="left";
      form_inputs[1].onclick=function() { //OK
	  log("OK ");
	  if (!mere_confirm) { 
	      var ta = prompt_win.document.getElementsByTagName("textarea")[0];
	      result_handler(ta.value.replace(/^\s*|\s*$/g,""), prompt_win);
	  }
	  else result_handler(true, prompt_win);
	  log("OK, close win");
	  prompt_win.close();
      }
      prompt_win.resizeTo(body.offsetWidth+50,body.offsetHeight+100);
      if (ta) ta.focus();
  }
  function confirm2(str, result_handler) {
      prompt2(str, "", function(res, pwin) { 
	  if (res==null) result_handler(false, pwin);
	  else result_handler(true, pwin);
      }, true);
  } 
}