slow! / DGY Duckduckgo/Google Columns & YouTube Sort by date

// ==UserScript==
// @name DGY Duckduckgo/Google Columns & YouTube Sort by date
// @version      2.1.5
// @updateURL    https://openuserjs.org/meta/slow!/DGY_DuckduckgoGoogle_Columns_YouTube_Sort_by_date.meta.js
// @namespace    DGY
// @run-at       document-start
// @description  Sort by date as default at youtube & google-video.  Duckduckgo and Google results also formatted to 2 columns.  See GM menu to disable columns.  Also makes links go directly to target and not via the search website's advertising department.
// @license      GPL-3.0
// @copyright    2017, slow! (https://openuserjs.org/users/slow!)
// @include       http*://duckduckgo.com/*
// @include       http*://www.youtube.*
// @include       http*://www.google.*
// @include       https://encrypted.google.*
// @exclude       http*://*.google.*/maps/*
// @exclude       http*://*.google.*/imgres*
// @grant GM.getValue
// @grant GM.setValue
// @grant GM.deleteValue
// @grant GM.addStyle
// @grant GM.xmlHttpRequest
// @grant GM_registerMenuCommand
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_addStyle
// @grant GM_xmlhttpRequest
// @resource jquery    https://code.jquery.com/jquery-3.2.1.js
// @resource jqueryui  https://code.jquery.com/ui/1.11.4/jquery-ui.js
// @resource polyfill  https://raw.githubusercontent.com/SloaneFox/code/master/gm4-polyfill-1.0.1.js
// @resource regcmd    https://raw.githubusercontent.com/SloaneFox/code/master/gm-popup-menus-1.3.7.js
// ==/UserScript==

// @updated       Feb 2018.  Updated for GM4 + performance.
// @updated       Dec 2016.  Updated for Chrome and other bugfixes.
// @updated       July 2016. Bug when sort by relevance is clicked, was being ignored.
// @updated       May 2016.  Exclude google image site, 'imgres?' address above.
// @updated       Feb 2016.  2.0.7 Fixes bug handling google video search in date order.  Adds submenu module.
// @updated       Nov 2015.  2.0 Use of mutation observer since DOMNodeInserted is being removed.
// @updated       2015.  1.6 updated for google chrome/chromium
// @updated       2014.  Youtube interface changed to use results in iframe, unable to change parent href.
// @updated       1st  of May, 2013.  Duckduckgo changed style, columns are now going left to right, so the format for Duck is now in row order (terraced);
// @updated       27th of May, 2010. Page layout changed.
// @updated       27th of April, 2010. GM menu option added to toggle columns.  When selected search results are presented from then on in a three column layout.

//console.log("BEGIN readystatechange ====> ",document.readyState,"Typeof this",typeofObj(this));
var iframe=window.parent!=window, ss=sessionStorage;
if (iframe) return; //!!
var gm4=typeof GM != "undefined", youtube;

if ( /\.youtube\./.test(location.host)) { youtube=true;}
if (/\/results/.test(location.pathname)) results_page=true;
if (/search_sort/.test(location.search)) sorted_page=true;
if (/zimyt/.test(location.search)) reflexive=true;         // zimty=2 is the marker of DGY processed.

if(youtube && results_page && !sorted_page) {
	console.log("Reload with correct URI:",location.href+"&search_sort=video_date_uploaded"+"&zimyt=2");
	location=location.href+"&search_sort=video_date_uploaded"+"&zimyt=2";
	return;
} else if(youtube&&!results_page) return; else console.log("Address ok",location);

var duck=false, ducklite=false, google=false, googlev=false, goo_images=false, goo_cse=false, 
	duckresultsclass="results_links_deep"; var vgoogle=false, aol=false;

if ( /^duckduckgo/.test(location.host)) { duck=true;youtube=false; }
if ( /\.google/.test(location.host)) { duck=false;youtube=false; google=true; if (/^cse/.test(host)) goo_cse=true;}

var indiv_res_selector, indiv_res_not_padded_out;
if (youtube) indiv_res_selector="ytd-video-renderer"; //.ytd-item-section-renderer"; //".item-section>li";
if (duck) indiv_res_selector="."+duckresultsclass;
if (goo_cse) { indiv_res_selector="div.gsc-result";	} 
if (google) { indiv_res_selector=".g";indiv_res_not_padded_out=".g:not(.card-section,g-blk)";}

var results_list_selector="#contents #contents";  ////"#results"; // yt as default values
if(duck) results_list_selector="#links";

//console.log("Setup for site, indiv_res_selector:",indiv_res_selector,", yt:",youtube,"duck",duck,"goo_cse",goo_cse,"google",google,"results_list_selector:",results_list_selector);

collimate("preform",indiv_res_selector);
var cnt=(new Date).getTime();
function tstamp() {return (((new Date).getTime()-cnt)/1000).toFixed(3);}

if (!iframe) ss.floglineindex=1;

String.prototype.justify = justify;
String.prototype.count=function(str) { return (this.match(str,"g")||[]).length;};
String.prototype.parse = function (r, nlimit_str) { var i=this.lastIndexOf(r);var end=this.lastIndexOf(nlimit_str);if (end==-1) end=this.length; if(i!=-1) return this.substring(i+r.length, end); };  //return string after last position of "r" in str and before "nlimit_str" or end of string.
this.unsafeWindow=unsafeWindow;

function log(t) {
	console.log.apply(console,arguments);
};

log=function(){};

var flog=function(s) { //log to file ~/Dest./afile
	s=ss.floglineindex+" - "+s+"\n";
	ss.floglineindex=Number(ss.floglineindex)+s.count("\n");
	ss.fmsg+=s;
}

var page_key=location.host+location.pathname, host=window.document.location.host;
var href=window.document.location.href;path=window.document.location.pathname;
var uwin=unsafeWindow;
var toolbelt=uwin.toggleToolbelt || ( uwin.yt && uwin.yt.www && uwin.yt.www.search ? uwin.yt.www.search.toggleToolbelt : function(){} );
var pageLoaded, pagele, obs;

var results_page, sorted_page, reflexive, listening="";

var late_classes=[], fitting, already_done;

if ( /^duckduckgo/.test(location.host)) { duck=true;youtube=false }
if ( /\.google/.test(location.host)) { duck=false;youtube=false; google=true; if (/^cse/.test(host)) goo_cse=true;}
if ( /\.youtube\./.test(location.host)) { youtube=true;}
if (/tbm=isch/.test(location.search)) goo_images=true;
if (/tbm=vid/.test(location.search)) googlev=true;
if (/lite/.test(location.pathname)) ducklite=true;
if ( /^video.google/.test(location.host))	vgoogle=true;
else if (/^video.aol/.test(location.host))	aol=true;


if (iframe) try { log("Parent href:" + window.parent.location.href); }catch(e){}

log("matches:"+[duck,google,youtube,goo_cse,googlev,goo_images].map(Number).join("")); //parseInt("0111", 2) ==> 7 //closest to binary literal 0b111


//GM_platform_wrapper("DGY Duckduckgo/Google Cols, Youtube Sort by Date", 6, waitTillLoaded);

//////////////////////////////////////////////
if (! (duck||google||youtube)) return; //For chrome ////////////////////////////////////////////////


