Greasy Fork is available in English.

Hide Threads and Replies by Poster

Hides threads based on the player(s) that posted the thread or replied. Applies to all sub-forums, your Clan forum and your Mail. Also appplies to individual threads.

Tính đến 02-12-2017. Xem phiên bản mới nhất.

// ==UserScript==
// @author https://greasyfork.org/en/users/85040-dan-wl-danwl
// @name Hide Threads and Replies by Poster
// @namespace daniel.church@btinternet.com
// @grant none
// @match https://www.warzone.com/*
// @description Hides threads based on the player(s) that posted the thread or replied. Applies to all sub-forums, your Clan forum and your Mail. Also appplies to individual threads.
// @version 2.2.0.7
// ==/UserScript==
var v = '2.2.0.7';

console.log('Dan\'s userscript version: ' + v);
/*
First released on 8/12/2016 see https://www.warzone.com/Forum/222938-dans-userscript-hide-threads-replies-poster for evidence.

Jump to last page links are now no longer removed.Fixed bug that caused Add/Remove player from blocklist and Add/Remove thread from thread exceptions buttons to get placed in the wrong place.Fixed bug that caused threads with all-caps subjects to not be hidden.Fixed bug that caused blank posts to not be hidden.

Known bugs:
hideThreads not hiding threads
Blocking then unblocking players in current session forces threads by the previousely blocked poster to not hide (in the downvoted threads).
Visual errors.
*/

var userscripts =
{
	mulis: function()
	{
		console.log('window.MULIS_USERSCRIPT = ' + window.MULIS_USERSCRIPT);
		return window.MULIS_USERSCRIPT;
	}
};

function fixBlank(tag, number, newText, useLoop, updatePlayers)
{
	//makes blanked-out things visable globaly by replacing the things' innerHTML with new text
	var object = tag[number];
	var ObjectHasBlankChar = function(object)
	{
		return object.innerHTML.match(/\uA0/gi) || object.innerHTML.match(/\uAD/gi) || object.innerHTML.match(/\u2DE/gi) || object.innerHTML.match(/\u00AD/gi) || object.innerHTML.match(/\u02DE/gi) || object.innerHTML.match(/\u1361/gi) || object.innerHTML.match(/\u1680/gi) || object.innerHTML.match(/\u180E/gi) || object.innerHTML.match(/\u2000/gi) || object.innerHTML.match(/\u2001/gi) || object.innerHTML.match(/\u2002/gi) || object.innerHTML.match(/\u2003/gi) || object.innerHTML.match(/\u2004/gi) || object.innerHTML.match(/\u2005/gi) || object.innerHTML.match(/\u2006/gi) || object.innerHTML.match(/\u2007/gi) || object.innerHTML.match(/\u2008/gi) || object.innerHTML.match(/\u2009/gi) || object.innerHTML.match(/\u200A/gi) || object.innerHTML.match(/\u200B/gi) || object.innerHTML.match(/\u202F/gi) || object.innerHTML.match(/\u205F/gi) || object.innerHTML.match(/\u2800/gi) || object.innerHTML.match(/\u3000/gi) || object.innerHTML.match(/\u3164/gi) || object.innerHTML.match(/\uFEFF/gi);
	};
	var FixBlankMain = function(object)
	{
		if (ObjectHasBlankChar(object))
		{
			if (tag === document.getElementsByTagName('font'))
			{
				if (object.parentNode === "[object HTMLTableCellElement]" && object.innerHTML !== "WarLight Creator" && object.innerHTML !== "Script Creator")
				{
					object.innerHTML = newText;
				}
			}
			else
			{
				object.innerHTML = newText;
			}
			if (updatePlayers)
			{
				localStorageChecks();
				fixPAndPsBug();
				PlayersToPThenPs();
			}
		}
	};

	if (useLoop)
	{
		while (number < tag.length)
		{
			FixBlankMain(tag[number]);
			number++;
		}
	}
	else
	{
		FixBlankMain(object);
	}
}

//required global vars
var	Players,
	threads,
	_threads;

//removes dublicates from localStorage
function localStorageRemoveDublicates(LSITEM)
{
	var	ObjectLS = LSITEM.split(','),
		ObjectLSNo = 0,
		ObjectLS1 = LSITEM.split(','),
		ObjectLSNo1 = 0,
		ls_object,
		numMatches = 0;

	while (ObjectLSNo < ObjectLS.length)
	{
		if (ObjectLSNo === ObjectLS.length)
		{
			ObjectLSNo = 0;
		}

		while (ObjectLSNo1 < ObjectLS.length)
		{
			ls_object = ObjectLS[ObjectLSNo];
			if (ls_object === ObjectLS1[ObjectLSNo1])
			{
				numMatches++;
			}
			if (numMatches > 1)
			{
				//remove the dublicate
				if (LSITEM === localStorage.Players)
				{
					localStorage.Players = localStorage.Players.replace(ls_object, '');
				}
				else if (LSITEM === localStorage.threads)
				{
					localStorage.threads = localStorage.threads.replace(ls_object, '');
				}
				else
				{
					localStorage._threads = localStorage._threads.replace(ls_object, '');
				}
				numMatches = 0;//reset matches
			}
			ObjectLSNo1++;
		}
		ObjectLSNo++;
	}
}

//check localStorage for players and threads
function localStorageChecks()
{
	var PlayersLS = localStorage.Players;

	if (!PlayersLS)
	{
		localStorage.Players = '[blank name],Wally Balls,H-to-the-O-V,';
		PlayersLS = localStorage.Players;
	}
	else
	{
		//if [blank name] is being used, prevent loads of random [blank name]s from appearing
		if (PlayersLS.match(/\[blank name\]/))
		{
			//if there's more than one [blank name], fix the bug
			if (PlayersLS.match(/\[blank name\]/g).length > 1)
			{
				localStorage.Players = PlayersLS.replace(PlayersLS.match(/\[blank name\],/), '').replace(PlayersLS.match(/\[blank name\]/g), '');
				localStorage.Players = '[blank name],' + localStorage.Players;
				PlayersLS = localStorage.Players;
			}
		}
		localStorageRemoveDublicates(PlayersLS);
	}

	Players = PlayersLS.split(',');

	console.log('Currently hiding threads and repllies by ' + Players);

	//thread excepions
	var threadsLS = localStorage.threads;

	if (!threadsLS || threadsLS === '')
	{
		localStorage.threads = 'localStorage.threads_first-item(do_not_remove_this)';//prevents visual UI bugs
	}
	else
	{
		localStorageRemoveDublicates(threadsLS);
	}

	threads = localStorage.threads.split(',');

	//hiding individual threads
	var _threadsLS = localStorage._threads;

	if (!_threadsLS || _threadsLS === '')
	{
		localStorage._threads = 'localStorage._threads_first-item(do_not_remove_this)';
	}
	else
	{
		localStorageRemoveDublicates(localStorage._threads);
	}

	_threads = localStorage.getItem('_threads').split(',');

	//show/hide OT threads
	if (!localStorage.DanHTRBP_hidingOT)
	{
		localStorage.DanHTRBP_hidingOT = 'no';
	}

	console.log('localStorage.DanHTRBP_hidingOT = ' + localStorage.DanHTRBP_hidingOT);

	//MOTW
	if (!localStorage.getItem('MOTW'))
	{
		localStorage.MOTW = 'no';
	}

	console.log('localStorage.MOTW = ' + localStorage.MOTW);

	//blank posts message
	if (!localStorage.bpDialogue)
	{
		localStorage.bpDialogue = 'yes';
	}

	console.log('localStorage.bpDialogue = ' + localStorage.bpDialogue);

	//ability to hide UI elements
	if (!localStorage.DanHTRBP_hidingUI)
	{
		localStorage.DanHTRBP_hidingUI = 'no';
	}

	console.log('localStorage.DanHTRBP_hidingUI = ' + localStorage.DanHTRBP_hidingUI);

	var	uiDisplay = document.getElementById('uiDisplay');

	if (!uiDisplay)
	{
		var	nextSelector;
		var	newNextSelector = '#HiddenThreadsRow td:nth-last-child(2)';
		var	isAllF = location.pathname.match(/\/forum\/forum/i);

		if (isAllF)
		{
			nextSelector = ', #HiddenThreadsRow td:nth-last-child(2)';
			newNextSelector = '#HiddenThreadsRow td:nth-last-child(3)';
		}

		document.head.innerHTML += '<style id = "uiDisplay">.PlayersTD, .ThreadExceptionsTD, .UIElement, #HiddenThreadsRow td:last-child' + nextSelector + '\n{\n\tdisplay: table-cell;\n}\n\n' + newNextSelector + '\n{\n\tborder-top-right-radius: 0px;\n}</style>';
		uiDisplay = document.getElementById('uiDisplay');
	}
	if (localStorage.DanHTRBP_hidingUI === 'no')
	{
		uiDisplay.innerHTML = uiDisplay.innerHTML.replace(/none/g, 'table-cell').replace('8px', '0px');
	}
	else
	{
		uiDisplay.innerHTML = uiDisplay.innerHTML.replace(/table-cell/g, 'none').replace('0px', '8px');
	}
}
localStorageChecks();//perform the checks

