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

// ==UserScript==
// @name DGY Duckduckgo/Google Columns & YouTube Sort by date
// @version      2.2.7
// @updateURL    https://openuserjs.org/meta/slow!/DGY_DuckduckgoGoogle_Columns_YouTube_Sort_by_date.meta.js
// @namespace    DGY
// @run-at       document-end
// @description  Sort by date as default acout 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-only
// @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
// @require  https://code.jquery.com/jquery-3.2.1.js
// @require  https://code.jquery.com/ui/1.12.1/jquery-ui.js
// @require  https://raw.githubusercontent.com/SloaneFox/code/master/gm4-polyfill-1.0.1.js
// @require  https://raw.githubusercontent.com/SloaneFox/code/master/gm-popup-menus-1.4.0.js
// ==/UserScript==

// @updated       Spet 2020. Removed div.module blocking access to top of page links.
// @updated       July 2018. Increased minimum height of result at DDG
// @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, &search_sort=relevance
// @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), "head",document.head);
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;  // will  progress to &sp=CAI%253D.  %253D is hex indicator for CGI: %3D, an equals '='
if (/sp=CAI/.test(location.search)) sorted_page=true;
if (/zimyt/.test(location.search)) reflexive=true;         // zimty=2 is the marker of DGY processed.
$("#search").on("keyup", x=>console.log(221199883344,x.key) );

function secsSinceEpoch() {
    return ((new Date).getTime()/1000).toFixed(0);
}

var prev_tstamp;
if(ss.dgy_lsecs) {
    console.log("have date",ss.dgy_lsecs);
    prev_tstamp=ss.dgy_lsecs;
    ss.dgy_lsecs=secsSinceEpoch();
} else { 
    console.log("no dgy_lsecs",);
    ss.dgy_lsecs=secsSinceEpoch();
    prev_tstamp=ss.dgy_lsecs - 5;
}

function seconds_diff() { return secsSinceEpoch() - prev_tstamp;}

console.log("ss.dgy_lsecs",ss.dgy_lsecs, "diff to prev load :",seconds_diff());

if (seconds_diff() < 5 ) { 
    console.log("diff < 5"); 
    return; 
}

if(youtube && results_page && !sorted_page && ! reflexive) {

	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"+"&sp=CAI%253D";
	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;}


// Two key selectors, one for eaech list item and one for list container:
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);

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, pagelen, 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();
	log("loader readystatechange ====> ",document.readyState,`, head is::${document.head}`); 	//," no.of ",indiv_res_selector,"=",$(indiv_res_selector).length);

	await init_globs();
	log("awaited globs, ",document.readyState,indiv_res_selector, "#:",$(indiv_res_selector).length);

	if (/complete|interactive/.test(document.readyState) 
		&& ( $(indiv_res_selector).length || ducklite)) { 
		log("dlite or indiv_res_selector",indiv_res_selector);
		mainline();}      
	else document.addEventListener("readystatechange",x=>{
		log("loader() END.  Event readystatechange ====> ",document.readyState);
		//		if(document.readyState=="interactive") mainline();// collimate("preform"); 
		//if(document.readyState=="complete") mainline();
		mainline();
	});
} catch(e){console.log("Error in loader",e);}};

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

	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;
		});
		$('[aria-label="Search filters"]').click();		//let filter=$("a.filter").get().find(ael=>/relevance/i.test(ael.textContent));		//if(filter) filter.href+="&search_sort=relevance";
		setTimeout(x=> {
			var as=$("a").get().find(el=>/relevan/i.test(el.textContent.trim()));
			if(as) as.href+="&search_sort=relevance";
			else console.log("At youtube no filters to fix.");
		},0);
		$('[aria-label="Search filters"]').click();
	}
	log("DGY main done.");
	//	},0);
	blockDomains();
    setTimeout(x=>$(window).scrollTop(scrollPos),250); //restores
} catch(e){console.log("Error in main",e,e.stack);}}

function bodymsg(msg) {
	var b=$("body");
	if(!msg) {
		b.attr("dgy-msgs","[]");
		console.log("insertPageFunc:",typeof insertPageFunc, typeof removeIdClass);
		insertPageFunc(function bodymsg() { 
			console.log("DGY stored messages:");
			JSON.parse($("body").attr("dgy-msgs")).forEach(el=>console.log(el));
		});
	}
	else { 
		prev_msg_ar=JSON.parse(b.attr("dgy-msgs"));
		prev_msg_ar.push(msg);
		b.attr("dgy-msgs",JSON.stringify(prev_msg_ar));
	}
}

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>
	console.log("Blocking domains",blocked_domains);
	blocked_domains.forEach(function(v, i, ar){
		console.log("check for domain:",v);		//var span=$("span.result__url__domain:contains("+v+")");
		var jqincantation="[data-domain]:contains("+v+")";
		var div=$(jqincantation);
		console.log("Got div",div, "from jqincantation",jqincantation);		//span.closest(".result").remove();
		div.remove();
	});
}