if(!chromeInit())
	loader(); //in chrome, this is called instead after jquery is loaded via platform_wrapper loadScript().

if (google) {
	inhibitGoogleTracker();
	mkLinksDirect();
	if (iframe) window.addEventListener("load", function(){
		inhibitGoogleTracker();
	});
}

var columns,no_of_cols,blocked_domains,ddgcrsfs_glob;

async function init_globs() {
	if (init_globs.done) return; init_globs.done=true;
	columns=await GM.getValue("columns", true);
	no_of_cols=await GM.getValue("no_of_cols", 2);
	// name: extensions.greasemonkey.scriptvals.userscripts.org/YouTube Sort by date.no_of_cols
	blocked_domains=await GM.getValue("blocked_domains", []);
	ddgcrsfs_glob=await GM.getValue("ddgcrsfs",false);
}

async function loader() { try{
	//await dumptagdb();return;//!!
	if(!plat_chrome) await loadJsResources();
	await init_globs();
	//console.log("loader readystatechange ====> ",document.readyState," no.of ",indiv_res_selector,"=",$(indiv_res_selector).length);
	if (/complete|interactive/.test(document.readyState) 
		&& ( $(indiv_res_selector).length || ducklite)) { mainline();}      
	else document.addEventListener("readystatechange",x=>{
		console.log("Event readystatechange ====> ",document.readyState);
//		if(document.readyState=="interactive") mainline();// collimate("preform"); 
		if(document.readyState=="complete") mainline();
	});
} catch(e){console.log("Error in loader",e);}};

function mainline(){ try{
	//console.log("main this is",typeofObj(this), this==window);	console.log("main is submenuModule",typeof submenuModule);
	if (already_done) { log("Already_done");return;}
	already_done=true;
	regMenu();
	GM_addStyle2(".putToEnd {position:relative}", "putToEnd");
	pagelen=$(document).height();

	if (google) handleGoogle();
	else  putAtEndAndCollimate("main"); // DDG and youtube 
	//noFlicker(); //clears blank no flicker div.
	if (youtube) $(document).click(function(e){
		var text=$(e.target).parents(".filter-col").find("h4").text();
		if (/sort/i.test(text)) sorted_page=true;
	});
	console.log("DGY main done.");
	//	},0);
	blockDomains();
} catch(e){console.log("Error in main",e);}}

function blockDomains() {       	// to specified: <span class="result__url__domain">experts-exchange.com</span>
	// ancestor:     <div data-nir="1" class="result results_links_deep highlight_d" id="r1-1"><div class="result__body links_main links_deep"><h2 style="margin: 0px;" class="result__title"><a href="http://www.experts-exchange.com/questions/21946163/Cisco-command-for-changing-subnet-mask.html" class="result__a"><b>Cisco</b> command for changing <b>subnet mask</b> - Experts-Exchange</a><a style="position: relative;" href="http://www.experts-exchange.com/questions/21946163/Cisco-command-for-changing-subnet-mask.html" class="result__check"><span class="result__check__tt">Your browser indicates if you've visited this link</span></a></h2><div class="result__snippet">Hi, I have a <b>Cisco</b> 1600 series <b>router</b> and I need to <b>change</b> the <b>subnet mask</b> from 25 to 24 bits. ie 172.24.224.1/25 to 172.24.224.1/24. Can someone show me the command ...</div><div class="result__extras"><div class="result__extras__url"><span class="result__icon"><a title="Search domain www.experts-exchange.com" href="/?q=cisco%20router%20change%20%22subnet%20mask%22+site:www.experts-exchange.com"><img src="//icons.duckduckgo.com/ip2/www.experts-exchange.com.ico" class="result__icon__img" title="Search domain www.experts-exchange.com" height="16" width="16"></a></span><a href="http://www.experts-exchange.com/questions/21946163/Cisco-command-for-changing-subnet-mask.html" class="result__url"><span class="result__url__domain">experts-exchange.com</span><span class="result__url__full">/questions/21946163/Cisco-command-for-chan...</span></a></div><a class="result__menu" title="Search domain www.experts-exchange.com" href="/?q=cisco%20router%20change%20%22subnet%20mask%22+site:www.experts-exchange.com">More results</a></div></div></div>
	blocked_domains.forEach(function(v, i, ar){
		var span=$("span.result__url__domain:contains("+v+")");
		span.closest(".result").remove();
	});
}

function putAtEndAndCollimate(from) { 
	//console.log("putAtEndAndCollimate from:"+from+", iframe: "+iframe);
	pageLoaded=true;
	if (duck) {       //////duckduckgo putatend ids
		snippetFontSize();
		if (ducklite) {
			//$("table").wrapAll("<div id="+results_list_selector.substring(1)+"></div>");
			var c=$(".result-snippet:first").closest("table");
			//c.attr("id",results_list_selector.substring(1)); //set tbody to #links id.
			results_list_selector="table";
			var tb=c.find("tbody:first");
			var fourths=tb.find("> tr:nth-child(4n+1)"); //1st of each set of 4.
			//f.find("+ tr + tr + tr").addClass("sib3")	
			fourths.addClass("fourthform");
			fourths.each(function(){
				var group4=$(this).add($(this).find("+ tr,+ + tr, + tr + tr + tr")); // add three next neighbours "+" is direct net sib, "~" is general next sib.
				group4.wrapAll("<div class='"+duckresultsclass+" dgy'></div>");
			});
			$(".dgy>:nth-child(4)").remove();
		}
		if ($(results_list_selector).length==0) {
			console.info("No #links for duckduckgo @"+location.href);
			return;
		}
		fixCss(results_list_selector, "z-index","17");
		fixCss(".result--more, .result--more__btn",null,"position: absolute;bottom:0;", true);//loads more
		$(".result--more").addClass("DGYabs");
		$(".result--more").click();
		//putToEnd(".result--more");
		putToEnd(".results--sidebar");
		fixCss("#links_wrapper","padding-left","20px");
		fixCss(".result__check","position","relative");
		fixCss(".results--sidebar",{top:50,right:50,zIndex:999});
		fixCss($(".results--sidebar").parent(),{poistion:"static"});
		fixCss(".link-text", "font-size","80%");
		fixCss(".results__title","margin","0");
		putAtEnd("ads");
		putAtEnd("side");
		rm("#side");
		rm("#feedback");
		$(".result-sponsored").closest("."+duckresultsclass).addClass("duckad");
		fixCss(".result--sep","display","none", true);
		putAtEnd("web-result-sponsored",0,0,true);
		putToEnd(".duckad");
		putToEnd(".sponsored");
		putToEnd(".badge-link");
		fixCss("#logo", "margin", "5px 10px -5px 10px"); 
		fixCss("#search_form_homepage", "margin","10px 0px 14px 0px");
		fixCss("#content",{padding:0});
		fixCss("#content_wrapper",{margin: 0,padding:0});   	//addEventListener("resize", function(){
		fixCss(".large",{fontSize:"100%"});
		fixCss(".snippet, .url",{fontSize:"80%"});
		fixCss(".result__title","margin","0");
	} //end if(duck)
	if (youtube) {
		putToEnd("#guide");
		putToEnd(".yt-consent");
		//putToEnd("#guide-inner-content");
		putToEnd("#subscribe-button","delete");
		$("ytd-channel-renderer").remove();
		putToEnd("#ticker"); putToEnd(".style-destructive");
		putToEnd("ytd-movie-renderer");
		if ($(results_list_selector)[0]) {
			putAtEnd("feed-pyv-container");
			putAtEnd("feed-item-dismissable");
			putAtEnd("branded-page-v2-secondary-col"); //removes main promoted/popular vid.
			putAtEnd("ticker");
			putToEnd("#ticker-content");
			putToEnd(".pyv-afc-ads-container");
			putToEnd(".signin-container");
			putToEnd("#yt-masthead-signin");
			putToEnd(".alerts-wrapper");
			putToEnd("#yt-consent-dialog");
			fixCss("#content","width" ,"100%"); //rejigs shape
			rm("#appbar-guide-menu"); // box on left col.
			fixCss(".yt-lockup-badges","margin",-4);
			fixCss(".search-pager",{width:"100%",float:"left"});
			fixCss("#page-manager.ytd-app",{marginTop:25});
			//			fixCss("yt-next-continuation",{display:"inline-block"});
			$("body").addClass("DGYbody");
			fixPageLinks();
		}
	}//end if youtube
	log("collimate cols, from:"+from+", cols:"+columns+", no of cols: "+no_of_cols+ ", list id: "+results_list_selector);
	var list=$(results_list_selector); // #search-results, #center_col, or #links
	//console.log("Container is ",list.length,$(results_list_selector),results_list_selector,	"No. of results under it:",$(indiv_res_selector).length,indiv_res_selector,$(indiv_res_selector));
	if (!list.length || !$(indiv_res_selector).length) {
		console.info("DGY.js.  No results/list for "+$(results_list_selector).length,$(indiv_res_selector).length);
		//if (from != "frtout") setTimeout(collimate,200, "frtout");
		//noFlicker();
		return;
	}
	collimate("putAtEndAndCollimate");
	var page=document.getElementById("page"); 
	if (page) page.setAttribute("style", "margin-left: 5px ! important");
	$("#page").css("padding-left", "10px");
	rm("#slim_appbar > *:not(:first-child)",true,true); //.slice(1)
}//end putAtEndAndCollimate

