// ==UserScript==
// @name          deviantPLUS v3
// @namespace     deviantPLUS
// @description	  Enhances deviantART by adding a toolbar to text fields
// @include       http://*.deviantart.com*
// ==/UserScript==

/*
	TODO:
	* Import should have the option for importing via URL or copy/paste
	* Multi-button export should somehow be implemented
	* Button recovery 
		- Recover default buttons via the User Scripts menu
		- Custom buttons by clicking a "Recover Button" button and entering the ID
			- Would be case-sensitive, but I don't know any way around that other than 
			  forcing lower-case and a bunch of other restrictions on all button names =/
	* Create paging system for button icons
		- Eliminate icon names from selection box, add to title attribute
	* New Button Type: Insert From URL
		- Provide a URL and clicking the button will load document at URL and
		  insert contents.
		- Store last modification date of CSS file as button property
			- Update date and re-save button with each update
*/

var loc=window.location.href;
if(top != self && !loc.match('shout.deviantart.com')) return

GM_log('Running deviantPLUS v3');

skipConfirm=false;

var dpVersion='3.2';

if(unsafeWindow.deviantART){
	// For some reason these lines seem to get executed several times, for
	// two of which the unsafeWindow.deviantART object does not exist =/
	var subscriber = unsafeWindow.deviantART.deviant.subbed;
	var username = unsafeWindow.deviantART.deviant.username;
}

// Don't bother running the script if they're not logged in.
if(unsafeWindow.deviantART && !unsafeWindow.deviantART.deviant.loggedIn) return;

var aryStyleText=[];
var buttonSetImage='url(http://dp.thezikes.org/Images/button_grey_all.png)';

var Global={
	URL:{
		Icons:'http://dp.thezikes.org/Icons/icons.txt',
		Buttons:'http://dp.thezikes.org/Buttons/defaultbuttons.dp.js',
		Version:'http://dp.thezikes.org/Updates/version.txt',
		ReleaseNotes:'http://dp.thezikes.org/Updates/releasenotes.txt'
	},
	Element:{
		Body:document.body
	},
	Default:{
		Apply:'1|1|1|1|1|1|1|1|1|1|1|1|1|1|1',
		Order:'',
		Active:'',
		Buttons:''
	},
	GM_Key:{
		Apply:'dpApply',
		Order:'dpOrder',
		Active:'dpActive',
		Buttons:'dpButtons'
	},
	XPath:{
		AllToolbars:'//div[contains(@class,"dpToolbar")]',
		Comments:'//form[@action="http://comments.deviantart.com/post"]//textarea | //div[contains(@class,"talk-post-reply")]//textarea',
		Shoutbox:'//dl[contains(@class,"shouts")]//input[@name="body"] | //input[@id="shout-body"]',
		JournalBody:'//div[@id="journal"]//form[contains(@action,"journal/update")]//textarea[@name="body"]',
		JournalHeader:'//textarea[@name="jheader"]',
		JournalFooter:'//textarea[@name="jfooter"]',
		Descriptions:'//textarea[@id="devdesc"]',
		Literature:'//div[@id="modalspace"]//form[@id="text_container_clone"]/div[contains(@class,"textentrier")]//textarea[@id="modalTextEntry"]',
		Prints:'//textarea[@id="printdesc"]',
		News:'//textarea[@id="newsarticle"]',
		Help:'//textarea[@id="helpdesk-body"]',
		CSS:'//textarea[@name="jcss"]'
	}
}

function $E(){
	function applyObj(to, obj){
		for(prop in obj) if(obj.hasOwnProperty(prop)){
			if(typeof(obj[prop])=='object'){
				applyObj(to[prop], obj[prop]);
			}else{
				to[prop]=obj[prop];
			}
		}
	}
	if(arguments.length==0) return;
	var elm=document.createElement(arguments[0]);
	[arguments[1], arguments[2]].forEach(function(arg,idx,ary){
		if(typeof(arg)=='object'){
			if(arg instanceof Array){
				arg.forEach(function(append,idx,ary){
					if(typeof(append)=='string'){
						append=$S(append);
					}
					elm.appendChild(append)
				});
			}else{
				for(prop in arg) if(arg.hasOwnProperty(prop)){
					if(prop=='events'){
						var events=arg[prop];
						for(evt in events) if(events.hasOwnProperty(evt)){
							elm.addEventListener(evt, events[evt], false);
						}
					}else{
						if(typeof(arg[prop])=='object'){
							applyObj(elm[prop], arg[prop]);
						}else{
							elm[prop]=arg[prop];
						}
					}
				}
			}
		}
	});
	return elm;
}

function $S(str){
	return document.createTextNode(str);
}

// Classes
var Apply = { // Controls where toolbars are applied
	body:true,
	comments:true,
	descriptions:true,
	forums:true,
	notes:true,
	shoutboard:true,
	shoutbox:true,
	prints:true,
	header:true,
	footer:true,
	signature:true,
	literature:true,
	news:true,
	help:true,
	css:true,
	importSettings:function(strSettings){
		var arySettings=strSettings.split('|').clean();
		var obj={'1':true, '0':false, 'null':true, 'undefined':true};
		this.body=obj[String(arySettings[0])];
		this.comments=obj[String(arySettings[1])];
		this.descriptions=obj[String(arySettings[2])];
		this.forums=obj[String(arySettings[3])];
		this.notes=obj[String(arySettings[4])];
		this.shoutboard=obj[String(arySettings[5])];
		this.shoutbox=obj[String(arySettings[6])];
		this.prints=obj[String(arySettings[7])];
		this.header=obj[String(arySettings[8])];
		this.footer=obj[String(arySettings[9])];
		this.signature=obj[String(arySettings[10])];
		this.literature=obj[String(arySettings[11])];
		this.news=obj[String(arySettings[12])];
		this.help=obj[String(arySettings[13])];
		this.css=obj[String(arySettings[14])];
	},
	exportSettings:function(){
		var arySettings=[
			(this.body ? 1 : 0),
			(this.comments ? 1 : 0),
			(this.descriptions ? 1 : 0),
			(this.forums ? 1 : 0),
			(this.notes ? 1 : 0),
			(this.shoutboard ? 1 : 0),
			(this.shoutbox ? 1 : 0),
			(this.prints ? 1 : 0),
			(this.header ? 1 : 0),
			(this.footer ? 1 : 0),
			(this.signature ? 1 : 0),
			(this.literature ? 1 : 0),
			(this.news ? 1 : 0),
			(this.help ? 1 : 0),
			(this.css ? 1 : 0)
		];

		return arySettings.join("|");
	},
	save:function(){
		GM_setValue(Global.GM_Key.Apply,this.exportSettings())
	}
};
function keySet(){
	this.keys=[];
	this.addKey=function(key, value){
		if(!this.keyExists(key))
			this.keys.push({'key':key,'value':value});
	}
	this.keyExists=function(key){
		var blnKeyExists=false
		this.keys.forEach(function(theKey, idx, ary){if(key===theKey.key) blnKeyExists=true})
		return blnKeyExists;
	}
	this.getKey=function(key){
		var intIndex=-1;
		this.keys.forEach(function(theKey, idx, ary){if(key===theKey.key) intIndex=idx})
		if(intIndex!=-1)
			return this.keys[intIndex];
		else
			return false;
	}
	this.applyKeys=function(str){
		this.keys.forEach(function(theKey,idx,ary){
			str=str.replace(new RegExp("<%"+theKey.key+".*?%>","g"), theKey.value);
		});
		return str;
	}
	this.extractKeys=function(str){
		var lines=str.split("\n").clean();
		str.split('\n').clean().forEach(function(line, idx, ary){
			var matches=line.match(/<%(.+?)%>/g);
			if(matches){
				matches.forEach(function(match, idx, ary){
					match=match.substring(2,match.length-2).split(':').clean();
					var key=match[0];
					var prmpt=match[1] || key;
					if(!this.keyExists(key)){
						var val=prompt(prmpt,"");
						val = val || "";
						this.addKey(key, val);
					}
				},this)
			}
		},this);
	}
}
var Timer= new (function(msg){
	this.lastTime=new Date().getTime();
	this.total=0;
	GM_log(msg)
	this.newTime=function(msg){
		var time=new Date().getTime();
		var diff=time-this.lastTime;
		this.lastTime=time;
		GM_log(diff+"ms: "+msg);
		this.total+=diff;
	}
	this.progressTime=function(msg){
		var time=new Date().getTime();
		var diff=time-this.lastTime;
		GM_log(diff+"ms: "+msg);
	}
	this.totalTime=function(){
		var time=new Date().getTime();
		var diff=time-this.lastTime;
		this.lastTime=time;
		this.total+=diff;		
		GM_log("Script completed in: "+this.total+"ms")
	}
})("Begin timer")

function Toolbar(type){
	this.buttons=[];	
	this.applied=false;
	this.tb=$E('div', {className:'dpToolbar'});
	
	this.type=type || 'comments';
	
	this.apply=function (textField){
		if(this.applied) return;
		if(textField.getAttribute('hasToolbar')=='true') return;
		
		this.tb.style.width=textField.style.width;
		this.tb.setAttribute('type',this.type);
		
		for(var i=0;i<this.buttons.length;i++){
			var btn = Buttons.make(this.buttons[i]);
			if(btn !== false){
				if(btn.getAttribute('allowedIn').indexOf(this.type)>-1){
					if(btn.getAttribute('subscriberonly')=='true'){
						if(subscriber) this.tb.appendChild(btn);
					}else{
						this.tb.appendChild(btn)
					}
				}
			}
		}
		if(this.tb.childNodes.length!=0){
			textField.parentNode.insertBefore(this.tb,textField);
			this.tb.textField=textField;
			textField.setAttribute('hasToolbar','true');
			this.applied=true;
		}
	}
	
	this.LoadActive=function (){
		Buttons.Order.forEach(function(btn){
			if(Buttons.Active.has(btn) && !this.buttons.has(btn)){
				this.buttons.push(btn)
			}
		},this)
	}
	return this;
}
Toolbar.attach=function(box,type){
	if(type=='comments' && Apply.comments==false) return;
	var tb=new Toolbar(type);
	tb.LoadActive();
	tb.apply(box);
}
Toolbar.refreshAll=function(){
	$x(Global.XPath.AllToolbars).forEach(function(el){
		$(el).nextSibling.setAttribute('hasToolbar','false');
		$(el).remove();
	});
	pageCheck.applyAll();
}