//some required global variables
var h = location.pathname,
	genF = h.includes("m/f1") || h.includes("m/F1"),
	mapF = h.includes("m/f4") || h.includes("m/F4"),
	ladF = h.includes("m/f5") || h.includes("m/F5"),
	progF = h.includes("m/f6") || h.includes("m/F6"),
	helpF = h.includes("m/f7") || h.includes("m/F7"),
	OTF = h.includes("m/f8") || h.includes("m/F8"),
	clansF = h.includes("m/f9") || h.includes("m/F9"),
	stratF = h.includes("m/f10") || h.includes("m/F10"),
	subForum = genF || mapF || ladF || progF || helpF || OTF || clansF || stratF,
	allF = h.includes("m/fo") || h.includes("m/Fo"),
	threadP =  h.includes("m/1") || h.includes("m/2") || h.includes("m/3") || h.includes("m/4") || h.includes("m/5") || h.includes("m/6") || h.includes("m/7") || h.includes("m/8") || h.includes("m/9"),
	discussionP = location.href.includes("https://www.warzone.com/Discussion/?ID="),
	mail = h.includes("/Discussion/MyMail"),
	clanF = h.includes("/Clans/forum") || h.includes("/Clans/Forum");

//prevents certain people from using all features
function isValidUser()
{
	var MailLink = document.getElementById('MailLink');
	var ret = true;

	if (!MailLink) {return;}

	var user = MailLink.nextElementSibling.href;
	var ppl =
	[
		9071760924,
		5614353942,
		3085172703
	];
	var i = 0;

	while (i < ppl.length)
	{
		if (user.match(ppl[i]))
		{
			ret = false;
			break;
		}
		i++;
	}
	return ret;
}
if (!isValidUser())
{
	throw new Error();
}

var PlayersNo = 0,
	threadsNo = 0,
	_threadsNo = 0;

//Players array to another array where Players[PlayersNo] is a single var
//And Player string array (for hidden players)
var p = [];
var ps = "";
var pNo = 0;
var pS = [];
var psS = "";
var pSNo = 0;

function PlayersToPThenPs()
{
	PlayersNo = 0;
	while (PlayersNo < Players.length-1)
	{
		ps = Players[PlayersNo];
		p.push(ps);
		PlayersNo++;
	}
	pNo = 0;
	PlayersNo = 0;
	while (pNo < p.length)
	{
		psS = "\n" + p[pNo];
		if (pNo === p.length-1)
		{
			psS += '.';//if last item of pS, add a fullstop at the end.
		}
		pS.push(psS);
		pNo++;
	}
	pNo = 0;
}
PlayersToPThenPs();
window.p = p;
function fixPAndPsBug()
{
//fixes bug that causes p and pS to not reset when Player changes are made
	for (var i=Players.length-1; i>=0; i--)
	{
		p.splice(i, 1);
		pS.splice(i, 1);
	}
}
//thread exceptions
var t = [],
	ts = "",
	tNo = 0;
//thread excepions array to another array where threads[threadsNo] is a single var
function threadsToT()
{
	console.log('threads.length = ' + threads.length);
	t = [];
	ts = '';
	tNo = 0;
	while (threadsNo < threads.length)
	{
		ts = threads[threadsNo];
		t.push(ts);
		//console.log('t added; current ts:\n' + t);
		threadsNo++;
	}
	threadsNo = 0;
	console.log('t = ' + t);
	window.t = t;
}
threadsToT();

//hides individual threads
var _t = [],
	_ts = "",
	_tNo = 0;

function _threadsTo_t()
{
	console.log('_threads.length = ' + _threads.length);
	_t = [];
	_ts = '';
	_tNo = 0;
	while (_threadsNo < _threads.length)
	{
		_ts = _threads[_threadsNo];
		_t.push(_ts);
		//console.log('_t added; current _ts:\n' + _t);
		_threadsNo++;
	}
	_threadsNo = 0;
	console.log('_t = ' + _t);
	window._t = _t;
}
_threadsTo_t();

function fixThreadExceptionsBug()
{
	for (var i=threads.length-1; i>=0; i--)
	{
		t.splice(i, 1);
	}
}

//adds players/threads to the hide/exceptions list
function addToArray(ARRAY, ARRAYITEM, NUMBER)
{
	var array_is_players = ARRAY === 'Players';
	var main = typeof NUMBER === 'string';
	var item = ARRAYITEM.innerHTML;
	var ls_group = localStorage.Players;
	var btn_class = 'PlayerName';
	var btn_class_prefix = ARRAY;

	if (array_is_players && main)
	{
		item = ' by ' + ARRAYITEM;
	}
	else
	{
		if (main)
		{
			item = ARRAYITEM;
		}

		ls_group = localStorage.threads;
		btn_class = 'ThreadLink';
		btn_class_prefix = 'ThreadExceptions';
	}

	if (ls_group.match(item))
	{
		//if the player/thread is already there, don't add it
		return;
	}

	if (array_is_players)
	{
		//updates and remember Players
		if (main)
		{
			localStorage.Players += ARRAYITEM + ',';
		}
		else
		{
			localStorage.Players += ARRAYITEM.innerHTML.replace(' by ', '') + ',';
		}

		fixPAndPsBug();
		localStorageChecks();
		PlayersToPThenPs();
	}
	else
	{
		//update and remember threads
		if (main)
		{
			localStorage.threads += ',' + ARRAYITEM;
		}
		else
		{
			localStorage.threads += ',' + ARRAYITEM.innerHTML;
		}

		localStorageChecks();
		threadsToT();
	}

	var UpdateBtns = function()
	{
		var btn_class_items = document.getElementsByClassName(btn_class);
		var btn_class_item_counter = 0;
		var btn_class_item;

		while (btn_class_item_counter < btn_class_items.length)
		{
			btn_class_item = btn_class_items[btn_class_item_counter];
	
			if (btn_class_item.innerHTML === item)
			{
				//make the thread visable
				if (array_is_players)
				{
					btn_class_item.parentNode.parentNode.removeAttribute('class');
					btn_class_item.parentNode.parentNode.removeAttribute('style');
				}
				//update the buttons
				document.getElementsByClassName(btn_class_prefix + 'HBtn')[btn_class_item_counter].style.display = 'none';
				document.getElementsByClassName(btn_class_prefix + 'SBtn')[btn_class_item_counter].removeAttribute('style');
			}

			btn_class_item_counter++;
		}
	};

	if (subForum || allF || clanF || mail)
	{
		UpdateBtns();
		hideThreads();
	}
	if (array_is_players && threadP || discussionP)
	{
		hideReplies();
	}
	console.log('added ' + item + ' to ' + ARRAY);
}

//removes a player from the list
function removePlayer(ARRAYITEM, NUMBER)
{
	var main = typeof NUMBER === 'string';
	var item;

	if (main)
	{
		item = ARRAYITEM;
	}
	else
	{
		item = ARRAYITEM.innerHTML.replace(/\u0020/, '').replace('by ', '');
	}

	if (localStorage.Players.match(item) === null)
	{
		//if the player isn't there, don't remove it
		return;
	}

	if (subForum || allF || clanF || mail)
	{
		if (main)
		{
			item = ' by ' + ARRAYITEM;
		}
		else
		{
			item = ARRAYITEM.innerHTML;
		}

		var PlayerNameNo = 0;
		var PlayerName = document.getElementsByClassName('PlayerName');

		while (PlayerNameNo < PlayerName.length)
		{
			if (PlayerName[PlayerNameNo].innerHTML === item)
			{
				//make the thread visable
				PlayerName[PlayerNameNo].parentNode.parentNode.removeAttribute('class');
				PlayerName[PlayerNameNo].parentNode.parentNode.removeAttribute('style');
				//update the buttons
				document.getElementsByClassName('PlayersSBtn')[PlayerNameNo].style.display = 'none';
				document.getElementsByClassName('PlayersHBtn')[PlayerNameNo].removeAttribute('style');
			}

			PlayerNameNo++;
		}
	}

	//redefine item
	if (main)
	{
		item = ARRAYITEM;
	}
	else
	{
		item = ARRAYITEM.innerHTML.replace(/\u0020/, '').replace('by ', '');
	}

	for (var i=Players.length-1; i>=0; i--)
	{
		if (Players[i] === item)
		{
			localStorage.Players = localStorage.Players.replace(item+",","");//update and remember Players
			//break;
		}
	}
	for (var ii=p.length-1; ii>=0; ii--)
	{
		if (p[ii] === item)
		{
			p.splice(ii, 1);
			//break;
		}
	}
	for (var iii=pS.length-1; iii>=0; iii--)
	{
		if (pS[iii] === "\n" + item)
		{
			pS.splice(iii, 1);
			//break;
		}
	}
	console.log('removed ' + item);
	localStorageChecks();

	if (subForum || allF || clanF || mail)
	{
		hideThreads();
	}

	if (threadP || discussionP)
	{
		hideReplies();
	}
}

//makes it possable to remove a thread exception
function removeThread(ARRAYITEM, NUMBER)
{
	var main = typeof NUMBER === 'string';
	var item;

	if (main)
	{
		item = ARRAYITEM;
	}
	else
	{
		item = ARRAYITEM.innerHTML;
	}

	if (localStorage.threads.match(item) === null || item === 'localStorage.threads_first-item(do_not_remove_this)')
	{
		//if the thread isn't there, don't remove it
		return;
	}

	for (var iv=threads.length-1; iv>=0; iv--)
	{
		if (threads[iv] === item)
		{
			localStorage.threads = localStorage.threads.replace(',' + item, '');//update and remember threads
		}
	}
	for (var v=t.length-1; v>=0; v--)
	{
		if (t[v] === item)
		{
			t.splice(v, 1);
		}
	}

	if (subForum || allF || clanF || mail)
	{
		//updates all thead excepions buttons
		var ThreadLink = document.getElementsByClassName('ThreadLink');
		var ThreadLinkNo = 0;

		while (ThreadLinkNo < ThreadLink.length)
		{
			if (ThreadLink[ThreadLinkNo].innerHTML === item)
			{
				document.getElementsByClassName('ThreadExceptionsSBtn')[ThreadLinkNo].style.display = 'none';
				document.getElementsByClassName('ThreadExceptionsHBtn')[ThreadLinkNo].removeAttribute('style');
			}

			ThreadLinkNo++;
		}
	}

	console.log('removed ' + item);
	localStorageChecks();

	if (subForum || allF || clanF || mail)
	{
		hideThreads();
	}
}