function collimate(from) { try{
	//console.log("collimate cols, from:"+from+", cols:"+columns+", no of cols: "+no_of_cols+ ", list id: "+results_list_selector+", indiv_res_selector:"+indiv_res_selector );
	if(from=="preform") {
		//console.log("preforming, width",window.innerWidth); //", list",list.length,$("#guide").length);
		if(youtube) {
			fixCss("#guide","display","none",true);
			fixCss("ytd-movie-renderer","display","none !important",true);
			fixCss(results_list_selector,"column-count",no_of_cols||2,true,"dgy-colcnt");
			return;
		} 
		if(ducklite) {	fixCss(".result--more",null,"position:absolute;bottom:0;",true);
					return; } //indiv_res_selector+=",td";                     //fixCss("#spinnerContainer","display","none",true);		//		if(youtube) 
		
		GM_addStyle2(indiv_res_selector+"   { max-width:"+(0.4*window.innerWidth|0)+"px;} "
				+"#page-manager             {margin-left:0;}  "
				+"ytd-search[center-results] > #container.ytd-search { justify-content:left; -webkit-justify-content:left; margin-top:4px;} " // display-block
					 ,"preform");
		GM_addStyle2(indiv_res_selector      
					 +"{ display: list-item;" //inline-block;    //inline-table; " //table;inline  "
					 +"float: left;"
					 +"text-overflow:ellipsis;overflow:hidden; "
					 +"clear:none !important;"
					 +"} ","iressel1");
		GM_addStyle2(indiv_res_selector+" *:not(img) { "                     //+":nth-child(2n+1) * { "
					 +"text-overflow:ellipsis; " //  overflow:hidden; "
					 +"vertical-align: top;"
					 +"} ","iresselnot1");
		GM_addStyle2(results_list_selector+"   { min-width:"+(window.innerWidth|0)+"px;} ","reslistsel");
		return;
	} //from preform
	if (! columns || no_of_cols<2) {
		return;
	}
	if(youtube) {
		$("dgy-colcnt").remove();
		let isScrolling;
		$(document).on("scroll keydown",function(e) {
			//console.log("key",e.key);
			if(e.type=="scroll")
				allButLast();
			return;
			//clearTimeout( isScrolling );			isScrolling = setTimeout(()=>{      			console.log("scrolled");				allButLast();			},50);
		});
		var inds=$(),lastOne=$();
		var orig_indiv_sel=indiv_res_selector;
		
		function allButLast() {
			var diff=$(orig_indiv_sel).not(inds);
			//console.log("#diff:"+diff.length+"\nLast one:",diff.last()[0]);
			if(diff.length) {
				//lastOne.removeClass("dgy-end-res").addClass("dgy-indiv-res");
				lastOne.toggleClass("dgy-end-res dgy-indiv-res");
				diff.addClass("dgy-indiv-res");
         		lastOne=diff.last();
				//lastOne.removeClass("dgy-indiv-res").addClass("dgy-end-res");
				lastOne.toggleClass("dgy-indiv-res dgy-end-res");
      			inds=inds.add(diff);
			} else console.log("no diff");
			console.log("#.dgy at end",$(".dgy-end-res").length, "#inds",inds.length,"total #indivs",$(orig_indiv_sel).length);
		}
		
		allButLast();
		indiv_res_selector=".dgy-indiv-res";
		GM_addStyle2(".dgy-end-res { clear:both; bottom:0; }","endres");
	}

	var list=$(results_list_selector); // #search-results, #center_col, or #links
	var full_reses=""+(indiv_res_not_padded_out||indiv_res_selector);
	
	
	//console.log("Container is ",list.length,$(results_list_selector),results_list_selector,	"No. of results under it:",$(indiv_res_selector).length,indiv_res_selector,$(indiv_res_selector));
	
	var winWidth=window.innerWidth-(plat_chrome?0:100);
	var msmargin=(duck ? "5px" : "1px");
	list.addClass("DGYcolsort");
	if (duck) { //////////////////////////////  duckduckgo cols  \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
		//indiv_res_selector="."+duckresultsclass;
		//fixCss(indiv_res_selector, "padding","10px 0px 10px 5px"); //needs 'px'es
		GM_addStyle2(".result__check { display:none;}");
		if (from && from[0]=="t"){
			var numbered=document.getElementsByClassName("icon_fav2");
			numbered=$(".icon_fav, .icon_fav2");
			for(var i=0;i<numbered.length;i++) {
				var el=numbered[i].firstElementChild;
				if(el) el.innerHTML = "<font size=1 style='opacity:0.4'>"+(i+1)+")</font>" + el.innerHTML;
			}
		}
	}//end if (duck) /////////////////////\\\\\\\\\\\\\\\\\\\\
	var margin=20,padding=0, no_to_packin=0;
	list.css({"left": 20, "box-sizing":"border-box"}); //, "padding":0, "border":0});//box-sizing is not inheritable.
	fitting=calcFitting(list, no_of_cols, no_to_packin, margin, (youtube?120:30));
	//fitting={"width":600, "height":300, "winwidth":window.innerWidth, "quantity":6, "margin":10 };
	
	if(youtube) GM_addStyle2("#page-manager {margin-left:0;} "
							 // +"ytd-search[center-results] #container.ytd-search {display:block;}"
							);
	if (duck) { fitting.width-=2; fitting.height-=2;} // setTimeout(x=>$(indiv_res_selector).css({paddingTop:"5px"}),1000); }
	GM_addStyle2(indiv_res_selector + "{ box-sizing:border-box;"
				 +"margin: 0px "+fitting.margin+"px "+fitting.margin+"px 0px !important;"
				 +"padding: "+(duck?0:0)+"px "+padding+"px "+padding+"px 0px;"
				 //+"border: 0 !important;"
				 //+"border: 1px solid red;" //transparent
				 +" }");
	
	list.css({"max-width":fitting.winwidth, "min-width": fitting.winwidth, "padding":0});
	list.css({margin: (fitting.margin||padding)+"px 0px 0px "+(fitting.margin||padding)+"px"}); // margin of a container pushes contents from its edge.
	//list.css({fontSize:fitting.height/4|0});
	//console.log("add styles els max width: ",fitting.width);
	GM_addStyle2(indiv_res_selector      
				 +"{ display: list-item;" //inline-block;    //inline-table; " //table;inline  "
				 +"float: left; max-width: "+(fitting.width)+"px;"
				 +"min-width: "+(fitting.width-5)+"px; "
				 +"text-overflow:ellipsis;overflow:hidden; "
				 +"clear:none !important;"
				 +"} ","iressel");
	GM_addStyle2(indiv_res_selector+" *:not(img) { "                     //+":nth-child(2n+1) * { "
				 +"max-width: "+(fitting.width)+"px;"
				 +"text-overflow:ellipsis; " //  overflow:hidden; "
				 +(!duck?"vertical-align: top;":"")
				 +"} ","iresselnot");
	GM_addStyle2(full_reses+"{"
				 +"max-height: "+fitting.height+"px;"
				 +(!false?"min-height: "+fitting.height+"px;":"")
				 +"}", "fullres");
	//console.log("Added col style for "+$(indiv_res_selector).length+" elements, width:"+fitting.width+", h: "+fitting.height+" indiv_res_selector:"+indiv_res_selector+", list ww:"+fitting.winwidth+", list: "+list+", results lists:"+list.length);
	document.body.style.wordWrap="normal";
} catch(e){console.log("Error in collimate",e);};
						 } //collimate()

