dev_note_search2

searching notes!

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name       		dev_note_search2
// @namespace  	 	dev_note_search2
// @description 	searching notes!
// @match       	http://*.deviantart.com/notifications/notes/*
// @match       	https://*.deviantart.com/notifications/notes/*
// @version     	1.1.18
// @author			http://dediggefedde.deviantart.com
// @grant			none
// ==/UserScript==



function injected(){ 

var mapfolder=[];
var mapwords=[];
    
//speed up indexing notes!
//Amount of notes requested on each index-cycle.
//But: progressbar can only update once a cycle!
	//numbers for a 380 Notes Scan:
	//370:	4884 ms needed	- 77,8 Notes/s
	//100:	6487 ms needed	- 58,6 Notes/s <-standard
	//50:	7950 ms needed	- 47,8 Notes/s
	//10:	17714 ms needed	- 21,5 Notes/s
	
//if you've got around 10.000 Notes (default: 2.8 min) you can reduce the time by settings this number higher!
//Any Value above 100 will increase the update-speed and decrease how often the Progressbar is updated.
//Any Value above your total amount of Notes won't make a difference.

var note_index_steps=100;


if (typeof uneval === "undefined") {
    uneval = function(a){
 	   return (JSON.stringify(a))||'';
    };
}

//remove the /* and */ and reload to remove all stored data!
//Put them back to use the script afterwards!
/*
	var keys = GM_listValues();
	for (var i=0, key=null; key=keys[i]; i++) {
	  GM_deleteValue(key);
	}
*/

// var $=unsafeWindow.jQuery,holder,query,offset,fPage,pPage,lPage;
// var DiFi=unsafeWindow.DiFi;

var noteauthor=[]; //list of authors
var notetitle=[]; //list of titles
var notetext=[]; //list of word -> list of index for other lists
var notedata=[]; //note-id, folder, note-date 
var noteamount=[]; //count , updatedate

var safheader=""; //old note-menu stored to be restored when leaving search
var lastactfolder=""; //last active folder for continue indexing
var aktfolder=""; //current selected folder (per dropdown)
var aktindexfirstnoteid=""; //last note scanned in indexing -> used in updating index.
var totalamm; //total amount of notes in current folder
var newaddedli; // added notes used by checknewnotes
var toindexnoteoffsets=[]; //note's offset that still needs to be scanned
var resarr=[]; //array of note-indices that matches the current search
var aktsort=4; // sorting of search results: up&down: 01 name|23 author|45 date

var GM_setValue; //indexedDB: replace GM_functions!
var transaction; //indexedDB
var objectStore; //indexedDB

//style
var sty=document.createElement("style");
sty.innerHTML="h2.dev_note_search2_search input[type='text']{"+
	"background-color: #BBCCBA;"+
    "border: 1px inset #5E7264;"+
    "border-radius: 7px;"+
    "color: #3C4441;"+
    "display: inline-block;"+
    "margin-left: 10px;"+
    "padding: 2px;"+
	"padding-left:4px;"+
	"width:70%;"+
    "vertical-align: middle;}"+
"div.dev_note_header{"+
	"background: linear-gradient(0deg, rgba(0,0,0,0.2) 0%, rgba(255,255, 255, 0.5) 100%) repeat scroll 0 0 rgba(0, 0, 0, 0);"+
	"padding: 0 0 0 6px!important;height:20px;}"+
"div.dev_note_header>div{"+
	"height:20px;cursor:pointer;}"+
"li.dev_noteentry>span, div.dev_note_header>div{"+
	"display:inline-block;"+
	"width:33.33%;"+
	"}"+
"#dev_note_search2_search_info{"+
	"font-size:8pt;width:30%;margin:0;}"+
"li.dev_noteentry{"+
	"min-height: 5px !important;"+
	"cursor:pointer;"+
	"padding:6px 0 6px 6px!important;"+
	"}"+
"h2.dev_note_search2_search span{"+
	"margin-left: 10px;"+
	"width: 80px;"+
	"display: inline-block;"+	
	"vertical-align: middle;"+	
	"font-size:10pt;}"+
"#dev_note_search2_search_index, #dev_note_search2_removeall_index{"+
	"position:absolute;right:0;height:18px;font-size:8pt;padding:0;"+
	"}"+
"#dev_note_search2_removeall_index{right:70px;}"+
"h2.dev_note_search2_search span.dev_note_search2_search_header{"+
	"font-size:14pt;height:30px;display:inline-block;}"+
".dev_aktsort_down{"+
	// "background: linear-gradient(0deg, #afdbae 0%, #E4F4E3 100%) repeat scroll 0 0 rgba(0, 0, 0, 0);}"+
	"background: linear-gradient(0deg, rgba(175,155,40,0.2) 0%, rgba(72, 194, 27, 0.5) 100%) repeat scroll 0 0 rgba(0, 0, 0, 0);}"+
".dev_aktsort_up{"+
	"background: linear-gradient(180deg, rgba(175,155,40,0.2) 0%, rgba(72, 194, 27, 0.5) 100%) repeat scroll 0 0 rgba(0, 0, 0, 0);}"+
"h2.dev_note_search2_search input[type='submit'],h2.dev_note_search2_search select{"+
	"border-radius: 7px;"+
	"background: linear-gradient(0deg, #E2E9E3, #D3DFD5) repeat scroll 0 0 transparent;"+
	"border: 1px solid #93A98F;"+
	"padding: 3px;"+
	"margin: 6px;"+
	"float: left;"+
	"cursor:pointer;"+
	"color: #2C3635;}"+	
"h2.dev_note_search2_search input[type='submit']:active{"+
	"border:1px inset #93A98F;"+
	"background: linear-gradient(180deg, #E2E9E3, #B5C9B8) repeat scroll 0 0 transparent;}";
	
document.body.appendChild(sty);

//removes all elements of array subtrahend from array minuend with creating a new one.
function arrsubstract(minuend, subtrahend){
	var ruckarr=[];
	for(var i=0;i<minuend.length;i++)
		if(subtrahend.indexOf(minuend[i])==-1)ruckarr.push(minuend[i]);
	return ruckarr;
}
//merges two array unique into a 3rd one.
function arrmerge(arr1, arr2){
	var ruckarr=getUnique(arr1);
	if(arr2==null)return arr1;
	if(arr1==null)return arr2;
	for(var i=0;i<arr2.length;i++)
		if(ruckarr.indexOf(arr2[i])==-1)ruckarr.push(arr2[i]);
	return ruckarr;
}
//makes an array unique
function getUnique(arr){
   var u = {}, a = [];
   if(arr==null)return arr;
   for(var i = 0, l = arr.length; i < l; ++i){
      if(u.hasOwnProperty(arr[i])) {
         continue;
      }
      a.push(arr[i]);
      u[arr[i]] = 1;
   }
   return a;
}
//returns an array with all elements from two array that are in both.
function getintersection(arr1,arr2){
	var resarr=new Array();
	if(arr1==null)return arr2;
	if(arr2==null)return arr1;
	for (var i = 0; i < arr1.length; i++) {
		if (arr2.indexOf(arr1[i]) != -1) {
			resarr.push(arr1[i]);
		}
	}
	return resarr;
}

//remove slashes from string
function stripslashes(str) {
	str=str.replace(/\\'/g,'\'');
	str=str.replace(/\\"/g,'"');
	str=str.replace(/\\0/g,'\0');
	str=str.replace(/\\\\/g,'\\');
	return str;
}
    
//takes a quary-string and returns a list of matched note-indices (regarding the script-lists)
//"" and * are handled here, + and - on the click-event.
function search(query,mode){ //mode: 0:author, 1: title, 2:text
	try{
	var returnarr=[];
	if(query==""||query=="*")return null; //empty searches
	query=query.toLowerCase(); //case insensitive
	
	var inquote=false; //this block replaces all spaces with $ within quotes.
	for(var i=0;i<query.length;i++){
		if(inquote){
			if(query[i]==" ")query=query.substr(0,i)+"$"+query.substr(i+1);
			if(query[i]=="\""||query[i]=="'")inquote=false;
		}else{
			if(query[i]=="\""||query[i]=="'")inquote=true;
		}
	}
	
	query=query.replace(/["']/g,""); //remove quotes. protected spaces are now $
	switch(mode){
	case 0: //author search
		var searchwords=query.split(" ");
		for(var j=0;j<searchwords.length;j++){ //any of those words
			for(var i=0;i<noteauthor[aktfolder].length;i++){ //all found note-indices
				if(noteauthor[aktfolder][i].toLowerCase().indexOf(searchwords[j].replace(/\$/g," "))!=-1)returnarr.push(i); //add found note-index to return-array if not already part of
			}
		}
		break;
	case 1: //title search: like author
		var searchwords=query.split(" ");
		for(var j=0;j<searchwords.length;j++){
			for(var i=0;i<notetitle[aktfolder].length;i++){
				if(notetitle[aktfolder][i].toLowerCase().indexOf(searchwords[j].replace("$"," "))!=-1)returnarr.push(i);
			}
		}
		break;
	case 2: //text search:
		var searchwords=query.split(" ");
		for(var i=0;i<searchwords.length;i++){
			if(searchwords[i].split("$").length==1){ //no protected spaces/quotes:
				if(searchwords[i][searchwords[i].length-1]=="*" && searchwords[i][0]=="*"){ //*-cases: *word*
					searchwords[i]=searchwords[i].substr(1,searchwords[i].length-2); //make *word* to word
					var indexF=mapfolder.indexOf(aktfolder);if(indexF<0)indexF=0;
					// for(var w in notetext[aktfolder]){ //go through all stored keywords
					for(var w =0;w<mapwords[indexF].length;++w){//  in notetext[indexF]){ //go through all stored keywords
						if(mapwords[indexF][w].indexOf(searchwords[i])!=-1){ //a keyword contains "word"
							// for(var j=0;j<notetext[aktfolder][w].length;j++) //add all note-indices of this word to the returnlist (if not already there)
							for(var j=0;j<notetext[indexF][w].length;j++) //add all note-indices of this word to the returnlist (if not already there)
								// returnarr.push(parseInt(notetext[aktfolder][w][j]));
								returnarr.push(parseInt(notetext[indexF][w][j]));
						}
					}
				}else if(searchwords[i][searchwords[i].length-1]=="*"){ //*-cases: word*
					searchwords[i]=searchwords[i].substr(0,searchwords[i].length-1); //word* -> word
					var indexF=mapfolder.indexOf(aktfolder);if(indexF<0)indexF=0;
					for(var w =0;w<mapwords[indexF].length;++w){//  in notetext[indexF]){
						if(mapwords[indexF][w].indexOf(searchwords[i])==0){ //keyword beginns with "word"
							for(var j=0;j<notetext[indexF][w].length;j++)
								returnarr.push(parseInt(notetext[indexF][w][j]));
						}
					}
				}else if(searchwords[i][0]=="*"){ //*-cases: *word
					searchwords[i]=searchwords[i].substr(1); //*word -> word
					var indexF=mapfolder.indexOf(aktfolder);if(indexF<0)indexF=0;
					for(var w =0;w<mapwords[indexF].length;++w){// in notetext[indexF]){
						if(mapwords[indexF][w].indexOf(searchwords[i])==mapwords[indexF][w].length-searchwords[i].length){ //keyword ends with "word"
							for(var j=0;j<notetext[indexF][w].length;j++)
								returnarr.push(parseInt(notetext[indexF][w][j]));
						}
					}
				}else{ //no * case
					var indexF=mapfolder.indexOf(aktfolder);if(indexF<0)indexF=0;
					var indexW=mapwords[indexF].indexOf(searchwords[i]);
					// console.log(indexW,notetext[indexF].length,typeof notetext[indexF][indexW],indexW >-1 , notetext[indexF].length<indexW , typeof notetext[indexF][indexW]!= "undefined");
					if(indexW >-1 && notetext[indexF].length>indexW && typeof notetext[indexF][indexW]!= "undefined"){
						for(var j=0;j<notetext[indexF][indexW].length;j++){//add all note-indices of this word to the returnlist (if not already there)
							indexW=mapwords[indexF].indexOf(searchwords[i]);
							returnarr.push(parseInt(notetext[indexF][indexW][j]));
						}
					}
					// console.log(returnarr);
				}
			}else{ //protected spaces/quotes -> $
				returnarr=returnarr.concat(search(searchwords[i].replace(/\$/g," ").trim(),mode)); 
				//make a normal search like there were no "
				var leerwords=searchwords[i].split("$"); //words within quotes
				var aktretarr=returnarr;
				//now make a difi-request: get the full text of the notes that matches the normal search and check if the originally search matches their text. 
				//if yes, the note with the data-noteid-property will get removed.
				for(var j=0;j<aktretarr.length;j++){ 
					DiFi.pushPost('Notes', 'display_note', [aktfolder,notedata[aktfolder][aktretarr[j]][0]],function(success,data){
						var tnotetext=$(data.response.content.body).find("textarea.mcb-body").html();
						var swords=/[^ \$]*\$([^ \$]*\$?)*/g
						var row="";
						while(row=swords.exec(query)){
							var spacedwords=row[0].replace("$"," ");
								if((tnotetext.indexOf(spacedwords)==-1&&tnotetext.indexOf("*")==-1)||
								(spacedwords.indexOf("*")!=-1)&&tnotetext.match(new RegExp(spacedwords.replace(/\*/g,"[^ ]*?"),"i"))==null){
									$("li.note[data-noteid="+data.response.content.noteid+"]").remove();
								}
						}
						// tnotetext
					});
					
				}
				// DiFi.timer(2000); //just for record: this will do send() after 2s.				
				DiFi.send(); //bunch the pushpost before sending makes it into one request which is faster.				
			}
		}
		break;
	}
	}catch(ex){
		console.log("Search error",ex);
		return [];
	}
	return returnarr;
}

//load the data from indexedDB for this folder
//will be called the number of folders times.
function loaddata(folder){
	transaction = db.transaction(["devnotesearch2"], "readwrite"); //new transaction for getting data
	var objectStore = transaction.objectStore("devnotesearch2"); 
	transaction.onerror = function(event) { //in case of an error, something went wrong...
		console.log(event)
	};  
	//mozilla's homepage: defining onsuccess after calling get would be fine...
	//if not found, get will also succeed, but with event.target.result=undefined.	
	objectStore.get("noteauthor_"+folder).onsuccess=function(event){ //load authorlist
		if(typeof event.target.result!="undefined")noteauthor[folder]=eval(event.target.result.value);
	};
	objectStore.get("notetitle_"+folder).onsuccess=function(event){//load titlelist
		if(typeof event.target.result!="undefined")notetitle[folder]=eval(event.target.result.value);
	};
	objectStore.get("notedata_"+folder).onsuccess=function(event){ //load data-list (see header-variables)
		if(typeof event.target.result!="undefined")notedata[folder]=eval(event.target.result.value);
	};
	objectStore.get("noteamount_"+folder).onsuccess=function(event){ //load stored amount and last update
		if(typeof event.target.result!="undefined")noteamount[folder]=eval(event.target.result.value);
	};
	objectStore.get("toindexnoteoffsets").onsuccess=function(event){ //load last indexed note.
		if(typeof event.target.result!="undefined")toindexnoteoffsets=eval(event.target.result.value);
	};
	objectStore.get("lastindexfolder").onsuccess=function(event){ //load last indexed folder
		if(typeof event.target.result!="undefined")lastindexfolder=event.target.result.value;
	};
	objectStore.get("notetext_"+folder).onsuccess=function(event){ //load all the content-data (word-lists)
		if(typeof event.target.result=="undefined")return;
		
		//word(18)noteid(19)wordpos(18)noteid(19)wordpos(17)word(18)noteid(19)wordpos
		var rawdata=event.target.result.value.split(String.fromCharCode(17));
		var zrawdata1="", zrawdata2="";
		var indexW,indexF;
        if(mapfolder.indexOf(folder)==-1){
			mapfolder.push(folder);
			indexF=mapfolder.indexOf(folder);
			mapwords[indexF]=[];
		}else
			indexF=mapfolder.indexOf(folder);
		notetext[indexF]=new Array();
		// console.log(rawdata);
		for(var i=0;i<rawdata.length;i++){
			zrawdata1=rawdata[i].split(String.fromCharCode(18)); //noteid(19)wordpos
			zrawdata2=zrawdata1.shift(); //word
            if(mapwords[indexF].indexOf(zrawdata2)==-1)
				mapwords[indexF].push(zrawdata2);
			indexW=mapwords[indexF].indexOf(zrawdata2);
			// notetext[folder][zrawdata2]=zrawdata1;
			notetext[indexF][indexW]=zrawdata1;
		}
		// console.log(mapwords,mapfolder);
		//display the info-text
		$("#dev_note_search2_search_folders").change();
	};
}

//convert the note's message into word-list entries
function adddata(message, noteid, folder){
	try{
		if(message==null||message=="")return;
		var elements=message.replace(/[\W\s]/g," ").replace(/ {2,}/," ").split(" "); //only \w-character words are liked. numbers are part of \w
		for(var i =0;i<elements.length;i++){ //all new words
			if(typeof elements[i]=="undefined"||elements[i]==""||elements[i][0]==" ")continue; //empty words and strange accidents don't count.
			elements[i]=elements[i].toLowerCase(); //case insensitive
			
			var indexF=mapfolder.indexOf(folder);
			if(mapwords.length<=indexF||indexF<0||notetext.length<=indexF)continue;
			var	indexW=mapwords[indexF].indexOf(elements[i]);
			if(typeof notetext[indexF]=="undefined"){ //word not yet listed
				notetext.push([[noteid]]);
			} else { //word already part of list
				
				if(indexW<0){
					mapwords[indexF].push(elements[i]);		
					notetext[indexF].push([]);
				}
				indexW=mapwords[indexF].indexOf(elements[i]);
				if(indexW<0||indexW>=notetext[indexF].length||typeof notetext[indexF][indexW]=="undefined")continue;
				if(
				$.inArray(noteid, notetext[indexF][indexW])==-1
				 //this note is not already added (e.g. 2 times word in a note)
				&&notetext[indexF][indexW].push) //and the array is legit
					notetext[indexF][indexW].push(noteid); //then add this note's index (pointing to other lists)
			}
			
		}
	}catch(ex){
		console.log("MSG-convert error: ",ex);
		return;
	}
}

//this goes from newest to oldest note until it finds a note with the last indexed note id, stored in noteamount[folder][2]
//this is actually how getnotes() also looked like before made pausable and turning the pushposts into bunches.
function checknewnotes(folder,offset){	
if(offset==40)return;
	//in case there is no last indexed id as there was no index, make a full index
	var indexF=mapfolder.indexOf(folder);
	// var	indexW=mapwords[indexF].indexOf(elements[i]);
	// if(typeof notetext[folder]=="undefined"&&totalamm!=-1){getnotes(folder,Math.floor(totalamm/10)*10,true);return;}
	if((indexF<0 || typeof notetext[indexF]=="undefined")&&totalamm!=-1){getnotes(folder,Math.floor(totalamm/10)*10,true);return;}
	if(totalamm==-1){ //folder unknown full
		noteauthor[folder]=[]; //everywhere 0!
		notetitle[folder]=[];
		notetext[indexF]=[];
		notedata[folder]=[];
		// mapfolder=[];
		// mapwords=[];
		noteamount[folder]=[0,(new Date).toLocaleString(),""];
		lastindexfolder=folder;
		aktindexfirstnoteid="";
		var intex="";
		saveindexnotes(folder, intex); //save 0...
		$("#dev_note_search2_search_folders").change();	//display 0 Notes indexed	
	}
	
	DiFi.pushPost('Notes', 'display_folder', [folder,offset,false],function(success,data){
		var aktsite=$(data.response.content.body); //parse note-page (<10 notes)
			aktsite.find("li.note").each(function(){ //break when the last indexed note was found. All notes before that (newer) will be in newaddedli.
				if($(this).attr("data-noteid")!=noteamount[folder][2]){
					newaddedli=newaddedli.add($(this));
				}else
					return false; //false will break the each-loop
			});
			if(newaddedli.length==0)return; //no new notes
			if(aktsite.find("li.note[data-noteid='"+noteamount[folder][2]+"']").length==0&&aktsite.find("li.note").length>0){ //the last indexed note is not on this site
				checknewnotes(folder,offset+10); //recursive call to scan the next page.
			}else{
				//reverse order of found new notes (convert to oldes->newest)
				$(newaddedli.get().reverse()).each(function(){
					
					if(NoteAlreadyScanned($(this).attr("data-noteid"),folder))return;
					
					//username is a must have.
					if($(this).find("span.sender a.username,span.sender span.username").html()==null){
						return;
					}
					if(typeof $(this).find("div.note-preview").html()=="undefined"){
						noteauthor[folder].push($(this).find("span.sender a.username,span.sender span.username").html());
						notetitle[folder].push($(this).find("span.subject a").html());
						
						var dstime=Date.parse($(this).find("span.ts").attr("title"));
						if(isNaN(dstime))dstime=Date.parse($(this).find("span.ts").html());
						aktindexfirstnoteid=$(this).attr("data-noteid");
						notedata[folder].push(new Array($(this).attr("data-noteid"),
							$(this).find("span.subject a").attr("data-folderid"),
							dstime));
						
						return;
					}
						
				
					noteauthor[folder].push($(this).find("span.sender a.username,span.sender span.username").html());
					//otherwise noteauthor has a problem
					notetitle[folder].push($(this).find("span.subject a").html());
					//title just assumes, there is a note title
					//no convert and add the text into word-list.
					//note-preview contains the whole text, but without linebreaks(spaces inserted) and without html
					//notedata[folder].length is the new index after this entry is pushed into notedata!
					adddata($(this).find("div.note-preview").html(),notedata[folder].length,folder);
					//parse the time when the note was sent/recieved.
					var dtime=Date.parse($(this).find("span.ts").attr("title"));
					if(isNaN(dtime))dtime=Date.parse($(this).find("span.ts").html());
					//the display switches: one says the date, one xx minutes ago.
					
					aktindexfirstnoteid=$(this).attr("data-noteid"); //last indexed note will be overwritten untill the newset index.
					//add note-id, folderid and recieved date to notedata.
					notedata[folder].push(new Array($(this).attr("data-noteid"),
						$(this).find("span.subject a").attr("data-folderid"),
						(new Date(dtime)).toLocaleString()));
				});
				
				var intex="";
				saveindexnotes(folder,intex);

				//progressbar and title
				$("#dev_note_search2_search_index").css("background-image","").attr("title","100%: "+noteauthor[folder].length+"/"+totalamm+", "+Math.round(100*(intex.length+uneval(noteauthor[folder]).length+uneval(notetitle[folder]).length+uneval(notedata[folder]).length)/1024/1024)/100+"MB storage used");

			}
		// }
	});
	DiFi.send();
}
 
// var aktstartdat; //time measurement.

//saves the values to indexedDB!
function saveindexnotes(folder, intex){
	try{
		if(typeof intex=="undefined"||intex==null)intex="";
		var indexF=mapfolder.indexOf(folder);
		// var	indexW=mapwords[indexF].indexOf(elements[i]); 
		// for(var el in notetext[folder]){//convert word-list into a string. saves some bytes in contrast to uneval().
			// intex+=String.fromCharCode(17)+el+String.fromCharCode(18)+notetext[folder][el].join(String.fromCharCode(18)); 
		// }
		for(var el =0;el<mapwords[indexF].length;++el){//in notetext[indexF]){//convert word-list into a string. saves some bytes in contrast to uneval().
			intex+=String.fromCharCode(17)+mapwords[indexF][el]+String.fromCharCode(18)+notetext[indexF][el].join(String.fromCharCode(18)); 
		}
		
		//noteamount, updatedate and last indexed note to be changed
		noteamount[folder]=[noteauthor[folder].length,(new Date).toLocaleString(),aktindexfirstnoteid];

		//elements in folder...
		//this updates info-text during scan
		if(typeof noteamount[aktfolder]!="undefined"&&noteamount[aktfolder].length>1)
			$("#dev_note_search2_search_info").html(noteamount[aktfolder][0]+" Notes fetched<br/> Updated on"+noteamount[aktfolder][1]);
		
		// setTimeout(function(){ //neded for the original GM_setValue. Now IndexDb
			GM_setValue("notetext_"+folder,intex.substr(1));
			GM_setValue("noteauthor_"+folder,uneval(noteauthor[folder]));
			GM_setValue("notetitle_"+folder,uneval(notetitle[folder]));
			GM_setValue("noteamount_"+folder,uneval(noteamount[folder]));				
			GM_setValue("notedata_"+folder,uneval(notedata[folder]));				
			GM_setValue("toindexnoteoffsets",uneval(toindexnoteoffsets));
			GM_setValue("lastindexfolder",uneval(lastindexfolder));
		// },0);
	}catch(ex){
		console.log("indexDB-storage error: ",ex);
		return;
	}
}
function NoteAlreadyScanned(id,folder){
	try{
	for(var i=0;i<notedata[folder].length;i++)
		if(notedata[folder][i][0]==id)return true;
	return false;
	}catch(ex){
		console.log("Note-Check error: ",ex);
		return;
	}
}

//index your notes anew or continue after break.
function getnotes(folder,offset,neu){ 
	try{
	if(typeof folder=="undefined"||folder<0)return;
	if(totalamm==0){ //folder empty
		noteauthor[folder]=new Array(); //everywhere 0!
		notetitle[folder]=new Array();
		notetext[folder]=[];
		if(mapfolder.indexOf(folder)<0){
			mapfolder.push(folder);
			mapwords.push([]);
		}
		notedata[folder]=new Array();
		noteamount[folder]=[0,(new Date).toLocaleString(),""];
		lastindexfolder=folder;
		aktindexfirstnoteid="";
		var intex="";
		saveindexnotes(folder, intex); //save 0...
		$("#dev_note_search2_search_folders").change();	//display 0 Notes indexed	
		return;
	}
	if(neu){ //indexing started
		if(toindexnoteoffsets.length>0){return;} //already running!
		noteauthor[folder]=[];
		notetitle[folder]=[];
		if(mapfolder.indexOf(folder)<0){
			mapfolder.push(folder);
			mapwords.push([]);
		}
		notedata[folder]=[];
		noteamount[folder]=[];
		lastindexfolder=folder;
		aktindexfirstnoteid="";
		for(var i=offset;i>=0;i-=10) //create all note-offset I want to scan! offset=(page-1)*10.
			toindexnoteoffsets.push(i); //go from high to 0: old notes first!
	}
	if(offset==-10){ //finished: all notes scanned, toindexnoteoffsets empty.
		var intex="";
		saveindexnotes(folder, intex); //save all data.
		//update progressbar
		if(typeof noteauthor[folder]=="undefined"||noteauthor[folder]==null)return;
		$("#dev_note_search2_search_index").css("background-image","").attr("title","100%: "+noteauthor[folder].length+"/"+totalamm+", "+Math.round(100*(intex.length+uneval(noteauthor[folder]).length+uneval(notetitle[folder]).length+uneval(notedata[folder]).length)/1024/1024)/100+"MB storage used");
		//update info-text
		$("#dev_note_search2_search_folders").change();
	}else{
		var runter=note_index_steps; //number of offsets within a request. Is set at top. default 100
		if(offset%note_index_steps!=0)runter=offset%note_index_steps; //360: first 6*10, then only 10*10.
		for(var i=0;i<toindexnoteoffsets.length&&i<runter/10;i++){ //bunch of difi-posts.
			DiFi.pushPost('Notes', 'display_folder', [folder,toindexnoteoffsets[i],false],function(success,data){
				//remove offset from list
				
				toindexnoteoffsets.splice(toindexnoteoffsets.indexOf(parseInt(data.response.content.offset)),1);
				//update progressbar
				if(totalamm==0)totalamm=1;
				$("#dev_note_search2_search_index").css("background-image","linear-gradient(90deg, #9AD15F "+(Math.round((totalamm-toindexnoteoffsets.length*10)/totalamm*100))+"%, #D3DFD5 "+(Math.round((totalamm-toindexnoteoffsets.length*10)/totalamm*100)+10)+"%)").attr("title",Math.round((totalamm-toindexnoteoffsets.length*10)/totalamm*100)+"%: "+(totalamm-toindexnoteoffsets.length*10)+"/"+totalamm);
				//get jquery-object for notes page
				var aktsite=$(data.response.content.body);
				if(aktsite.find("li.note").length!=0){ //no empty pages
					//reverse order for oldes to newest notes!
					$(aktsite.find("li.note").get().reverse()).each(function(){
						// see checknewnotes for this
						try{
							if(NoteAlreadyScanned($(this).attr("data-noteid"),folder))return false; //true: next item
							if($(this).find("span.sender a.username,span.sender span.username").html()==null){ //no sender recognized
								return true; //true: next item;
							}
							if(typeof $(this).find("div.note-preview").html()=="undefined"){
								noteauthor[folder].push($(this).find("span.sender a.username,span.sender span.username").html());
								notetitle[folder].push($(this).find("span.subject a").html());
								
								var dstime=Date.parse($(this).find("span.ts").attr("title"));
								if(isNaN(dstime))dstime=Date.parse($(this).find("span.ts").html());
								if(isNaN(dstime))dstime=0;
								aktindexfirstnoteid=$(this).attr("data-noteid");
								notedata[folder].push(new Array($(this).attr("data-noteid"),
									$(this).find("span.subject a").attr("data-folderid"),
									dstime));
									
								return true; //no preview: next item
							}
							
							noteauthor[folder].push($(this).find("span.sender a.username,span.sender span.username").html());
							notetitle[folder].push($(this).find("span.subject a").html());
							
							adddata($(this).find("div.note-preview").html(),notedata[folder].length,folder);
							var dtime=Date.parse($(this).find("span.ts").attr("title"));
							if(isNaN(dtime))dtime=Date.parse($(this).find("span.ts").html());
							aktindexfirstnoteid=$(this).attr("data-noteid");
							notedata[folder].push(new Array($(this).attr("data-noteid"),
								$(this).find("span.subject a").attr("data-folderid"),
								dtime));
						}catch(ex2){
							console.log("Error checking Offset "+offset+":",ex2);
							return true; //error: next item;
						}
					});
					saveindexnotes(folder);
					
					//all note's scanned: call the finish-feature of this functio
					//are note_index_steps note scanned at once, you can scan the next note_index_steps Notes!
					if(toindexnoteoffsets.length==0)getnotes(folder,-10,false); else
					if((toindexnoteoffsets.length*10-10)%note_index_steps==0)getnotes(folder,(toindexnoteoffsets.length*10-10),false);
				}
			});
		}
		DiFi.send();
	}
	}catch(ex){
		console.log("Error in fetching notes: ",ex);
		return;
	}
}

function addlayout(){
	if($("dev_note_search2_tab").length>0)return;
	aktfolder="1"; //standard is inbox.
	aktsort=4; //standard is sorting results with date
	resarr=[]; //show no notes at the beginning (index of notes to show)
	
	//search-entry on the left
	var tab=$('<a class="f folder-link dev_search_tab" title="Search" href="#" onclick="return false;" id="dev_note_search2_tab"><i class="icon i1"></i><span class="ttext">Search</span></a>');
	//make the search-form undo-able
	$("div.messages-menu div.pager-holder div.pager2 div.page2").children().click(function(){
		if(safheader!=""){
			$("h2.mczone-title").empty();
			$("h2.mczone-title").css("height","");
			$("h2.mczone-title").first().append(safheader);
		}
		if(lastactfolder!=""){ //switch to last selected folder!
			lastactfolder.addClass("selected");
			$("#dev_note_search2_tab").removeClass("selected");
		}		
	});
	$("#notes a.folder-link").first().before(tab); //insert "search"
	// $("div.messages-menu div.pager-holder div.pager2 div.page2 div.header").first().after(tab); //insert "search"
    tab.click(function(event){//and click event
		event.preventDefault();
		event.stopPropagation(); //no parent-clicks needed!
		$(".dev_note_header").remove(); //no double search forms!
		//folder where you came from
		lastactfolder=$("div.messages-menu div.pager-holder div.pager2 div.page2 a.selected").removeClass("selected").first();
		$("#dev_note_search2_tab").addClass("selected"); //search is now selected
		if($("#dev_note_search2_search_title").length==0)safheader=$("h2.mczone-title").first().children();
    	var header1=$("td.notes-left h2.mczone-title").first().empty();
    	var header2=$("td.notes-right h2.mczone-title").first().empty(); //no double search forms!
		header1.addClass("dev_note_search2_search");
		header2.addClass("dev_note_search2_search");

		$( window ).resize(function(){ //adapt search form to window's site
			$("#dev_note_search2_search_info").width($("h2.dev_note_search2_search").eq(1).width()-320);
			$("h2.dev_note_search2_search input[type='text']").width($("h2.dev_note_search2_search").first().width()-130);
		});
		//inset search form
		header1.append($("<span class='dev_note_search2_search_header'>Search:</span><div class='dev_search_formfield'><span>Username:</span><input id='dev_note_search2_search_name' type='text'/></div>"+
		"<div class='dev_search_formfield'><span>Subject:</span><input id='dev_note_search2_search_title' type='text'/></div><div class='dev_search_formfield'><span>Text:</span><input id='dev_note_search2_search_text' type='text'/></div>")).css({"height":"110px","background-size":"contain","padding":"10px 0px"});
		header1.find("input[type='text']").keydown(function(event){ //enter means search!
			if(event.which==13)$("#dev_note_search2_search_submit").click();
		});
		header2.append("<input type='submit' onclick='return false;'  id='dev_note_search2_search_submit' value='Search'/>"+
		"<input type='submit' onclick='return false;'  id='dev_note_search2_search_addindex' value='Refresh'/>"+
		"<select id='dev_note_search2_search_folders'></select><span id='dev_note_search2_search_info'></span>");
		header1.prepend("<input type='submit' onclick='return false;'  id='dev_note_search2_search_index' value='Index Notes'/>");
		header1.prepend("<input type='submit' onclick='return false;'  id='dev_note_search2_removeall_index' value='Reset to Default'/>");
		$("#dev_note_search2_search_addindex").first().click(function(){ //refresh-button to update index
			//total amount of notes is displayed at each note-folder's rel-attribute
			totalamm=parseInt($("a.folder-link[data-folderid="+aktfolder+"]").attr("rel").replace(/,/g,""));
			newaddedli=$([]);
			checknewnotes(aktfolder,0);
		});
		//load data for each folder and generate the dropdown!
		$("div.messages-menu div.pager-holder div.pager2 div.page2 a.folder-link").not(".dev_search_tab").each(function(){
			if($(this).html()=="Search")return;	
			var wert=$(this).attr("data-folderid");
			 if(typeof(noteamount[wert])=="undefined"){ //only load first
				// setTimeout(function(){
				loaddata(wert);
				// },0);
			 }
			$("#dev_note_search2_search_folders").first().append("<option value='"+$(this).attr("data-folderid")+"'>"+$(this).attr("title")+"</option>");
		});
		$("#dev_note_search2_search_folders option").first().addClass("selected"); //select "inbox"
		$("#dev_note_search2_search_folders").change(function(){ //change will update the info-text and chooses aktfolder
			if($(this).prop("selectedIndex")==-1)$(this).prop("selectedIndex",0); //stange=first
			aktfolder=$(this).val();

			if(toindexnoteoffsets.length>0){ //continue scan?
				if(confirm("You interrupted the last scan of your folder '"+lastindexfolder+"'.\n Do you want to continue indexing it?")){
					totalamm=parseInt($("a.folder-link[data-folderid="+aktfolder+"]").attr("rel").replace(/,/g,""));
					getnotes(aktfolder,0,false);
				}else{ //no...
					toindexnoteoffsets=[];
					// GM_setValue("toindexnoteoffsets",uneval(toindexnoteoffsets));
				}
			}
			if(typeof(noteamount[aktfolder])=="undefined") //no indexed notes!
				$("#dev_note_search2_search_info").html("No notes fetched so far!<br/>Press \"Index Notes\"!");
			else //show the indexed note's amount and update-Date in the info-text-field!
				$("#dev_note_search2_search_info").html(noteamount[aktfolder][0]+" Notes fetched<br/> Updated on "+noteamount[aktfolder][1]);
		}).keyup(function() { //using dropdown with keyboard
			$(this).change();
		}).change(); //and do it already once!
		
		$("#dev_note_search2_removeall_index").click(function(){
			location.href="http://www.deviantart.com/notifications/notes/#1_0/#killoldindex";
			location.reload();
		});
		$("#dev_note_search2_search_index").click(function(){
			//index notes!
			//total amount of notes is displayed at each rel-attribute
			totalamm=parseInt($("a.folder-link[data-folderid="+aktfolder+"]").attr("rel").replace(/,/g,""));
			if(totalamm==-1){
				newaddedli=$([]);
				checknewnotes(aktfolder,0);
			}else{
				getnotes(aktfolder,Math.floor(totalamm/10)*10,true);
			}
		});
		
		//make a search!
		//here is also the actuall search and use of search() defined!
		header2.find("#dev_note_search2_search_submit").click(function(){
			resarr=getUnique(search($("#dev_note_search2_search_name").val(),0)); //search authors
			resarr=getintersection(resarr,search($("#dev_note_search2_search_title").val(),1)); //search titles
			//use intersection to have notes that match author AND title
			var query=$("#dev_note_search2_search_text").val().trim(); //and now the text-search...
			var queryplus=query.match(/\+("[^"]*?"|[^ "]*)/g); //all words with a + before (also +"asd dsa")
			var queryminus=query.match(/-("[^"]*?"|[^ "]*)/g); //same with -
			var querynotplus=query.replace(/(\+|-)("[^"]*?"|[^ "]*)/g,""); //and words with neither
			if(queryplus==null) //no plus words?
				resarr=getintersection(resarr,search(querynotplus,2)); //normal search 
			else{
				for(var i=0;i<queryplus.length;i++){ //otherwise go through all + words
					//and connect their searches with ANDs!
					resarr=getintersection(resarr,search(queryplus[i].substr(1).trim(),2));  
				}
				//at last merge the result with the not-plus words for an stronger OR.
				resarr=arrmerge(resarr,search(querynotplus.trim(),2));
			}
			if(queryminus!=null){ //there were - words.
				var notresarr=search(queryminus.join(" ").replace("-",""),2); //find notes with those words
				resarr=arrsubstract(resarr,notresarr); //and remove them from the list!
			}
			resarr=getUnique(resarr); //in case something got wrong: unique id.
			//WHY ARE THERE STILL DOUBLE ENTRIES?
			
			$("div.dev_aktsort_down,div.dev_aktsort_up").click().click(); //refresh sorting!
			
			displayresarr(); //show found notes!
		});
		
		//note-headers for sorting!
		$("ul.notes").first().before($("<div class='dev_note_header'></div>").first().append($("<div class='dev_notetitle'>Subject</div>").click(function(){
			$(".dev_aktsort_down").removeClass("dev_aktsort_down");
			$(".dev_aktsort_up").removeClass("dev_aktsort_up");
			if(resarr==null)return; //no notes to sort
			if(aktsort==0){ //toggle between 0 and 1
				$(this).addClass("dev_aktsort_up");
				aktsort=1;
				resarr=resarr.sort(function(a,b){return notetitle[aktfolder][a].toLowerCase()<=notetitle[aktfolder][b].toLowerCase();}); //sort subjects ascending
			}else{
				$(this).addClass("dev_aktsort_down");
				aktsort=0;
				resarr=resarr.sort(function(a,b){return notetitle[aktfolder][a].toLowerCase()>=notetitle[aktfolder][b].toLowerCase();});	//sort subjects descending
			}
			displayresarr(); //show sorted notes
		})).first().append($("<div class='dev_noteauthor'>Username</div>").click(function(){
			$(".dev_aktsort_down").removeClass("dev_aktsort_down");
			$(".dev_aktsort_up").removeClass("dev_aktsort_up");
			if(resarr==null)return;
			if(aktsort==2){//toggle between 2 and 3
				$(this).addClass("dev_aktsort_up");
				aktsort=3;
				resarr=resarr.sort(function(a,b){return noteauthor[aktfolder][a].toLowerCase()<=noteauthor[aktfolder][b].toLowerCase();});	//sort usernames ascending
			}else{
				$(this).addClass("dev_aktsort_down");
				aktsort=2;
				resarr=resarr.sort(function(a,b){return noteauthor[aktfolder][a].toLowerCase()>=noteauthor[aktfolder][b].toLowerCase();}); //sort usernames descending
			}
			displayresarr();
		})).first().append($("<div class='dev_notedata dev_aktsort_down'>Date</div>").click(function(){
			$(".dev_aktsort_up").removeClass("dev_aktsort_up");
			$(".dev_aktsort_down").removeClass("dev_aktsort_down");
			if(resarr==null)return;
			if(aktsort==4){//toggle between 4 and 5
				$(this).addClass("dev_aktsort_up");
				aktsort=5;
				resarr=resarr.sort(function(a,b){return notedata[aktfolder][a][2]>=notedata[aktfolder][b][2];});
				//sort dates ascending
			}else{
				$(this).addClass("dev_aktsort_down");
				aktsort=4;
				resarr=resarr.sort(function(a,b){return notedata[aktfolder][a][2]<=notedata[aktfolder][b][2];});	
				//sort dates descending
			}
			displayresarr();
		})));
		displayresarr(); //show no notes at the beginning
    });	
	
}
function displayresarr(){ //show the notes which indices are in resarr
	var body=$("ul.notes").first();
	body.empty(); //empty the old displayed list
	
	if(resarr==null)return; //new list empty?
	for(var i=0;i<resarr.length;i++){		
		//append a new li for every note. info and style are also inserted. also note-id in ''.
		body.append($("<li class='dev_noteentry "+(i%2==0?"even":"odd")+" note ui-draggable' data-noteid='"+notedata[aktfolder][resarr[i]][0]+"' data-folderid='"+notedata[aktfolder][resarr[i]][1]+"'  data-cached='false'>"+
			"<span class='dev_notetitle'>"+notetitle[aktfolder][resarr[i]]+"</span>"+
			"<span class='dev_noteauthor'>"+noteauthor[aktfolder][resarr[i]]+"</span>"+
			"<span class='dev_notedata'>"+(new Date(notedata[aktfolder][resarr[i]][2])).toLocaleString()+"</span>"+
		"</li>").click(function(){ //click on the li:
			$("li.current-note").removeClass("current-note");
			$(this).addClass("current-note"); //note highlight
			location.href=location.href.replace(/\/\d+$/,"")+"/"+$(this).attr("data-noteid"); //adapt displayed url!
			DiFi.pushPost("Notes","display_note",[$(this).attr("data-folderid"),$(this).attr("data-noteid")],function(success,data){ //display the note via difi!
				$("div.push").first().html("<a id=\"note-body\" class=\"anchor\"></a>"+
				stripslashes(data.response.content.body)); //difi slashes lot of things...
				$("div.note-controls.current-note-actions").css("display",""); //otherwise, the buttons are hidden...
			});
			DiFi.send();
		}));
	}
}
var db;
function indexedDBinit(neu){
	//indexedDB:
	if(location.href.substring(location.href.length-("#killoldindex").length)=="#killoldindex"){
		indexedDB.deleteDatabase('devnotesearch2');
		location.href="http://www.deviantart.com/notifications/notes/#1_0/";
	}
	var request = indexedDB.open("devnotesearch2",1);
		
	request.onerror = function(event) {
		console.log(event);
	};
	request.onupgradeneeded = function(event) { 
	  if(event!=null)db = event.target.result;
	  var objectStore = db.createObjectStore("devnotesearch2",{keyPath:"name"});
	  objectStore.createIndex("name", "name", { unique: true });
	}
	request.onsuccess = function(event) {
		db = request.result;
		db.onabort = function(e) {
			db.close();
			db = null;
		 }
		// db = event.target.result;
		// var objectStore = db.createObjectStore("devnotesearch2",{keyPath:"name"});
		// objectStore.createIndex("name", "name", { unique: true });
		try{
			transaction = db.transaction(["devnotesearch2"], "readwrite");
		}catch(e){
			request.onupgradeneeded(null);
			return;
		}
		objectStore = transaction.objectStore("devnotesearch2");
		var putter=objectStore.put({name:"test",value:"erfolgreich"});
			putter.onerror=function(event){console.log("ERR:",event);};
			putter.onsuccess=function(event){};
		objectStore.get("test").onsuccess=function(event){ //load authorlist
			if(typeof event.target.result!="undefined")console.log(event.target.result.value);
		};
			
		transaction.onerror = function(event) {
			console.log(event)
		};  
		GM_setValue=function(Gname,Gvalue){//{name:Gname,value:Gvalue}
			// transaction = db.transaction(["devnotesearch2"], "readwrite");
			// var objectStore = transaction.objectStore("devnotesearch2");
			// transaction.onerror = function(event) {
				// console.log(event)
			// };  
			items.push({name:Gname,value:Gvalue});
			if($("#overlaysavingprocess").length==0)
				$("body").append($("<div style='height:20px;width:100px;position:fixed;background-color:#aaffaa;color:#008800;top:50%;left:50%;margin-top:-10px;margin-left:-50px;border:1px solid green;z-index:99;border-radius:5px;text-align:center;line-height:20px;' id='overlaysavingprocess' len=1>Saving Data...</div>"));
			else
				$("#overlaysavingprocess").attr("len",parseInt($("#overlaysavingprocess").attr("len"))+1);
			// var putter=objectStore.put(data);//{name:Gname,value:Gvalue}
			// putter.onerror=function(event){console.log("ERR:",event);};
			// putter.onsuccess=function(event){
				// $("#overlaysavingprocess").attr("len",parseInt($("#overlaysavingprocess").attr("len"))-1);
				// if($("#overlaysavingprocess").attr("len")==0)$("#overlaysavingprocess").remove();
			// };
			if(!safeworking)putNext();
		};
		function putNext() {
			if(!safeworking){
				transaction = db.transaction(["devnotesearch2"], "readwrite");
				objectStore = transaction.objectStore("devnotesearch2");
			}
            if (items.length>0){
                safeworking=true;
                objectStore.put(items.shift()).onsuccess = putNext;
				$("#overlaysavingprocess").attr("len",parseInt($("#overlaysavingprocess").attr("len"))-1);
				if($("#overlaysavingprocess").attr("len")==0)$("#overlaysavingprocess").remove();
            } else {   // complete
                safeworking=false;
            }
        }   
		addlayout();
	};
}
var items=[];
var safeworking=false;
indexedDBinit();
};
// GM_xmlhttpRequest({
	// url:"http://phi.pf-control.de/jquery_min.js",
	// method:"GET",
	// onload: function(data){
		// eval(data.responseText);
		// injected();
	// }
// });

var el=document.createElement("script");
el.innerHTML="("+injected.toString()+")();";
document.body.appendChild(el);