var IconCache = new (function(){
	this.cached=false;
	this.icons=[];
	this.extract=function(str){
		str.split("\n").forEach(function(line,idx,ary){
			if(line.replace(/ /,'')!='') this.icons.push(line);
		},this);
		this.cached=true;
	}
	this.getIcons=function(){
		if(this.cached){
			var elArray=[];
			this.icons.forEach(function(icon,idx,ary){
				elArray.push("<div class='IconItem'><img src='http://dp.thezikes.org/Icons/"+icon+"' /> "+icon+"</div>")
			},elArray);
			return elArray.join('');
		}else{
			GM_log("Tried to retrieve icons before they were loaded.");
			return [];
		}
	}
	this.fill=function(list){
		if(!this.cached){
			get(Global.URL.Icons, function(filecontents){
				IconCache.extract(filecontents);
				IconCache.fill(list);
			});
		}else{
			list.innerHTML=IconCache.getIcons();
			var fn=function(evt){
				var txt=$('txtCustomIcon');
				txt.value=this.firstChild.getAttribute('src');
				$('IconList').style.display='none';
				txt.selectionEnd=txt.selectionStart=txt.value.length;
				txt.focus();
			}
			for(var x=0;x<list.childNodes.length; x++){
				addEvent(list.childNodes[x], 'click', fn)
			}
			list.className=list.className.replace(/loading/,'');
		}
	}
})();

// Prototype.js extend method
Object.extend = function(dest, src){
	for(var prop in src) if(src.hasOwnProperty(prop)){
		dest[prop]=src[prop];
	}
	return dest;
}