function handleGoogle() {
	log("handleGoogle start");
	inhibitGoogleTracker();
	var matched;
	var change, dest1, dest=""+document.location;
	dest1=dest;
	$(".g a").removeAttr("onmousedown"); //Remove redirect to yt prior to going to href.
	if (vgoogle) {
		if (/so=[^1]/.test(dest))                    change=true;
		if ( ! /so=/.test(dest) )                         change=true;
		dest=dest.replace(/&so=\d/g, "");
		if ( dest && ! /&so=/.test(dest))          dest=dest.replace(/\?/,"?so=1&");
		if (columns) {
			if ( /view=[^1]/.test(dest))                 change=true;
			if (  ! /view=/.test(dest) )                    change=true;
			dest=dest.replace(/&view=\d/g, "");
			if ( dest && ! /&view=/.test(dest))      dest=dest.replace(/\?/,"?view=1&");
		}
	} else
		if (google) {
			if (goo_images) {
				setTimeout(function(){
					var links=$("a.rg_l, a.rg_fbl");
					links.each(convertHref);
				},1000);
			} //else mkLinksDirect($(".g").find("a:first"));
			if ( ! /resnum=0/.test(dest) ) {
				dest=dest.replace(/&resnum=\d/g, "&resnum=1");
				dest=dest.replace(/&tbs=(?!sbd)/g, "&tbs=sbd:1,");
				if ( dest != dest1)     change=true;
			}
		} //elseif(google)
	else { //else if vgoogle
		var sel=uwin.document.sFilter.maintab;//aol
		if (sel.selectedIndex!=3) {
			sel.selectedIndex=3;
			sel.onchange();
		}
	} ///end if/elses block
	if (change && ! /start=/.test(dest) )
		document.location=dest;
	$("#tads").remove();
	$("#mbEnd").remove();
	results_list_selector="#center_col";
	if (goo_cse) {
		results_list_selector="div.gsc-results";
		$("a[data-cturl]").each(function(){
			var href=$(this).data("cturl");
			//log("got href:"+href);
			href=href.split(/url\?q=|&/)[1];
			this.dataset.cturl=href; //cant use jquery on data.
			//log("set to:"+this.dataset.cturl);
		});
		fixCss("div.gsc-result *:not(img)","padding-bottom",7);
	}
	if (google) { //not vgoogle
		log("no vgoogle");
		var tbpi=document.getElementById("tbpi");
		if (tbpi && /^\W*Hide/.test(tbpi.textContent) && typeof unsafeWindow.google.Toolbelt == "function") 
			unsafeWindow.google.Toolbelt.toggle();
		pagelen=$(document).height()/2;
		putAtEnd("rhs");
		putAtEnd("wmxmsg");
		putToEnd("#bottomads");
		putToEnd(".gb_Rb"); //gb_2c, gb_ac, gb_g
		putToEnd("#gbw");
		putToEnd("#taw");
		rm("DIV#lb");
		rm("#footer");
		putToEnd(".kno-ftr");
		putToEnd("iframe",null,2000);
		fixCss("html","overflow","scroll");
		// var d=$(document);
		// d.on("keydown", function(e){
		// 	var alpha=window.innerHeight, aswitch={PageDown:alpha,PageUp:-alpha,ArrowDown:alpha/50,ArrowUp:-alpha/50,End:99999};
		// 	var top=d.scrollTop();
		// 	console.log("Caught event type:",e.type,"key:",e.key,"top",top,"asw",aswitch[e.key]);
		// 	d.scrollTop(top+aswitch[e.key]);
		// });
		rm("[role=dialog]");
		rm("div._OKe");
		rm("div._tN _fXg");
		rm("#botstuff");
		putToEnd(".gsc-adBlock");
		putToEnd(".gsc-adBlockNoHeight");

		rm("._cwc");
		rm("#cnso, #cnsi, #taw",true, true);	//rm("#cnsi",true,true);
		$(".ads-ad").remove();
		fixCss("#res",{margin: 0,padding:0});
		fixCss("#rhs","margin-left",0);
		putToEnd("#rhscol");
		fixCss("g-flippy-carousel",{left:5, width:"95%"});
		$(".g g-flippy-carousel").closest(".g").addClass("card-section");
		$(".bl").remove();
		fixCss("g-left-button", "left",-18);
		fixCss("g-right-button", "margin-top",-40);
		fixCss("#foot","float","left");
		fixCss("#iur","display","inline-block");
		fixCss("div.action-menu-panel", "top", "-20px", true); //action-menu-panel
		fixCss("div.action-menu-panel", "max-height", "55px", true); //action-menu-panel
		if (goo_images) return true;
		collimate("handleGoogle");         /////////////// >>>>>>>>>>>>>>>>>>>>>>
		if (fitting) fixCss("#imagebox_bigimages", {maxHeight:"100%"}) //fitting.height*1.5});
	} //end if (google)
	else if (vgoogle) {
		var tbh=document.getElementById("tbt-hide");
		if (tbh && ! invisible(tbh)) {
			clickElem(tbh);
		}
		var putatend=document.getElementById("suggestion-bottom");
		if (putatend) document.body.appendChild(putatend);
		var putatend=document.getElementById("youtube-text-container");
		if (putatend) document.body.appendChild(putatend);
		putatend=document.getElementsByClassName("message"); 
		for(var i=0; i < putatend.length; i++) document.body.appendChild(putatend[i]);
	}
	window.scrollBy(0,1);	window.scrollBy(0,-1);
	return true;
} //end handleGoogle;