function putAtEndAndCollimate(from) { 
	//console.log("putAtEndAndCollimate from:"+from+", iframe: "+iframe,"indiv_res_selector",indiv_res_selector,"results_list_selector",results_list_selector);
	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();
		var zero="#zero_click_wrapper";
		//zero.css({maxHeight: "unset",fontSize:"x-small"});
		rm(zero);
		//$(indiv_res_selector).eq(0).before(zero);
		//putToEnd(".result--more");
		fixCss("#zci-videos","display","none",true,"yt-guide");
		putToEnd(".results--sidebar");
		putToEnd(".module--news");
        putToEnd(".results--ads");
		putToEnd("div.module");
		putToEnd(".related-searches");
		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) {
		log("put to end video-ads ytp-ad-module");
        putToEnd(".module--images");
		putToEnd(".video-ads .ytp-ad-module");
		rm(".ytd-carousel-ad-renderer");
		rm(".ytd-horizontal-card-list-renderer");
		putToEnd("#guide");
		putToEnd(".yt-consent");
		rm("paper-dialog",0,true);
		rm("iron-overlay-backdrop",0,true);
		rm(".td-consent-bump-lightbox");
		rm("#consent-bump");
		//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");
			//doubleAct();
			setTimeout(doubleAct,2000);
			function doubleAct() {
				putAtEnd ("ytd-mini-guide-renderer");
				//putAtEnd("ytd-item-section-renderer");
				//putAtEnd("ytd-continuation-item-renderer");
                window.scrollTo(1,0);
				console.log("doubleAct");
			}
			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
	console.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") {  // for the 'else' see DGYcolsort far below
		console.log("preforming, width",window.innerWidth); //", list",list.length,$("#guide").length);
		if(youtube) {
			fixCss("#guide","display","none",true,"yt-guide");
			//fixCss("ytd-movie-renderer","display","none !important",true,"yt-ytd");
			//fixCss("ytd-movie-renderer","display","list-item !important",true,"yt-ytd");
			//fixCss("ytd-movie-renderer","float","left !important",true,"yt-ytd2");
			fixCss(results_list_selector,"column-count",no_of_cols||2,true,"dgy-colcnt"); // Is removed later.
			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) {
		log("Collimate adter preform",$(indiv_res_selector),$(results_list_selector));
		log("css id yt-ytd2",$("#yt-ytd2")[0], "BADges:",$("[id=badges]").length);
		$("#dgy-colcnt").remove();
		fixCss("[id=badges]","display","none", true, "bdg22");
		fixCss(indiv_res_selector+" paper-button","display","none", true, "pb22");
		//$("[id=badges]").remove();
		log("head is ",$("head"), "bgg id",$("#bdg22"));
		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;}","dcheck");
		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, minHeight=youtube?120 : duck? 120 : 30;
	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, minHeight); //(youtube?120:30));
	//fitting={"width":600, "height":300, "winwidth":window.innerWidth, "quantity":6, "margin":10 };
	
	if(youtube) GM_addStyle2("#page-manager {margin-left:0;} ","ytpm"
							 // +"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
				 +" }","irsbox");
	
	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; "
				 +"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;" // no height makes gaps but with height cuts longer blurbs short.
				 +(!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,e.stack);};
						 } //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();
	$("g-section-with-header").remove();
	$("ytd-horizontal-card-list-renderer").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.
	let el = document.createElement('style');
	el.setAttribute('type', 'text/css');
	el.textContent = style;
	if (!document.body) {
		console.log("No body, head?",document.head,"adding id:",id);
		if(document.head)
			document.head.insertBefore(el,document.head.firstChild);
		else console.log("Cant add css ",style);
	}
	else document.body.appendChild(el);
	if(id) el.id=id;
	//console.log("added style",style,"id",id, "is",el.id);
}

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($(sel).length) bodymsg("rm'ed "+sel);
 
	if (perm) GM_addStyle2(sel+" {display:none !important;}","selrm");
	if (hide) $(sel).css("display","none");
	else $(sel).remove();
}

function insertPageFunc(func) {
	$("head").prepend("<script>"+func.toString()+"</script>");
}

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(){});
	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.");
	});
	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) 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);

	});
	registerMenuCommand( "Don't show results from...", function() {
		sprompt("Enter name of server domain whose results\nyou no longer wish to see, eg, codeburst.io "
				+"\n\t\tCurrent set of domains set to not show up in results:\n"+blocked_domains.join("\n")
				+"\nIf domain entered is already on our list it will get removed.",
				"", function(reply) {
					console.log("Dont show resuklts from, reply:",reply);
					if (!reply) return;
					var already_domain_pos=blocked_domains.indexOf(reply);
					if (already_domain_pos==-1)
						blocked_domains.push(reply);
					else
						blocked_domains=blocked_domains.splice(already_domain_pos,1);
					GM.setValue("blocked_domains",blocked_domains);
					console.log("Saved 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"); }



function chromeInit() {
	window.plat_chrome=false;
	//if (!this.GM_getValue || "Barychelidae"!=GM_getValue("arachnoidal","Barychelidae")){ //chromium
	//if (/Chrome/.test(navigator.userAgent)) {
	if (GM=="undefined") {
		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()