var config =
{
	update: function()
	{
		localStorageChecks();
		if (allF && localStorage.DanHTRBP_hidingOT === 'no')
		{
			//show OT threads and hide the downvoted OT threads
			OT.removeClassNames();
		}
		if (subForum || allF || clanF || mail)
		{
			hideThreads();//if on forum, hide threads
		}
		if (threadP || discussionP)
		{
			hideReplies();//if on forum post, hide replies
		}
	},
	advanced: function()
	{
		var	areArent;

		//hide/show OT threads
		if (localStorage.DanHTRBP_hidingOT === 'yes')
		{
			areArent = 'are';
		}
		else
		{
			areArent = 'aren\'t';
		}

		var DanHTRBP_hidingOT_Confirm = function(){return confirm('Currently, you ' + areArent + ' hiding OT threads. Click OK to change this.');};

		if (DanHTRBP_hidingOT_Confirm())
		{
			//remembers the responce
			if (localStorage.DanHTRBP_hidingOT === 'no')
			{
				localStorage.DanHTRBP_hidingOT = 'yes';
			}
			else
			{
				localStorage.DanHTRBP_hidingOT = 'no';
			}
			config.update();
		}

		//hide/unhide MOTW threads
		if (localStorage.MOTW === 'yes')
		{
			areArent = 'are';
		}
		else
		{
			areArent = 'aren\'t';
		}

		var changeMOTW = function(){return confirm('Currently, you ' + areArent + ' hiding Map of the Week threads. Click OK to change this.');};

		if (changeMOTW())
		{
			//remembers the responce
			if (localStorage.MOTW === 'no')
			{
				localStorage.MOTW = 'yes';
			}
			else
			{
				localStorage.MOTW = 'no';
			}
			config.update();
		}

		//hide/show blank posts messages
		if (localStorage.bpDialogue === 'yes')
		{
			areArent = 'are';
		}
		else
		{
			areArent = 'aren\'t';
		}

		var changeBpDialogue = function(){return confirm('Currently, you ' + areArent + ' hiding blank posts dialogues. Click OK to change this.');};

		if (changeBpDialogue())
		{
			//remembers the responce
			if (localStorage.bpDialogue === 'no')
			{
				localStorage.bpDialogue = 'yes';
			}
			else
			{
				localStorage.bpDialogue = 'no';
			}
			config.update();
		}

		//hide / no longer hide UI elements that allow users to show posts that have been posted by players on their Block List
		if (localStorage.DanHTRBP_hidingUI === 'no')
		{
			areArent = 'aren\'t';
		}
		else
		{
			areArent = 'are';
		}

		var changeUIDisplay = function(){return confirm('Currently, you ' + areArent + ' hiding the UI. Click OK to change this.');};

		if (changeUIDisplay())
		{
			if (localStorage.DanHTRBP_hidingUI === 'no')
			{
				localStorage.DanHTRBP_hidingUI = 'yes';
			}
			else
			{
				localStorage.DanHTRBP_hidingUI = 'no';
			}
			config.update();
		}

		var export_settings = function(){return confirm('Click OK to export the current settings.');};

		if (export_settings())
		{
			var exported_settings = [];

			exported_settings.push(localStorage.Players);
			exported_settings.push(localStorage.threads);
			exported_settings.push(localStorage._threads);
			exported_settings.push(localStorage.MOTW);
			exported_settings.push(localStorage.DanHTRBP_hidingUI);
			exported_settings.push(localStorage.DanHTRBP_hidingOT);
			exported_settings.push(localStorage.bpDialogue);

			var exported_settings_txt = JSON.stringify(exported_settings);

			prompt('Current settings:', exported_settings_txt);
		}

		var import_settings = function(){return confirm('Click OK to import settings.');};

		if (import_settings())
		{
			try{
			var exported_settings = function(){return prompt('Paste exported settings here.');};
			var _exported_settings = exported_settings();

			if (_exported_settings && _exported_settings !== '')
			{
				var parsed_settings = JSON.parse(_exported_settings);

				var setting_MOTW = parsed_settings[3];
				var setting_hidingUI = parsed_settings[4];
				var setting_hidingOT = parsed_settings[5];
				var setting_bpDialogue = parsed_settings[6];
	
				if (setting_MOTW !== 'yes' && setting_MOTW !== 'no')
				{
					throw 'Invalid MOTW setting value';
				}
				else if (setting_hidingUI !== 'yes' && setting_hidingUI !== 'no')
				{
					throw 'Invalid hiding UI setting value';
				}
				else if (setting_hidingOT !== 'yes' && setting_hidingOT !== 'no')
				{
					throw 'Invalid hiding OT setting value';
				}
				else if (setting_bpDialogue !== 'yes' && setting_bpDialogue !== 'no')
				{
					throw 'Invalid bp dialogue setting value';
				}

				localStorage.Players = parsed_settings[0];
				localStorage.threads = parsed_settings[1];
				localStorage._threads = parsed_settings[2];
				localStorage.MOTW = setting_MOTW;
				localStorage.DanHTRBP_hidingUI = setting_hidingUI;
				localStorage.DanHTRBP_hidingOT = setting_hidingOT;
				localStorage.bpDialogue = setting_bpDialogue;

				alert('Imported settings. Refreshing.');
				location.reload();
			}
			}catch(err){console.log(err); prompt('Error while importing settings. Message Dan with these details:', _exported_settings + '\n\nError:\n' + err + '\n\nStack trace:\n' + err.stack);}
		}
	},
	isMultiple: function(LSITEM, TEXT)
	{
		var	ObjectLS = LSITEM.split(','),
			ObjectLSNo = 0;

		while (ObjectLSNo < ObjectLS.length)
		{
			if (TEXT === ObjectLS[ObjectLSNo])
			{
				return true;//prevent returning false if dublicate found
			}
			else
			{
				return false;
			}
			ObjectLSNo++;
		}
	},
	players:
	{
		view: function()
		{
			if (localStorage.Players.match(','))
			{
				alert('Currently hiding posts by:' + pS);
			}
			else
			{
				alert('You\'re not hiding posts by anyone.');
			}
		},
		add: function()
		{
			var newPlayer = function()
			{
				return prompt('Input a player name below.', '');
			};
			var _newPlayer = newPlayer();

			if (_newPlayer && _newPlayer !== '')
			{
				//if didn't press cancel and added a player name
				if (_newPlayer.match(/,/))
				{
					//if the player name includes any commas, prevent the player name being added
					alert('Player names aren\'t allowed to contain commas (,).');
				}
				else if (config.isMultiple(localStorage.Players, _newPlayer))
				{
					//if the player is already added, prevent it from being added again
					alert('You already have this player on your Block List');
				}
				else
				{
					addToArray('Players', _newPlayer, '');//add new player to players array
					config.ui.disableButtons();//(un)disable buttons
				}
			}
		},
		remove: function()
		{
			var oldPlayer = function()
			{
				return prompt('Input a player name below.', '');
			};
			var _oldPlayer = oldPlayer();

			if (_oldPlayer && _oldPlayer !== '')
			{
				//if didn't press cancel and added a player name, remove the player
				removePlayer(_oldPlayer, '');
				config.ui.disableButtons();//(un)disable buttons
			}
		}
	},
	threads:
	{
		view: function()
		{
			if (localStorage.threads.match(','))
			{
				alert('Currently not hiding these threads:\n' + localStorage.threads.replace('localStorage.threads_first-item(do_not_remove_this),', '').replace('localStorage.threads_first-item(do_not_remove_this)', ''));
			}
			else
			{
				alert('You don\'t have any thread exceptions.');
			}
		},
		add: function()
		{
			var newThread = function()
			{
				return prompt('Input a thread title below.', '');
			};
			var _newThread = newThread();

			if (_newThread && _newThread !== '')
			{
				//if didn't press cancel and added a thread name
				if (_newThread.match(/,/))
				{
					//if the player name includes any commas, prevent the player name being added
					alert('Thread subjects aren\'t allowed to contain commas (,)');
				}
				else if (config.isMultiple(localStorage.threads, _newThread))
				{
					//if the thread is already added, prevent it from being added again
					alert('You already have this thread on your Thread Exceptions');
				}
				else
				{
					addToArray('threads', _newThread, '');//add thread to thread exceptions array
					config.ui.disableButtons();//(un)disable buttons
				}
			}
		},
		remove: function()
		{
			var oldThread = function()
			{
				return prompt('Input a thread title below.', '');
			};
			var _oldThread = oldThread();

			if (_oldThread && _oldThread !== '')
			{
				//if didn't press cancel and added a thread name, remove the thread
				removeThread(_oldThread, '');
				config.ui.disableButtons();//(un)disable buttons
			}
		}
	},
	_threads:
	{
		update: function()
		{
			localStorageChecks();//updates definition of _threads
			_threadsTo_t();//updates _t
			if (subForum || allF || clanF || mail)
			{
				hideThreads();//refreshes threads
			}
		},
		view: function()
		{
			if (localStorage._threads.match(','))
			{
				alert('Currently hiding these threads:\n' + localStorage._threads.replace('localStorage.threads_first-item(do_not_remove_this),', '').replace('localStorage.threads_first-item(do_not_remove_this)', ''));
			}
			else
			{
				alert('Currently not hiding any individual threads.');
			}
		},
		add: function()
		{
			var newThread = function()
			{
				return prompt('Input a thread title below.', '');
			};
			var _newThread = newThread();

			if (_newThread && _newThread !== '')
			{
				//if didn't press cancel and added a thread name, add and remember the thread then update
				if (_newThread.match(/,/))
				{
					alert('Thread subjects aren\'t allowed to contain commas (,)');
				}
				else if (config.isMultiple(localStorage._threads, _newThread))
				{
					//if the thread is already added, prevent it from being added again
					alert('You already hiding this thread');
				}
				else
				{
					localStorage._threads += ',' + _newThread;//add the _thread
					config._threads.update();//update _threads
					config.ui.disableButtons();//(un)disable buttons
				}
			}
		},
		remove: function()
		{
			var oldThread = function()
			{
				return prompt('Input a thread name below.', '');
			};
			var _oldThread = oldThread();

			if (_oldThread && _oldThread !== '')
			{
				//if didn't press cancel and added a thread name, remember the thread then update
				if (!localStorage._threads.match(_oldThread) || _oldThread === 'localStorage.threads_first-item(do_not_remove_this)')
				{
					//if the thread isn't there, don't remove it
					return;
				}
				localStorage._threads = localStorage._threads.replace(',' + _oldThread, '');
				config._threads.update();
				config.ui.disableButtons();//(un)disable buttons
			}
		}
	},
	toDefault: function()
	{
		//Resets players
		var resetPlayers = function()
		{
			return confirm('Reset Players?');
		};

		if (resetPlayers())
		{
			localStorage.removeItem('Players');
		}

		//Resets thread exceptions
		var resetThreads = function(){return confirm('Reset Thread Exceptions?');};

		if (resetThreads())
		{
			localStorage.removeItem('threads');
		}

		//Resets hidden threads
		var reset_Threads = function(){return confirm('Reset Hidden Threads?');};

		if (reset_Threads())
		{
			localStorage.removeItem('_threads');
		}

		//Resets hiding off-topic threads
		var resetOT = function(){return confirm('Unhide off-topic threads?');};

		if (resetOT())
		{
			localStorage.removeItem('DanHTRBP_hidingOT');
		}

		//Resets hiding MOTW threads
		var resetMOTW = function(){return confirm('Unhide Map of the Week threads?');};

		if (resetMOTW())
		{
			localStorage.removeItem('MOTW');
		}

		//Resets hiding blank posts dialogues
		var resetBP = function(){return confirm('Unhide blank posts dialogues?');};

		if (resetBP())
		{
			localStorage.removeItem('bpDialogue');
		}

		//Resets hiding the UI
		var resetPlayersUI = function(){return confirm('Unhide UI?');};

		if (resetPlayersUI())
		{
			localStorage.removeItem('DanHTRBP_hidingUI');
		}

		//if anything is restored to default, update everything
		if (resetPlayers || resetThreads || reset_Threads || resetOT || resetMOTW || resetBP || resetPlayersUI)
		{
			localStorageChecks();
			PlayersToPThenPs();
			threadsToT();
			_threadsTo_t();
			if (allF && resetOT && localStorage.DanHTRBP_hidingOT === 'no')
			{
				//show OT threads and hide the downvoted OT threads
				OT.removeClassNames();
			}
			if (subForum || allF || clanF || mail)
			{
				hideThreads();//if on forum, hide threads
			}
			if (threadP || discussionP)
			{
				hideReplies();//if on a thread, hide replies
			}
			config.ui.disableButtons();//(un)disable buttons
		}
	},
	ui:
	{
		createOverlays: function()
		{
			//whole UI overlay
			if (document.getElementsByClassName('overlay').length === 0)
			{
				//if an overlay doesn't exist, create one and style it
				var overlay = document.createElement('div');
				var overlayStyle = document.createElement('style');

				overlay.className = 'overlay';
				document.body.appendChild(overlay);

				overlayStyle.innerHTML = '.overlay\n{\n\tdisplay: none;\n\tbackground: white none repeat scroll 0% 0%;\n\ttop: 0;\n\tright: 0;\n\tbottom: 0;\n\ttop: 0;\n\topacity: 0.5;\n\twidth: 100%;\n\theight: 100%;\n\tposition: fixed;\n\tz-index: 98;\n}';
				document.head.appendChild(overlayStyle);

				console.log('overlay created');
			}

			document.getElementsByClassName('overlay')[0].id = 'mainOverlay';

			//parcial overlays
			var newOverlays =
			[
				document.createElement('div'),
				document.createElement('div'),
				document.createElement('div')
			];
			var newOverlaysNo = 0;
			var newOverlayStyle = document.createElement('style');

			newOverlayStyle.innerHTML = '.overlayParcial\n{\n\tmargin-right: -98px;\n\tposition: static !important;\n\tz-index: 100 !important;\n\tborder-radius: 5px;\n\twidth: 98px !important;\n\theight: 77px !important;\n\tfloat: left;\n}';
			document.head.appendChild(newOverlayStyle);

			var row = document.getElementsByClassName('config_dan_userscript_row');

			while (newOverlaysNo < newOverlays.length)
			{
				newOverlays[newOverlaysNo].className = 'overlay overlayParcial';
				row[newOverlaysNo].appendChild(newOverlays[newOverlaysNo]);
				row[newOverlaysNo].insertBefore(newOverlays[newOverlaysNo], row[newOverlaysNo].children[row[newOverlaysNo].children.length-2]);
				newOverlaysNo++;
			}

			console.log('created parcial overlays');
		},
		disableButtons: function()
		{
			var configbtn = document.getElementsByClassName('config_dan_userscript_button');
			var overlayParcial = document.getElementsByClassName('overlayParcial');

			if (localStorage.Players.match(/,/))
			{
				configbtn[2].removeAttribute('disabled');
				configbtn[2].style.cursor = "";
				overlayParcial[0].style.display = "";
			}
			else
			{
				//if no Players, disable the button
				configbtn[2].setAttribute('disabled', '');
				configbtn[2].style.cursor = 'auto';
				//add an overlay on top
				overlayParcial[0].style.display = 'block';
			}
			if (localStorage.threads.match(/,/))
			{
				configbtn[5].removeAttribute('disabled');
				configbtn[5].style.cursor = "";
				overlayParcial[1].style.display = "";
			}
			else
			{
				//if no threads, disable the button
				configbtn[5].setAttribute('disabled', '');
				configbtn[5].style.cursor = 'auto';
				//add an overlay on top
				overlayParcial[1].style.display = 'block';
			}
			if (localStorage._threads.match(/,/))
			{
				//if no Players, disable the button
				configbtn[8].removeAttribute('disabled');
				configbtn[8].style.cursor = "";
				//add an overlay on top
				overlayParcial[2].style.display = "";
			}
			else
			{
				//if no Players, disable the button
				configbtn[8].setAttribute('disabled', '');
				configbtn[8].style.cursor = 'auto';
				//add an overlay on top
				overlayParcial[2].style.display = 'block';
			}
		},
		show: function()
		{
			document.getElementById('mainOverlay').style.display = 'block';
			document.getElementById('config_dan_userscript').style.display = 'block';

			config.ui.disableButtons();
		},
		hide: function()
		{
			var overlayParcial = document.getElementsByClassName('overlayParcial');

			document.getElementById('config_dan_userscript').removeAttribute('style');
			document.getElementById('mainOverlay').style.display = 'none';

			overlayParcial[0].style.display = "";
			overlayParcial[1].style.display = "";
			overlayParcial[2].style.display = "";
		},
		build: function()
		{
			var newDiv =
			[
				document.createElement('div'),//main container
				document.createElement('div')//header
			];

			var newDivRow =
			[
				document.createElement('div'),//first row
				document.createElement('div'),//second row
				document.createElement('div'),//third row
				document.createElement('div')//bottom row
			];

			var uistyle = document.createElement('style');

			uistyle.innerHTML = '#config_dan_userscript\n{\n\tposition: fixed;\n\ttop: 0;\n\tright: 0;\n\tbottom: 0;\n\tleft: 0;\n\tmargin: auto;\n\tpadding: 10px;\n\tmax-width: 523px;\n\tmax-width: -webkit-fit-content;\n\tmax-width: -moz-fit-content;\n\theight: 307.5px;\n\tborder: 2px solid #000;\n\tborder-radius: 10px;\n\tbackground-color: #f00;\n\tline-height: 1.25;\n\tcolor: #fff;\n\ttext-align: center;\n\tdisplay: none;\n\tz-index: 99;\n\t}\n\n#config_dan_userscript, .config_dan_userscript_button\n{\n\tfont-family: sans-serif;\n\tfont-size: 16pt;\n}\n\n#config_dan_userscript_header\n{\nmargin-bottom: 5px;\n\twidth: 100%;\n\theight: 27.5px;\n\tfont-weight: bold;\n}\n\n.config_dan_userscript_row\n{\n\tmargin-bottom: 5px;\n\theight: 77px;\n}\n\n.config_dan_userscript_row:last-child\n{\n\theight: 27px;\n\tfloat: right;\n}\n\n.config_dan_userscript_description\n{\n\tpadding: 12.5px 0;\n\twidth: 155px;\n\tfloat: left;\n}\n\.config_dan_userscript_description_1\n{\n\tpadding: 25.5px 0;\n}\n\n.config_dan_userscript_button\n{\n\tmargin-right: 10px;\n\tpadding: 10.5px 0;\n\twidth: 98px;\n\theight: 52px;\n\tborder: 2px solid #000;\n\tborder-radius: 5px;\n\tbackground-color: #00f;\n\tcolor: #d5ffd5;\n\tcursor: pointer;\n\tfloat: left;\n}\n\n.config_dan_userscript_viewbutton\n{\n\tpadding: 23.5px 0;\n\theight: 26px;\n}\n\n.config_dan_userscript_row *:last-child\n{\n\tmargin: 0;\n\theight: 77px;\n}\n\n.config_dan_userscript_bottom\n{\n\tpadding: 0;\n\theight: 27px !important;\n\tbackground-color: #000080;\n}';
			document.head.appendChild(uistyle);

			newDiv[0].id = 'config_dan_userscript';
			document.body.appendChild(newDiv[0]);

			newDiv[1].id = 'config_dan_userscript_header';
			newDiv[1].innerHTML = 'Configure Dan\'s Userscript (v ' + v + ') Settings';
			newDiv[0].appendChild(newDiv[1]);

			newDivRow[0].className = 'config_dan_userscript_row';
			newDivRow[0].innerHTML = '<div class = "config_dan_userscript_description config_dan_userscript_description_1">Block List:</div><div class = "config_dan_userscript_button config_dan_userscript_viewbutton" onclick = "config.players.view();">View</div><div class = "config_dan_userscript_button" onclick = "config.players.add();">Add<br>Player</div><button class = "config_dan_userscript_button" onclick = "config.players.remove();">Remove<br>Player</button>';
			newDiv[0].appendChild(newDivRow[0]);

			newDivRow[1].className = 'config_dan_userscript_row';
			newDivRow[1].innerHTML = '<div class = "config_dan_userscript_description">Thread<br>Exceptions:</div><div class = "config_dan_userscript_button config_dan_userscript_viewbutton" onclick = "config.threads.view();">View</div><div class = "config_dan_userscript_button" onclick = "config.threads.add();">Add<br>Thread</div><button class = "config_dan_userscript_button" onclick = "config.threads.remove();">Remove<br>Thread</button>';
			newDiv[0].appendChild(newDivRow[1]);

			newDivRow[2].className = 'config_dan_userscript_row';
			newDivRow[2].innerHTML = '<div class = "config_dan_userscript_description">Hide these<br>threads:</div><div class = "config_dan_userscript_button config_dan_userscript_viewbutton" onclick = "config._threads.view();">View</div><div class = "config_dan_userscript_button" onclick = "config._threads.add();">Add<br>Thread</div><button class = "config_dan_userscript_button" onclick = "config._threads.remove();">Remove<br>Thread</button>';
			newDiv[0].appendChild(newDivRow[2]);

			newDivRow[3].className = 'config_dan_userscript_row';
			newDivRow[3].innerHTML = '<div class = "config_dan_userscript_button config_dan_userscript_bottom" onclick = "config.advanced();">Advanced</div><div class = "config_dan_userscript_button config_dan_userscript_bottom" onclick = "config.toDefault();">Reset</div><div class = "config_dan_userscript_button config_dan_userscript_bottom" onclick = "config.ui.hide();" style = "width: 94px;">Close</div>';
			newDiv[0].appendChild(newDivRow[3]);
		}
	}
};
config.ui.build();
config.ui.createOverlays();
window.config = config;