function putAtEnd(idOrClassOrObj, class_name, obj, place) { //id parameter can also be a class name.
	if (!idOrClassOrObj.charAt) { return putAtEnd("","",idOrClassOrObj, null, place);}
	var putatend=$(idOrClassOrObj?"#"+idOrClassOrObj:"")[0];  // try as id
	if (putatend) 
		append(putatend, place);
	else {
		if (idOrClassOrObj) putAtEnd("", idOrClassOrObj, null, place);// try it as a class name
		var i=0;
		if (class_name) {
			putatend=$("."+class_name); 
			for(; i < putatend.length; i++) append(putatend[i],place);
			if (i) return true;
		}
		if (obj) { append(obj, place); return true;}
	}
	function append(el) {
		//log("putAtEnd #"+el.id+", class:"+el.className+", "+el+(place?" placed":""));
		if ( ! place) {
			document.body.appendChild(el);
			el.style.setProperty("position","relative","important");

		}
		else {
			var p=document.querySelectorAll(results_list_selector)[0];
			if(p) p.appendChild(el);
		}
		$(el).addClass("putAtEnd");
	} //append()
} //putAtEnd()

function putToEnd(selector,del,repeat) {
	var jels=$(selector);
	if(selector[0]=="#") jels=$("[id="+selector.substr(1)+"]");
	log("putToEnd "+selector,jels.length);
	if(del) jels.remove();
	else jels.appendTo(document.body);
	jels.addClass("putToEnd");
	jels.css({position: "relative",opacity:0.23});
	if (repeat) setTimeout(putToEnd,repeat,selector,del);
}

function fixPageLinks() { //Fix links to page 1,2 3...<next>, at bottom of page.
	if (!sorted_page) return;
	var pagers=$(".yt-uix-pager-button"), href=location.href;
	pagers.each(function(){
		var h=this.href, search_value;
		if (/search_sort/.test(h)) return false;
		search_value=href.split("search_sort=")[1].split("&")[0];
		this.href=h.replace("&","&search_sort="+search_value+"&");
	});
	if (/search_sort/.test(href)) {
		var search_value=href.split("search_sort=")[1].split("&")[0];
		$("#masthead-search-term").after("<input id=dgymst type=hidden name=search_sort value="+search_value+">");
		// window.addEventListener("click",function(e){
		// 	if ($(e.target).is("span.yt-uix-button-content"))
		// 		noFlicker(true);
		// });
	}
}//fixPageLinks()

// function noFlicker(start) {
// 	//log("noflick "+!!start+" parent len:"+$("#noFlicker").parent().length);
// 	if (noFlicker.disabled) return;
// 	if (start) {
// 		if (!noFlicker.el) {
// 			noFlicker.el=document.createElement("div");
// 			document.body.insertBefore(noFlicker.el,document.body.firstChild);
// 			noFlicker.el.id="noFlicker";
// 			noFlicker.el.style.cssText= "z-index:2999999999; padding-right:2000px;padding-bottom:2000px; position:absolute; background-color: white;";
// 		} else 	noFlicker.el.style.setProperty("display","block"); //$(noFlicker.el).prependTo("body");
// 	}
// 	else 
// 		setTimeout(function(){$(noFlicker.el).css("display","none");},100); //put to end of exec queue.
// }

function GM_addStyle2(style, id) { //precedence: !important, as tag attribute, more specific selectors, <script> elements later in doc.
	//console.log("Add style id:", id,", style:",style);
	//GM.addStyle(style);
	//var s=$("head style:last");
	//s.addClass("GM_Style");
	//	$("head").prepend(s);
	//$("body").append(s);
	let el = document.createElement('style');
	el.setAttribute('type', 'text/css');
	el.textContent = style;
	if (!document.body)
		document.head.insertBefore(el,document.head.firstChild);
	else document.body.appendChild(el);
	//if (id) s[0].id=id;
	if(id) el.id=id;
	//console.log("added",el,document.head.childElementCount);
}

function fixCss(sel, name_Or_obj, value, perm,id) { //allows logging.
	//log("fixCss:"+sel+", "+name_Or_obj+", "+value+" #els:"+$(sel).length);
	if (value !== null) {
		if (perm)
			if(name_Or_obj)
				GM_addStyle2(sel + "{ "+name_Or_obj+":"+value +"}",id);
		    else GM_addStyle2(sel + "{ "+value +"}",id);
		else 
			$(sel).css(name_Or_obj,value); // a name
	}
	else
		$(sel).css(name_Or_obj); //an object;
}


function rm(sel, hide, perm){
	//log("rm "+$(sel).length+" "+sel+" hide:"+hide);
	if (perm) GM_addStyle2(sel+" {display:none !important;}");
	if (hide) $(sel).css("display","none");
	else $(sel).remove();
}

function removeIdClass(id, class_name) {
	var putatend;
	if (id) {
		putatend=document.getElementById(id);
		if (putatend) putatend.parentNode.removeChild(putatend);
	}
	if (class_name) {
		var el,i=0,els=document.body.getElementsByClassName(class_name);
		while (els.length){
			el=els[i];
			el.parentNode.removeChild(el);
		}
	}
}

function regMenu() {
	//    if (!plat_chrome)
	//console.log("regMenu this:",typeofObj(this));
	submenuModule.register("DGY columns & Sort by Date");
	//try { submenuModule.register("DGY columns & Sort by Date"); } catch(e) {}; // if site down and update needed?
	GM_registerMenuCommand( "========Sort By Date======", function(){});
	GM_registerMenuCommand("Youtube sort by date -- Toggle collimation ["+!!columns+"].", function() {
		columns^=true;
		GM_setValue("columns", columns);
		alert("Collimation "+(columns?"on":"off")+", at "+location+", reload to see effect.");
	});
	GM_registerMenuCommand("Set number of columns ["+no_of_cols+"]...", function() {
		columns^=true;
		var reply=prompt("Set number of columns to display ( >0 )",no_of_cols);
		reply=parseInt(reply);
		if (reply > 0) GM.setValue("no_of_cols", reply);
	});
	if (duck) GM_registerMenuCommand( "Change result snippets' font size", function() {
		var cv=snippetFontSize(null,true);
		var res=prompt("Give below the new font size in percent, use zero to reset.",cv).replace(/\D*/g,"");
		snippetFontSize(res);

	});
	GM_registerMenuCommand( "Don't show results from...", function() {
		sprompt("Enter name of server domain whose result you no longer "
				+"wish to see.\n Current set of domains set to not show up in results:\n"+blocked_domains.join("\n")
				+"\nIf name entered is already on list it'll be removed.",
				"", function(reply) {
					if (!reply) return;
					var already_domain=blocked_domains.indexOf(reply);
					if (already_domain!=-1)
						blocked_domains.push(reply);
					else
						blocked_domains=blocked_domains.splice(already_domain,1);
					GM.setValue("blocked_domains",blocked_domains);
					blockDomains();
				});
	});
	GM_registerMenuCommand( "_____________________________________", function(){});
}

