IDEAL Scripts

All IDEAL Scripts for idealclan.eu merged into one

As of 2016-12-19. See the latest version.

// ==UserScript==
// @name        IDEAL Scripts
// @version     0.83
// @description All IDEAL Scripts for idealclan.eu merged into one
// @author      Orrie
// @namespace   http://idealclan.eu/viewtopic.php?f=7&t=1791#p57645
// @icon        https://dl.dropboxusercontent.com/u/12497046/wot/projects/statscript/modules/ideal/team_ideal.png
// @include     http://*idealclan.eu/*
// @grant       GM_xmlhttpRequest
// @connect     eu.wargaming.net
// @connect     api.worldoftanks.eu
// @connect     api.twitch.tv
// @require     https://greasyfork.org/scripts/18946-tablesort/code/Tablesort.js?version=120660
// @license     Mr Sexii License
// ==/UserScript==


(function() {
	// global variables
	var d = document, date = new Date();

	// script variables
	var bs = {
		href: d.location.href,
		vers: ((GM_info) ? GM_info.script.version : ""),
		tw: {
			api: "https://api.twitch.tv/kraken/streams/?channel=",
			key: "fbs3puqef627klk0wf9jrgjach2h3y9"
		},
		cw: {
			status: JSON.parse(localStorage.getItem("battles_force")) || false,
			event: false,
			gold: true,
			fame: 400,
			tier: "Ɵ",
			bats: "Ɵ",
			elo: "Ɵ",
			current: 0
		},
		dyn: {
			conc: [],
			plan: 0,
			check: 0,
			gold: 0
		},
		clan: {
			ideal: 500010805,
			id: JSON.parse(localStorage.getItem("battles_clanid")) || 500010805,
			tag: "Ɵ",
			emblem: "Ɵ",
			color: "Ɵ"
		},
		table: {
			static: 9,
			eu: [17, 18, 19, 20, 21, 22, 23, 24],
			c: "",
			s: []
		},
		app_id: "a7595640a90bf2d19065f3f2683b171c",
		db: "https://dl.dropboxusercontent.com/u/12497046/wot/projects/statscript/modules/ideal/img/",
		web: { // browser detection
			gecko: typeof InstallTrigger !== 'undefined',
			chrome: !!window.chrome && !!window.chrome.webstore
		},
		time: {
			h: date.getHours(),
			m: date.getMinutes(),
			o: ((date.getTimezoneOffset() > 0) ? -Math.abs(date.getTimezoneOffset()) : Math.abs(date.getTimezoneOffset()))/60
		},
		debug: ((d.getElementsByClassName("headerbnl")[0].innerHTML.match(/Orrie/)) ? true : false)
	};
	bs.api = {
		event: "https://api.worldoftanks.eu/wot/globalmap/events/?application_id="+bs.app_id+"&limit=1",
		clan: "https://eu.wargaming.net/globalmap/game_api/clan/"+bs.clan.id+"/battles",
		bats: "https://eu.wargaming.net/globalmap/game_api/map_fill_info?aliases=",
		tourney: "https://eu.wargaming.net/globalmap/game_api/tournament_info?alias=",
		prov: "https://eu.wargaming.net/globalmap/game_api/province_info?alias=",
		provs: "https://api.worldoftanks.eu/wot/globalmap/clanprovinces/?application_id="+bs.app_id+"&clan_id="+bs.clan.id,
		divs: "https://eu.wargaming.net/globalmap/game_api/wot/clan_tactical_data", // need authentication from global map
		raids: "https://eu.wargaming.net/globalmap/game_api/wot/raids" // need authentication from global map
	};
	bs.time.r = ((bs.time.m >= 15 && bs.time.m <= 45) ? [bs.time.h,"30"] : ((bs.time.m <= 15) ? [bs.time.h,"00"] : [(bs.time.h+1),"00"]));
	bs.time.t = bs.time.r[0]+"_"+bs.time.r[1];

	// image codes and stream list
	var img = {
		// icons
		// eu clans
		ideal: "clan-ideal.png",
		s3al: "clan-s3al.png",
		e50m: "clan-e50m.png",
		fame: "clan-fame.png",
		omni: "clan-omni.png",
		ptsd: "clan-ptsd.png",
		rsop: "clan-rsop.png",
		s4: "clan-s4.png",
		vole: "clan-vole.png",
		vter: "clan-vter.png",
		santi: "clan-santi.png",
		// na clans
		bulba: "clan-bulba.png",
		// ru clans
		mamb: "clan-mamb.png",
		// esl teams
		kb: "team-kb.png",
		navi: "team-navi.png",
		penta: "team-penta.png",
		// other
		circ: "fag-circ.png",
		fnd: "fag-friend.png",
		foch: "fag-foch.png",
		sela: "fag-sela.png",
		syb: "fag-syb.png",
		qb: "fag-qb.png",
		wg: "fag-wg.png",
		// flags
		au: "flag-au.png",
		ca: "flag-ca.png",
		cz: "flag-cz.png",
		de: "flag-de.png",
		en: "flag-en.png",
		fi: "flag-fi.png",
		no: "flag-no.png",
		pl: "flag-pl.png",
		ru: "flag-ru.png",
		se: "flag-se.png",
		us: "flag-us.png"
	},
	streams = [
		// IDEAD
		["Evidence",        "evidence__",      "ideal", "en",        "0"],
		["HowTheStoryEnds", "howthestoryends", "ideal", "en",        "0"],
		["Kriegerseele",    "kriegerseele_",   "ideal", ["en","de"], "0"],
		["Orrie",           "orrie_",          "ideal", ["en","no"], "0"],
		["Taylor_Swift",    "gashting",        "ideal", "en",        "0"],
		["Remmke",          "remmke",          "ideal", ["en","de"], "0"],
		["R0XJi",           "roxjiwot",        "ideal", ["en","fi"], "0"],
		["Sekundenkleber",  "sekundenkleber",  "ideal", ["en","de"], "0"],
		["veitileiN",       "veitilein",       "ideal", ["en","de"], "0"],
		// IDEAD friends
		["Keezoo",             "keezoo__",           ["fnd","fame"], "pl",        "0"],
		["TheGaymingLion",     "thegaminglion7",     ["fnd","fame"], "en",        "0"],
		["Weenis",             "weeniswot",          ["fnd","fame"], "en",        "0"],
		["McMokka",            "mcmokka",            ["fnd","s4"],   ["en","de"], "0"],
		["Otto_von_HEATmarck", "otto_von_heatmarck", ["fnd","s4"],   ["en","de"], "0"],
		["Fjellreven",         "fjellreven_tv",      "fnd",          ["en","no"], "0"],
		// S3AL
		["Andgus",          "andgus_swe",      "s3al",           ["en","se"], "1"],
		["Atrevir",         "atrevir",         "s3al",           "en",        "1"],
		["DMminion",        "dmminion",        "s3al",           "en",        "1"],
		["Dukkerz",         "dukkerz",         "s3al",           "en",        "1"],
		["Elecktr",         "elecktr_pl",      "s3al",           "en",        "1"],
		["Faptastic_Panda", "faptastic_panda", "s3al",           "en",        "1"],
		["Fosco",           "fosc0",           "s3al",           "en",        "1"],
		["Hallucinogen",    "hailucinogen",    "s3al",           "en",        "1"],
		["Hassh",           "hashonline",      "s3al",           "en",        "1"],
		["Jona",            "jonasb7",         "s3al",           "en",        "1"],
		["Kapz93",          "kapz93",          "s3al",           "en",        "1"],
		["Marty_vole",      "marty_vole",      ["s3al", "vole"], ["en","cz"], "1"],
		["OffCerium",       "offcerium",       "s3al",           "en",        "1"],
		["POtkanzoR",       "potkanzor",       "s3al",           "en",        "1"],
		["Richblaster",     "richblaster",     "ptsd",           "ptsd",      "1"],
		["RoyM18",          "roym18",          "s3al",           "en",        "1"],
		["Trechy",          "trechy",          "s3al",           ["en","se"], "1"],
		["Sukkamurmeli",    "sukkamurmeli",    "s3al",           "en",        "1"],
		["Tarantula",       "kridtv",          "s3al",           ["en","se"], "1"],
		// FAME
		["Dakillzor",      "dakillzor",       "fame", "en",        "1"],
		["Decha",          "dechapl",         "fame", "en",        "1"],
		["Deekay",         "dkns_eu",         "fame", "en",        "1"],
		["Dyaebl",         "dyaebl",          "fame", ["en","pl"], "1"],
		["Failware",       "failwarelp",      "fame", "en",        "1"],
		["FieserFettsakk", "fieserfettsakk_", "fame", ["en","de"], "1"],
		["Floris",         "florisgg",        "fame", "en",        "1"],
		["Kajzoo",         "kajzoo",          "fame", "en",        "1"],
		["CarryBarry",     "swift_m0ti0n",    "fame", "en",        "1"],
		["Mailand",        "mailand121",      "fame", "en",        "1"],
		["Nicktast1c",     "nicktast1c",      "fame", "en",        "1"],
		["RavenHR",        "ravenhr",         "fame", "en",        "1"],
		["Schockisch",     "schockisch",      "fame", "en",        "1"],
		["Shishx",         "shishx",          "fame", "en",        "1"],
		["Skarium",        "skarium1",        "fame", "en",        "1"],
		["TCAmir",         "tcamir",          "fame", "en",        "1"],
		["Tyne",           "k1ll_5t3al_tyne", "fame", ["en","fi"], "1"],
		["X3N4",           "x3n4",            "fame", "en",        "1"],
		["Xaneleon",       "xaneleon",        "fame", "en",        "1"],
		["Yung",           "yung_xd",         "fame", ["en","se"], "1"],
		// RSOP
		["CharCharro", "charcharro", "rsop", ["en","fi"], "1"],
		["Choppy",     "choppyyxd",  "rsop", ["en","fi"], "1"],
		["Count_TR",   "count_tr",   "rsop", ["en","fi"], "1"],
		["Muppetti",   "muppetti",   "rsop", ["en","fi"], "1"],
		// OMNI
		["Genghiswolves", "genghiswolves", "omni", "en", "1"],
		["Tomosa",        "tomosasamosa",  "omni", "en", "1"],
		["TotallyMeYou",  "totallymeyou",  "omni", "en", "1"],
		// Other Clans (Only 1 streamer)
		["Morgotz",       "morgotz",       "e50m",  "en",        "1"],
		["No6ody",        "no6ody",        "s4",    ["en","de"], "1"],
		["skill4ltu",     "skill4ltu",     "santi", "en",        "1"],
		// WGL
		["Knäckebröd WGL", "knackebrod_wgl", "kb", "en", "1"],
		// Amerifats/AZNs/Austrians
		["Barks_Internally", "barks_internally", "bulba", "au", "2"],
		["Overlord_Prime",   "overlord_prime",   "bulba", "us", "2"],
		["Eural",            "x3eural",          "ptsd",  "ca", "2"],
		["Sela",             "selawot",          "sela",  "us", "2"],
		["Vetro",            "vetro_",           "us",    "us", "2"],
		["Zeven",            "zeven_na",         "us",    "us", "2"],
		// Eastern Overlords
		["LuciqueII",     "pukanuragan",  "mamb", "ru", "3"],
		["Near_You",      "near_you",     "mamb", "ru", "3"],
		["Skylex",        "skylex_pro",   "mamb", "ru", "3"],
		["LeBwa",         "lebwa_wot",    "navi", "ru", "3"],
		["Straik",        "straikoid",    "navi", "ru", "3"],
		["StoleYourBike", "viilageidiot", "syb",  "ru", "3"],
		// Honourable Mentions & Wargaming Affiliates, Brought to you by PENTA™
		["WGL English",     "wgl_en",     "wg",   "en", "4"],
		["WGL Europe",     "wgleu",      "wg",   "en", "4"],
		["Ectar",      "murphy1up",  "wg",   "en", "4"],
		["Circon",     "circon",     "circ", "en", "4"],
		["SirFoch",    "sirfoch",    "foch", "en", "4"],
		["Quickybaby", "quickybaby", "qb",   "en", "4"]
	];

	// only run if at host or if pathname is index.php
	if ((/php/i.test(bs.href) === false && /index\.php/i.test(bs.href) === false) || (/php/i.test(bs.href) && /index\.php/i.test(bs.href))) {
		// script functions
		var sf = {
			elem: function (tag, name, html, extra) { // element creation
				var element = d.createElement(tag);
				if (name) {element.className = name;}
				if (html) {element.innerHTML = html;}
				if (extra) {
					for (var _e in extra) {
						if (extra.hasOwnProperty(_e)) {
							element[_e] = extra[_e];
						}
					}
				}
				return element;
			},
			tw: { // twich stream status
				handlerMain: function(data) { // data handler
					var onlineStreams = [];
					// empty online tables
					for (var _t=0, _t_len = (streamTable.length-2); _t<_t_len; _t++) {
						if (streamTable[_t].childElementCount > 0) {
							streamTable[_t].innerHTML = "";
						}
					}
					// roll through streams and append rows to specified table
					if (data.streams.length) {
						for (var _l=0, _l_len = data.streams.length; _l<_l_len; _l++) {
							var stream = data.streams[_l], streamName = stream.channel.name,
							offlineRow = d.getElementById(streamName),
							onlineRow = offlineRow.cloneNode(true);
							onlineRow.classList.remove('streamHide');
							onlineRow.cells[0].innerHTML = "<div class='b-info'><span class='s-status'>"+stream.channel.status+"</span><span class='s-game'>Playing <a href='https://www.twitch.tv/directory/game/"+stream.game+"'>"+stream.game+"</a></span><span class='s-img'><img src='"+stream.preview.medium+"'></span></div>";
							onlineRow.cells[3].className = "s-online";
							onlineRow.cells[3].innerHTML = stream.viewers;
							offlineRow.classList.add('streamHide');
							streamTable[onlineRow.className].appendChild(onlineRow);
							onlineStreams.push(streamName);
						}
						// check if any streams went offline
						var hiddenStreams = d.getElementsByClassName("streamHide");
						for (var _h=0, _h_len = hiddenStreams.length; _h<_h_len; _h++) {
							var streamID = hiddenStreams[_h].id;
							if (onlineStreams.indexOf(streamID) == -1) {
								hiddenStreams[_h].classList.remove('streamHide');
							}
						}
					}
					else {
						streamTable[1].appendChild(sf.elem("tr", "", "<td colspan='5'>No Streams Online</td>"));
					}
					// update date and stream amount
					d.getElementById('js-streamsOnline').innerHTML = onlineStreams.length;
					d.getElementById('js-streamUpdate').innerHTML = new Date().toLocaleTimeString("en-GB");
				},
				handlerError: function() {
					for (var _t=0, _t_len = (streamTable.length-2); _t<_t_len; _t++) {
						if (streamTable[_t].childElementCount > 0) {
							streamTable[_t].innerHTML = "";
						}
					}
					streamTable[1].appendChild(sf.elem("tr", "", "<td colspan='5'>Error Fetching Streams</td>"));
					d.getElementById('js-streamUpdate').innerHTML = new Date().toLocaleTimeString("en-GB");
				},
				updater: function () { // updater handler
					sf.request("twitchDataInterval", bs.tw.api, sf.tw.handlerMain, "tw");
				}
			},
			cw: { // battle scheduler
				handlerEvent: function(data) { // event checker
					// check if active event exists
					var event = data.data[0];
					if (event.status == "ACTIVE" || !bs.cw.status) {
						if (event.status == "ACTIVE") {
							bs.cw.event = true;
							var tierCheck = [
								event.fronts[0].front_id.match(/tier_(\d)+/),
								event.event_id.match(/(first|second|third)/)[0],
								{first: 6, second: 8, third: 10}
							];
							bs.cw.tier = (tierCheck[0]) ? tierCheck[0][0] : tierCheck[2][tierCheck[1]];
							d.getElementById('js-eventName').innerHTML = event.event_name+" • ";

						}
						sf.request("mainData", bs.api.clan, sf.cw.handlerMain, "cw");
						d.getElementById('js-tableStats').classList.remove("b-display-none");
					}
					else {
						// empty table
						battleTable.lastElementChild.innerHTML = "";
						battleTable.lastElementChild.appendChild(sf.elem("tr", "t-cwText", "<td colspan='23'>See you next time.</td>"));
						clearInterval(updateInterval);
					}
					// insert update timestamp
					d.getElementById('js-batttleUpdate').textContent = new Date().toLocaleTimeString("en-GB");
				},
				handlerMain: function(data) { // data handler
					var battleProvinces = [], battle,
					battleFragment = d.createDocumentFragment();
					// store data
					bs.clan.tag = data.clan.tag;
					bs.clan.emblem = data.clan.emblem_url;
					bs.clan.color = data.clan.color;
					bs.cw.bats = data.clan.appointed_battles_count;
					bs.cw.current = data.battles.length;
					bs.cw.elo = {
						6: data.clan.elo_rating_6,
						8: data.clan.elo_rating_8,
						10: data.clan.elo_rating_10
					};
					style.textContent += ".t-clantag {color: "+bs.clan.color+";}";
					// go through battles and planned battles
					for (var _b=0, _b_len = data.battles.length; _b<_b_len; _b++) {
						battle = data.battles[_b];
						if (battleProvinces.indexOf(battle.province_id) == -1) {
							battleProvinces.push(battle.province_id);
							battleFragment.appendChild(sf.elem("tr", "battle "+battle.province_id+" attack", "<td><a href='https://eu.wargaming.net/globalmap/#province/"+battle.province_id+"'>"+battle.province_name+"</a></td><td>"+sf.cw.mapFix(battle.arena_name)+"</td><td></td><td class='t-gold'><span></span><i class='i-gold'></i></td><td class='t-fame'>Ɵ</td><td></td><td></td><td id='"+battle.enemy.id+"'><a target='_blank' href='https://eu.wargaming.net/clans/"+battle.enemy.id+"/'>["+battle.enemy.tag+"] <img src='"+battle.enemy.emblem_url+"'></a><span class='t-elo'>("+battle.enemy["elo_rating_"+((bs.cw.event) ? bs.cw.tier : "10")]+")</span></td><td class='t-battle'>Ɵ</td><td class='t-battle t-border'>Ɵ</td>"+bs.table.c));
						}
					}
					for (var _bp=0, _bp_len = data.planned_battles.length; _bp<_bp_len; _bp++) {
						battle = data.planned_battles[_bp];
						if (battleProvinces.indexOf(battle.province_id) == -1) {
							battleProvinces.push(battle.province_id);
							battleFragment.appendChild(sf.elem("tr", "battle "+battle.province_id+" attack", "<td><a href='https://eu.wargaming.net/globalmap/#province/"+battle.province_id+"'>"+battle.province_name+"</a></td><td>"+sf.cw.mapFix(battle.arena_name)+"</td><td></td><td class='t-gold'><span>"+battle.province_revenue+"</span><i class='i-gold'></i></td><td class='t-fame'>Ɵ</td><td></td><td></td><td>Not Started</td><td class='t-battle'>Ɵ</td><td class='t-battle t-border'>Ɵ</td>"+bs.table.c));
						}
					}
					// show foes and battle count if clan has any battles and remove loading indicator
					if (bs.cw.bats > 0) {
						style.textContent += ".t-battle {display: table-cell !important;}";
						battleTable.lastElementChild.innerHTML = ""; // empty table
					}
					battleTable.lastElementChild.appendChild(battleFragment);
					// insert clan name
					d.getElementById('js-clan').innerHTML = "<span class='t-clantag'>["+bs.clan.tag+"]</span> "+data.clan.name+" <img src='"+bs.clan.emblem+"'> • ";
					// insert battle count
					d.getElementById('js-battles').textContent = bs.cw.bats;
					// send request for detailed battle information
					if (bs.cw.bats > 0) {
						sf.request("batsData", bs.api.bats+battleProvinces.join("&aliases="), sf.cw.handlerBats, "cw");
					}
					// send request for clan provinces
					sf.request("provsData", bs.api.provs, sf.cw.handlerProvs, "cw");
				},
				handlerBats: function(data, mode) { // battles handler
					for (var _bd=0, _bd_len = data.data.length; _bd<_bd_len; _bd++) {
						var battle = data.data[_bd],
						battleRow = d.getElementsByClassName(battle.alias)[0],
						enemyID = battleRow.children[7].id,
						battleType = ((battle.owner_clan_id == bs.clan.id) ? "Defense" : ((battle.owner_clan_id == enemyID) ? "Owner" : "Attack")),
						primeTime = [sf.cw.time(parseFloat(battle.primetime.match(/\d+/g)[0])), battle.primetime.match(/\d+/g)[1], parseFloat(battle.primetime.match(/\d+/g)[0])];
						if (battleType == "Defense") {
							battleRow.classList.remove("attack");
							battleRow.classList.add("defense");
						}
						// modify cells cells
						battleRow.children[2].textContent = primeTime[0]+":"+primeTime[1];
						battleRow.children[2].dataset.sort = primeTime[2]+""+primeTime[1];
						battleRow.children[3].firstElementChild.textContent = battle.revenue;
						battleRow.children[6].textContent = battleType;
						// get correct battle count and schedule
						sf.request("tourneyData", bs.api.tourney+battle.alias+"&round=1", sf.cw.handlerTourney, "cw");
						// get province famepoints if event
						if (bs.cw.event) {
							sf.request("provData", bs.api.prov+battle.alias, sf.cw.handlerProv, "cw", (battle.is_wagon_train) ? "×20" : (battle.is_enclave_ring) ? "×5" : (battle.is_enclave_center) ? "×3" : "");
						}
					}
					// refresh table
					sortTable.refresh();
				},
				handlerTourney: function(data) { // tournament handler
					var battleRow = d.getElementsByClassName(data.province_id)[0],
					primeTime = [sf.cw.time(parseFloat(data.start_time.match(/\d+/g)[0])), data.start_time.match(/\d+/g)[1], parseFloat(data.start_time.match(/\d+/g)[0])],
					ownerClan = (data.owner) ? (data.owner.id == bs.clan.id) || false : false,
					cellOwnerTime = false,
					attackers = [data.pretenders, 0];
					bs.dyn.check ++;
					// check attackers
					if (attackers[0]) {
						var _pre_len = attackers[0].length,
						attacker_ids = [];
						for (var _pre=0; _pre<_pre_len; _pre++) {
							attacker_ids.push(attackers[0][_pre].id);
						}
						if (!ownerClan && attacker_ids.indexOf(bs.clan.id) == -1) {
							battleRow.parentElement.removeChild(battleRow);
						}
					}
					else if (data.battles) {
						var _bat_len = data.battles.length,
						attacker_ids = [];
						for (var _bat=0; _bat<_bat_len; _bat++) {
							var battle = data.battles[_bat];
							attacker_ids.push(battle.first_competitor.id);
							if (battle.second_competitor) {
								attacker_ids.push(data.battles[_bat].second_competitor.id);
							}
						}
						if (!ownerClan && attacker_ids.indexOf(bs.clan.id) == -1) {
							battleRow.parentElement.removeChild(battleRow);
						}
					}
					if (data.is_superfinal) {
						attackers = 1;
					}
					else if (attackers[0]) {
						attackers = attackers[0].length;
					}
					else {
						attackers = attackers[1];
						for (var _bc=0, _bc_len = data.battles.length; _bc<_bc_len; _bc++) {
							attackers += ((data.battles[_bc].is_fake) ? 1 : 2);
						}
					}
					// find how many battles
					var battles = (attackers !== 0) ? Math.ceil(Math.log2(attackers))+1 : 0;
					// modify cells
					battleRow.children[1].textContent = sf.cw.mapFix(data.arena_name);
					battleRow.children[2].textContent = primeTime[0]+":"+primeTime[1];
					battleRow.children[2].dataset.sort = primeTime[2]+""+primeTime[1]+"."+battles;
					battleRow.children[3].firstElementChild.textContent = data.province_revenue;
					battleRow.children[5].innerHTML = (data.owner) ? "<a target='_blank' href='https://eu.wargaming.net/clans/"+data.owner.id+"/'><span class='t-clantag' style='color: "+data.owner.color+";'>["+data.owner.tag+"]</span> <img src='"+data.owner.emblem_url+"'></a>" : "No Owner";
					if (data.owner && bs.cw.tier !== "Ɵ") {
						battleRow.children[5].appendChild(sf.elem("span", "t-elo", "("+data.owner["elo_rating_"+((bs.cw.event) ? bs.cw.tier : "10")]+")"));
					}
					// only continue if there are any attackers
					if (attackers) {
						var emptyCells = ((primeTime[2]-bs.table.eu[0])*2)+bs.table.static,
						lastBattle = battles+emptyCells,
						lastGroup = data.battles[data.battles.length-1],
						freeRound = (primeTime[1] == "15") ? false : battleRow.children[7].innerHTML == "Not Started" && lastGroup && lastGroup.is_fake && lastGroup.first_competitor.id == bs.clan.id;
						battleRow.children[8].textContent = attackers;
						battleRow.children[9].textContent = battles;
						for (var _e=bs.table.static+1; _e<battleRow.childElementCount; _e++) {
							var cell = battleRow.children[_e];
							if (_e > emptyCells && _e <= lastBattle) {
								var timeClass = "."+cell.classList.item(1),
								timePrevClass = "."+cell.previousElementSibling.classList.item(1);
								if (bs.table.s.indexOf(timeClass) == -1 || bs.table.s.indexOf(timePrevClass) == -1) {
									bs.table.s.push(timePrevClass, timeClass);
									if (_e == lastBattle) {
										bs.table.s.push(timePrevClass+" + th", timePrevClass+" + td", timeClass+" + th", timeClass+" + td");
									}
								}
								if (ownerClan && _e !== lastBattle) {
									cell.className += " t-noFight";
								}
								else {
									cell.className += " t-fight";
									if (bs.dyn.conc[_e]) {
										bs.dyn.conc[_e] ++;
									}
									else {
										bs.dyn.conc[_e] = 1;
									}
								}
								if (_e == lastBattle) {
									if (ownerClan) {
										cell.className += " js-last";
									}
									if (!data.owner || (battleRow.children[6] == "Planned" && !data.owner.division_id)) {
										cell.className += " t-noOwner";
									}
									cell.innerHTML = "♖";
									cellOwnerTime = [parseFloat(cell.classList.item(1).match(/\d+/g)[0]), parseFloat(cell.classList.item(1).match(/\d+/g)[1])];
								}
								else {
									cell.innerHTML = "&#9876;";
								}
								if (primeTime[1] == "15") {
									battleRow.classList.add("timeShift");
									cell.innerHTML += "<span class='t-timeShift'>+</span>";
								}
							}
						}
						if (bs.dyn.check == bs.cw.bats || bs.dyn.plan > 0) {
							d.getElementById('js-battlesConc').textContent = bs.dyn.conc.sort(function(a,b){return b-a;})[0];
							style.textContent += bs.table.s.join(", ")+" {display: table-cell !important;}";
						}
						// check if battle is planned or not started and change state to ongoing
						if (battleRow.children[6].innerHTML !== "Attack" && !/\[/i.test(battleRow.children[7].textContent) && new Date().getHours() >= primeTime[0]-1 && new Date().getHours() < cellOwnerTime[0]) {
							switch(battleRow.children[6].innerHTML) {
								case ("Planned"):
									battleRow.children[6].textContent = "Defense";
									battleRow.children[7].textContent = "Ongoing";
									break;
								case ("Defense"):
									battleRow.children[7].textContent = "Ongoing";
									break;
								default:
									break;
							}
						}
						else if (battleRow.children[6].innerHTML == "Planned") {
							battleRow.children[6] = "Finished";
						}
						// check if no opponent - free round
						if (freeRound) {
							battleRow.children[7].textContent = "Free Round";
							battleRow.children[7].classList.add("t-bold");
						}
					}
					else {
						var lastBattle = battleRow.getElementsByClassName("t-"+primeTime[0]+"_00")[0];
						battleRow.children[7].textContent = "Division Underway or Spyplane Module";
						battleRow.children[8].classList.add("t-error");
						if (primeTime[1] == "15") {
							battleRow.classList.add("timeShift");
							lastBattle.innerHTML = "♖<span class='t-timeShift'>+</span>";
						}
						else {
							lastBattle.innerHTML = "♖";
						}
						lastBattle.classList.add("t-noFight");
					}
					if (ownerClan) {
						bs.dyn.gold += data.province_revenue;
						d.getElementById('js-gold').textContent = bs.dyn.gold; // insert gold count
					}
					if (bs.cw.gold && data.province_revenue === 0) {
						d.getElementById('js-goldInfo').textContent = "(No Gold Revenue in Event!)";
						bs.cw.gold = false;
						style.textContent += "th.t-gold, td.t-gold {display: none;}";
					}
					// refresh table
					battleRow.children[2].dataset.sort = (battleRow.children[6].innerHTML == "No Division" || attackers === 0) ? 50+primeTime[2]+""+primeTime[1] : primeTime[2]+""+primeTime[1]+"."+battles+""+((battleRow.children[6].innerHTML == "Attack") ? 1 : 0)+""+cellOwnerTime[0]+""+cellOwnerTime[1];
					sortTable.refresh();
				},
				handlerProvs: function(data) { // clan provinces handler
					var provs = data.data[bs.clan.id],
					ownedProvinces = [], provTimes = [],
					provFragment = d.createDocumentFragment();
					if (battleTable.rows[1] && battleTable.rows[1].classList.contains("t-cwText")) {
						battleTable.lastElementChild.innerHTML = ""; // empty table
					}
					if (provs) {
						for (var _p=0, _p_len = provs.length; _p<_p_len; _p++) {
							var prov = provs[_p],
							battleRow = d.getElementsByClassName(prov.province_id)[0],
							primeTime = [sf.cw.time(parseFloat(prov.prime_time.match(/\d+/g)[0])), prov.prime_time.match(/\d+/g)[1], parseFloat(prov.prime_time.match(/\d+/g)[0])+bs.table.eu.length];
							if (!battleRow) {
								var provRow = sf.elem("tr", "province "+prov.province_id+" defense", "<td><a href='https://eu.wargaming.net/globalmap/#province/"+prov.province_id+"'>"+prov.province_name+"</a></td><td>"+sf.cw.mapFix(prov.arena_name)+"</td><td data-sort='"+primeTime[2]+""+primeTime[1]+"'>"+primeTime[0]+":"+primeTime[1]+"</td><td class='t-gold'><span>"+prov.daily_revenue+"</span><i class='i-gold'></i></td><td class='t-fame'>Ɵ</td><td><a target='_blank' href='https://eu.wargaming.net/clans/"+bs.clan.id+"/'><span class='t-clantag'>["+bs.clan.tag+"]</span> <img src='"+bs.clan.emblem+"'></a><span class='t-elo'>("+bs.cw.elo[prov.max_vehicle_level]+")</span></td><td>Defense</td><td>No Attacks</td><td class='t-battle' data-sort='99'>Ɵ</td><td class='t-battle t-border' data-sort='99'>Ɵ</td>"+bs.table.c),
								provTime = "t-"+primeTime[0]+"_00",
								provTimeClass = "."+provTime+", ."+provTime+" + td, ."+provTime+" + th",
								lastBattle = provRow.getElementsByClassName(provTime)[0];
								ownedProvinces.push(prov.province_id);
								bs.dyn.gold += prov.daily_revenue;
								bs.cw.tier = prov.max_vehicle_level;
								if (primeTime[1] == "15") {
									provRow.classList.add("timeShift");
									lastBattle.innerHTML = "♖<span class='t-timeShift'>+</span>";
								}
								else {
									lastBattle.innerHTML = "♖";
								}
								lastBattle.classList.add("t-noFight");
								if (provTimes.indexOf(provTimeClass) == -1) {
									provTimes.push(provTimeClass);
								}
								if (bs.cw.gold && prov.daily_revenue === 0) {
									d.getElementById('js-goldInfo').textContent = "(No Gold Revenue in Event!)";
									bs.cw.gold = false;
									style.textContent += "th.t-gold, td.t-gold {display: none;}";
								}
								// get province famepoints if event
								if (bs.cw.event) {
									sf.request("provData", bs.api.prov+prov.province_id, sf.cw.handlerProv, "cw");
								}
								provFragment.appendChild(provRow);
							}
						}
						// display finals column
						style.textContent += provTimes.join(", ")+" {display: table-cell !important;}";
						// insert province count
						d.getElementById('js-provs').textContent = provs.length;
						// insert gold count
						d.getElementById('js-gold').textContent = bs.dyn.gold;
						// send request for divisions
						sf.request("divsData", bs.api.divs, sf.cw.handlerDivs, "cw");
						// send request for raids if event
						if (bs.cw.event) {
							sf.request("raidsData", bs.api.raids, sf.cw.handlerRaids, "cw");
						}
					}
					else if (bs.cw.bats === 0) {
						battleTable.lastElementChild.innerHTML = ""; // empty table
						provFragment.appendChild(sf.elem("tr", "t-cwText", "<td colspan='23'>No Battles</td>"));
					}
					battleTable.lastElementChild.appendChild(provFragment);
					if (battleTable.parentNode.offsetWidth !== battleTable.parentNode.scrollWidth) {
						var tableExpand = d.getElementById('js-expand');
						tableExpand.textContent = "❐";
						tableExpand.addEventListener('click', function() {
							battleTable.parentNode.classList.toggle("b-fullHeight");
						}, false);
					}
					// refresh table
					sortTable.refresh();
				},
				handlerProv: function(data, coef) { // province handler
					var prov = data.province,
					battleRow = d.getElementsByClassName(data.province.alias)[0],
					style = "t-green", fame = "Ɵ", sort = 0;
					if (prov.money_box) {
						if (data.owner.id == bs.clan.id) {
							style = "t-red";
							fame = -Math.abs(data.province.money_box.risky_fame_points)
						}
						else {
							fame = "+"+data.province.money_box.capture_fame_points;
						}
						sort = fame;
					}
					else if (prov.is_enclave) {
						fame = prov.single_province_fp;
						coef = prov.fame_points_coefficient;
						sort = fame;
					}
					else if (prov.enclave_neighbours_number) {
						fame = prov.enclave_neighbours_number+"/"+prov.number_of_enclave_provinces;
						sort = prov.enclave_neighbours_number/prov.number_of_enclave_provinces;
						// change fame column title
						d.getElementById('js-fame').textContent = "Fame & Enclaves";
					}
					else if (prov.raids) {
						if (prov.raids.secondary_mission_reward) {
							fame = prov.raids.secondary_mission_reward;
						}
						else {
							style = "";
						}
					}
					if (battleRow) {
						battleRow.children[4].innerHTML = "<span class='"+style+"'>"+fame+"</span>"+((coef) ? " "+coef : "");
						battleRow.children[4].dataset.sort = sort;
					}
				},
				handlerDivs: function(data) { // divisions handler
					var divsId = JSON.stringify(data).match(/\d{9}/g);
					if (divsId.indexOf(bs.clan.id.toString()) !== -1) {
						for (var _p=0, _p_len = data.data.length; _p<_p_len; _p++) {
							var div = data.data[_p],
							battleRow = d.getElementsByClassName(div.alias)[0];
							if (!div.division) {
								if (battleRow && battleRow.classList.contains('defense')) {
									var defBattle = battleRow.getElementsByClassName("js-last")[0];
									battleRow.children[2].dataset.sort = 5000;
									battleRow.children[6].textContent = "No Division";
									battleRow.children[6].classList.add("t-bold");
									if (defBattle) {
										defBattle.classList.remove("t-fight");
										defBattle.classList.add("t-noFight");
									}
								}
								else if (!battleRow) {
									bs.dyn.plan ++;
									battleTable.lastElementChild.appendChild(sf.elem("tr", "planned "+div.alias, "<td><a href='https://eu.wargaming.net/globalmap/#province/"+div.alias+"'>"+div.name+"</a></td><td></td><td></td><td class='t-gold'><span></span><i class='i-gold'></i></td><td class='t-fame'>Ɵ</td><td></td><td>Planned</td><td>Planned</td><td class='t-battle'>Ɵ</td><td class='t-battle t-border'>Ɵ</td>"+bs.table.c));
									sf.request("batsData", bs.api.bats+div.alias, sf.cw.handlerBats, "cw");
								}
							}
							else {
								// sometimes future defenses wont show up in planned battles
								if (div.attackers.length > 0 && battleRow && battleRow.classList.contains('province')) {
									bs.dyn.plan ++;
									battleTable.lastElementChild.appendChild(sf.elem("tr", "planned "+div.alias, "<td><a href='https://eu.wargaming.net/globalmap/#province/"+div.alias+"'>"+div.name+"</a></td><td></td><td></td><td class='t-gold'><span></span><i class='i-gold'></i></td><td class='t-fame'>Ɵ</td><td></td><td>Defense</td><td>Planned</td><td class='t-battle'>Ɵ</td><td class='t-battle t-border'>Ɵ</td>"+bs.table.c));
									battleRow.parentNode.removeChild(battleRow);
									sf.request("tourneyData", bs.api.tourney+div.alias+"&round=1", sf.cw.handlerTourney, "cw");
								}
							}
						}
						if (bs.dyn.plan > 0) {
							style.textContent += ".t-battle {display: table-cell !important;}";
						}
						// refresh table
						sortTable.refresh();
					}
					else {
						d.getElementById('js-error').textContent = "Division Data not Available!";
					}
				},
				handlerRaids: function(data) { // raids handler for campaign events
					for (var _r=0, _r_len = data.length; _r<_r_len; _r++) {
						var raid = data[_r],
						battleRow = d.getElementsByClassName(raid.province.id)[0],
						fame = raid.fame_points, bonus = raid.bonus_fame_points, denyFame = 0, sort = fame+bonus, coef = raid.battle_coef;
						if (battleRow) {
							denyFame = parseFloat(battleRow.children[4].innerHTML.match(/\d+/));
							battleRow.children[4].innerHTML = "<span>"+fame+" + "+bonus+((denyFame) ? " + "+denyFame : "")+"</span> "+coef;
							battleRow.children[4].dataset.sort = sort+denyFame;
						}
					}
				},
				handlerError: function(name, data) { // error handler
					switch(name) {
						case ("mainData"):
							battleTable.lastElementChild.appendChild(sf.elem("tr", "t-cwText", "<td colspan='23'>Clan ID Error</td>"));
							inputSpan.lastElementChild.textContent = "Clan ID invalid!";
							localStorage.removeItem("battles_clanid");
							break;
						case ("divsData"):
							d.getElementById('js-error').textContent = "Division Data not Available!";
							break;
						default: break;
					}
				},
				time: function (hour, min, type) { // time converter
					var time = hour+bs.time.o;
					if (time >= 24) {
						time -= 24;
					}
					else if (time <= 0) {
						time += 24;
					}
					if (type == "s") {
						time = "t-"+time+"_"+min+((time === 0 && min == "00") ? " t-24_00" : "");
					}
					return time;
				},
				timer: function () { // timestamp handler
					var dateNow = new Date(),
					time = {
						h: sf.cw.time(16)-dateNow.getHours(),
						m: 60-dateNow.getMinutes()-1,
						s: 60-dateNow.getSeconds()-1
					};
					var timeSpan = d.getElementById('js-timePrime');
					if (timeJump && !bs.cw.event && bs.cw.status) {
						timeSpan.textContent = "No Event Running";
						timeSpan.classList.add("t-bold");
						clearInterval(timeInterval);
					}
					else if (time.h >= 0 && (time.s > 0 || time.m < 15)) {
						timeSpan.textContent = ((time.h > 0) ? time.h+" Hours, " : "")+((time.m > 0) ? time.m+" Mins, " : "")+time.s+" Secs";
					}
					else if (time.h < 0 && bs.cw.bats !== "Ɵ") {
						if (bs.cw.bats === 0) {
							timeSpan.textContent = "No Planned Battles";
							timeSpan.classList.add("t-bold");
							clearInterval(timeInterval);
						}
						else {
							timeSpan.classList.add("h-shadow");
							timeSpan.innerHTML = "<span style='color:#ff0000;'>X</span><span style='color:#ff2a00;'></span><span style='color:#ff5500;'>e</span><span style='color:#ff7f00;'></span><span style='color:#ffaa00;'>n</span> <span style='color:#ffff00;'>i</span><span style='color:#aaff00;'></span><span style='color:#55ff00;'>s</span> <span style='color:#00ff80;'>a</span> <span style='color:#00aaff;'>f</span><span style='color:#0055ff;'></span><span style='color:#0000ff;'>g</span><span style='color:#2e00ff;'></span><span style='color:#5d00ff;'>t</span><span style='color:#8b00ff;'>.</span>";
							if (bs.cw.current > 0) {
								d.getElementById('js-provStatus').textContent = "Next Opponent (ELO)";
							}
							clearInterval(timeInterval);
						}
					}
					else {
						timeSpan.textContent = "Hold on a sec...";
					}
					timeJump = true;
				},
				mapFix: function(name) { // map name fixer
					var fixedNames = {
						"114_czech/name": "Pilsen"
					};
					return (fixedNames[name]) ? fixedNames[name] : name;
				},
				updater: function () { // updater handler
					var dateNow = new Date(),
					newDate = [dateNow.getHours(), dateNow.getMinutes()],
					newTime = ((newDate[1] >= 15 && newDate[1] <= 45) ? [newDate[0],"30"] : ((newDate[1] <= 15) ? [newDate[0],"00"] : [(newDate[0]+1),"00"]));
					if (bs.time.r[0] !== newTime[0] || bs.time.r[1] !== newTime[1]) {
						bs.time.r = newTime;
						bs.dyn = {conc:[],plan:0,check:0,gold:0};
						sf.request("mainData", bs.api.clan, sf.cw.handlerMain, "cw");
						// insert update timestamp
						d.getElementById('js-batttleUpdate').textContent = new Date().toLocaleTimeString("en-GB");
					}
				}
			},
			buttonHide: function (name, item, img, slave) {
				var buttonDiv = sf.elem("div", "b-buttonHide", "<a href='#' onClick='return false;'><img src='"+img+"'><span>Hide</span> "+name+" Panel</a><span> • </span>"),
				buttonState = JSON.parse(localStorage.getItem(item)) || false;
				buttonDiv.firstElementChild.addEventListener('click', function() {
					this.children[1].textContent = (buttonState) ? "Hide" : "Show";
					slave.classList.toggle("b-display-none");
					buttonState = (buttonState) ? false : true;
					localStorage.setItem(item, buttonState);
				}, false);
				if (buttonState) {
					buttonDiv.firstElementChild.children[1].textContent = "Show";
					slave.classList.toggle("b-display-none");
				}
				return buttonDiv;
			},
			request: function (name, api, handler, mode, extra) { // request handler
				// GreaseMonkey xmlhttpRequest
				GM_xmlhttpRequest({
					method: "GET",
					url: api,
					headers: {
						"Accept": "application/json",
						"Client-ID": bs.tw.key
					},
					onload: function(resp) {
						var data = JSON.parse(resp.responseText);
						if (resp.status == 200) {
							if (bs.debug) {console.info(name, data, new Date().toLocaleTimeString("en-GB"));}
							handler(data, extra);
						}
						else {
							console.error("Error with API", name, api, resp);
							sf[mode].handlerError(name);
						}
					},
					onerror: function(resp) {
						console.error("Error accessing API", name, api, resp);
					}
				});
			}
		};

		// inserting style into head
		var style = sf.elem("style", "idealStreamsScript", "", {type:"text/css"}),
		styleText = [
			".b-panel {display: table; width: 100%;}",
			".p-helper {display: table-cell; width: 100%;}",
			".b-buttonHide {display: inline;}",
			".b-buttonHide img {margin-right: 3px; vertical-align: sub;}",
			// twitch stream status
			".b-streams {display: table-cell; font-size: 11px; max-width: 400px; min-width: 340px; padding-left: 10px;}",
			".b-streams .s-helper {display: inline-block;}",
			".b-streams .h-streams {background-color: #D1E8FE; border: 1px solid;border-radius: 10px 10px 0 0; margin-top: -2px; text-align: center;}",
			".b-streams .h-streams .h-streams-info {border-bottom: 1px solid #F5F5F5; margin: 0 auto; padding: 4px 0px; width: 325px;}",
			".b-streams .h-streams .h-streams-info > * {display: inline-block;}",
			".b-streams .h-streams .h-streams-info .h-left {width: 10%;}",
			".b-streams .h-streams .h-streams-info .h-mid {width: 80%;}",
			".b-streams .h-streams .h-streams-info .h-right {width: 10%;}",
			".b-streams .h-streams .h-streams-info img {vertical-align: bottom;}",
			".b-streams .h-streams .h-streams-head {border-spacing: 0; text-align: center; width: 323px;}",
			".b-streams .h-streams .h-streams-head tr th {line-height: 20px;}",
			".b-streams .h-streams .h-streams-head tr th:nth-of-type(1) {width: 0px;}",
			".b-streams .h-streams .h-streams-head tr th:nth-of-type(2) {width: 145px;}",
			".b-streams .h-streams .h-streams-head tr th:nth-of-type(3) {width: 75px;}",
			".b-streams .h-streams .h-streams-head tr th:nth-of-type(4) {width: 60px;}",
			".b-streams .h-streams .h-streams-head tr th:nth-of-type(5) {width: 40px;}",
			".b-streams .b-streams-holder {border-left: 1px solid; border-right: 1px solid; max-height: "+((bs.web.chrome) ? "336" : "345")+"px; overflow-y: auto;}",
			".b-streams .b-streams-holder .t-streams {border-spacing: 0; text-align: center; width: 100%;}",
			".b-streams .b-streams-holder .t-streams tr:nth-child(even) {background-color: #FBFBFB;}",
			".b-streams .b-streams-holder .t-streams tr:nth-child(odd) {background-color: #EFEFEF;}",
			".b-streams .b-streams-holder .t-streams tr:hover {background-color: #FEFAC0;}",
			".b-streams .b-streams-holder .t-streams tr td {line-height: 19px; border-bottom: 1px dotted #B1B1B1;}",
			".b-streams .b-streams-holder .t-streams tr td:nth-of-type(1) {width: 0px;}",
			".b-streams .b-streams-holder .t-streams tr td:nth-of-type(2) {width: 145px;}",
			".b-streams .b-streams-holder .t-streams tr td:nth-of-type(3) {width: 75px;}",
			".b-streams .b-streams-holder .t-streams tr td:nth-of-type(3) img {display: inline-block; margin: -3px 1px 0; vertical-align: middle;}",
			".b-streams .b-streams-holder .t-streams tr td:nth-of-type(4) {width: 60px;}",
			".b-streams .b-streams-holder .t-streams tr td:nth-of-type(5) {width: 40px;}",
			".b-streams .b-streams-holder .t-streams tr td:nth-of-type(5) img {display: inline-block; margin: -4px 2px 0; vertical-align: middle;}",
			".b-streams .b-streams-holder .t-streams .streamIdeal tr:last-of-type td {border-bottom: 1px solid #CC5BFF;}",
			".b-streams .b-streams-holder .t-streams .streamSeperator td {border-top: 1px solid #CD2911;}",
			".b-streams .b-streams-holder .t-streams td.s-online {color: #4D7326;}",
			".b-streams .b-streams-holder .t-streams td.s-offline {color: #930D0D;}",
			".b-streams .b-streams-holder .t-streams .b-info {background-color: #FEFAC0; border: 1px dotted #B1B1B1; display: none; margin: -11px 0px 0px -282px; padding-bottom: 8px; position: absolute; width: 280px;}",
			".b-streams .b-streams-holder .t-streams .b-info > span {display: block;}",
			".b-streams .b-streams-holder .t-streams .b-info .s-status {font-weight: bold;}",
			".b-streams .b-streams-holder .t-streams .b-info .s-game {}",
			".b-streams .b-streams-holder .t-streams .b-info .s-img img {width: 200px;}",
			".b-streams .b-streams-holder .t-streams tr:hover .b-info {display: block;}",
			".b-streams .b-streams-holder .streamHide {display: none;}",
			".b-streams .b-streams-holder img {display: block; margin: 0 auto;}",
			".b-streams .f-streams {background-color: #D1E8FE; border: 1px solid; border-top: 0; border-radius: 0 0 10px 10px; padding: 3px 0px; text-align: center;}",
			".b-streams .f-streams .f-battles-info > * {display: inline-block;}",
			// battle scheduler
			".b-battles {border: 1px solid; border-radius: 10px; display: table; font-size: 11px; width: 75%; min-width: 1280px; margin: 15px auto 15px;}",
			".b-battles .h-battles {background-color: #D1E8FE; border-radius: 10px 10px 0 0;}",
			".b-battles .h-battles .h-battles-info {border-bottom: 1px solid #F5F5F5; margin: 0 auto; padding: 4px 0px; width: 98%;}",
			".b-battles .h-battles .h-battles-info > * {display: inline-block;}",
			".b-battles .h-battles .h-battles-info .h-left {width: 15%;}",
			".b-battles .h-battles .h-battles-info .h-left a {margin-right: 5px;}",
			".b-battles .h-battles .h-battles-info .h-mid {text-align: center; width: 70%;}",
			".b-battles .h-battles .h-battles-info .h-right {text-align: right; width: 15%;}",
			".b-battles .h-battles .h-battles-info .h-right .h-expand {cursor: pointer; font-size: 2em; line-height: 10px; vertical-align: sub;}",
			".b-battles .h-battles .h-battles-info .h-right .h-force {cursor: pointer; margin-right: 15px;}",
			".b-battles .h-battles .h-battles-info .h-right .h-force input {height: 15px; vertical-align: bottom;}",
			".b-battles .h-battles .h-battles-info img {max-height: 16px; vertical-align: bottom;}",
			".b-battles .h-battles .h-battles-info .h-shadow {font-weight: bold; text-shadow: 0px 0px 1px rgba(27,27,28, 1), 0px 0px 2px rgba(27,27,28, 1);}",
			".b-battles .b-battles-holder {background-color: #FBFBFB; max-height: 221px; overflow-y: auto;}",
			".b-battles .b-battles-holder.b-fullHeight {max-height: unset;}",
			".b-battles .b-battles-holder .t-battles {border-spacing: 0; text-align: center; width: 100%;}",
			".b-battles .b-battles-holder .t-battles .t-time {display: none; position: relative;}",
			".b-battles .b-battles-holder .t-battles thead tr {background-color: #D1E8FE;}",
			".b-battles .b-battles-holder .t-battles tbody tr:nth-child(even) {background-color: #FBFBFB;}",
			".b-battles .b-battles-holder .t-battles tbody tr:nth-child(odd) {background-color: #EFEFEF;}",
			".b-battles .b-battles-holder .t-battles tbody tr:hover {background-color: #FEFAC0;}",
			".b-battles .b-battles-holder .t-battles tr .t-"+bs.time.t+" {background-color: rgba(254,252,223, 0.5); border-left: 1px solid #808080; border-right: 1px solid #808080;}",
			".b-battles .b-battles-holder .t-battles tr .t-"+bs.time.t+" + th, .b-battles .b-battles-holder .t-battles tr .t-"+bs.time.t+" + td {background-color: rgba(224,223,218, 0.5); border-right: 1px solid #808080;}",
			".b-battles .b-battles-holder .t-battles tr .t-border {border-right: 2px solid rgba(194, 173, 173, 0.5);}",
			".b-battles .b-battles-holder .t-battles tr th {border-bottom: 1px solid #808080; line-height: 20px;}",
			".b-battles .b-battles-holder .t-battles tr td {line-height: 19px; border-bottom: 1px dotted #B1B1B1;}",
			".b-battles .b-battles-holder .t-battles tr td:first-of-type {max-width: 100px; overflow: hidden; padding: 0 5px; text-overflow: ellipsis; white-space: nowrap;}",
			".b-battles .b-battles-holder .t-battles tr td.t-title {font-weight: bold;}",
			".b-battles .b-battles-holder .t-battles tr td.t-good {color: #4D7326;}",
			".b-battles .b-battles-holder .t-battles tr td.t-bad {color: #930D0D;}",
			".b-battles .b-battles-holder .t-battles tr td.t-plan {color: #FFE400;}",
			".b-battles .b-battles-holder .t-battles tr td.t-fight {color: #4D7326; font-size: 15px; font-weight: bold;}",
			".b-battles .b-battles-holder .t-battles tr td.t-noFight {color: #808080; font-size: 14px;}",
			".b-battles .b-battles-holder .t-battles tr td.t-fight.t-noOwner {color: #808080;}",
			".b-battles .b-battles-holder .t-battles tr td.t-error {color: #CD2911;}",
			".b-battles .b-battles-holder .t-battles tr.t-cwText td {font-size: 26px; line-height: 54px;}",
			".b-battles .b-battles-holder .t-battles tr.timeShift td:nth-child(3) {color: #25931A;}",
			".b-battles .b-battles-holder .t-battles tr.timeShift td .t-timeShift {font-size: 8px; position: absolute;}",
			".b-battles .b-battles-holder .t-battles img {height: 16px; margin-bottom: 2px; vertical-align: bottom;}",
			".b-battles .f-battles {background-color: #D1E8FE; border-radius: 0 0 10px 10px; padding: 3px 0px;}",
			".b-battles .f-battles .f-battles-info {margin: 0 auto; width: 98%;}",
			".b-battles .f-battles .f-battles-info > * {display: inline-block; vertical-align: middle;}",
			".b-battles .f-battles .f-battles-info .f-left {width: 20%;}",
			".b-battles .f-battles .f-battles-info .f-left > span {margin-left: 5px;}",
			".b-battles .f-battles .f-battles-info .f-left .f-inputText {color: #CD2911;}",
			".b-battles .f-battles .f-battles-info .f-left .f-inputText.t-green {color: #4D7326;}",
			".b-battles .f-battles .f-battles-info .f-mid {text-align: center; width: 60%;}",
			".b-battles .f-battles .f-battles-info .f-mid table {margin: 0 auto;}",
			".b-battles .f-battles .f-battles-info .f-mid table td {padding: 0 10px;}",
			".b-battles .f-battles .f-battles-info .f-mid #js-goldInfo {margin-left: 3px;}",
			".b-battles .f-battles .f-battles-info .f-mid #js-error {display: block;}",
			".b-battles .f-battles .f-battles-info .f-right {text-align: right; width: 20%;}",
			".b-battles .f-battles .f-battles-info img {max-height: 16px; vertical-align: bottom;}",
			// toggle overrides
			".t-elo {margin-left: 3px;}",
			".t-gold {color: #FFC364;}",
			"i.i-gold {color: #FFC364; background: url('"+bs.db+"cw/gold.png') no-repeat right; display: inline-block; vertical-align: middle; height: 15px; width: 15px; margin-left: 2px;}",
			".b-display-none {display: none;}",
			".b-display-block {display: block;}",
			".t-battle {display: none;}",
			".t-bold {font-weight: bold;}",
			".t-green {color: #4D7326;}",
			".t-red {color: #930D0D;}"
		];
		style.textContent = styleText.join("");
		d.head.appendChild(style);

		// prepare static html
		var streamers = streams.length,
		chatPanel = d.getElementsByClassName("tablebg")[0],
		parentPanel = sf.elem("div", "b-panel", ""),
		streamPanel = sf.elem("div", "b-streams", "<span class='s-helper'></span><div class='h-streams'><div class='h-streams-info'><div class='h-left'><a target='_blank' href='https://www.twitch.tv/directory/game/World%20of%20Tanks'><img src='"+bs.db+"tw/twitch.png'></a></div><div class='h-mid'>Total Streams: "+streamers+" • Streams Online: <span id='js-streamsOnline'>0</span></div><div class='h-right'><a target='_blank' href='https://greasyfork.org/en/scripts/20094-ideal-scripts'><img src='"+bs.db+"tw/fork.png'></a></div></div><table class='h-streams-head'><thead><tr><th></th><th>Name</th><th>Clan/Team</th><th>Viewers</th><th>Flag</th></thead></table></div><div class='b-streams-holder'><table class='t-streams'><tbody class='streamIdeal'></tbody><tbody class='streamOnline'></tbody><tbody class='streamAmerica'><tbody class='streamRussia'><tbody class='streamCommunity'></tbody><tbody class='streamSeperator'><tr><td colspan='5'></td></tr></tbody><tbody class='streamOffline'></tbody></table></div><div class='f-streams'><div class='f-mid'>Updates Every 2 Mins • Last Updated: <span id='js-streamUpdate'>Updating...</span></div></div>"),
		battlePanel = sf.elem("div", "b-battles", "<div class='h-battles'><div class='h-battles-info'><div class='h-left'><a target='_blank' href='https://greasyfork.org/en/scripts/20094-ideal-scripts'><img src='"+bs.db+"cw/fork.png'></a><a href='https://eu.wargaming.net/clans/wot/"+bs.clan.id+"/globalmap'><img src='"+bs.db+"cw/wg.png'></a><a href='https://eu.wargaming.net/globalmap/'><img src='"+bs.db+"cw/cw.png'></a></div><div class='h-mid'><span id='js-eventName'></span><span id='js-clan'></span><span id='js-timePrime'>Ɵ</span></div><div class='h-right'></span><span class='h-force'><label id='js-force'>Campaign Only: <input type='checkbox' name='force'></label></span><span class='h-expand' id='js-expand'></div></div></div><div class='b-battles-holder'><table class='t-battles sortable'><thead><tr><th>Province</th><th>Map</th><th id='js-sort' class='sort-default' data-sort-method='number' data-sort-order='desc'>Timezone</th><th class='t-gold'>Gold</th><th class='t-fame' id='js-fame'>Fame</th><th>Owner (ELO)</th><th>Type</th><th id='js-provStatus'>Status</th><th class='t-battle'>Attackers</th><th class='t-battle t-border'>Turns</th></tr></thead><tbody></tbody></table></div><div class='f-battles'><div class='f-battles-info'><div class='f-left' id='js-input'><input type='text' name='id' placeholder='Clan ID' value='"+bs.clan.id+"' list='clanid' maxlength='9' size='9'><datalist id='clanid'><option value='500010805'>IDEAL</option><option value='500003585'>RSOP</option><option value='500017824'>OMNI</option><option value='500025989'>FAME</option><option value='500034335'>S3AL</option><option value='500049085'>S4</option></datalist><span class='f-inputImage'><img src='https://wot-life.com/img/clanicon/"+bs.clan.id+".png'></span><span class='f-inputText'>"+((bs.clan.id !== bs.clan.ideal) ? "</span><span class='f-inputBack'>Back to <a href='#' onclick='localStorage.removeItem(\"battles_clanid\"); location.reload();'>[IDEAL]</a></span>" : "")+"</div><div class='f-mid'><table id='js-tableStats' class='b-display-none'><tr><td>Current(Concurrent)[Planned] Battles: <span id='js-battles'>0</span>(<span id='js-battlesConc'>0</span>)[<span id='js-battlesPlan'>0</span>]</td><td>Last Updated: <span id='js-batttleUpdate'>Ɵ</span> [UTC"+((bs.time.o >= 0) ? "+" : "")+bs.time.o+"]</td></tr><tr><td>Owned Provinces: <span id='js-provs'>0</span></td><td>Gold Income: <span class='t-gold' id='js-gold'>0</span><i class='i-gold'></i><span id='js-goldInfo'></span></td></tr><tr><td colspan='2'><span id='js-error'></span></td></tr></table></div><div class='f-right'>v"+bs.vers+"</span></div></div></div>");
		chatPanel.parentNode.insertBefore(parentPanel, chatPanel);
		parentPanel.appendChild(chatPanel);
		parentPanel.appendChild(streamPanel);
		parentPanel.parentNode.insertBefore(battlePanel, parentPanel);

		// toggle button to hide/show new panels and chat
		var rightSide = d.getElementsByClassName("rightside")[3];
		rightSide.insertBefore(sf.buttonHide("Chat",    "chat_panelState",    bs.db+"tw/chat.png",   chatPanel),   rightSide.firstElementChild);
		rightSide.insertBefore(sf.buttonHide("Stream",  "stream_panelState",  bs.db+"tw/twitch.png", streamPanel), rightSide.firstElementChild);
		rightSide.insertBefore(sf.buttonHide("Battles", "battles_panelState", bs.db+"cw/cw.png",     battlePanel), rightSide.firstElementChild);

		// table references
		var streamTable = streamPanel.children[2].firstElementChild.childNodes,
		battleTable = battlePanel.children[1].firstElementChild;

		// fill stream table
		var streamString = [],
		streamFragment = d.createDocumentFragment();
		for (var _s=0; _s<streamers; _s++) {
			var stream = streams[_s],
			streamRow = sf.elem("tr", stream[4], "<td></td><td><a target='_blank' href='https://www.twitch.tv/"+stream[1]+"'>"+stream[0]+"</a></td><td>"+((stream[2].constructor === Array) ? "<img src='"+bs.db+"tw/"+img[stream[2][0]]+"' alt='clan'><img src='"+bs.db+"tw/"+img[stream[2][1]]+"' alt='team'>" : "<img src='"+bs.db+"tw/"+img[stream[2]]+"' alt='clan'>")+"</td><td class='s-offline'>Offline</td><td>"+((stream[3].constructor === Array) ? "<img src='"+bs.db+"tw/"+img[stream[3][0]]+"' alt='flag'><img src='"+bs.db+"tw/"+img[stream[3][1]]+"' alt='flag'>" : "<img src='"+bs.db+"tw/"+img[stream[3]]+"' alt='flag'>")+"</td>", {id:stream[1]});
			streamString.push(stream[1]);
			streamFragment.appendChild(streamRow);
		}
		streamTable[6].appendChild(streamFragment);
		// create twitch api url
		bs.tw.api += streamString.join(",");

		// time cells for header and body rows
		var timeFragment = d.createDocumentFragment();
		for (var _tc=0, _tc_len = bs.table.eu.length; _tc<_tc_len; _tc++) {
			var t = bs.table.eu[_tc],
			times = [sf.cw.time(t,"00","s"), sf.cw.time(t)+":00", sf.cw.time(t,"30","s"), sf.cw.time(t)+":30"];
			timeFragment.appendChild(sf.elem("th", "t-time "+times[0], times[1]));
			bs.table.c += "<td class='t-time "+times[0]+"'></td>";
			if (_tc !== _tc_len-1) {
				timeFragment.appendChild(sf.elem("th", "t-time "+times[2], times[3]));
				bs.table.c += "<td class='t-time "+times[2]+"'></td>";
			}
		}
		battleTable.firstElementChild.firstElementChild.appendChild(timeFragment);

		// button to force load cw battles
		var forceSpan = d.getElementById('js-force');
		forceSpan.lastElementChild.checked = (bs.cw.status) ? true : false;
		forceSpan.addEventListener('click', function() {
			localStorage.setItem("battles_force", this.lastElementChild.checked);
			location.reload();
		}, false);

		// add custom input for checking other clans
		var inputSpan = d.getElementById('js-input');
		inputSpan.firstElementChild.addEventListener('input', function() {
			var value = this.value;
			if (value.length == 9 && value[0] == "5") {
				inputSpan.children[2].firstElementChild.src = "https://wot-life.com/img/clanicon/"+value+".png";
				inputSpan.children[3].innerHTML = "Stored! <a href='#' onclick='location.reload();'>Refresh?</a>";
				inputSpan.children[3].classList.add("t-green");
				if (inputSpan.children.length == 5) {
					inputSpan.children[4].textContent = "";
				}
				localStorage.setItem("battles_clanid", value);
			}
			else if (value.length > 0 && value[0] !== "5") {
				inputSpan.children[3].textContent = "Not Valid!";
			}
			else {
				inputSpan.children[3].textContent = "Missing";
			}
		}, false);

		// add intervals for time and round updater
		var timeJump = false,
		timeInterval = setInterval(sf.cw.timer,1000), // 1 second
		updateInterval = setInterval(sf.cw.updater,120000); // 2 minutes

		// activate tablesort function for battle scheduler
		var sortTable = false;
		if (Tablesort) {
			// Numeric sort
			Tablesort.extend('number', function(item) {
				return item.match(/^-?(\d)*-?([,\.]){0,1}-?(\d)+([E,e][\-+][\d]+)?%?$/); // Number
			}, function(a, b) {
				a = parseFloat(a);
				b = parseFloat(b);

				a = isNaN(a) ? 0 : a;
				b = isNaN(b) ? 0 : b;
				return a - b;
			});
			sortTable = new Tablesort(battleTable);
		}
		else {
			window.alert("Error activating tablesort, please refresh - if this shit continues, poke Orrie");
		}

		// insert update status - will crash the tablesorter if inserted earlier
		battleTable.lastElementChild.appendChild(sf.elem("tr", "t-cwText", "<td colspan='23'>Updating...</td>"));

		// activate handler functions through xmlhttp request
		// send request to twitch api with 2mins frequency
		sf.request("twitchData", bs.tw.api, sf.tw.handlerMain, "tw");
		window.setInterval(sf.tw.updater, 120000);
		// send request to wargaming api to see if an event is running
		sf.request("eventData", bs.api.event, sf.cw.handlerEvent, "cw");
	}
}(window));