//main
var	sHT = document.createElement("button"),
	hT = document.createElement("button"),
	td1 = document.createElement("td"),
	settings_btn = document.createElement("a"),
	sHTS = sHT.style,
	hTS = hT.style,
	a = document.getElementsByTagName("a"),
	aNo = 0,
	f = document.getElementsByTagName("font"),
	fNo = 0,
	d = document.getElementsByTagName("tr"),
	dNo = 0,
	dNoStart = '',
	dh = " detail_hidden",
	dhCN = document.getElementsByClassName(dh),
	ds = " detail_shown",
	dsCN = document.getElementsByClassName(ds),
	dg = " detail_good",
	db = "detail_blank",
	dbCN = document.getElementsByClassName(db),
	n = "none",
	y = "table-row";

window.d = d;
window.a = a;
window.dhCN = dhCN;
window.dsCN = dsCN;
window.dbCN = dbCN;

var ddM = document.getElementById('AccountDropDown');

if (ddM)
{
	ddM = ddM.nextElementSibling;
}

if (ddM)
{
	//create a settings button
	settings_btn.id = 'DansUserscriptBtn';
	settings_btn.innerHTML = "Dan's Userscript";
	settings_btn.className = 'dropdown-item';
	settings_btn.style.color = '#b6bd87';
	settings_btn.onclick = function()
	{
		config.ui.show();
	};

	//find the drop down divider an insert the settings button about it
	var ddM_child_counter = ddM.children.length - 1;
	var ddM_child;

	while (ddM_child_counter > -1)
	{
		ddM_child = ddM.children[ddM_child_counter];

		if (ddM_child.className === 'dropdown-divider')
		{
			ddM_child.insertAdjacentElement('beforebegin', settings_btn);
			break;
		}

		ddM_child_counter--;
	}
}