function convertHref(){ //from an $("a").each(), a has .rg_l , takes direct to image not via yt.
	// .find("img").removeAttr("jsaction");
	//console.log("convertHref ",this);
	fixhref(this);
	if (!convertHref.listener) {
		//convertHref.listener=true;
		// nodeMutationListener(document, "a.rg_l", function(nodes) { //document is target since lower ones get renewed.
		// 	//log("New link(s) <a> at gooimg, mutated:"+nodes.length+" "+nodes[0].parentNode.dataset["ri"] +" th: "+nodeInfo(nodes[0]));
		// 	for(var i=0; i<nodes.length;i++) 
		// 		fixhref(nodes[i]);
		// });
	}
	function fixhref(el) {
		$(el).removeAttr("jsaction"); //prevents http calls to google when hovering over image.
		var ref=decodeURIComponent(el.href);
		var pindex=ref.indexOf("&imgrefurl=",1);
		if (pindex==-1) pindex=ref.indexOf("&imgurl=",1);
		if (pindex==-1) return;
		var ref2=ref.substring(pindex+11);
		ref2=ref2.replace(/&.*/,"");
		//console.log("fixhref, change ",el.href, "to",ref2);
		$(el).addClass("dgy-href-direct");
		el.href=ref2;
	}

	//that.attr("oldhref",ref);
	//log(convertHref.count+" set to "+ref2+"\t.Was:"+ref);
	//window.status="href fix:convertHref:"+convertHref.count;
};


function mkLinksDirect(links) { //capture events so google doesn't send them to google.com.
	if (!mkLinksDirect.ev) { // && false) {
		mkLinksDirect.ev=true;
		function catchEvent(type,obj){
			if (!obj) obj=window;
			//log("Catch "+type+", on:"+obj);
			obj.addEventListener(type, function(e){
				var parent=""+e.target.parentNode, src=e.target.src||"", text=e.target.textContent||"";
				if (src) src=src.substring(0,40);
				if (text) text=text.substring(0,40);
				// log(" Event: "+e.type+", currentTarget:"+e.currentTarget+", target:"+e.target+", parent:"+parent.substring(0,40)
				//     +", cancelable:"+e.cancelable+", eventPhase:"+e.eventPhase
				//     +", bubbles:"+e.bubbles+", listener:"+(obj||window)
				//     +", src:"+src+", text40:"+text+", href:"+e.target.href
				//    );
				if (/click/.test(e.type))
					if (e.target.href) {
						var href=decodeURIComponent(e.target.href), dhref;
						dhref=href.split("&url=")[1]||"";
						dhref=dhref.split("&")[0];
						if (dhref) href=dhref;
						if (href && e.button==0) document.location=href;
						else if (href && e.button==1) window.open(href, '_blank');
					}// end if(href)
				else return; //allow click through if not going to a href.
				if (e.target.value===undefined) {
					//log("Blocking "+e.type+" "+e.target+" "+typeof e.target.value);
					e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation();
				}
			},true);
			obj["on"+type]=function(e){
				//log("--"+e.type);
			};
		}//catchEvent()

		// ar=["click", "blur", "focus" , "unload","pagehide", "popstate",
		//     "pageshow","focus","mousedown","message","open","mouseup","toggle",
		//     "resize", "visibilitychange", "orientationchange", "touchstart", "mouseup",
		//     //"webkitvisibilitychange",
		//     "DOMFocusIn", "DOMFocusOut" ];
		//
		//clicks, focus, blur, visibilitychange and resize events: google sends marketing data etc. back to google.com.  It also send a message every 30 secs to google.
		var ar=["click","blur","focus", "visibilitychange", "resize"];
		// for (i in ar) catchEvent(ar[i]);
		// for (i in ar) catchEvent(ar[i], document);
		//var html=document.documentElement; //also used by google.
	}
}

function inhibitGoogleTracker() {
	var i, end_id=setInterval(null), begin_id=inhibitGoogleTracker.si_begin;
	if (!inhibitGoogleTracker.si_begin) {
		inhibitGoogleTracker.si_begin=setInterval(null);
		navigator.__proto__.sendBeacon=function(){ log("Attempt to sendbeacon");return true;};
	}
	else {
		for (i=begin_id; i<=end_id;i++) setTimeout(function(){
			clearInterval(i); //google sends back marketing messages with setInterval.
			//console.log("Cleared intervals:"+begin_id+"-"+end_id);
		},10000);
		// $("form").each(function(){
		//     this.addEventListener("submit", function(){log("Submit or not?")});
		//     this.addEventListener("blur", function(){log("blur form or not?")});
		//     this.addEventListener("focus", function(){log("focus form or not?")});
		// });
		// var setint=window.setInterval;
		// window.setInterval=function(f,t){
		//     //log("setInterval "+f+" "+t);
		//     setint(f,t);
		// };
	}
}

function invisible(elem){ return getComputedStyle(elem, null).display=="none";  }
function clickElem(elem) {
	var pseudo_event = window.document.createEvent("MouseEvents");
	// type,    canBubble, cancelable,  view,      detail,           screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget)
	pseudo_event.initMouseEvent("click", true,            true,            window, 0,                   0,   0,                       0,      0,                false,   false, false,    false,                0,           null);
	elem.dispatchEvent(pseudo_event);
}

function getById(id) {
	var el=window.document.getElementById(id);
	return el;
}

function justify (max_line, char) {
	if (this.length<=max_line) return this;
	var res="", last_newline_pos=0;char=char||" ";
	this.split(char).forEach(function(v, i, ar){
		res+=v;
		if (i==ar.length-1) return;
		if (res.length-last_newline_pos >= max_line) {
			res+=(/\s/.test(char)?"":char)+"\n"; last_newline_pos=res.length; }
		else res+=char;
	});
	return res;
};
function vscroll(y) {
	var factor=1;
	if (y>0) for (; y >= 0; y--)
		window.scrollByLines( 1);
	else for (; y <= 0; y++)
		window.scrollByLines( -1);
}
function childids(el) {
	roll="";
	if (el.children) {
		for (var i=0;i<el.children.length;i++)
			if (el.children[i].id)
				roll+=el.children[i].id+" ";
	}
	if (roll) roll="childids:"+roll;
	return roll;
}