// Prototyping
Object.extend(String.prototype,{
	makeUrl:function(){
		var str=this.toString();
		var url='';
		if(str.match(/^http:\/\//i)){
			url=str;
		}else if(str.match(/^www|^[a-z]*\./i)){
			url='http://'+str;
		}else{
			url=str;
		}
		return url;
	}
});

Object.extend(Array.prototype,{
	remove:function(itm){
		for(var i=0; i<this.length; i++){
			if(this[i]==itm){
				delete this[i];
			}
		}
		return this;
	},
	has:function(itm){
		for(var i=0; i<this.length; i++){
			if(this[i]===itm){
				return true;
			}
		}
		return false;
	},
	clean:function(){
		var out=[];
		for (var i=0; i<this.length; i++){
			if(this[i]!='' && this[i]!=null && this[i]!=undefined){
				out.push(this[i]);
			}
		}
		return out;
	},
	unique:function(){
		var out=[];
		for(var i=0; i<this.length; i++){
			if(!out.has(this[i])){out.push(this[i])}
		}
		return out;
	},
	find:function(itm){
		for(var i=0; i<this.length; i++){
			if(this[i]==itm) return i;
		}
		return -1;
	},
	move_element:function(idx, delta){
		var idx2, tmp;
		if(idx<0 || idx>=this.length){return false;}
		idx2=idx+delta;
		if(idx2<0 || idx2 >= this.length || idx2==idx){return false;}
		tmp=this[idx2]; this[idx2]=this[idx]; this[idx]=tmp;
		return true;
	}
});

function $(id){
	if(arguments.length>1){
		var els=new NodeList();
		Array.prototype.forEach.call(arguments, function(arg){
			els.addNode(arg);
		});
		return els;
	}else{
		var el=(typeof(id)=='string'?document.getElementById(id):id);
		if(el){
			el.remove=function(){this.parentNode.removeChild(this)};
		}
		return el;
	}
}

// Get elements by xpath
function $x(xpath,root){
	var got=document.evaluate(xpath,root||document,null,null,null), result=[];
	while(next=got.iterateNext()) result.push(next);
	return result;
}

function NodeList(ary){
	this.nodes=ary || [];
	this.each=function(fn){
		this.nodes.forEach(function(node,idx,ary){
			fn(node, idx, ary);
		});
	};
	this.apply=function(mthd){this.each(function(node){$(node)[mthd]()}); return this}
	this.addNode=function(node){
		if(node instanceof Array){
			node.forEach(function(itm){
				this.addNode(itm);
			},this)
		}else{
			this.nodes.push(node);
		}
	}
}

function addEvent(obj, evType, fn, useCapture){
	if(!obj) return;
	if(typeof(evType)=='string') evType=[evType];
	evType.forEach(
		function(evnt, idx, ary){
			obj.addEventListener(evnt, fn, useCapture);
		}
	)
}
function extractNumberFromURL(url){var tmp=url.match(/(\d*)\/?$/); return (tmp && tmp[1] ? tmp[1] : tmp) || '';}

function get(url,cb){GM_xmlhttpRequest({method:"GET", url:url, headers:{'User-Agent':'Firefox / GreaseMonkey / deviantPLUS'}, onload:function(xhr){cb(xhr.responseText)}})}
function post(url,data,cb){GM_xmlhttpRequest({method:"POST", url:url, headers:{'User-Agent':'Firefox / GreaseMonkey / deviantPLUS', 'Content-type':'application/x-www-form-urlencoded'},data:encodeURI(data),onload:function(xhr){cb(xhr.responseText)}})}

function getParent(el, pTagName){
	if (el == null)
		return null;
	else if(el.nodeType == 1 && (pTagName == null || el.tagName.toLowerCase() == pTagName.toLowerCase()))	// Gecko bug, supposed to be uppercase
		return el;
	else
		return getParent(el.parentNode, pTagName);
}
unsafeWindow.getParent = getParent;

function surroundText(tf,left,right){
	var tmpScroll=tf.scrollTop;
	t=tf.value;
	s=tf.selectionStart;
	e=tf.selectionEnd;
	var selectedText=tf.value.substring(s,e);
	tf.value=t.substring(0,s)+left+selectedText+right+t.substring(e)
	tf.selectionStart=s+left.length;
	tf.selectionEnd=s+left.length+selectedText.length;
	tf.scrollTop=tmpScroll;
	tf.focus();
}
function insertText(tf,txt){
	var tmpScroll=tf.scrollTop;
	t=tf.value;
	s=tf.selectionStart;
	e=tf.selectionEnd;
	var selectedText=tf.value.substring(s,e);
	tf.value=t.substring(0,s)+txt+selectedText+t.substring(e)
	tf.selectionStart=s;
	tf.selectionEnd=s+txt.length;
	tf.scrollTop=tmpScroll;
	tf.focus();
}

// Initialize
(function(){
	Timer.newTime("Initializing.");
	var dpApply=GM_getValue(Global.GM_Key.Apply, Global.Default.Apply);
	dpApply = (dpApply == "" ? dpApplyDefault : dpApply);
	Apply.importSettings(dpApply);
	Apply.save();
	Timer.newTime("Finished initializing.");
})()

//////////////////////////////////////
////       Load the Buttons       ////
//////////////////////////////////////

var Buttons={
	Button:{},
	Order:[],
	Active:[],
	'reset':function(){
		GM_setValue(Global.GM_Key.Buttons, Global.Default.Buttons);
		GM_setValue(Global.GM_Key.Active, Global.Default.Active);
		GM_setValue(Global.GM_Key.Order, Global.Default.Order);
		Buttons.Button={};
		Buttons.Order=[];
		Buttons.Active=[];
		Buttons.load();
	},
	'add':function(btns,save,update){
		// Is the value a string?
		if(typeof(btns)=='string'){
			// Eval string and add result button object
			return Buttons.add(eval('('+btns+')'),save,update);
		}
		
		// Is the value an array of buttons?
		if(btns instanceof Array){
			// Loop through array values and add each button individually
			btns.forEach(function(btn){
				Buttons.add(btn,save,update);
			});
			
		// Is the value already an object?
		}else if(typeof(btns)=='object'){
			
			// Combine namespace and name for unique name
			var btnName=(btns.ns.replace(/[\:\|]/,'')+':'+btns.name.replace(/[\:\|]/,'')).replace(/\s/g,'');
			
			// Check to see if button with that name already exists
			if(Buttons.Button[btnName]!==undefined){
				// Button exists
				
				// Ok to update existing?
				if(!update){
					// Does the button's name already denote a duplicate?
					if(btns.name.indexOf('_dup')!==-1){
						// Yes, increment duplication
						var parts=btns.name.split('_dup');
						btns.name=parts[0]+'_dup'+(parseInt(parts[1],10)+1);
					}else{
						// No, mark as duplicate
						btns.name+='_dup1';
					}
					// Recreate full name
					btnName=(btns.ns.replace(/[\:\|]/,'')+':'+btns.name.replace(/[\:\|]/,'')).replace(/\s/g,'');
				}
			}
			
			// Store button
			Buttons.Button[btnName]=btns;
			
			// If the button does not exist in the Order list, append it
			if(!Buttons.Order.has(btnName)){
				Buttons.Order.push(btnName);
			}
			
			// If the button does not exist in the Active list, append it
			if(!Buttons.Active.has(btnName)){
				Buttons.Active.push(btnName);
			}
		}
		
		if(save!==false){
			// Save button
			Buttons.save();
		}
	},
	'import':function(url, fn_oncomplete){
		var trusted=false;
		if(url.match(/^http:\/\/dp.thezikes.org\/Buttons/)){
			trusted=true;
		}
		fn_oncomplete=fn_oncomplete || function(){};
		get(url, function(results){
			if(!trusted && !confirm('!!! WARNING !!!\n\nDo not install deviantPLUS buttons from sources you do not trust!  Malicious button code is capable of accessing and manipulating your deviantART account, so install at your own risk.\n\nClick OK to continue installing or Cancel to stop.')){
				return;
			}
			Buttons.add(results, false);
			Buttons.save();
			if($('listButtons')) loadListButtons();
			fn_oncomplete();
			alert('Import complete!');
		});
	},
	'delete':function(btn){
		delete Buttons.Button[btn];
		Buttons.Order.remove(btn);
		Buttons.Active.remove(btn);
		Buttons.save();
	},
	'save':function(){
		var btnList=[];
		for(btn in Buttons.Button) if(Buttons.Button.hasOwnProperty(btn)){
			if(!btnList.has(btn)) btnList.push(btn);
			GM_setValue(btn, uneval(Buttons.Button[btn]));
		}
		GM_setValue(Global.GM_Key.Buttons, btnList.clean().join('|'));
		GM_setValue(Global.GM_Key.Order, Buttons.Order.clean().join('|'));
		GM_setValue(Global.GM_Key.Active, Buttons.Active.clean().join('|'));
	},
	'load':function(fn_onload){
		fn_onload=fn_onload || function(){};
		var strButtonList=GM_getValue(Global.GM_Key.Buttons,Global.Default.Buttons);
		Buttons.Order=GM_getValue(Global.GM_Key.Order,strButtonList).split('|').clean().unique();
		Buttons.Active=GM_getValue(Global.GM_Key.Active,strButtonList).split('|').clean().unique();
		if(strButtonList==''){ 
			// Buttons not loaded, import defaults
			Buttons.import(Global.URL.Buttons, function(){
				pageCheck.applyAll();
				fn_onload();
			});
		}else{
			// Buttons loaded, continue
			var ary=strButtonList.split(/\|/).clean().unique();
			ary.forEach(function(btn){
				var btnJSON=GM_getValue(btn,null);
				if(btnJSON===null){
					// Button does not exist, confirm removal
					GM_log('WARNING: Button "'+btn+'" does not exist!');
				}else{
					Buttons.add(btnJSON)
				}
			});
			fn_onload();
		}
	},
	'activate':function(btn){
		if(btn=='' || btn==undefined) return;
		if(!Buttons.Active.has(btn)){
			Buttons.Active.add(btn);
		}
		GM_setValue(Global.GM_Key.Active, Buttons.Active.clean().unique().join('|'))
	},
	'deactivate':function(btn){
		if(btn=='' || btn==undefined) return;
		Buttons.Active.remove(btn);
		GM_setValue(Global.GM_Key.Active, Buttons.Active.clean().unique().join('|'))
	},
	'moveUp':function(btn){
		var ret=Buttons.Order.move_element(Buttons.Order.find(btn),-1)
		GM_setValue(Global.GM_Key.Order, Buttons.Order.clean().unique().join('|'));
		return ret;
	},
	'moveDown':function(btn){
		var ret=Buttons.Order.move_element(Buttons.Order.find(btn),1);
		GM_setValue(Global.GM_Key.Order, Buttons.Order.clean().unique().join('|'));
		return ret;
	},
	'make':function(str){
		var objButton;
		if(Buttons.Button[str]){
			objButton = Buttons.Button[str]
		}else{
			var ns=str.split(':').clean()[0];
			var name=str.split(':').clean()[1];
			var json=GM_getValue(str, "");
			if(json==""){
				GM_log("The custom button "+str+" does not exist");
				/*var remove=confirm("The custom button "+str+" does not exist, remove it from index?");
				if(remove){
					Buttons.delete(str);
				}*/
				return false;
			}
			objButton = eval('('+json+')');
		}

		if(!objButton.styles){
			objButton.styles={};
			objButton.styles.backgroundImage=buttonSetImage;
		}

		var btn=$E('a', {href:'#'});

		if(objButton.icon){
			btn.appendChild($E('i',{style:{backgroundImage:'url('+objButton.icon+')'}}));
		}
		if(objButton.styles){
			for(prop in objButton.styles){
				btn.style[prop]=objButton.styles[prop]
			}
		}
		// This actually worked on the first try! O.o
		['styles','depressedStyles','hoverStyles'].forEach(function(style,idx,ary){
			if(objButton[style]){
				addEvent(
					btn,
					{styles:'mouseout',depressedStyles:'mousedown',hoverStyles:['mouseover','mouseup']}[style],
					function(evt){
						for(prop in objButton[style]){
							this.style[prop]=objButton[style][prop];
						}
					}
				);
			}
		});

		btn.className='dpButton '+(!!objButton.className ? objButton.className : '');
		btn.setAttribute('title',objButton.title);
		btn.setAttribute('allowedin',objButton.allowedIn)
		switch(objButton.type){
			case 'surround':
				// Create an anonymous function that returns an anonymous function and then call it anonymously
				addEvent(btn, 'click', (function(left, right){
					return function(evt){
						var tf=getParent(this,'div').nextSibling;
						var keys=new keySet();
						[left, right].forEach(function(str,idx,ary){
							keys.extractKeys(str);
						});
						var tmpLeft = keys.applyKeys(left);
						var tmpRight = keys.applyKeys(right);
						surroundText(tf,tmpLeft,tmpRight);
						evt.preventDefault();
					}
				})(objButton.surroundText.left.toString(),objButton.surroundText.right.toString()),true);
				// No, srsly
				break;
			case 'insert':
				// Do it again!
				addEvent(btn, 'click', (function(str){
					return function(evt){
						evt.preventDefault();
						var tf=getParent(this,'div').nextSibling;
						var keys=new keySet();
						keys.extractKeys(str);
						var tmpStr=keys.applyKeys(str);
						insertText(tf,tmpStr);
					}
				})(objButton.insertText.toString()),true);
				break;
			case 'advanced':
				for(evt in objButton.events){addEvent(btn, evt, objButton.events[evt])}
				break;
			case 'replacemap':
				get(objButton.replaceMapURL,function(txt){
					var ary=eval(txt);
					function regexify(str){
						return RegExp(str.replace(/(\W)/g, "\\$1"),"g");
					}
					addEvent(btn, 'click', function(evt){
						evt.preventDefault();
						var tf=getParent(this,'div').nextSibling;
						var str=tf.value;
						ary.forEach(function(itm){
							if(itm[0]!=='' && itm[0]!==':'){
								str=str.replace(regexify(itm[0]),':thumb'+itm[1]+':');
							}
						});
						tf.value=str;
					});
				})
				break;
		}
		return btn;
	}
}

Buttons.load();

function setStatusMessage(msg, timeout){
	if($('dpStatusMessage')){
		$('dpStatusMessage').innerHTML=msg;		
		$('dpStatusMessage').style.display="block";
		window.setTimeout(function(){
			if($('dpStatusMessage')) $('dpStatusMessage').style.display="none";		   
		}, timeout || 5000);
	}
}

var PrefsWindow={
	Width:700,
	Height:500,
	Tabs:[
		{
			id:'dpTabButtons',
			title:'Buttons',
			active:true,
			page:{
				id:'dpPageButtons',
				contents:"<table width='100%' id='tblCustomButtons'>"
								+"<tr>"
									+"<td>"
										+"<div id='listButtons'></div>"
										+"<div align='right'>"
											+"<input type='button' id='btnReset' value='Reset'/> "
											+"<input type='button' id='btnImport' value='Import'/>"
											+"<input type='button' id='btnNew' value='New Button'/>"
										+"</div>"
									+"</td>"
									+"<td class='scrollvert'>"
										+"<div id='ScrollingDiv'>"
											+"<label for='txtCustomNamespace'>Namespace:</label>"
											+"<input type='text' id='txtCustomNamespace' value='"+username+"' />"

											+"<label for='txtCustomName'>Name:</label>"
											+"<input type='text' id='txtCustomName' />"

											+"<label for='txtCustomTitle'>Title:</label>"
											+"<input type='text' id='txtCustomTitle' />"

											+"<label for='txtCustomIcon'>Icon:</label>"
											+"<input type='text' id='txtCustomIcon' />"
											+"<input type='button' value='&#9662;' id='btnShowIcons' /><br />"

											+"<label for='txtCustomDescription' style='font-weight:normal; font-size:11px;'>Description:</label> <br />"
											+"<textarea id='txtCustomDescription' rows='3'></textarea>"

											+"<label for='cbSubscriberOnly' style='width:115px; text-align:left'>Subscribers Only:</label>"
											+"<input type='checkbox' id='cbSubscriberOnly' /> <br />"
											+"<table width='100%'><tr>"
												+"<td valign='top' align='right' width='86'><strong style='white-space:nowrap'>Show in:</strong></td>"
												+"<td valign='top'>"
													+"<input type='checkbox' id='cbJournalBody' checked='checked' /><label class='cb' for='cbJournalBody'>Journal Body</label><br />"
													+"<input type='checkbox' id='cbJournalHeader' checked='checked' /><label class='cb' for='cbJournalHeader'>Journal Header</label><br />"
													+"<input type='checkbox' id='cbJournalFooter' checked='checked' /><label class='cb' for='cbJournalFooter'>Journal Footer</label><br />"
													+"<input type='checkbox' id='cbCSS' checked='checked' /><label class='cb' for='cbCSS'>Journal CSS</label><br />"
													+"<input type='checkbox' id='cbComments' checked='checked' /><label class='cb' for='cbComments'>Comments</label><br />"
													+"<input type='checkbox' id='cbForums' checked='checked' /><label class='cb' for='cbForums'>Forums</label><br />"
													+"<input type='checkbox' id='cbDescriptions' checked='checked' /><label class='cb' for='cbDescriptions'>Deviation Descriptions</label><br />"
													+"<input type='checkbox' id='cbLiterature' checked='checked' /><label class='cb' for='cbLiterature'>Literature</label><br />"
												+"</td><td valign='top'>"	
													+"<input type='checkbox' id='cbNotes' checked='checked' /><label class='cb' for='cbNotes'>Notes</label><br />"
													+"<input type='checkbox' id='cbShoutboards' checked='checked' /><label class='cb' for='cbShoutboards'>Shoutboards</label><br />"
													+"<input type='checkbox' id='cbShoutboxes' checked='checked' /><label class='cb' for='cbShoutboxes'>Shoutboxes</label><br />"
													+"<input type='checkbox' id='cbPrintsDesc' checked='checked' /><label class='cb' for='cbPrintsDesc'>Prints Descriptions</label><br />"
													+"<input type='checkbox' id='cbSignatures' checked='checked' /><label class='cb' for='cbSignatures'>Signatures</label><br />"
													+"<input type='checkbox' id='cbNews' checked='checked' /><label class='cb' for='cbNews'>News Articles</label><br />"
													+"<input type='checkbox' id='cbHelp' checked='checked' /><label class='cb' for='cbHelp'>Help Desk</label><br />"
												+"</td>"
											+"</tr></table>"

											+"<label for='selCustomType'>Button Type:</label>"
											+"<select id='selCustomType'><option value='insert'>Insert</option><option value='surround'>Surround</option><option value='replacemap'>Replace Map</option><option value='advanced'>Advanced</option></select>"

											+"<div id='trButtonTypeProperties'>"
												+"<div id='pgInsert' class='page active'>"
													+"<label for='txtCustomInsert'>Text to Insert:</label> <br />"
													+"<textarea id='txtCustomInsert' rows='3'></textarea>"
												+"</div>"
												+"<div id='pgAdvanced' class='page'>"
													+"<label for='txtCustomClickFunction'>Click Function:</label> <br />"
													+"<textarea id='txtCustomClickFunction' rows='9'></textarea>"
												+"</div>"
												+"<div id='pgReplaceMap' class='page'>"
													+"<label for='txtReplaceMapURL'>URL:</label>"
													+"<input type='text' id='txtReplaceMapURL' />"
												+"</div>"
												+"<div id='pgSurround' class='page'>"
													+"<label for='txtCustomSurroundLeft'>Text on Left:</label> <br />"
													+"<textarea id='txtCustomSurroundLeft'></textarea><br />"
													+"<label for='txtCustomSurroundRight'>Text on Right:</label> <br />"
													+"<textarea id='txtCustomSurroundRight'></textarea>"
												+"</div>"
											+"</div><br/>"
											+"<div align='right'>"
												+"<input type='button' id='btnExport' value='Export' />"
												+"<input type='button' id='btnSaveCustom' value='Save' />"
											+"</div>"
										+"</div>"
									+"</td>"
							+"</table>",
				init:function(){
					addEvent($('selCustomType'), 'change', function(){
						var pc=$('trButtonTypeProperties');
						for(var x=0; x<pc.childNodes.length; x++){
							pc.childNodes[x].className='page';
						}
						$('pg'+this.options[this.selectedIndex].text.toString().replace(/ /g,'')).className+=' active';
					});
					
					function save_click(){
						var ns=$('txtCustomNamespace');
						var name=$('txtCustomName');
						var title=$('txtCustomTitle');
						var desc=$('txtCustomDescription');
						var icon=$('txtCustomIcon');
						var type=$('selCustomType');
						var insert=$('txtCustomInsert');
						var custom=$('txtCustomClickFunction');
						var surroundLeft=$('txtCustomSurroundLeft');
						var surroundRight=$('txtCustomSurroundRight');
						var replacemapurl=$('txtReplaceMapURL');

						var Checks=['cbJournalBody','cbJournalHeader','cbJournalFooter','cbComments','cbForums','cbDescriptions','cbNotes','cbShoutboards','cbShoutboxes','cbPrintsDesc','cbSignatures', 'cbNews', 'cbHelp', 'cbCSS', 'cbLiterature'];
						var Values=['body|bodies',  'header',         'footer',         'comments',  'forums',  'descriptions',  'notes',  'shoutboard',   'shoutbox',    'prints',      'signature',    'news',   'help',   'css',   'literature'];

						var btnID=(ns.value.replace(/[\:\|]/g,'')+":"+name.value.replace(/[\:\|]/g,'')).replace(/\s/g,'');
						var newButton=GM_getValue(btnID, true)===true;

						var errs=[];
						if(ns.value==''){errs.push({msg:'Namespace field cannot be left blank.'})}
						if(name.value==''){errs.push({msg:'Name field cannot be left blank.'})}
						if(title.value==''){errs.push({msg:'Title field cannot be left blank.'})}
						switch(type.selectedIndex){
							case 0: // Insert
								if(insert.value==''){errs.push({msg:'An Insert type button requires text to be inserted.'})}
								break;
							case 1: // Surround
								if(surroundLeft.value=='' || surroundRight.value==''){errs.push({msg:'A Surround type button requires a Left and Right text value.'})}
								break;
							case 2: // Replace Map
								if(replacemapurl.value==''){errs.push({msg:'Must specify a URL for Replace Maps.'})}
								break;
							case 3: // Custom
								if(custom.value==''){errs.push({msg:'You must provide a click function in the form of function(evt){}'})}
								break;
						}
						if(errs.length>0){ // Cancel save D:
							var aryErrors=[];
							errs.forEach(function(item,idx,ary){aryErrors.push(item.msg)});
							alert(aryErrors.join("\n"));
						}else{ // Continue save :D

							if(!newButton && !skipConfirm){
								skipConfirm=false;
								if(!confirm("Overwrite existing button?")){return};
							}

							var strType=['insert','surround','replacemap','advanced'][type.selectedIndex]
							var btnObj={
								"ns":ns.value,
								"name":name.value,
								"title":title.value,
								"description":desc.value,
								"allowedIn":(function(chks,vals){
									var ret=[];
									chks.forEach(function(chk,idx){
										if($(chk).checked){
											ret.push(vals[idx].split('|').clean()[0]);
										}
									});
									return ret.join(',');
								})(Checks,Values),
								"type":strType,
								"icon":icon.value,
								"styles":{backgroundImage:buttonSetImage, backgroundPosition:'0 0'},
								"hoverStyles":{backgroundPosition:'-25px 0'},
								"depressedStyles":{backgroundPosition:'-50px 0'}
							};
							switch(strType){
								case "insert":
									btnObj.insertText=insert.value;
									break;
								case "surround":
									btnObj.surroundText={left:surroundLeft.value,right:surroundRight.value};
									break;
								case "replacemap":
									btnObj.replaceMapURL=replacemapurl.value;
									break;
								case "advanced":
									btnObj.events={
										"click":eval('('+custom.value+')')
									};
									break;
							}
							btnObj.subscriberOnly=!!$('cbSubscriberOnly').checked;

							Buttons.add(btnObj,true,true);


							if(newButton){ // Append to lists
								setStatusMessage("Created new button successfully!", 5000);
							}else{				
								setStatusMessage("Saved button successfully!", 5000);
							}
							loadListButtons();
							if($(btnID)){
								$(btnID).className+=' selected';
							}
						}					
					}
					
					addEvent($('btnSaveCustom'), 'click', save_click);
					
					addEvent($('btnExport'),'click',function(){
						var ns=$('txtCustomNamespace').value;
						var name=$('txtCustomName').value;
						var btnID=(ns.replace(/[\:\|]/g,'')+":"+name.replace(/[\:\|]/g,'')).replace(/\s/g,'');
						
						if(Buttons.Button[btnID] && !confirm('Save and export button?  This will overwrite the existing button with the same namespace and name.')){
							return;
						}
						skipConfirm=true;
						save_click();
						location.href='http://dp.thezikes.org/Buttons/export.php?ns='+escape(ns)+'&name='+escape(name)+'&obj='+escape(uneval(Buttons.Button[btnID]));
					});
					
					addEvent($('btnShowIcons'), 'click', function(){
						if($('IconList')==null){
							btn=$('btnShowIcons');
							txt=$('txtCustomIcon');
							var listWidth=258;
							var listHeight=205;
							var listLeft=txt.offsetLeft;
							var listTop=txt.offsetTop+txt.offsetHeight-1;
							var list=$E('div', {id:'IconList', className:'loading', style:{
								width:listWidth+'px',
								height:listHeight+"px",
								top:listTop+"px",
								left:listLeft+"px"
							}});
							$('ScrollingDiv').appendChild(list);
							IconCache.fill(list);
						}else{
							var list=$('IconList');
							list.style.display=(list.style.display=='none' ? 'block' : 'none');
						}
					});
					
					['change','click','focus','blur','keyup'].forEach(function(evt,idx,ary){
						addEvent($('txtCustomIcon'), evt, function(){
							this.style.backgroundImage='url('+this.value+')';
						});
					});
					
					loadListButtons();
				}
			}
		},
		{
			id:'dpTabToolbars',
			title:'Toolbars',
			active:true,
			page:{
				id:'dpPageToolbars',
				contents:"Choose which textboxes you would like the toolbars applied to."
					+"<div id='ApplyToolbars'>"
						+"<table width='100%'><tr>"
							+"<td valign='top'>"
								+"<input type='checkbox' id='cbApplyJournalBody' /><label class='cb' for='cbApplyJournalBody'>Journal Body</label><br />"
								+"<input type='checkbox' id='cbApplyJournalHeader' /><label class='cb' for='cbApplyJournalHeader'>Journal Header</label><br />"
								+"<input type='checkbox' id='cbApplyJournalFooter' /><label class='cb' for='cbApplyJournalFooter'>Journal Footer</label><br />"
								+"<input type='checkbox' id='cbApplyCSS' /><label class='cb' for='cbApplyCSS'>Journal CSS</label><br />"
								+"<input type='checkbox' id='cbApplyComments' /><label class='cb' for='cbApplyComments'>Comments</label><br />"
								+"<input type='checkbox' id='cbApplyForums' /><label class='cb' for='cbApplyForums'>Forums</label><br />"
								+"<input type='checkbox' id='cbApplyDescriptions' /><label class='cb' for='cbApplyDescriptions'>Deviation Descriptions</label><br />"
								+"<input type='checkbox' id='cbApplyLiterature' /><label class='cb' for='cbApplyLiterature'>Literature</label><br />"
								+"<input type='checkbox' id='cbApplyNotes' /><label class='cb' for='cbApplyNotes'>Notes</label><br />"
								+"<input type='checkbox' id='cbApplyShoutboards' /><label class='cb' for='cbApplyShoutboards'>Shoutboards</label><br />"
								+"<input type='checkbox' id='cbApplyShoutboxes' /><label class='cb' for='cbApplyShoutboxes'>Shoutboxes</label><br />"
								+"<input type='checkbox' id='cbApplyPrintsDesc' /><label class='cb' for='cbApplyPrintsDesc'>Prints Descriptions</label><br />"
								+"<input type='checkbox' id='cbApplySignatures' /><label class='cb' for='cbApplySignatures'>Signatures</label><br />"
								+"<input type='checkbox' id='cbApplyNews' /><label class='cb' for='cbApplyNews'>News Articles</label><br />"
								+"<input type='checkbox' id='cbApplyHelp' /><label class='cb' for='cbApplyHelp'>Help Desk</label><br />"
							+"</td>"
						+"</tr></table>"
						+"<button id='btnSaveToolbars'>Save Changes</button>"
					+"</div>",
				init:function(){
					var Checks=['cbApplyJournalBody','cbApplyJournalHeader','cbApplyJournalFooter','cbApplyComments','cbApplyForums','cbApplyDescriptions','cbApplyNotes','cbApplyShoutboards','cbApplyShoutboxes','cbApplyPrintsDesc','cbApplySignatures','cbApplyNews','cbApplyHelp','cbApplyCSS','cbApplyLiterature'];
					var Values=[
						'body','header','footer','comments','forums',
						'descriptions','notes','shoutboard','shoutbox',
						'prints','signature','news','help','css','literature'
					];
					Checks.forEach(function(chk,idx){
						$(chk).checked=Apply[Values[idx]];
					});
					addEvent($('btnSaveToolbars'), 'click', function(){
							Checks.forEach(function(chk,idx){
								Apply[Values[idx]]=($(chk).checked ? true : false);
							});
							Apply.save();
					});
				}
			}
		},
		{
			id:'dpTabHelp',
			title:'Help',
			active:true,
			page:{
				id:'dpPageHelp',
				contents:'<table id="tblHelp">'
					+'<tbody>'
						+'<tr>'
							+'<td class="subjects"><div class="holder"></div></td>'
							+'<td class="contents"><div></div></td>'
						+'</tr>'
					+'</tbody>'
				+'</table>',
				init:function(){
					var table=$x('//table[@id="tblHelp"]')[0];
					var subjects=$x('//table[@id="tblHelp"]//td[@class="subjects"]/div')[0];
					var contents=$x('//table[@id="tblHelp"]//td[@class="contents"]/div')[0];
					function addSubject(subj, url){
						subjects.appendChild(
							$E(
								'div',{
									className:'subject',
									events:{
										'click':function(){
											get(url,function(details){
												contents.innerHTML=formatWikiText(details);
											});
											for(var i=0; i<subjects.childNodes.length; i++){
												subjects.childNodes[i].className='subject';
											}
											this.className='subject selected'
										}
									}
								},[subj]
							)
						);
					}
					function formatWikiText(str){
						return str.replace(/\</g, '&lt;').replace(/\>/g, '&gt;')
							.replace(/^====== *(.*) *======$/mg,"<h3>$1</h3>")
							.replace(/\[\[([^\|]+)\]\]/g,"<a href=''>$1</a>")
							.replace(/\[\[([^\|]+)\|([^\|]+)\]\]/g,"<a href='$1'>$2</a>")
							.replace(/^((\t.+\n)+)$/gm, '<code style="display:block;">$1</code>').replace(/^\<pre\>\t/g,'<code>')
							.replace(/^''((.+\n?)+)''/gm, '<code style="display:block;">$1</code>')
							.replace(/\*\*(.+?)\*\*/g,'<strong>$1</strong>')
							.replace(/^[-]{2,}$/mg,'<hr />')
							.replace(/^\\\\/mg,'')
							.replace(/\n/g,'<br />')
							.replace(/(\<\/h3\>|\<hr \/\>)\<br \/\>/g,'$1');
					}
					
					addSubject('FAQ','http://dp.thezikes.org/wiki/data/pages/faq.txt');
					window.setTimeout(function(){
						get('http://dp.thezikes.org/wiki/data/pages/articles.txt',function(details){
							details.split(/\n/).forEach(function(line){
								subj=line.replace(/(\[\[|\]\])/g,'');
								addSubject(subj, 'http://dp.thezikes.org/wiki/data/pages/'+subj.replace(/ /g,'_').toLowerCase()+'.txt');
							});
						})
					},10);
					
				}
			}
		},
		{
			id:'dpTabAbout',
			title:'About',
			active:true,
			page:{
				id:'dpPageAbout',
				contents:"<h3 align='center'>deviantPLUS v"+dpVersion+"</h3>"
						+"<strong>Programmed By:</strong> <a href='http://zikes.deviantart.com/'>Zikes</a>, <a href='http://solitude12.deviantart.com/'>Solitude12</a>, and <a href='http://electricnet.deviantart.com/'>electricnet</a><br />"
						+"<strong>Designed By:</strong> <a href='http://mynti.deviantart.com/'>mynti</a>, <a href='http://solitude12.deviantart.com/'>Solitude12</a>, and <a href='http://electricnet.deviantart.com/'>electricnet</a><br /><br />"
						+"<div id='Updater'>Checking for updates...</div>"
						+"<br />"
						+"<h4>Release Notes</h4>"
						+"<div id='ReleaseNotes'></div>"
						+"<p class=\"yellow\">Button icons from <a href=\"http://www.famfamfam.com/lab/icons/silk/\">famfamfam.com</a> (with some modified by the wonderful mynti). Go check 'em out for 1000+ amazing, <em>free</em> 16x16 general purpose icons!</p>",
				init:function(){
					window.setTimeout(function(){
						get(Global.URL.Version, function(details){
							var updater=$('Updater');
							if(updater){
								var str=details.replace(/[^a-z0-9.]/g, '');
								if(str==dpVersion){
									updater.innerHTML='Your version of deviantPLUS is up to date.';
								}else{
									updater.innerHTML='Your version of deviantPLUS is not up to date, you may download the newer version here: <a href="http://dp.thezikes.org/deviantplus_v3.user.js">http://dp.thezikes.org/deviantplus_v3.user.js</a>';
								}
							}
						});
						get(Global.URL.ReleaseNotes, function(details){
							$('ReleaseNotes').innerHTML=details.replace(/\[(.*)\]/g, "<strong>$1</strong>")
								.replace(/\n/g,'<br />');
						});
					}, 1000);
				}
			}
		}
	],
	Output:{
		window:function(){

			Global.Element.Body.appendChild($E('span',{id:'dpPrefs_bgcover'},[$E('span', {id:'dpStatusMessage'})]));
			
			var dpWindow=$E(
				'div',{
					id:'dpPrefsWindow',
					style:{
						width:PrefsWindow.Width+'px',
						height:PrefsWindow.Height+'px',
						left:((document.documentElement.clientWidth/2) - (PrefsWindow.Width/2))+'px',
						top:((document.documentElement.clientHeight/2) - (PrefsWindow.Height/2))+'px'
					}
				}
			);

			dpWindow.innerHTML=PrefsWindow.Output.title()+PrefsWindow.Output.tabBar()+PrefsWindow.Output.pages();

			Global.Element.Body.appendChild(dpWindow);

			// Attach Window Close button event
			addEvent($('dpPrefsWindowTitleClose'),'click',function(){
				Toolbar.refreshAll();
				$('dpPrefsWindow','dpPrefs_bgcover').apply('remove');
			});

			// Attach tab button events
			PrefsWindow.Tabs.forEach(function(itm, idx, ary){
				addEvent($(itm.id),'click',function(){
					var page=$(this.getAttribute('for'));
					var tabs=$('dpPrefsWindowTabBar').childNodes;
					for(var x=0; x<tabs.length; x++){
						var tab=tabs[x];
						tab.className='dpPrefsTab'+(tab.getAttribute('for')==page.id ? ' active' : '');
						$(tab.getAttribute("for")).className="dpPrefsPage";
					}
					page.className='dpPrefsPage active';
				});
			});

			addEvent($('btnNew'), 'click', function(){
				var rows=$('listButtons').childNodes;
				for(var i=0; i<rows.length; i++){
					rows[i].className=rows[i].className.replace(/selected/g,'')
				}
				resetFields();
				setStatusMessage("Fields have been reset for adding.", 5000);		
			});
			addEvent($('btnReset'), 'click', function(){if(confirm('This will remove all buttons and reload the defaults, are you sure?')){Buttons.reset();}});

			PrefsWindow.Tabs.forEach(function(tab){
				if(tab.page.init){
					tab.page.init();
				}
			});

			addEvent($('btnImport'), 'click', function(){
				var url = prompt('Please enter the URL of the button to import:');
				if(url){
					Buttons.import(url.makeUrl()+"?"+(new Date()).getTime());
				}
			});

			/*addEvent(bg,'click',function(){
				$('dpPrefsWindow').parentNode.removeChild($('dpPrefsWindow'));
				$('dpPrefs_bgcover').parentNode.removeChild($('dpPrefs_bgcover'));
			},true);*/
		},
		title:function(){
			return "<div id='dpPrefsWindowTitle'>"
				+"<a id='dpPrefsWindowTitleClose'><img src='data:image/gif;base64,R0lGODlhDwAPAJEAAP////X09EdSS////yH5BAEHAAMALAAAAAAPAA8AAAIrnC2Zx6O/GJxnWpRAUAEox2lCt1mjJpoJqa5oabHsp6TnB7ZC1TZqw8MdCgA7' /></a>"
				+"deviantPLUS 3 <span>Preferences</span>"
			+"</div>"
		},
		tabBar:function(){
			var out=[];
			out.push("<div id='dpPrefsWindowTabBar'>");
			for(var i=0; i<PrefsWindow.Tabs.length; i++){
				var tab=PrefsWindow.Tabs[i];
				if(tab.active) out.push("<a id='"+tab.id+"' for='"+tab.page.id+"' class='dpPrefsTab"+(i==0 ? ' active' : '')+"'>"+tab.title+"</a>");
			}
			out.push("</div>");
			return out.join('');
		},
		pages:function(){
			var out=[];
			var tabs=PrefsWindow.Tabs;
			out.push("<div id='dpPrefsWindowBody'>");
			for(var i=0; i<tabs.length; i++){
				var tab=tabs[i];
				var page=tab.page;
				if(tab.active){
					out.push("<div id='"+page.id+"' class='dpPrefsPage"+(i==0 ? ' active' : '')+"'>");
					out.push(page.contents);
					out.push("</div>");
				}
			}
			out.push("</div>");
			return out.join('');
		}
	}
}

function showPrefs(){
	PrefsWindow.Output.window();
}

function loadListButtons(){
	var lb=$('listButtons');
	var id;
	var sel=lb.getElementsByClassName('selected');
	if(sel && sel[0]){
		id=sel[0].id;
	}
	lb.innerHTML=''; // empty it :D
	buttonloop: for(var i=0; i<Buttons.Order.length; i++){
		
		/*** BUTTON ***/
		var btnName = Buttons.Order[i];
		if(!btnName){continue buttonloop;}
		var btnObj=Buttons.Button[btnName];
		if(!btnObj){continue buttonloop;}
		lb.appendChild($E('div',{title:btnObj.description, className:'row'+(id && id==btnName ? ' selected' : ''), id:btnName, events:{
				click:function(evt){
					loadSavedButton(this.id);
					var rows=$('listButtons').childNodes;
					for(var i=0; i<rows.length; i++){
						rows[i].className=rows[i].className.replace(/selected/g,'')
					}
					this.className+=' selected';
				},
				selectstart:function(evt){
					evt.stopPropagation();
					evt.preventDefault();
				}
			}},[
			$E('i',{className:'icon',style:{backgroundImage:'url('+btnObj.icon+')'}}),
			$E('strong',[$S(btnObj.title)]),
			$E('br'),
			$S(btnObj.description || ''),
			$E('div', {className:"fade"}),
			$E('span', {
				title:(Buttons.Active.has(btnName) ? 'Disable' : 'Enable'),
				className:"active"+(Buttons.Active.has(btnName) ? '' : ' disabled'),
				events:{
					click:function(evt){
						evt.stopPropagation();
						if(this.className.indexOf("disabled")>-1){ // is disabled
							this.className="active";
							Buttons.activate(this.parentNode.id);
						} else { // is enabled							
							this.className="active disabled";
							Buttons.deactivate(this.parentNode.id);
						}
						loadListButtons();
					}					
				}
			}),
			$E('span', {
			   title:"Move Up",
			   className:"moveup",
			   events:{
					click:function(evt){
						evt.stopPropagation();
						if(Buttons.moveUp(this.parentNode.id)){
							loadListButtons();
						}
					}
			   }
			}),
			$E('span', {
			   title:"Move Down",
			   className:"movedown",
			   events:{
					click:function(evt){
						evt.stopPropagation();
						if(Buttons.moveDown(this.parentNode.id)){
							loadListButtons();
						}
					}
			   }
			}),
			$E('span', {
				title:"Delete",
				className:"delete",
				events:{
					click:function(evt){
						evt.stopPropagation();
						var id=this.parentNode.id;
						var btnObj=Buttons.Button[id];
						if(confirm("Are you sure you want to delete the " + btnObj.title + " button?")){
							Buttons.delete(id);
							loadListButtons();
							resetFields();
							setStatusMessage("Deleted button successfully!", 5000);
						}
					}
				}
			})
		]));
	}
}

function resetFields(){
	function set(ary, prop, val){ary.forEach(function(id){$(id)[prop]=val;})}
	
	$('txtCustomNamespace').value=username;
	$('txtCustomIcon').style.backgroundImage='';
	$('cbSubscriberOnly').checked=false;
	
	set(['txtCustomName', 'txtCustomTitle', 'txtCustomIcon', 
	'txtCustomDescription', 'txtCustomInsert', 'txtCustomClickFunction',
	'txtCustomSurroundLeft', 'txtCustomSurroundRight'
	],'value','');
	
	set(['cbJournalBody','cbJournalHeader','cbJournalFooter',
	'cbComments','cbForums','cbDescriptions','cbNotes',
	'cbShoutboards','cbShoutboxes','cbPrintsDesc','cbSignatures'
	],'checked',true);
	
	$('selCustomType').selectedIndex=0;
	var evt=document.createEvent('HTMLEvents');
	evt.initEvent('change',true,true);
	$('selCustomType').dispatchEvent(evt);
}

function loadSavedButton(btnName){
	var btnObj=Buttons.Button[btnName];
	
	// Load text inputs
	$('txtCustomNamespace').value=btnObj.ns || '';
	$('txtCustomName').value=btnObj.name || '';
	$('txtCustomTitle').value=btnObj.title || '';
	$('txtCustomIcon').value=btnObj.icon || '';
	$('txtCustomIcon').style.background='url('+btnObj.icon+') no-repeat 0 0';
	$('txtCustomDescription').value=btnObj.description || '';
	
	// Load Checkboxes
	$('cbSubscriberOnly').checked=(btnObj.subscriberOnly===true ? true : false);
	var Checks=['cbJournalBody','cbJournalHeader','cbJournalFooter','cbComments','cbForums','cbDescriptions','cbNotes','cbShoutboards','cbShoutboxes','cbPrintsDesc','cbSignatures','cbNews','cbHelp','cbCSS','cbLiterature'];
	var Values=['body|bodies',  'header',         'footer',         'comment',   'forum',   'description',   'note',   'shoutboard',   'shoutbox',    'print',       'signature',   'news',  'help',  'css',  'literature'];
	Checks.forEach(function(id,idx,ary){$(id).checked=(btnObj.allowedIn && btnObj.allowedIn.search(new RegExp(Values[idx]))!=-1)});
	
	// Load button type
	$('selCustomType').selectedIndex={'insert':0,'surround':1,'replacemap':2,'advanced':3}[btnObj.type];
	var evt=document.createEvent('HTMLEvents');
	evt.initEvent('change',true,true);
	$('selCustomType').dispatchEvent(evt);
	switch(btnObj.type.toLowerCase()){
		case 'surround':
			$('txtCustomSurroundLeft').value=btnObj.surroundText.left || '';
			$('txtCustomSurroundRight').value=btnObj.surroundText.right || '';
			break;
		case 'advanced':
			$('txtCustomClickFunction').value=btnObj.events.click || '';
			break;
		case 'replacemap':
			$('txtReplaceMapURL').value=btnObj.replaceMapURL || '';
			break;
		case 'insert':
		default:
			$('txtCustomInsert').value=btnObj.insertText || '';
			break;
	}
}

// SWEET JESUS OVERRIDE DA'S OWN CODE PLZ
var Overrides={
	GMI:function(){
		unsafeWindow.GMFrame_Gruser
	},
	reply:function(){
		unsafeWindow.Comment.reply = function (parentid, link, event, where) {
			if (event && (event.shiftKey || event.ctrlKey))
				return true;
			var obj, box;
			if (link.hasOpenReply){return unsafeWindow.cancelEvent();}
			link.hasOpenReply = true;

			// Create?  More like CLONE.
			box = unsafeWindow.Comment.create(link, where);
			obj = unsafeWindow.Comment.init(box, parentid, link);
			unsafeWindow.Comment.setup(obj);

			// Make a new toolbar.
			var textarea = box.getElementsByTagName('textarea')[0];
			if(textarea && Apply.comments){
				textarea.setAttribute("hasToolbar","false");
				Toolbar.attach(textarea,'comments');
			}

			return unsafeWindow.cancelEvent();
		}

		// For the message centre
		if(unsafeWindow.TalkPost){
			var script=$E('script', {type:'text/javascript'});
				script.innerHTML="var dp_tp_proto_on=TalkPost.prototype.on;\n"+
					"TalkPost.prototype.on=function(){\n"+
						"dp_tp_proto_on.apply(this);\n"+
						"var txt=Tree.get(this.node, '.text');\n"+
						"if(txt){applyDPToolbar(txt,'comments')}\n"+
					"}";
			document.getElementsByTagName('head')[0].appendChild(script);
		}
	}
}

unsafeWindow.applyDPToolbar=Toolbar.attach;

var pageCheck={
	shoutbox:function(){
		if(!Apply.shoutbox) return;
		if(loc.indexOf('shout.deviantart.com')!=-1){
			parent.document.getElementsByTagName('frameset')[0].setAttribute('rows','20,*,80');
		}
		$x(Global.XPath.Shoutbox).forEach(function(shoutBox){
			if(shoutBox.id=='shout-body'){
				Toolbar.attach(shoutBox, 'shoutbox');
			}else{
				Toolbar.attach(shoutBox, 'shoutbox');
				shoutBox.style.width='100%';
				shoutBox.style.marginTop='3px';
			}
		});
	},
	journal:function(){
		if(Apply.body){
			$x(Global.XPath.JournalBody).forEach(function(txt){
				Toolbar.attach(txt, 'body');
			});
		}
		
		if(Apply.header){
			$x(Global.XPath.JournalHeader).forEach(function(txt){
				Toolbar.attach(txt, 'header');
			});
		}
		
		if(Apply.footer){
			$x(Global.XPath.JournalFooter).forEach(function(txt){
				Toolbar.attach(txt, 'footer');
			});
		}
	},
	shoutboard:function(){
		if(!Apply.shoutboard) return;
		if(loc.indexOf('journal/enhancements')!=-1){
			var shoutBoard=$('shoutboard');
			if(shoutBoard){
				Toolbar.attach(shoutBoard,'shoutboard');
			}
		}
	},
	descriptions:function(){
		if(!Apply.descriptions) return;
		
		$x(Global.XPath.Descriptions).forEach(function(txt){
			Toolbar.attach(txt, 'descriptions');
		});

		var btn=$('addtext_button');
		if(btn){
			btn.addEventListener('click', function(){
				var interval=window.setInterval(function(){
					var txt=$x(Global.XPath.Literature);
					if(txt.length>0){
						window.clearInterval(interval);
						Toolbar.attach(txt[0],'literature');
					}
				},1);
			},true);
		}

	},
	notes:function(){
		if(!Apply.notes) return;
		if(loc.indexOf('my.deviantart.com/notes')!=-1){
			var notebody=$('notebody');
			if(notebody.tagName.toLowerCase()=='a'){
				notebody.id='notebodyA';
				notebody=$('notebody');
			}
				
			if(notebody){
				Toolbar.attach(notebody,'notes');
			}
		}
	},
	forums:function(){
		if(!Apply.forums) return;
		if(loc.indexOf('/journal/forum/')!=-1 || loc.indexOf('forum.deviantart.com')!=-1){
			var forumbody=$('commentbody');
			if(forumbody){
				Toolbar.attach(forumbody,'forums');
			}
		}
	},
	signatures:function(){
		if(!Apply.signature) return;
		if(loc.indexOf('deviantart.com/profile')!=-1){
			var sigBox=$('signature');
			if(sigBox){
				Toolbar.attach(sigBox,'signature');
			}
		}
	},
	comments:function(){
		if(!Apply.comments) return;
		$x(Global.XPath.Comments).forEach(function(el){
			Toolbar.attach(el, 'comments');
		});
	},
	prints:function(){
		if(!Apply.prints) return;
		$x(Global.XPath.Prints).forEach(function(el){
			Toolbar.attach(el, 'prints');
		});
	},
	news:function(){
		if(!Apply.news) return;
		$x(Global.XPath.News).forEach(function(el){
			Toolbar.attach(el, 'news');
		});
	},
	help:function(){
		if(!Apply.help) return;
		$x(Global.XPath.Help).forEach(function(el){
			Toolbar.attach(el, 'help');
		});
	},
	css:function(){
		if(!Apply.css) return;
		$x(Global.XPath.CSS).forEach(function(el){
			Toolbar.attach(el, 'css');
		});
	},
	applyAll:function(){
		for(prop in this) if(this.hasOwnProperty(prop) && prop!=='applyAll'){
			(this[prop])();
		}
	}
}

Overrides.reply();
pageCheck.applyAll();
addEvent(window,'click',function(evt){
	if(evt.button==0 && evt.target.nodeName && evt.target.nodeName.toLowerCase()=='a' && evt.target.href.match(/\.dp\.js$/i)){
		evt.preventDefault();
		Buttons.import(evt.target.href);
	}
});

Timer.newTime('Applying custom styles.');

// ==== Make moods look right-ish ====
// In the message centre replies
aryStyleText.push('.talk-post .h td.f.rr{background-color:rgb(222, 232, 229)}');
// TODO: In replies for other areas of the site
// TODO: In normal comments (user pages, deviations, etc)
// TODO: In forums

aryStyleText.push('div.item div.item-body .dpToolbar{width:99%;}');
aryStyleText.push('dl.simple dd .dpToolbar{width:80%; _width:100%;}');
aryStyleText.push('dd.textarea textarea, dd.textarea .dpToolbar{width:100% !important;}');
aryStyleText.push('.dpToolbar{margin-bottom:-1px;overflow:hidden;font-size:13px;clear:both;height:auto; border-bottom:1px solid #8A9D93;background:#54695d url(http://dp.thezikes.org/Images/bg_04.png) repeat-x bottom right;}');
aryStyleText.push('div[type="body"].dpToolbar, div[type="header"].dpToolbar, div[type="footer"].dpToolbar{border-color:rgb(127, 157, 185); border-width:1px; border-style:solid; width:100%;}');
aryStyleText.push('div.thought .dpToolbar{border:none;border-bottom:1px solid rgb(157,177,176);width:100%}');
aryStyleText.push('.dpToolbar a.dpButton, .ButtonList a.dpButton{display:block !important;height:20px !important;width:25px !important;padding:0 !important;overflow:hidden !important;float:left;text-decoration:none !important;text-align:center !important;cursor:default !important;margin:2px 0 2px 2px !important;}');
aryStyleText.push('#btnPreview{width:80% !important;}');
aryStyleText.push('#dpMoodEmote{position:relative;left:30px;}');
aryStyleText.push('.Invisible{display:none;}');
aryStyleText.push('#HelpItems{height:350px;overflow:auto;border-style:solid;}');
aryStyleText.push('.ButtonInfo Strong{font-size:8pt !important; white-space: nowrap;}');
aryStyleText.push('.nowrap{font-size:8pt !important; white-space: nowrap;}');
aryStyleText.push('.nowrap input{width:auto !important;}');
aryStyleText.push('.ButtonInfo input, .ButtonInfo select{width:100%;}');
aryStyleText.push('#submit .submissionstep .dpToolbar{width:402px !important}');
aryStyleText.push('#HelpItems div{height:339px;margin-left:10px;padding:5px;overflow:auto;}');
aryStyleText.push('.dpButton{display:block !important;height:20px !important;width:25px !important;padding:0 !important;overflow:hidden !important;float:left;text-decoration:none !important;text-align:center !important;cursor:default !important;margin:2px 0 2px 2px !important}');
aryStyleText.push('.dpButton i{display:block; width:25px; height:20px; background-repeat:no-repeat; background-position:center center;}');

aryStyleText.push('#dpPrefs_bgcover{position:fixed; top:0; left:0; bottom:0; right:0; background-image:url("http://st.deviantart.com/styles/minimal/minish/bg-fade.png"); z-index:251;}');

// Preferences Window Styles
aryStyleText.push('span#dpStatusMessage {display:none;position: absolute; right: 4px; top: 4px; background:#D6DED4; border:1px solid #000000; padding:2px; font-size:11px;z-index:252;}');
aryStyleText.push('#dpPrefsWindowTitle span{display:block; font-size:11pt; color:rgb(85,85,85); font-weight:normal;}');
aryStyleText.push('div.dpPrefsPage input[type="text"],#importArea input[type="text"], #ScrollingDiv textarea {padding:2px;font-size:12px;font-family:Verdana;-moz-border-radius: 4px !important;border:1px solid #6F7F74;}');
aryStyleText.push('#dpPrefsWindow{position:fixed; -moz-border-radius: 8px !important; background: url(http://st.deviantart.com/minish/main/bg-bubblb3.gif) repeat-x #BACAB8 0px -35px;  border:none; border-top:1px #BEC9BF solid; z-index:300; font-family:Verdana,sans-serif; font-size:9pt; font-size-adjust:none; font-style:normal; font-variant:normal; font-weight:normal; line-height:normal;}');
aryStyleText.push('#dpPrefsWindowTitle{text-align:left;width:100%;height:25px; padding:12px 20px 28px;color:#94a59b;color:#333333;font-family:Trebuchet MS; font-size:22px;font-weight:bolder;cursor:default;}')
aryStyleText.push('#dpPrefsWindowTitleClose{position:absolute;top:10px; right:10px;cursor:pointer;text-decoration:none !important}');
aryStyleText.push('#dpPrefsWindowTabBar{text-align:right;padding-top:1px;padding-left:10px !important; padding-right:10px !important; padding-bottom:1px;line-height:26px;background:transparent;height:25px;margin-top:-27px; border-bottom:#DDE5DC 1px solid;}');
aryStyleText.push('.dpPrefsTab{-moz-border-radius: 8px 8px 0px 0px !important;border:1px transparent solid;border-bottom:1px transparent solid !important;text-align:center; padding:5px 10px 5px 10px; cursor:pointer;text-decoration:none !important;}');
aryStyleText.push('.dpPrefsTab.active{font-weight:bolder; background:url(http://st.deviantart.com/minish/main/bg-bubblb.gif) repeat-x;border:1px #899E90 solid;border-bottom:1px #BACAB8 solid !important;cursor:default;}');
aryStyleText.push('#dpPrefsWindow a:link, #dpPrefsWindow a:visited{color:rgb(59, 90, 74) !important;}');
aryStyleText.push('#dpPrefsWindow p.yellow{border:1px solid #AEAF15; background-color:#FEFF7F; color:#4E4F05; padding:3px;}');
aryStyleText.push('#dpPrefsWindow p.yellow a:link, #dpPrefsWindow p.yellow a:visited{color:#5F5917 !important;}');
aryStyleText.push('#dpPageButtons{margin:0;padding:10px;padding-top:0 !important;}');

aryStyleText.push('#txtCustomDescription{width:250px !important; margin-left:97px; display:block;}');
aryStyleText.push('div#ScrollingDiv label[for*=txtCustomDescription]{margin-left:97px; text-align:left; width:80px}');
aryStyleText.push('div#ScrollingDiv label[for*=cbSubscriberOnly]{margin-left:97px;}');

aryStyleText.push('#tblCustomButtons{margin-top:7px !important;}');
aryStyleText.push('.scrollvert{overflow:auto;height:410px;display:block;}');
aryStyleText.push('#ScrollingDiv{margin:5px; margin-right:10px; position:relative;}');
aryStyleText.push('#tblCustomButtons textarea{width:100%;}');
aryStyleText.push('#tblCustomButtons, #tblCustomButtons td{margin:0; border:none; vertical-align:top;}');
aryStyleText.push('#tblCustomButtons label{padding-top:4px; padding-right:4px; font-weight:bold; width:94px; white-space:nowrap; text-align:right; font-size:12px;float:left; clear:both;}');
aryStyleText.push('#tblCustomButtons label+img{padding-top:4px;}');
aryStyleText.push('#tblCustomButtons label.ta{display:block; width:100%; white-space:nowrap; text-align:left; float:none;}');
aryStyleText.push('.MaxHeight{height:1000px;}');
aryStyleText.push('#trButtonTypeProperties .page{display:none;}');
aryStyleText.push('#trButtonTypeProperties .active{display:block !important;}');
aryStyleText.push('#txtCustomInsert{height:205px;}');
aryStyleText.push('#txtCustomSurroundRight, #txtCustomSurroundLeft{height:91px; margin-bottom:2px;}');
aryStyleText.push('#btnShowIcons{margin-bottom:4px;}');
aryStyleText.push('#cbSubscriberOnly{margin-top: 6px;}');
aryStyleText.push('.dpPrefsPage{display:none; margin:10px; position:relative;}');
aryStyleText.push('.dpPrefsPage.active{display:block;}');

aryStyleText.push('#dpPrefsWindow .loading{visibility: visible !important; background-image:url("http://dp.thezikes.org/Images/images/loading.gif"); background-position:50% 50%; background-repeat: no-repeat;}');

aryStyleText.push('#tblCustomButtons input[type="text"]{width:250px; margin-bottom:4px;}');

aryStyleText.push('#txtCustomIcon{background-position:2px center !important; background-repeat:no-repeat; background-color:#FFF !important; padding-top:4px !important; padding-left:30px !important; width:223px !important;}');

aryStyleText.push('#selActiveButtons, #selInactiveButtons{width:267px}');
aryStyleText.push('#selCustomButtons{width:165px;}');
aryStyleText.push('#txtImportCustom{width:400px}');
aryStyleText.push('#cornerBtns{float:right;}');
aryStyleText.push('#dpPrefsWindow #tblCustomButtons label.cb{float:none; text-align:left;padding-top:2px;font-size:11px; font-weight:normal; vertical-align:middle !important;}');
aryStyleText.push('#dpPrefsWindow #tblCustomButtons input[type="checkbox"]{margin-bottom:0;vertical-align:middle !important;}');

aryStyleText.push('#IconList{-moz-border-radius: 0px 0px 4px 4px !important;border:1px solid #6F7F74;border-top:dotted 1px #6F7F74 !important;position:absolute;background-color:#FFF; overflow:auto;}');
aryStyleText.push('#IconList .IconItem{height:27px; line-height:27px;}');
aryStyleText.push('#IconList .IconItem:hover{background:url(http://dp.thezikes.org/Images/bgmenubuttonvn3.png); color:#FFF; cursor:pointer; font-weight:bolder;}');
aryStyleText.push('#IconList .IconItem img{vertical-align:middle; margin:0 2px 3px 5px;}');

// Preferences window button list styles
aryStyleText.push('#listButtons{width:250px; height:380px; border-left:1px solid rgb(148, 160, 155); border-bottom:1px solid rgb(148, 160, 155);overflow:auto; margin-bottom:4px; clear:both; overflow-x:hidden; background-color:#D3DCD1;}');
aryStyleText.push('#listButtons .icon{position:absolute; top:0; left:0; display:block; width:25px; height:20px; background-position:center center; background-repeat:no-repeat;}');
aryStyleText.push('#listButtons .row{font-size:11px;line-height:1.3em; border-top:1px solid rgb(148, 160, 155); margin-bottom:-1px; padding:3px 3px 3px 24px !important;white-space:nowrap; position:relative; min-height:1.4em; color:#555; overflow-x:hidden; width:208px;}');
aryStyleText.push('#listButtons .row strong{font-size:12px; margin-bottom:4px; color:#000}');
aryStyleText.push('#listButtons .row img{position:absolute; top:3px;}');
aryStyleText.push('#listButtons .row:hover{background-color:#C5D3C3;}');
aryStyleText.push('#listButtons .row:hover span, #listButtons .row.selected span {display:block;}');
aryStyleText.push('#listButtons .row.selected{background-color:#4C85CC; border-color:#3A74C1; color:#ACE;}');
aryStyleText.push('#listButtons .row.selected strong{color:#FFF;}');
aryStyleText.push('#listButtons .row div.fade{background:url(http://dp.thezikes.org/Images/faderm2.png) repeat-y transparent; height:100%; width:25px; position:absolute; top:0px; right:0px; bottom:0px;}');
aryStyleText.push('#listButtons .row:hover div.fade{background-image:url(http://dp.thezikes.org/Images/fadehoverxo1.png);}');
aryStyleText.push('#listButtons .row.selected div.fade{background-image:url(http://dp.thezikes.org/Images/fadebluerj2.png);}');

aryStyleText.push('#listButtons .row span {cursor:pointer !important; display:none; position:absolute; top:5px; height:12px; width:20px; background:url(http://download.botdom.com/j8icy/modbuttons.gif) no-repeat;}');

aryStyleText.push('#listButtons .row span.delete { right:5px; background-position: -40px 0px;}');
aryStyleText.push('#listButtons .row span.delete:hover {background-position:-40px -12px;}');
aryStyleText.push('#listButtons .row span.delete:active {background-position:-40px -24px;}');
aryStyleText.push('#listButtons .row.selected span.delete {background-position:-140px 0px;}');
aryStyleText.push('#listButtons .row.selected span.delete:hover {background-position:-140px -12px;}');
aryStyleText.push('#listButtons .row.selected span.delete:active {background-position:-140px -24px;}');

aryStyleText.push('#listButtons .row span.movedown { right:25px; background-position: -20px 0px;}');
aryStyleText.push('#listButtons .row span.movedown:hover {background-position:-20px -12px;}');
aryStyleText.push('#listButtons .row span.movedown:active {background-position:-20px -24px;}');
aryStyleText.push('#listButtons .row.selected span.movedown {background-position:-120px 0px;}');
aryStyleText.push('#listButtons .row.selected span.movedown:hover {background-position:-120px -12px;}');
aryStyleText.push('#listButtons .row.selected span.movedown:active {background-position:-120px -24px;}');

aryStyleText.push('#listButtons .row span.moveup { right:45px; background-position: 0px 0px;}');
aryStyleText.push('#listButtons .row span.moveup:hover {background-position:0px -12px;}');
aryStyleText.push('#listButtons .row span.moveup:active {background-position:0px -24px;}');
aryStyleText.push('#listButtons .row.selected span.moveup {background-position:-100px 0px;}');
aryStyleText.push('#listButtons .row.selected span.moveup:hover {background-position:-100px -12px;}');
aryStyleText.push('#listButtons .row.selected span.moveup:active {background-position:-100px -24px;}');

aryStyleText.push('#listButtons .row span.active { right:68px; background-position: -60px 0px;}');
aryStyleText.push('#listButtons .row span.active:hover {background-position:-60px -12px;}');
aryStyleText.push('#listButtons .row span.active:active {background-position:-60px -24px;}');
aryStyleText.push('#listButtons .row.selected span.active {background-position:-160px 0px;}');
aryStyleText.push('#listButtons .row.selected span.active:hover {background-position:-160px -12px;}');
aryStyleText.push('#listButtons .row.selected span.active:active {background-position:-160px -24px;}');

aryStyleText.push('#listButtons .row span.active.disabled { background-position: -80px 0px;}');
aryStyleText.push('#listButtons .row span.active.disabled:hover {background-position:-80px -12px;}');
aryStyleText.push('#listButtons .row span.active.disabled:active {background-position:-80px -24px;}');
aryStyleText.push('#listButtons .row.selected span.active.disabled {background-position:-180px 0px;}');
aryStyleText.push('#listButtons .row.selected span.active.disabled:hover {background-position:-180px -12px;}');
aryStyleText.push('#listButtons .row.selected span.active.disabled:active {background-position:-180px -24px;}');

aryStyleText.push('#shout-box{width:100%}');
aryStyleText.push('.shouts+.altview{width:97% !important}');

aryStyleText.push('#btnReset{float:left;}');
aryStyleText.push('#ReleaseNotes{height:230px; overflow:auto;}');

aryStyleText.push('#tblHelp td{vertical-align:top;}');
aryStyleText.push('#tblHelp .contents>div{overflow:auto; height:405px; display:block;}');
aryStyleText.push('#tblHelp .contents>div code{border:1px dashed rgb(140,172,187); background:rgb(247,249,250); padding:2px;}');
aryStyleText.push('#tblHelp .subjects{background:rgb(211, 220, 209); width:250px; overflow-x:hidden; overflow-y:auto; height:405px; display:block; border:1px solid rgb(148,160,155)}');
aryStyleText.push('#tblHelp .subjects .holder{margin-top:-2px; margin-left:-1px}');
aryStyleText.push('#tblHelp .subjects .subject{font-weight:bolder; font-size:12px;line-height:1.3em; border-top:1px solid rgb(148, 160, 155); margin-bottom:-1px; padding:3px 3px 3px 24px !important;white-space:nowrap; position:relative; min-height:1.4em; color:#555; overflow-x:hidden; width:100%;}');
aryStyleText.push('#tblHelp .subjects .subject:hover{background-color:#C5D3C3;}');
aryStyleText.push('#tblHelp .subjects .selected, #tblHelp .subjects .selected:hover{background-color:#4C85CC; border-color:#3A74C1; color:#ACE;}');

GM_addStyle(aryStyleText.join('\n'))

GM_registerMenuCommand('deviantPLUS Preferences', PrefsWindow.Output.window)

Timer.newTime('Custom styles applied')

Timer.totalTime();