function checkF()
{
	//check forum type
	if (subForum || allF)
	{
		dNo = 3;
	}
	else
	{
		dNo = 4;
	}

	dNoStart = dNo;
	window.dNoStart = dNoStart;
	console.log('checkF dNo is ' + dNo);
}

function setTheadClassNames()
{
	//setTheadClassNames to prevent bugs
	checkF();

	var aNo = 0;
	var curr_a;
	var curr_a_href;

	while (aNo < a.length)
	{
		curr_a = a[aNo];
		curr_a_href = curr_a.href;

		if (curr_a_href.match(/\/\Discussion\/\?ID=/i) || curr_a_href.match(/\/\Forum\/\d/i))
		{
			if (!curr_a_href.match(/\?Offset=\d/i) && !curr_a_href.match(/\&Offset=\d/i))
			{
				curr_a.className = 'ThreadLink';
			}
		}

		aNo++;
	}
}

var ThreadLink = document.getElementsByClassName("ThreadLink");
window.ThreadLink = ThreadLink;

var TBL;

//styling info for hidden and unhidden threads
var detailShownRules = 'display: table';

if (allF || subForum || clanF || mail)
{
	detailShownRules += '-row';
}

detailShownRules += ' !important;';

document.head.innerHTML += '<style id = "Hide_Show_Threads" class = "Dan_Style">.detail_hidden, .detail_blank, .OT_hidden\n{\n\tdisplay: none !important;\n}\n\n.detail_shown\n{\n\t' + detailShownRules + '\n}\n\n.OT_shown\n{\n\tdisplay: table-row !important;\n}\n\n.detail_shown .sub-forum, .detail_shown td[valign="middle"], .OT_shown .sub-forum, .OT_shown td[valign="middle"]\n{\n\ttext-decoration: line-through;\n}\n\n.detail_good\n{\n\tdisplay: table-row !important;\n\ttext-decoration: none !important;\n}</style>';

//hides all-caps subjects
function hideAllCaps(ThreadLinkNo)
{
	var curr_d = document.getElementsByClassName('ThreadLink')[ThreadLinkNo].parentElement.parentElement;

	curr_d.className += dh;
	ThreadLink[ThreadLinkNo].title = 'This thread has an all-caps subject';
	console.log('ThreadLink[' + ThreadLinkNo + '].innerHTML = ' + ThreadLink[ThreadLinkNo].innerHTML);
}

//vars required for UI and hide/show replies
var psttbls = [],
	psttbl = "",
	psttblNo = 0,
	cIds = [],
	cId = "",
	cIdsNo = 0;

//makes it possable to hide and show OT threads
var	OT =
{
	buttonTd: document.createElement('td'),
	buttons:
	{
		hide: document.createElement('button'),
		show: document.createElement('button')
	},
	hidden: document.getElementsByClassName('OT_hidden'),
	shown: document.getElementsByClassName('OT_shown'),
	no: (function(){return OT.hidden.length-1;}),
	show: function()
	{
		OT.buttons.hide.style.display = 'none';

		console.log('OT.no() = ' + OT.no());
		while (OT.no() < OT.hidden.length && OT.no() >= 0)
		{
			OT.hidden[OT.no()].className = OT.hidden[OT.no()].className.replace('OT_hidden', 'OT_shown');
			console.log('unhid OT thread');
			OT.no = (function(){return OT.hidden.length-1;});
		}

		OT.buttons.show.style.display = 'block';
		if (OT.shown.length > 0)
		{
			if (OT.shown.length > 1)
			{
				OT.buttons.show.innerHTML = 'Hide ' + OT.shown.length + ' off-topic threads';
			}
			else
			{
				OT.buttons.show.innerHTML = 'Hide 1 off-topic thread';
			}
		}
	},
	hide: function()
	{
		OT.buttons.show.style.display = 'none';

		var	subForumCN = document.getElementsByClassName('sub-forum'),
			subForumCNNo = 0;

		//search through all threads
		while (subForumCNNo < subForumCN.length)
		{
			if (subForumCN[subForumCNNo].innerHTML.includes('Off-topic'))
			{
				//if the thread is in OT, hide it
				if (subForumCN[subForumCNNo].parentNode.className.match(/OT_shown/g))
				{
					subForumCN[subForumCNNo].parentNode.className = subForumCN[subForumCNNo].parentNode.className.replace('OT_shown', 'OT_hidden');
				}
				else if (subForumCN[subForumCNNo].parentNode.className.match(/OT_hidden/g) === null)
				{
					subForumCN[subForumCNNo].parentNode.className += 'OT_hidden';
				}
				console.log('hid OT thread');
			}
			subForumCNNo++;
		}

		if (OT.hidden.length > 0)
		{
			if (OT.hidden.length > 1)
			{
				OT.buttons.hide.innerHTML = 'Show ' + OT.hidden.length + ' off-topic threads';
			}
			else
			{
				OT.buttons.hide.innerHTML = 'Show 1 off-topic thread';
			}
		}
		OT.buttons.hide.style.display = 'block';
	},
	removeClassNames: function()
	{
		if (allF)
		{
			checkF();
			while (dNo < d.length)
			{
				d[dNo].className = d[dNo].className.replace('OT_hidden', '').replace('OT_shown', '');
				console.log('removed OT thread class name');
				dNo++;
			}
			checkF();
		}
	}
};
window.OT = OT;
OT.buttonTd.className = 'UIElement';
OT.buttons.hide.style.cursor = 'pointer';
OT.buttons.hide.onclick = function()
{
	OT.show();
	//to do: keep downvoted threads hidden
	//alert('clicked');
};