function calcFitting(container, ncols, quantity, margin, minHeight) {
	//console.log("calcFitting"+JSON.stringify(arguments));
	var w, ww=$(window).width()-container.position().left, h, wh=$(window).height(), device_size,
		total_margins, area, colmratio, nrows, rowmratio, new_margin=margin;
	ww*=0.95; //prevent scrollbar
	if (!quantity) {
		quantity=device_fit()*0.8;                                          // box sizing by default is content-box, padding, border and margin are excluded from width/height values (& their max'es), "box-sizing: border-box" includes all except margin.
		new_margin=margin*(quantity/margin); //eg, m=20 & q=20 gives factor = 1, margin reduced smaller for q.
	}
	if (!minHeight) minHeight=10;
	while (quantity>=2) {
		setDims();
		//log("Fitting "+(quantity|0)+" within container of WxH:"+(ww|0)+"x"+(wh|0)+", try width:"+(w|0)+", height:"+(h|0)+", margin:"+(new_margin|0)+", device:"+device_size);    //a container, eg, table, despite 'box-sizing:' its size is affected in reverse by margin size and not by padding size (box-sizing: excludes only margin fro size)
		if (h>=minHeight) break;
		quantity=quantity*.8|0;
		new_margin=margin*(quantity/margin);
	}
	function setDims() {
		area=ww*wh; colmratio=(ncols+1)/ncols;  nrows=quantity/ncols; rowmratio=(nrows+1)/nrows;
		total_margins=(ncols+1)*new_margin;
		w=(ww-total_margins)/ncols;
		h=((area/quantity)/(w+colmratio*new_margin))-rowmratio*new_margin;
	}//setDims()

	function device_fit() {
		var dw=innerWidth, dh=innerHeight;
		device_size=dw*dh/100000;
		return Math.exp(device_size*.0930525)*6.17212;
	}
	//console.log("fitting:", {"width":w|0, "height":h|0, "winwidth":ww|0, "quantity":quantity|0, "margin":new_margin|0 });
	return {"width":w|0, "height":h|0, "winwidth":ww|0, "quantity":quantity|0, "margin":new_margin|0 };
} //calcFitting()

function snippetFontSize(res,currentvalue) {
	if (currentvalue) return ddgcrsfs_glob||74; //GM_getValue("ddgcrsfs",74);
	if (res==undefined ) {
		var ddgcrsfs=ddgcrsfs_glob;  //GM_getValue("ddgcrsfs",false);
		if(ddgcrsfs) GM_addStyle2( ".result-snippet { font-size:"+ddgcrsfs+"%;}","ddgcrsfs");
	} else if (res!=0) {
		GM_addStyle2( ".result-snippet { font-size:"+res+"%;}","ddgcrsfs");
		GM.setValue("ddgcrsfs",res);
	} else if (res==0) { $("#ddgcrsfs").remove(); GM.deleteValue("ddgcrsfs"); }
}

function typeofObj(unknown_obj){ return ({}).toString.call(unknown_obj); }
function sprompt(pretext,initval,cb,cancelbtnText="Cancel",okbtnText="OK") { // "Cancel" has reply of false or null (if a prompt), "OK" gives reply of true or "", Escape key returns undefined reply.  undefined==null is true. but not for ""
	var input_tag, input_style="width:80%;font-size:small;";
	var confirm_prompt=initval===undefined;
	if (!confirm_prompt) input_tag=initval.length<50 ? "input" : (input_style="width:95%;height:100px;","textarea");
	if (!cb) cb=x=>x;
	var content=$("<div class=sfs-content tabindex=2 style='outline:none;white-space:pre-wrap;'>"
				  +"<div style='max-height:"+(window.innerHeight*0.72)+"px;'>"+pretext+"</div>"
				  +(initval!==undefined ? "<"+input_tag+" spellcheck='false' style='"+input_style+"'  tabindex='1'></"+input_tag+">":"")+"</div>");
	content.find("input:not(:checkbox),textarea").val(initval);
	content.resizable();
	var sp1=$(document).scrollTop();
	var dfunc=content.dialog.bind(content);
	var dialog=content.dialog({
		modal: true, width:"60%", // position: { my: "center", at: "center center-25%", of: window }, // Greater percent further to top.
		buttons: {
			[cancelbtnText]: function(e) { if (confirm_prompt) cb(false); else cb(null, $(this).find("input,textarea").val()); dfunc("close"); return false;},
			[okbtnText]: function(e) {  if (confirm_prompt) cb(true); else cb( $(this).find("input,textarea").val() || ""); dfunc("close"); return false;}
		},
		close: function(e) { dialog.off("keydown"); $(document).scrollTop(sp1); if (e.key=="Escape") cb(undefined); dfunc("destroy");}  // Called from jQ by Escape, trigger with Event("keydown")
	}).parent();
	if (cancelbtnText==-1) { dialog.find("button").each(function(){   if (this.textContent=="-1") $(this).remove(); }); }
	dialog.wrap("<div class=sfs-sprompt></div>"); // allows css rules to exclude other jqueryUi css on webpage from own settings, a
	dialog.keydown(function(e){	if (e.key == "Enter" && !/textarea/i.test(e.target.tagName)) $("button:contains("+okbtnText+")",this).click();  }); 
	dialog.css({"z-index":2147483647, position:"fixed", top: "50px" });
	dialog.find(".ui-dialog-titlebar").remove(); // No img in css for close 'x' at top right so remove.  Title bar not in normal confirm anyhow.
	dialog.draggable("option","handle", ".ui-dialog-buttonpane"); //
	dialog.resizable();
	setTimeout(function(){var ips=dialog.find("input,textarea");if (ips.length) ips.focus(); else content.focus();},100);
	return dialog; //.ui-dialog
}
function sconfirm(msg,cb,cancelbtnText,okbtnText) { return sprompt(msg,undefined,cb,cancelbtnText,okbtnText); }
function salert(msg,cb) { return sprompt(msg,undefined,cb,-1,"OK"); }


var jqueryui_dialog_css=(
	""
		+".ui-dialog-content,.ui-dialog,.ui-dialog textarea { font-size: 12px; font-family: Arial,Helvetica,sans-serif; border: 1px solid #757575; "
		+"    background:#002000; color:#ccc; padding:12px;margin:5px; } "
		+".ui-dialog-buttonpane { font-size: 10px; cursor:move; border: 1px solid #ddd; overflow:hidden; } "
		+".ui-dialog-buttonset { float:right; } "
		+".ui-widget-overlay { background: #aaaaaa none repeat scroll 0 0; opacity: 0.3;height: 100%; left: 0;position: fixed;  top: 0; width: 100%;}"
		+".ui-button,.ui-widget-content { text-align:left; border: solid 1px #757575; padding: 6px 13px;margin: 4px 3px 4px 0;} "
		+".ui-corner-all, .ui-dialog-buttonpane { border-radius: 5px; border-bottom-left-radius:30px; }"
		+".ui-button:hover { background-color: #ededed; } "
		+".ui-button { background-color: #f6f6f6;color:#333;}"
		+".ui-dialog {position:absolute;padding:3px;outline:none;}"
		+".ui-resizable-handle { position:absolute; cursor: url(data:image/svg+xml;base64,"
		+"iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAAAAACo4kLRAAAACXBIWXMAAAsTAAALEwEAmpwYAAABAUlEQVQY022RsWrCYACEvz9EK1HQCilYu+jWdNKlj9BNN1/Cp/IBFHTMExihdTCIm0sR26W6KNHkvw6lunjLjffdnXn7fG0/PzzeG0A/m+/Ve/REB3CL/laStn7RBTpOG0iTXgWg0ktSoO20DJDv5gBy3TxgWkQFAG+QSdnAAyhErMtuFSiN0nRUAqpuec2x2V/4YOr7fd2AH/ebR+zhbMOaCWJrF4GphfZ8sEhSNm3EVrJxY5pJkhGAkjtzNRxuyAGws2Ap0DKYWYDbQRek3e6K9A8/TNPhBf5mzbEBvDCTpCz0ADN25gJOkzPAeXICNL85spu8/N0B8LDafK0+ouQXfemVYVtdIewAAAAASUVORK5CYII="
		+") 10 10, row-resize; } .ui-resizable-sw {bottom:5px;left:5px;}"
		+".ui-resizable-w, .ui-resizable-e { width:10px;height:100%;top:-5px;} .ui-resizable-n, .ui-resizable-s { width:100%;height:10px;} .ui-resizable-n {top:-5px; } .ui-resizable-w {left:-1px; } .ui-resizable-e {right:-15px; }"
		+".ui-tooltip { font-size: 7px; }"
		+".sfswe-ticks * {font-size:11px;padding:0px;margin:2px;}"
		+".ui-dialog .sfs-content { position:static; overflow:auto;}"
		+ (str=>str+str.replace(/-moz-/g,"-webkit-"))(
			".sfs-content :-moz-any(div) { font-size:13px;padding:6px;margin:4px 3px 4px 0;color:#ccc;}"
				+".sfs-content :-moz-any(textarea,input) { font-size:13px;padding:6px;margin:4px 3px 4px 0;color:#eee;background-color:#002a00;}"
				+".sfs-content :-moz-any(span) { font-size:13px;padding:0;margin:0;color:#ccc;}"
				+".sfs-content :-moz-any(a,a:visited) { color:#ccc;text-decoration:underline; padding:0;margin:0;}")
		+".sfs-content a:hover {opacity:0.5;}")
	.replace(/\.ui/g,".sfs-sprompt .ui"); //prefix classes with namespace prevent interference.

async function loadJsResources() {  // loadJsResources allows the optional loading of js files unlike @require, it loads all js files listed as @resource.  In FF57.0.4 GM_getResourceText of resource urls from getResourceUrl was hanging.
	const metadata=(gm4 ? GM.info : GM_info).scriptMetaStr;
	const resar=metadata.split("// @resource ").slice(1);
	for (const r of resar) { await loadcode( (r.match(/http.*\.js\s*$/m)||[""])[0].trim());  }
	async function loadcode(url) { 
		if(!url) return;
		var etag=await myFetch(url,"HEAD"),strfy=JSON.stringify;
		//console.log(gm4,"Loadcode() --eval:",url,"ETag:",etag);
		var defaultval=strfy({src:"",tag:0});
		var str=gm4 ? await GM.getValue(url,defaultval) : GM_getValue(url,defaultval);
		var codeandtag=JSON.parse(str);
		if (etag!=codeandtag.tag) { 
			let resptxt=await myFetch(url);
			console.log("cache MISS, TAGS:",etag,"!=",codeandtag.tag,". Miss for ",url," Re-got:",resptxt.substr(0,50));
			if(!resptxt) console.log("Error getting ",url);
			else { 
				codeandtag={src:resptxt,tag:etag};
				let store_args=[url,strfy(codeandtag)];
				gm4 ? GM.setValue(...store_args) : GM_setValue(...store_args);
			}
		} //else console.log("cache HIT for "+url);
		//console.log("Eval in async loadcode, this==window?",this==window,typeofObj(this));
		try{ eval.call(this,codeandtag.src); } catch(e) {console.log("Eval of js Resource failed,",e.lineNumber,e);}
	}

	async function myFetch(url,method) {
		//console.log("myFetch",method,url);
		var resolver, promise=new Promise(r=>resolver=r);
		var reqobj={};
		reqobj.method=method||"GET";
		reqobj.url=url;
		reqobj.onload=function(response){
			var etag=extractETag(response.responseHeaders);
			if(reqobj.method=="HEAD") 
				resolver(etag);
			else resolver(response.responseText);
		};
		reqobj.onerror=reqobj.onabort=reqobj.ontimeout=e=>resolver(""); //console.log("Problem request, status unexpected "+e);
		gm4 ? GM.xmlHttpRequest(reqobj) : GM_xmlhttpRequest(reqobj);
		return promise;
	}

	function extractETag(headers){
		var etag=headers.search(/[\r\n]{2}[Ee][Tt]ag/);
		etag=headers.substr(etag+8);
		etag=etag.substr(0,etag.indexOf("\r\n")-1);
		etag=etag.substr(etag.indexOf('"')+1);
		return etag;
	}

	async function dumptagdb() {
		const metadata=(gm4 ? GM.info : GM_info).scriptMetaStr;
		const resar=metadata.split("// @resource ").slice(1);
		for (const r of resar) { 
			var jsfile=(r.match(/http.*\.js\s*$/m)||[""])[0]; 
			if(jsfile) 	{
				var defaultval=JSON.stringify({src:"",tag:0});
				let str=gm4 ? await GM.getValue(jsfile,defaultval) : GM_getValue(jsfile,defaultval);
				var codeandtag=JSON.parse(str);
				//console.log(jsfile+"\n"+codeandtag.tag+"\n"+codeandtag.src.substr(0,50).replace(/\n/g," "));
			}
		}
	}
}

function chromeInit() {
	window.plat_chrome=false;
	//if (!this.GM_getValue || "Barychelidae"!=GM_getValue("arachnoidal","Barychelidae")){ //chromium
	if (/Chrome/.test(navigator.userAgent)) {
		console.info("DGY userscript in non GM_ mode for chrome/safari etc.",this);
		window.plat_chrome=true; window.unsafeWindow=window;
		this.GM_getValue=function(a,b) { return localStorage[a]||b; };
		this.GM_setValue=function(a,b) { localStorage[a]=b; };
		this.GM_registerMenuCommand=x=>null;
		this.uneval=function(x) { return "("+JSON.stringify(x)+")";  }; //Diff is that uneval brackets string and json excludes code only data allowed in json.
		var xhr_queue=[], xhr=new XMLHttpRequest(), next_inqueue;
		xhr.onload=x=> { //arrow function means this remains window not xhr (as a function would).
			//console.log("eval in this.  this==window?",this==window);
			eval.call(this,xhr.response);
			if (next_inqueue=xhr_queue.shift()) {  xhr.open('GET', next_inqueue); xhr.send(); }
			else loader();
		};
		xhr.onerror=e=>console.log("XHR Error",e);
		xhr_queue.push("https://raw.githubusercontent.com/SloaneFox/code/master/gm4-polyfill-1.0.1.js");
		xhr_queue.push("https://code.jquery.com/jquery-3.2.1.js");
		xhr_queue.push("https://code.jquery.com/ui/1.12.1/jquery-ui.js");
		xhr_queue.push("https://raw.githubusercontent.com/SloaneFox/code/master/gm-popup-menus-1.3.6.js");
		xhr.open('GET', xhr_queue.shift()); xhr.send();

		return true;
	} else 
		return false;
} // chromeInit()