OT.buttons.show.style.cursor = 'pointer';
OT.buttons.show.onclick = function()
{
	OT.hide();
};

//makes it possable to hide threads
function hideThreads()
{
	try{
	//sets thread class so that Jump to Last Page links aren't counted as threads
	setTheadClassNames();

	if (allF)
	{
		var	td = document.getElementsByTagName('td');
		var	tdNo = 0;
		var curr_td;

		while (tdNo < td.length)
		{
			curr_td = td[tdNo];
			//decide which tds are subforums
			if (curr_td.parentElement.parentElement.parentElement.className === 'region' && curr_td.children.length === 0 && !curr_td.innerHTML.match(/\d/) && curr_td.innerText !== '')
			{
				curr_td.className = 'sub-forum';
				//console.log('td[' + tdNo + '] is a sub-forum');
			}
			tdNo++;
		}
		checkF();
		
	}

	//allows hiding threads from sub-forums
	if (allF)
	{
		if (localStorage.DanHTRBP_hidingOT === 'yes')
		{
				OT.hide();//hide the OT posts
				OT.buttonTd.removeAttribute('style');//show the show/hide buttons if not hiding OT posts
		}
		else
		{
			OT.buttonTd.style.display = 'none';//hide the show/hide buttons if not hiding OT posts
		}
	}
	else
	{
		OT.buttonTd.style.display = 'none';//hide the show/hide buttons if not hiding OT posts
	}

	var ThreadLink = document.getElementsByClassName('ThreadLink');
	var ThreadLinkNo = 0;
	var curr_ThreadLink;

	//hide all-caps
	checkF();

	var match_punctuation = function(curr_ThreadLink)
	{
		return curr_ThreadLink.innerText.match(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,\-.\/:;<=>?@\[\]^_`{|}~]/g);
	};
	var match_main = function(curr_ThreadLink)
	{
		var num_whitespace_matches = 0;

		if (curr_ThreadLink.innerText.match(/\s/))
		{
			num_whitespace_matches = curr_ThreadLink.innerText.match(/\s/g).length;
		}

		return curr_ThreadLink.innerText.match(/[A-Z]/g).length + num_whitespace_matches;
	}

	while (ThreadLinkNo < ThreadLink.length)
	{
		curr_ThreadLink = ThreadLink[ThreadLinkNo];

		if (curr_ThreadLink.innerText.match(/[A-Z]/))
		{
			//console.log('found A-Z');

			if (curr_ThreadLink.innerText.length - 1 === match_main(curr_ThreadLink))
			{
				console.log('found all-caps thread');
				hideAllCaps(ThreadLinkNo);
			}
			else if (match_punctuation(curr_ThreadLink))
			{
				if (curr_ThreadLink.innerText.length - 1 === match_main(curr_ThreadLink) + match_punctuation(curr_ThreadLink).length)
				{
					console.log('found all-caps thread');
					hideAllCaps(ThreadLinkNo);
				}
			}
		}

		fixBlank(ThreadLink, ThreadLinkNo, '[blank subject]', false, false);

		ThreadLinkNo++;
	}

	checkF();
	fNo = 0;
	ThreadLinkNo = 0;

	var curr_f;
	var curr_p;
	var curr_d;

	while (ThreadLinkNo < ThreadLink.length)
	{
		curr_f = f[fNo];
		curr_d = d[dNo];
		curr_ThreadLink = ThreadLink[ThreadLinkNo];
		pNo = 0;

		while (pNo < p.length)
		{
			curr_p = p[pNo];

			fixBlank(f, fNo, ' by [blank name]', false, true);

			if (curr_f.innerText === ' by ' + curr_p)
			{
				//hide threads by certain posters
				if (curr_d.className.match(/ detail_shown/))
				{
					curr_d.className = curr_d.className.replace(' detail_shown', ' detail_hidden');
				}
				else
				{
					console.log('init');
					curr_d.className += ' detail_hidden';
				}

				if (curr_d.style.display === 'table-row')
				{
					curr_d.removeAttribute('style');
				}
				console.log('hid thread by ' + curr_p);
			}
			pNo++;
		}

		if (localStorage.MOTW === 'yes')
		{
			//hide motw
			if (curr_ThreadLink.innerText.includes("Map of the week discussion: Week "))
			{
				if (curr_d.className.includes(' detail_shown'))
				{
					curr_d.className = curr_d.className.replace(' detail_shown', ' detail_hidden');
				}
				else
				{
					curr_d.className += ' detail_hidden';
				}
				curr_ThreadLink.title = 'Map of the Week is being hidden';
			}
		}
		else
		{
			if (curr_ThreadLink.innerText.includes('Map of the week discussion: Week '))
			{
				curr_d.className = curr_d.className.replace(' detail_hidden', '');
			}
		}
		fNo++;
		dNo++;
		ThreadLinkNo++;
	}

	var HideUnhideThreads = function(array)
	{
		checkF();
		ThreadLinkNo = 0;
		var index;

		var dont_hide_thread = array === t;

		if (array.length > 1)
		{
			while (ThreadLinkNo < ThreadLink.length)
			{
				curr_d = d[dNo];
				curr_ThreadLink = ThreadLink[ThreadLinkNo];
				index = 0;

				while (index < array.length)
				{
					if (curr_ThreadLink.innerText.includes(array[index]))
					{
						if (dont_hide_thread)
						{
							if (!curr_d.className.includes(' detail_good'))
							{
								curr_d.className += ' detail_good';
								curr_ThreadLink.title = 'This thread is NOT being hidden';
							}
						}
						else
						{
							if (curr_d.className.includes(' detail_shown'))
							{
								curr_d.className = curr_d.className.replace(' detail_shown', ' detail_hidden');
							}
							else
							{
								curr_d.className += 'detail_shown';
							}
							curr_ThreadLink.title = 'This thread is being hidden';
						}
					}
					index++;
				}

				dNo++;
				ThreadLinkNo++;
			}
		}
	};

	HideUnhideThreads(t);//thread exceptions
	HideUnhideThreads(_t);//hides individual threads

	hTS.display = 'none';
	if (dhCN.length > 0)
	{
		if (dhCN.length > 1)
		{
			sHT.innerHTML = 'Show ' + dhCN.length + ' hidden threads';
		}
		else
		{
			sHT.innerHTML = 'Show 1 hidden thread';
		}
		sHTS.display = 'block';
	}
	else
	{
		sHTS.display = 'none';
	}
	}catch(err){console.log(err);}
}

function showHiddenThreads()
{
	//makes it possable to show hidden threads
	try{
	console.log('showing hidden threads');

	var	dhNo = 0;
	var curr_dh;

	while (dhNo < dhCN.length)
	{
		curr_dh = dhCN[dhNo];

		if (curr_dh.className.includes('OT_hidden'))
		{
			curr_dh.style.display = 'table-row';
		}

		curr_dh.className = curr_dh.className.replace(' detail_hidden', ' detail_shown').replace('detail_hidden', 'detail_shown');
		dhNo = dhNo;
	}

	sHTS.display = "none";
	if (dsCN.length > 0)
	{
		if (dsCN.length > 1)
		{
			hT.innerHTML = "Hide " + dsCN.length + " threads";
		}
		else
		{
			hT.innerHTML = "Hide 1 thread";
		}
		hTS.display = "block";
	}
	else
	{
		hTS.display = "none";
	}
	console.log('shown hidden threads');
	}catch(err){console.log(err);}
}

function hideReplies()
{
	try{
	var table_left_col;
	var table_left_col_child;
	var table_left_col_child_counter;
	var players = [];
	var playerNo = 0;

	var aNo = 0;
	var curr_a;

	var tables = document.getElementsByTagName('table');
	var table_counter = 0;
	var table;

	while (table_counter < tables.length)
	{
		//get the post tables
		table = tables[table_counter];

		if (table.id.match(/PostTbl_/) && table.className.match(/region/))
		{
			psttbls.push(table);

			//get the player that posted the comment
			table_left_col = table.firstElementChild.children[1].firstElementChild.children;
			table_left_col_child_counter = 0;

			while (table_left_col_child_counter < table_left_col.length)
			{
				table_left_col_child = table_left_col[table_left_col_child_counter];

				if (table_left_col_child.tagName.toLowerCase() === 'a')
				{
					if (table_left_col_child.href.match(/\/Profile\?p=\d/))
					{
						players.push(table_left_col_child.innerText)
					}
				}
				table_left_col_child_counter++;
			}
		}
		table_counter++;
	}

	//hide main
	playerNo = 0;
	psttblNo = 0;

	var curr_psttbl;
	var player;

	while (playerNo < players.length)
	{
		curr_psttbl = psttbls[psttblNo];
		pNo = 0;

		while (pNo < p.length)
		{
			player = players[playerNo]
			if (player === (p[pNo]))
			{
				if (curr_psttbl.className.match(/ detail_shown/))
				{
					curr_psttbl.className = curr_psttbl.className.replace(' detail_shown', ' detail_hidden');
				}
				else
				{
					curr_psttbl.className += ' detail_hidden';
				}
				console.log('hid post by ' + player);
			}
			pNo++;
		}
		playerNo++;
		psttblNo++;
	}
	psttblNo = 0;

	//hides show downvoted/hidden reply link if a player on the hide list has had their comment to be downvoted or hidden
	fNo = 0;
	pNo = 0;
	var curr_f;
	window.f = [];
	
	while (fNo < f.length)
	{
		curr_f = f[fNo];
		pNo = 0;

		while (pNo < p.length)
		{
			if (curr_f.innerHTML.includes('- downvoted') || curr_f.innerHTML.includes('- hidden') && curr_f.nextElementSibling.children[0].children[1].children[0].innerHTML.includes(p[pNo]))
			{
				curr_f.style.display = 'none';
			}
			pNo++;
		}
		fNo++;
	}

	hTS.display = 'none';
	if (dhCN.length > 0)
	{
		if (dhCN.length > 1)
		{
			sHT.innerHTML = 'Show ' + dhCN.length + ' hidden replies';
		}
		else
		{
			sHT.innerHTML = 'Show 1 hidden reply';
		}
		sHTS.display = 'block';
	}
	else
	{
		sHTS.display = 'none';
	}
	}catch(err){console.log(err);}
}

function showHiddenReplies()
{
	try{
	var curr_psttbl;

	while (psttblNo < psttbls.length)
	{
		curr_psttbl = psttbls[psttblNo];
		curr_psttbl.setAttribute("class", curr_psttbl.className.replace(' detail_hidden', ' detail_shown'));
		psttblNo++;
	}

	sHTS.display = 'none';

	if (dsCN.length > 0)
	{
		if (dsCN.length > 1)
		{
			hT.innerHTML = 'Hide ' + dsCN.length + ' replies';
		}
		else
		{
			hT.innerHTML = 'Hide 1 reply';
		}
		hTS.display = 'block';
	}
	else
	{
		hTS.display = 'none';
	}
	}catch(err){console.log(err);}
}

if (subForum || allF || clanF || mail)
{
	try{
	var _table = document.getElementsByTagName('table')[document.getElementsByTagName('table').length - 1];

	if (_table)
	{
		if (_table.childNodes[1])
		{
			if (_table.childNodes[1].childNodes[0])
			{
				//defines where the X threads/posts hidden should be
				TBL = _table.childNodes[1].childNodes[0];
			}
		}
	}

	//spam
	/*if (subForum || allF)
	{
		var JTNSa = document.createElement("a"),
			td0 = document.createElement("td"),
			pages = 0;
		if (genF)
		{
			pages = 25;
			JTNSa.href = "/forum/f1-General?Offset=" + pages * 50;
		}
		if (mapF)
		{
			pages = 5;
			JTNSa.href = "/forum/f4-Map-Development?Offset=" + pages * 50;
		}
		if (ladF)
		{
			pages = 5;
			JTNSa.href = "/forum/f5-Ladder?Offset=" + pages * 50;
		}
		if (progF)
		{
			pages = 5;
			JTNSa.href = "/forum/f6-Programming?Offset=" + pages * 50;
		}
		if (helpF)
		{
			pages = 5;
			JTNSa.href = "/forum/f7-Help?Offset=" + pages * 50;
		}
		if (OTF)
		{
			pages = 20;
			JTNSa.href = "/forum/f8-topic?Offset=" + pages * 50;
		}
		if (clansF)
		{
			pages = 5;
			JTNSa.href = "/forum/f9-Clans?Offset=" + pages * 50;
		}
		if (stratF)
		{
			pages = 5;
			JTNSa.href = "/forum/f10-Strategy?Offset=" + pages * 50;
		}
		if (allF)
		{
			pages = 55;
			JTNSa.href = "/forum/Forum?Offset=" + pages * 50;
		}
		if (pages > 0)
		{
			JTNSa.innerHTML = "Jump to non-spam threads";
			td0.id = "spamTd";
			if (TBL !== undefined)
			{
				TBL.appendChild(td0);
				td0.parentNode.insertBefore(td0, td0.parentNode.childNodes[0]);
				td0.appendChild(JTNSa);
			}
		}
	}*/
	//make reset and restore buttons
	if (TBL)
	{
		td1.id = 'btnTd';
		td1.className = 'UIElement';
		TBL.appendChild(td1);
		td1.parentNode.insertBefore(td1, td1.parentNode.childNodes[0]);
		sHT.onclick = function()
		{
			showHiddenThreads();
		};
		sHTS.cursor = "pointer";
		td1.appendChild(sHT);
		hTS.cursor = "pointer";
		hT.onclick = function()
		{
			hideThreads();
		};

		td1.appendChild(hT);

		TBL.appendChild(OT.buttonTd);
		OT.buttonTd.parentNode.insertBefore(OT.buttonTd, OT.buttonTd.parentNode.children[1]);
		OT.buttonTd.appendChild(OT.buttons.hide);
		OT.buttonTd.appendChild(OT.buttons.show);
	}

	//makes blanked-out last post by players visable by changing the text to "by [blank name]"
	var s = document.getElementsByTagName('span'),
		sNo = 2;

	fixBlank(s, sNo, 'by [blank name]', true, false);

	sNo = 2;
	hideThreads();//hide threads straight away
	}catch(err){console.log(err);}
}
else if (threadP || discussionP)
{
	try{
	var _table = document.getElementsByTagName("table")[document.getElementsByTagName("table").length - 2];

	if (_table)
	{
		if (_table.childNodes[1])
		{
			if (_table.childNodes[1].childNodes[0])
			{
				TBL = _table.childNodes[1].childNodes[0];
			}
		}
	}

	//turns blanked-out subjects to [blank subject] so that subject becomes visible
	fixBlank(f, fNo, '[blank subject]', true, false);
	fNo = 0;

	//makes reset and restore buttons
	if (TBL)
	{
		td1.id = "btnTd";
		td1.className = 'UIElement';
		TBL.appendChild(td1);
		var btnTd = document.getElementById("btnTd");
		btnTd.parentNode.insertBefore(btnTd, btnTd.parentNode.childNodes[0]);
		sHT.onclick = function()
		{
			showHiddenReplies();
		};
		sHTS.cursor = "pointer";
		td1.appendChild(sHT);
		hTS.cursor = "pointer";
		hT.onclick = function()
		{
			hideReplies();
		};
		td1.appendChild(hT);
	}
	//hide blank posts
	var pfds = [],
		pfd = "",
		pfdNo = 0,
		divNo = 0,
		div = document.getElementsByTagName("div");
	if (!document.getElementById("SubjectBox") && !location.pathname.includes("/Discussion/Notes"))
	{
		while (divNo < div.length)
		{
			if (div[divNo].id.includes("PostForDisplay") && div[divNo].id != "PostForDisplay_-1")
			{
				pfd = div[divNo].id;
				pfds.push(pfd);
			}
			divNo++;
		}
		window.pfds = pfds;
	
		var curr_post_for_display;

		while (pfdNo < pfds.length)
		{
			curr_post_for_display = document.getElementById(pfds[pfdNo]);

			if (curr_post_for_display.innerHTML.length === curr_post_for_display.innerHTML.match(/\s/g).length || curr_post_for_display.innerText.match(/\s+Edited \d+\/\d+\/\d+ \d+:\d+:\d+/))
			{
				//"\n\nEdited 12/2/2017 18:13:45"
				var tbl = document.getElementById(pfds[pfdNo]).parentNode.parentNode.parentNode.parentNode;
				tbl.className = db;
			}

			pfdNo++;
		}
		if (localStorage.bpDialogue === 'no')
		{
			if (dbCN.length > 0)
			{
				if (dbCN.length === 1)
				{
					alert('1 blank post was hidden.');
				}
				else if (dbCN.length > 1)
				{
					alert(dbCN.length + ' blank posts were hidden.');
				}
			}
		}
	}

	hideReplies();//hide replies straight away
	}catch(err){console.log(err);}
}
//remove extra Muli's Userscript menu - a script causes this bug to happen
setTimeout('try{document.getElementsByClassName("userscript-menu")[1].remove();} catch(err) {}',750);
setTimeout('try{document.getElementsByClassName("userscript-menu")[1].remove();} catch(err) {}',1250);
//UI
//show and hide clicked are for making it possable to show and hide the downvoted threads an unlimited amount of time
function showClicked()
{
	try{
	$('tr[data-hidden]').show();
	var show = document.getElementById("show");
	show.id = "hide";
	var hide = document.getElementById("hide");
	hide.innerHTML = hide.innerHTML.replace("Show", "Hide");
	hide.onclick = function()
	{
		hideClicked();
	};
	}catch(err){console.log(err);}
}

function hideClicked()
{
	try{
	$('tr[data-hidden]').hide();
	var hide = document.getElementById("hide");
	hide.id = "show";
	var show = document.getElementById("show");
	show.innerHTML = show.innerHTML.replace("Hide", "Show");
	show.onclick = function()
	{
		showClicked();
	};
	}catch(err){console.log(err);}
}

function FixHiddenThreadsRow()
{
	try{
	var htr = document.getElementById('HiddenThreadsRow');
	var show = htr.children[0].children[0];

	if (show)
	{
		show.id = 'show';
		show = document.getElementById('show');
		show.innerHTML = 'Show ' + show.innerHTML.replace('hidden', 'downvoted');
	}

	var td2to6 =
	[
		document.createElement('td'),
		document.createElement('td'),
		document.createElement('td'),
		document.createElement('td'),
		document.createElement('td'),
		document.createElement('td'),
		document.createElement('td')
	];
	if (allF)
	{
		if (userscripts.mulis())
		{
			//if Muli's script enabled, hidden threads row looks quite bad, so make it look nicer
			setTimeout('var htr = document.getElementById("HiddenThreadsRow");var td2to6 = [document.createElement("td"),	document.createElement("td"),	document.createElement("td"),	document.createElement("td"),	document.createElement("td"),	document.createElement("td"),	document.createElement("td")];/*end of vars*/htr.appendChild(td2to6[0]);htr.insertBefore(td2to6[0], htr.childNodes[2]);',3000);
		}
		else
		{
			//hidden threads row looks bad, so make it look nicer
			htr.appendChild(td2to6[0]);
			htr.insertBefore(td2to6[0], htr.childNodes[0]);
			htr.appendChild(td2to6[1]);
			htr.insertBefore(td2to6[1], htr.childNodes[2]);
			htr.appendChild(td2to6[2]);
			htr.insertBefore(td2to6[2], htr.children[htr.children.length-1]);
			show.parentElement.removeAttribute('colSpan');
			show.parentElement.style.textAlign = 'left';
		}
	}
	else
	{
		var tds = [document.createElement('td'), document.createElement('td'), document.createElement('td')];

		//console.log('htr.children.length = ' + htr.children.length);
		if (htr.children.length < 4)
		{
			htr.appendChild(tds[0]);
			htr.insertBefore(tds[0], htr.children[0]);
			htr.appendChild(tds[1]);
			htr.insertBefore(tds[1], htr.children[htr.children.length-1]);
			htr.appendChild(tds[2]);
			htr.insertBefore(tds[2], htr.children[htr.children.length-1]);
			show.parentElement.removeAttribute('colSpan');
			show.parentElement.style.textAlign = 'left';
		}
	}

	show.onclick = function()
	{
		showClicked();
	};
	}catch(err){console.log(err);}
}

if (subForum || allF || clanF || mail || threadP || discussionP)
{
	try{
	var f = document.getElementsByTagName('font'),
		fNo = 0;

	var ActionsTh0 = document.createElement('th'),
		ActionsTh1 = document.createElement('th');

	//UI for sub-forums, all forums, mail and clan forum (i.e. non-thread pages or non-discussion pages)

	if (!threadP && !discussionP)
	{
		ActionsTh0.className = 'UIElement';
		ActionsTh0.innerHTML = 'Block List';
		ActionsTh0.style.cursor = 'pointer';
		ActionsTh0.style.minWidth = '90px';
		ActionsTh0.style.maxWidth = '90px';
		ActionsTh0.onclick = function()
		{
			config.players.view();
		};
		ActionsTh1.className = 'UIElement';
		ActionsTh1.innerHTML = 'Thread Exceptions';
		ActionsTh1.style.cursor = 'pointer';
		ActionsTh1.style.minWidth = '145px';
		ActionsTh1.style.maxWidth = '145px';
		ActionsTh1.onclick = function()
		{
			config.threads.view();
		};
	
		if (mail || clanF)
		{
			d[1].appendChild(ActionsTh0);
			d[1].appendChild(ActionsTh1);
		}
		else
		{
			d[2].appendChild(ActionsTh0);
			d[2].appendChild(ActionsTh1);
		}

		checkF();
		fNo = 0;
		sNo = 2;

		var ThreadLinkNo = 0;
		var curr_ThreadLink;
		var curr_d;
		var curr_f;
		var curr_s;
		var curr_blocklist;
		var curr_thread_exception;

		while (ThreadLinkNo < ThreadLink.length)
		{
			curr_ThreadLink = ThreadLink[ThreadLinkNo];
			curr_f = curr_ThreadLink.nextElementSibling.nextElementSibling;
			curr_d = curr_ThreadLink.parentElement.parentElement;

			if (allF)
			{
				curr_s = curr_d.children[4].children[1];
			}
			else if (mail)
			{
				curr_s = curr_d.children[2].children[1];
			}
			else
			{
				curr_s = curr_d.children[3].children[1];
			}

			var PlayersTD = document.createElement('td'),
			PlayersHBtn = document.createElement('button'),
			PlayersSBtn = document.createElement('button');

			PlayersTD.className = 'PlayersTD';

			//var PlayersTDCN = document.getElementsByClassName('PlayersTD');

			curr_d.appendChild(PlayersTD);

			PlayersHBtn.innerHTML = 'Add';
			PlayersHBtn.className = 'PlayersHBtn';
			PlayersSBtn.innerHTML = 'Remove';
			PlayersSBtn.className = 'PlayersSBtn';

			//decides if you get to see the hide posts or unhide posts by players button
			//preventing style getting overidden bug using matched as classname
			if (p.length < 1)
			{
				//only shows hide button
				PlayersHBtn.style.display = 'table-row';
				PlayersSBtn.style.display = 'none';
			}
			else
			{
				pNo = 0;

				while (pNo < p.length)
				{
					if (curr_f.innerText.replace('by ', '') === p[pNo])
					{
						curr_f.className = 'Matched';
						PlayersHBtn.style.display = 'none';
						PlayersSBtn.style.display = 'table-row';
					}
					if (curr_f.className === '')
					{
						PlayersHBtn.style.display = 'table-row';
						PlayersSBtn.style.display = 'none';
					}
					pNo++;
				}
			}

			curr_blocklist = curr_d.children[curr_d.children.length - 1];

			curr_blocklist.appendChild(PlayersHBtn);
			curr_blocklist.appendChild(PlayersSBtn);

			var ThreadExceptionsTD = document.createElement('td'),
				ThreadExceptionsHBtn = document.createElement('button'),
				ThreadExceptionsSBtn = document.createElement('button');

			ThreadExceptionsTD.className = 'ThreadExceptionsTD';

			var ThreadExceptionsTDCN = document.getElementsByClassName('ThreadExceptionsTD');

			curr_d.appendChild(ThreadExceptionsTD);

			ThreadExceptionsHBtn.innerHTML = 'Add';
			ThreadExceptionsHBtn.className = 'ThreadExceptionsHBtn';
			ThreadExceptionsSBtn.innerHTML = 'Remove';
			ThreadExceptionsSBtn.className = 'ThreadExceptionsSBtn';

			//decides if you get to see the add or remove a thread from thread exceptions
			if (curr_ThreadLink.title === 'This thread is NOT being hidden')
			{
				ThreadExceptionsHBtn.style.display = 'none';
				ThreadExceptionsSBtn.style.display = 'table-row';
			}
			else
			{
				ThreadExceptionsHBtn.style.display = 'table-row';
				ThreadExceptionsSBtn.style.display = 'none';
			}

			curr_thread_exception = curr_blocklist.nextElementSibling;
			curr_thread_exception.appendChild(ThreadExceptionsHBtn);
			curr_thread_exception.appendChild(ThreadExceptionsSBtn);
	
			curr_f.className = 'PlayerName';
			//curr_f.innerHTML = ' by 12345678901234567890123456789012345678901234567890';
			//curr_ThreadLink.innerHTML = '12345678901234567890123456789012345678901234567890';
			//curr_s.innerHTML = 'by 12345678901234567890123456789012345678901234567890';
			if (ActionsTh0.parentNode.childNodes[5].style.minWidth !== '468px')
			{
				if (curr_f.innerHTML.length + curr_s.innerHTML.length > 85)
				{
					//resize thread width to make the table look better
					//if thread poster name last replier length is greater than 85
					ActionsTh0.parentNode.childNodes[5].style.minWidth = '468px';
					ActionsTh0.parentNode.childNodes[5].style.maxWidth = '468px';
				}
			}
			sNo++;
			fNo++;
			ThreadLinkNo++;
		}
	}

	//assigning onclick using a normal loop doesn't work how it should, so using a function that makes each onclick for each type of button one at a time - this works how it should
	var DecideOnClickForBtn = function(btn_no, _function, btn_for_what)
	{
		var btn;
		var btn_type;
		var remove_item = false;

		if (btn_for_what === 'Players')
		{
			btn_type = document.getElementsByClassName('PlayerName');
			btn = document.getElementsByClassName('PlayersHBtn')[btn_no];

			if (_function === removePlayer)
			{
				btn = document.getElementsByClassName('PlayersSBtn')[btn_no];
				remove_item = true;
			}
		}
		else
		{
			btn_type = document.getElementsByClassName('ThreadLink');
			btn = document.getElementsByClassName('ThreadExceptionsHBtn')[btn_no];

			if (_function === removeThread)
			{
				btn = document.getElementsByClassName('ThreadExceptionsSBtn')[btn_no];
				remove_item = true;
			}
		}
		if (btn)
		{
			btn.onclick = function()
			{
				if (remove_item)
				{
					_function(btn_type[btn_no], btn_no);
				}
				else
				{
					_function(btn_for_what, btn_type[btn_no], btn_no)
				}
			};
			GiveOnClickToBtn(btn_no + 1, _function, btn_for_what);
		}
		else
		{
			if (btn_for_what === 'Players' && !remove_item)
			{
				GiveOnClickToBtn(0, removePlayer, btn_for_what);
			}
			else if (btn_for_what === 'Players' && remove_item)
			{
				GiveOnClickToBtn(0, addToArray, 'threads');
			}
			else if (btn_for_what === 'threads' && !remove_item)
			{
				GiveOnClickToBtn(0, removeThread, 'threads');
			}
		}
	};

	var GiveOnClickToBtn = function(btn_no, _function, btn_for_what)
	{
		DecideOnClickForBtn(btn_no, _function, btn_for_what);
	};

	GiveOnClickToBtn(0, addToArray, 'Players');

	if (document.getElementById('HiddenThreadsRow'))
	{
		FixHiddenThreadsRow();
	}
	}catch(err){console.log(err);}
}

//makes blanked-out links visable globaly by replacing the link's innerHTML with [blank name]
var a = document.getElementsByTagName("a"),
	aNo = 0;

fixBlank(a, aNo, '[blank name]', true, false);