SteamGifts Helper

In SteamGifts, improve some features

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name            SteamGifts Helper
// @namespace       iFantz7E.SteamGiftsHelper
// @version         1.71
// @description     In SteamGifts, improve some features
// @match           *://www.steamgifts.com/*
// @icon            https://cdn.steamgifts.com/img/favicon.ico
// @run-at          document-start
// @grant           GM_addStyle
// @grant           GM_xmlhttpRequest
// @grant           GM_setClipboard
// @grant           GM_getValue
// @grant           GM_setValue
// @grant           GM_listValues
// @grant           GM_deleteValue
// @connect         store.steampowered.com
// @connect         www.steamgifts.com
// @connect         www.sgtools.info
// @connect         steamdb.info
// @license         GPL-3.0-only
// @copyright       2015, 7-elephant
// @supportURL      https://steamcommunity.com/id/7-elephant/
// @contributionURL https://www.paypal.me/iFantz7E
// ==/UserScript==

// License: GPL-3.0-only - https://spdx.org/licenses/GPL-3.0-only.html
// Compatibility: Firefox 14+ from Mutation Observer

// Since 16 Feb 2015
// https://greasyfork.org/scripts/8111-steamgifts-helper

(function()
{
	"use strict";
	// jshint multistr:true
	
function initStyle()
{
	var imgB64SdbPartial = "data:image/svg+xml;base64,\
PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJN\
NjMuOSAwQzMwLjUgMCAzLjEgMTEuOSAwLjEgMjcuMWwzNS42IDYuN2MyLjktMC45IDYuMi0xLjMgOS42LTEuM2wxNi43LTEw\
Yy0wLjItMi41IDEuMy01LjEgNC43LTcuMiA0LjgtMy4xIDEyLjMtNC44IDE5LjktNC44IDUuMi0wLjEgMTAuNSAwLjcgMTUg\
Mi4yIDExLjIgMy44IDEzLjcgMTEuMSA1LjcgMTYuMy01LjEgMy4zLTEzLjMgNS0yMS40IDQuOGwtMjIgNy45Yy0wLjIgMS42\
LTEuMyAzLjEtMy40IDQuNS01LjkgMy44LTE3LjQgNC43LTI1LjYgMS45LTMuNi0xLjItNi0zLTctNC44TDIuNSAzOC40QzQu\
OCA0MiA4LjUgNDUuMyAxMy4zIDQ4LjIgNSA1MyAwIDU5IDAgNjUuNSAwIDcxLjkgNC44IDc3LjggMTIuOSA4Mi42IDQuOCA4\
Ny4zIDAgOTMuMiAwIDk5LjYgMCAxMTUuMyAyOC42IDEyOCA2NCAxMjggOTkuMyAxMjggMTI4IDExNS4zIDEyOCA5OS42IDEy\
OCA5My4yIDEyMy4yIDg3LjMgMTE1LjEgODIuNiAxMjMuMiA3Ny44IDEyOCA3MS45IDEyOCA2NS41IDEyOCA1OSAxMjMgNTIu\
OSAxMTQuNiA0OC4xIDEyMi45IDQzIDEyNy45IDM2LjcgMTI3LjkgMjkuOSAxMjcuOSAxMy40IDk5LjIgMCA2My45IDBabTIy\
LjggMTQuMmMtNS4yIDAuMS0xMC4yIDEuMi0xMy40IDMuMy01LjUgMy42LTMuOCA4LjUgMy44IDExLjEgNy42IDIuNiAxOC4x\
IDEuOCAyMy42LTEuOCA1LjUtMy42IDMuOC04LjUtMy44LTExLTMuMS0xLTYuNy0xLjUtMTAuMi0xLjV6bTAuMyAxLjdjNy40\
IDAgMTMuMyAyLjggMTMuMyA2LjIgMCAzLjQtNS45IDYuMi0xMy4zIDYuMi03LjQgMC0xMy4zLTIuOC0xMy4zLTYuMiAwLTMu\
NCA1LjktNi4yIDEzLjMtNi4yem0tNDEuNyAxOC41IDAgMGMtMS42IDAuMS0zLjEgMC4yLTQuNiAwLjRsOS4xIDEuN2ExMC44\
IDUgMCAxIDEtOC4xIDkuM2wtOC45LTEuN2MxIDAuOSAyLjQgMS43IDQuMyAyLjQgNi40IDIuMiAxNS40IDEuNSAyMC0xLjUg\
NC42LTMgMy4yLTcuMi0zLjItOS4zLTIuNi0wLjktNS43LTEuMy04LjYtMS4zem02My43IDE2LjYgMCA5LjNjMCAxMS0yMC4y\
IDE5LjktNDUgMTkuOS0yNC45IDAtNDUtOC45LTQ1LTE5LjlsMC05LjJjMTEuNSA1LjMgMjcuNCA4LjYgNDQuOSA4LjYgMTcu\
NiAwIDMzLjYtMy4zIDQ1LjItOC43em0wIDM0LjYgMCA4LjhjMCAxMS0yMC4yIDE5LjktNDUgMTkuOS0yNC45IDAtNDUtOC45\
LTQ1LTE5LjlsMC04LjhjMTEuNiA1LjEgMjcuNCA4LjIgNDUgOC4yIDE3LjYgMCAzMy41LTMuMSA0NS04LjJ6IiBmaWxsPSI";

	GM_addStyle
	(" \
		/* SGH Modify CSS */ \
		header { position: fixed !important; top: 0px; left: 0px; right: 0px; z-index: 6001; } \
		.global__image-outer-wrap--game-large img { width: 292px !important; height: 136px !important; } \
		.global__image-outer-wrap--game-xlarge img { width: 500px; max-height: 215px; } \
		.giveaway__row-outer-wrap { padding-left: 6px !important; padding-right: 6px !important; } \
		.markdown .spoiler:not(:hover) a { color: #8693A7 !important; } \
		.markdown .spoiler:not(:hover) { color: #8693A7 !important; } \
		.page__outer-wrap { text-shadow: none !important; } \
		.sidebar__navigation.bundles_section { width: 336px; max-width: 336px; } \
		.sidebar__mpu { height: auto !important; } \
		.comments a[href*='steamgifts.com/giveaway/'], .comments a[href^='/giveaway/'] \
		  , .page__description a[href*='steamgifts.com/giveaway/'], .page__description a[href^='/giveaway/'] { \
		  padding: 2px; background-color: #B2DBF2; } \
		.comments a[href*='sgtools.info/giveaways/'], .page__description a[href*='sgtools.info/giveaways/'] { \
		  padding: 2px; background-color: #FFC1C1; } \
		.comments a[href*='itstoohard.com/puzzle/'], .page__description a[href*='itstoohard.com/puzzle/'] \
		  , .comments a[href*='jigidi.com/'], .page__description a[href*='jigidi.com/'] { \
		  padding: 2px; background-color: #FBBD77; } \
		.homepage_heading { border-radius: 4px; \
			background-image: linear-gradient(#515763 0%, #2f3540 100%); \
			background-image: -moz-linear-gradient(#515763 0%, #2f3540 100%); \
			background-image: -webkit-linear-gradient(#515763 0%, #2f3540 100%); } \
		*::-moz-selection { color: #E8EAEF; background-color: #5A7ED7; text-shadow: none; } \
		*::selection { color: #E8EAEF; background-color: #5A7ED7; text-shadow: none; } \
		.pagination + .widget-container { margin-top: 40px; } \
		div[class^='sidebar__entry-'], div.sidebar__error { \
			-webkit-touch-callout: none !important; \
			-webkit-user-select: none !important; \
			-khtml-user-select: none !important; \
			-moz-user-select: none !important; \
			-ms-user-select: none !important; \
			user-select: none !important; } \
	");
	
	GM_addStyle
	(" \
		/* SGH Main CSS */ \
		.sgh_body { padding-top: 39px; } \
		.sgh_hidden { display: none; } \
		.sgh_page { border-top: 0px !important; padding-top: 8px !important; \
		  padding-bottom: 5px; } \
		.sgh_page.sgh_page_border { \
		  box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.3) !important; \
		  border-bottom: 1px solid #D2D6E0; } \
		.sgh_page:not(.sgh_page_border) { \
		  box-shadow: none !important; } \
		.sgh_SGv2Dark .sgh_page.sgh_page_border { \
		  box-shadow: 0px 1px 0px #393936 !important; \
		  border-bottom: 1px solid #070707; } \
		.sgh_rowShown.sgh_rowShown_inactive { display: none !important; } \
		.sgh_rowHidden:not(.sgh_rowHidden_inactive):not(.sgh_rowOwned) { display: none !important; } \
		.sgh_rowLast:not(.sgh_rowLast_inactive) { border-bottom: 0px !important; } \
		/* .sgh_rowOwned:first-child, .sgh_rowNotInterested:first-child, .sgh_rowWished:first-child { */ \
		/*   border-top: 1px solid #D2D6E0; } */ \
		.sgh_SGv2Dark .sgh_rowOwned:first-child, .sgh_SGv2Dark .sgh_rowNotInterested:first-child \
		, .sgh_SGv2Dark .sgh_rowWished:first-child { \
		  border-top: 1px solid #050504; } \
		.sgh_rowOwned, .sgh_rowNotInterested, .sgh_rowWished { \
		  border-left: 1px solid #D2D6E0 !important; \
		  border-right: 1px solid #D2D6E0 !important; \
		  padding-left: 5px !important; padding-right: 5px !important; \
		  transition: background 300ms ease-in 0s; } \
		.sgh_SGv2Dark .sgh_rowOwned, .sgh_SGv2Dark .sgh_rowNotInterested, .sgh_SGv2Dark .sgh_rowWished { \
		  border-left: 0px !important; \
		  border-right: 0px !important; \
		  box-shadow: none !important; } \
		.sgh_rowNotInterested { background-color: #F0E4E5; } \
		.sgh_SGv2Dark .sgh_rowNotInterested { background-color: #70504F; } \
		.sgh_rowWished { background-color: #D8E5F0; } \
		.sgh_SGv2Dark .sgh_rowWished { background-color: #172A3B; } \
		.sgh_rowOwned { background-color: #DFF0D8; } \
		.sgh_SGv2Dark .sgh_rowOwned { background-color: #607D42; } \
		/* .sgh_rowOwned:has(> .is-faded) { background-color: rgb(235, 241, 236) !important; } /* /* CSS4 */ \
		.sgh_rowEnterNotInterested:not([style*='background-color:']) { \
		  background-color: #F0E8EA !important; \
		  transition: background 300ms ease-in 0s; } \
		.sgh_SGv2Dark .sgh_rowEnterNotInterested:not([style*='background-color:']) { \
		  background-color: #571C1A !important; } \
		.sgh_rowEnterWished:not([style*='background-color:']) { \
		  background-color: #D8E5F0 !important; \
		  transition: background 300ms ease-in 0s; } \
		.sgh_SGv2Dark .sgh_rowEnterWished:not([style*='background-color:']) { \
		  background-color: #172A3B !important; } \
		.sgh_rowEnterOwned:not([style*='background-color:']) { \
		  background-color: #DFF0D8 !important; \
		  transition: background 300ms ease-in 0s; } \
		.sgh_SGv2Dark .sgh_rowEnterOwned:not([style*='background-color:']) { \
		  background-color: #607D42 !important; } \
		.sgh_appNotInterested, .featured__outer-wrap .global__image-outer-wrap.sgh_appNotInterested { \
		  background-color: #F0D9D8 !important; \
		  transition: background 300ms ease-in 0s; } \
		.sgh_appWished, .featured__outer-wrap .global__image-outer-wrap.sgh_appWished { \
		  background-color: #D8E5F0 !important; \
		  transition: background 300ms ease-in 0s; } \
		.sgh_appOwned, .featured__outer-wrap .global__image-outer-wrap.sgh_appOwned { \
		  background-color: #9AC96B !important; \
		  transition: background 300ms ease-in 0s; } \
		.sgh_linkNotInterested { background-color: #F9DBE3 !important; padding: 2px; \
		  transition: background 300ms ease-in 0s; } \
		.sgh_linkWished { background-color: #C2E0F0 !important; padding: 2px; \
		  transition: background 300ms ease-in 0s; } \
		.sgh_linkOwned { background-color: #D3E4C7 !important; padding: 2px; \
		  transition: background 300ms ease-in 0s; } \
		.sgh_linkOwned.table_image_thumbnail { border: solid 3px #9AC96B; } \
		.sgh_linkNotInterested.table_image_thumbnail { border: solid 3px #F9DBE3; } \
		.sgh_linkWished.table_image_thumbnail { border: solid 3px #C2E0F0; } \
		.sgh_noti { text-align: center; } \
		.sgh_column_small { width: 90px; } \
		.sgh_noTransition { transition: all 0s ease 0s !important; } \
		.sgh_ga_shortcut_input { height: 100%; -moz-box-flex: 1; flex: 1 1 0%; \
		  line-height: 18px !important; padding: 0px !important; border: 0px none !important; } \
		.sgh_ga_shortcut_link { display: none; } \
		.sgh_gaOwned .fa, .sgh_gaOwned:visited .fa { \
		  vertical-align: text-bottom; color: #739650 !important; } \
		.sgh_gaUnknown .fa, .sgh_gaUnknown:visited .fa { \
		  vertical-align: text-bottom; color: #968B50 !important; } \
		.sgh_gaFiltered .fa, .sgh_gaFiltered:visited .fa { \
		  vertical-align: text-bottom; color: #888 !important; } \
		.sgh_gaLvlRequired .fa, .sgh_gaLvlRequired:visited .fa { \
		  vertical-align: text-bottom; color: #B0255A !important; } \
		.sgh_gaEnded .fa, .sgh_gaEnded:visited .fa { \
		  vertical-align: text-bottom; color: #6b7a8c !important; } \
		.sgh_gaEntered .fa, .sgh_gaEntered:visited .fa { \
		  vertical-align: text-bottom; color: #4B72D4 !important; } \
		.sgh_gaMissingBase .fa, .sgh_gaMissingBase:visited .fa { \
		  vertical-align: text-bottom; color: #4B72D4 !important; padding-left: 2px; } \
		.sgh_gaNotFound .fa, .sgh_gaNotFound:visited .fa { \
		  vertical-align: text-bottom; color: #6b7a8c !important; } \
		.markdown h1 .sgh_fa { font-size: 28px; } \
		.markdown h2 .sgh_fa { font-size: 18px; } \
		.markdown h3 .sgh_fa { font-size: 14px; } \
		.sgh_pointer { cursor: pointer; } \
	");
	
	GM_addStyle
	(" \
		/* SGH Icon CSS */ \
		.sgh_icon_sdb { padding-left: 3px; margin-left: 2px; margin-top: 5px; } \
		.sgh_icon_sdb_div { \
		  width: 14px; height: 14px; opacity: 0.35; display: inline-block; \
		  background-image: url(" + imgB64SdbPartial + "jNDY1NjcwIi8+PC9zdmc+); } \
		.table__column__heading .sgh_icon_sdb_div { vertical-align: text-bottom; margin-bottom: 1px; } \
		.sgh_SGv2Dark .sgh_icon_sdb_div { \
		  opacity: 0.55; \
		  background-image: url(" + imgB64SdbPartial + "jQTBBMEEwIi8+PC9zdmc+); } \
		.sgh_icon_sdb_div.sidebar__navigation__item__count { \
		  opacity: 0.9; \
		  background-image: url(" + imgB64SdbPartial + "jNkI3QThDIi8+PC9zdmc+); } \
		.sgh_SGv2Dark .sgh_icon_sdb_div.sidebar__navigation__item__count { \
		  opacity: 0.9; \
		  background-image: url(" + imgB64SdbPartial + "jN0M5MDlDIi8+PC9zdmc+); } \
		.sgh_icon_sdb_sec { margin-top: 0px; vertical-align: text-top; display: inline-block; } \
	");
	
	GM_addStyle
	(" \
		/* SGH SteamDB box */ \
		.sgh_sdbBox { border: 1px solid #D2D6E0; max-width: 334px; max-height: 360px; \
		  margin-bottom: 35px; overflow: auto; } \
		.sgh_sdbBox > .table { width: 410px; border: 0; border-collapse: separate; \
		  border-color: #ddd; \
		  font-size: 13px; background-color: #fff; border-spacing: 0; color: #333; } \
		.sgh_sdbBox > .table tr:hover { \
		  background-color: #f5f5f5; } \
		.sgh_sdbBox > .table th { vertical-align: bottom; text-transform: uppercase; \
		  color: #7f7f7f; border-bottom: 1px solid #ddd; background-color: #f5f5f5; \
		  font-weight: 700; font-size: 11px; } \
		.sgh_sdbBox > .table tr:first-child th { \
		  border-top: 0; } \
		.sgh_sdbBox > .table td, .sgh_sdbBox > .table th { \
		  padding: 8px; line-height: 20px; text-align: left; \
		  border-top: 1px solid #ddd; border-left: 1px solid #ddd; } \
		.sgh_sdbBox > .table td:nth-child(1), .sgh_sdbBox > .table th:nth-child(1) { \
		  width: 46px !important; border-left: 0; } \
		.sgh_sdbBox > .table td:nth-child(2), .sgh_sdbBox > .table th:nth-child(2) { \
		  width: 40px !important; } \
		.sgh_sdbBox > .table td:nth-child(4), .sgh_sdbBox > .table th:nth-child(4) { \
		  width: 60px !important; } \
		.sgh_sdbBox > .table td:nth-child(5), .sgh_sdbBox > .table th:nth-child(5) { \
		  display: none; } \
		.sgh_sdbBox a { color: #0072c6; } \
		.sgh_sdbBox .fa { font-size: 16px; } \
		.sgh_sdbBox .owned { background-color: #DDF7D3 !important; } \
	");
}

function attachOnLoad(callback)
{
	window.addEventListener("load", function(e) 
	{
		callback();
	});
}

function attachOnReady(callback) 
{
	document.addEventListener("DOMContentLoaded", function(e) 
	{
		callback();
	});
}

function insertBeforeElement(newNode, referenceNode) 
{
    referenceNode.parentNode.insertBefore(newNode, referenceNode);
}

function insertAfterElement(newNode, referenceNode) 
{
    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

function reload()
{
	var curHref = window.location.href;
	var posHashtag = curHref.indexOf("#");
	if (posHashtag > -1)
	{
		window.location = curHref.substr(0, posHashtag);
	}
	else
	{
		window.location = curHref;
	}
}

function getQueryByName(name, url) 
{
	if (!url) url = location.search;
    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
    var results = regex.exec(url);
    return (results === null) ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}

var isVisible = (function()
{
	var stateKey;
	var eventKey;
	var keys = 
	{
		hidden: "visibilitychange",
		webkitHidden: "webkitvisibilitychange",
		mozHidden: "mozvisibilitychange",
		msHidden: "msvisibilitychange"
	};
	for (stateKey in keys) 
	{
		if (stateKey in document) 
		{
			eventKey = keys[stateKey];
			break;
		}
	}
	return function(c) 
	{
		if (c) 
		{
			document.addEventListener(eventKey, c);
		}
		return !document[stateKey];
	}
})();

function addKey(eleListener, eleClick, keyCodes, keyName, keyTitleMode, keyModifierName, checkModifierCallback)
{
	/* 
		eleClick:
			element, query
		keyCodes:
			code, name, array
		keyTitleMode:
			0: do nothing
			1: append value
			2: add title if not exist
			4: override title
			8: append textContent
			16: append textContent of firstElementChild
		keyModifierName:
			Ctrl, Ctrl+Shift, Alt
	*/
	
	keyCodes = keyCodes || [0];
	keyName = keyName || "";
	keyTitleMode = keyTitleMode || 0;
	keyModifierName = keyModifierName || "";
	
	if (typeof checkModifierCallback !== "function")
	{
		checkModifierCallback = function(ev) 
		{
			return ev.ctrlKey && ev.shiftKey && ev.altKey;
		};
	}
	
	if (typeof eleClick === "string")
	{
		keyTitleMode = 0;
	}
	
	if (!Array.isArray(keyCodes))
	{
		keyCodes = [keyCodes];
	}
	
	if (eleListener && eleClick)
	{
		// apply title
		var keyTitle = keyModifierName ? keyModifierName + "+" + keyName : "";
		if (keyTitle !== "" && keyTitleMode !== 0)
		{
			if ((keyTitleMode & 1) === 1)
			{
				// 1: append value
				if (typeof eleClick.value !== "undefined")
				{
					eleClick.value += " (" + keyTitle + ")";
				}
			}
			if ((keyTitleMode & 2) === 2)
			{
				// 2: add title if not exist
				if (!eleClick.title)
				{
					eleClick.title = keyTitle;
				}
			}
			if ((keyTitleMode & 4) === 4)
			{
				// 4: override title
				eleClick.title = keyTitle;
			}
			if ((keyTitleMode & 8) === 8)
			{
				// 8: append textContent
				eleClick.textContent += " (" + keyTitle + ")";
			}
			if ((keyTitleMode & 16) === 16)
			{
				// 16: append textContent of firstElementChild
				if (eleClick.firstElementChild)
				{
					eleClick.firstElementChild.textContent += " (" + keyTitle + ")";
				}
			}
		}
		
		eleListener.addEventListener("keydown", function (ev)
		{
			if (checkModifierCallback(ev))
			{
				var isSameKey = false;
				
				for (var i = 0; i < keyCodes.length; i++)
				{
					var keyCode = keyCodes[i];
					if (typeof keyCode === "number")
					{
						isSameKey = (ev.keyCode === keyCode);
					}
					else
					{
						// Firefox 32+
						isSameKey = (typeof ev.code !== "undefined" && ev.code === keyCode)
					}
					
					if (isSameKey)
					{
						break;
					}
				}
				
				if (isSameKey)
				{
					ev.preventDefault();
					
					var eleClickCur = null;
					
					if (typeof eleClick === "string")
					{
						eleClickCur = document.querySelector(eleClick);
					}
					else
					{
						eleClickCur = eleClick;
					}					
					
					if (eleClickCur)
					{
						eleClickCur.focus();
						eleClickCur.click();
					}
					
					return false;
				}
			}
		}, true);
	}
}

function addKeyCtrl(eleListener, eleClick, keyCode, keyName, keyTitleMode)
{
	addKey(eleListener, eleClick, keyCode, keyName, keyTitleMode, "Ctrl", function(ev)
	{
		return ev.ctrlKey && !ev.shiftKey && !ev.altKey;
	});
}

var timeoutList = [];
var intervalList = [];

function setTimeoutCustom(func, tm, params)
{
	var id = setTimeout(func, tm, params);
	timeoutList.push(id);
	return id;
}

function clearTimeoutAll()
{
	for (var i = 0; i < timeoutList.length; i++)
	{
		clearTimeout(timeoutList[i]);
	}
}

function setIntervalCustom(func, tm, params)
{
	var id = setInterval(func, tm, params);
	intervalList.push(id);
	return id;
}

function clearIntervalAll()
{
	for (var i = 0; i < intervalList.length; i++)
	{
		clearInterval(intervalList[i]);
	}
}

function randNum(min, max)
{
	return Math.round(Math.random() * (max - min) + min);
}

function normalizeArray(arr)
{
	arr = arr.filter(function(elem, index, self) 
	{
		return index === self.indexOf(elem);
	});
	return arr;
}

function normalizeArray2D(arr)
{
	arr = arr.filter(function(elem, index, self) 
	{		
		for (var i = 0; i < self.length; i++)
		{
			if (self[i][0] === elem[0])
			{
				return index === i;
			}
		}
		
		return false;
	});
	return arr;
}

function getGaId(url)
{
	var rgxSite = /^https?:\/\/((www\.)?steamgifts\.com\/(giveaway|happy-holidays)|www\.sgtools\.info\/giveaways)\//i;
	if (rgxSite.test(url))
	{
		return url.replace(rgxSite, "").split("/")[0];
	}
	
	return "";
}

function getUnixTimestamp()
{
	return parseInt(Date.now() / 1000);
}

function resetProfileCacheTimestamp()
{
	GM_setValue(name_profile_time, 0);
	console.log("Cache: refresh");
}

function isProfileCacheExpired()
{
	var isExpired = false;
	var timestampExpired = 5 * 60;
	
	var profileTimestamp = GM_getValue(name_profile_time, 0);
	
	var profileTimestampDiff = getUnixTimestamp() - profileTimestamp;
	if (profileTimestampDiff > timestampExpired)
	{
		isExpired = true;
	}
	
	if (!isExpired)
	{
		var profileJson = GM_getValue(name_profile_json, 0);
		if (!profileJson)
		{
			isExpired = true;
		}
	}
	
	if (!isExpired)
	{
		console.log("Cache: " + profileTimestampDiff + "s");
	}
	
	return isExpired;
}

function setProfileCache(json)
{
	GM_setValue(name_profile_json, json);
	GM_setValue(name_profile_time, getUnixTimestamp());
}

function markOwned(query, getElementCallback, getProductIdCallback
	, classOwned, classNotInterested, classWished, getCountCallback)
{
	if (!document.querySelector(query))
	{
		//console.log("markOwned: empty");
		return;
	}
	
	if (!getElementCallback)
	{
		getElementCallback = function(ele, type)
		{
			// type -> 1: Owned, 2: Ignored, 3: Wishlist
			return ele;
		};
	}
	
	if (!getProductIdCallback)
	{
		getProductIdCallback = function(ele)
		{
			return ele.getAttribute("href");
		};
	}
	
	if (!getCountCallback)
	{
		getCountCallback = function(appCount, subCount, appOwned, subOwned)
		{
		};
	}
	
	if (!classOwned) classOwned = "";
	if (!classNotInterested) classNotInterested = "";
	if (!classWished) classWished = "";
	
	var apps = [];
	var subs = [];
	
	var rgxId = /[0-9]{3,}/g;
	var rgxApp = /((:\/\/(store\.steampowered\.com|steamcommunity\.com|steamdb\.info)(\/agecheck)?\/app|\/steam\/apps)\/[0-9]+|^[0-9]{3,}$)/i;
	var rgxSub = /(:\/\/(store\.steampowered\.com|steamdb\.info)\/sub|\/steam\/subs)\/[0-9]+/i;
	
	var markFromJson = function(dataRes)
	{
		if (!dataRes)
		{
			//console.log("markFromJson: empty");
			return;
		}
		
		var countOwned = [0, 0];
		var countAll = [0, 0];
		
		if (typeof dataRes["rgOwnedApps"] !== "undefined"
			&& typeof dataRes["rgOwnedPackages"] !== "undefined"
			&& typeof dataRes["rgIgnoredApps"] !== "undefined")
		{
			var eleApps = document.querySelectorAll(query);
			for (var i = 0; i < eleApps.length; i++)
			{
				var attrHref = getProductIdCallback(eleApps[i]);
				var ids = attrHref.match(rgxId);
				if (ids)
				{
					var valId = parseInt(ids[0]);
						
					if (rgxApp.test(attrHref))
					{
						if (dataRes["rgOwnedApps"].indexOf(valId) > -1)
						{
							var ele = getElementCallback(eleApps[i], 1);
							if (ele && classOwned !== "")
							{
								ele.classList.add(classOwned);
							}
							countOwned[0]++;
						}
						else
						{
							//console.log("App: not owned - https://store.steampowered.com/app/" + id + "/");
							if (dataRes["rgWishlist"].indexOf(valId) > -1)
							{
								var ele = getElementCallback(eleApps[i], 3);
								if (ele && classWished !== "")
								{
									ele.classList.add(classWished);
								}
							}
							else if (dataRes["rgIgnoredApps"][valId] === 0)
							{
								var ele = getElementCallback(eleApps[i], 2);
								if (ele && classNotInterested !== "")
								{
									ele.classList.add(classNotInterested);
								}
							}
						}
						countAll[0]++;
					}
					else if (rgxSub.test(attrHref))
					{								
						if (dataRes["rgOwnedPackages"].indexOf(valId) > -1)
						{
							var ele = getElementCallback(eleApps[i], 1);
							if (ele && classOwned !== "")
							{
								ele.classList.add(classOwned);
							}
							countOwned[1]++;
						}
						else
						{
							//console.log("Sub: not owned - https://store.steampowered.com/sub/" + id + "/");
						}
						countAll[1]++;
					}
				}
			}
		}
		
		if (countAll[0] > 1)
		{
			console.log("App: owned " + countOwned[0] + "/" + countAll[0]);
		}
		if (countAll[1] > 1)
		{
			console.log("Sub: owned " + countOwned[1] + "/" + countAll[1]);
		}
		
		getCountCallback(countAll[0], countAll[1], countOwned[0], countOwned[1]);
	}

	// Force mark from cache
	{
		setTimeoutCustom(function()
		{
			// Delay after script ran
			var profileJson = GM_getValue(name_profile_json, 0);
			markFromJson(profileJson);
		}, 300);
	}
		
	if (isProfileCacheExpired())
	{
		GM_xmlhttpRequest(
		{
			method: "GET",
			url: "https://store.steampowered.com/dynamicstore/userdata/?t=" + getUnixTimestamp(),
			onload: function(response) 
			{
				console.log("markOwned: userdata " + response.responseText.length + " bytes");
				
				var dataRes = JSON.parse(response.responseText);
				
				setProfileCache(dataRes);				
				markFromJson(dataRes);
				
			} // End onload
		});
	}
}

function applyIcon(gaUrl, elesGa, className, icon, titleStatus, titleGame)
{
	var gaIdCur = getGaId(gaUrl);
	
	for (var i = 0; i < elesGa.length; i++)
	{
		if (elesGa[i].dataset.sghGaId === gaIdCur)
		{
			if (className && !elesGa[i].classList.contains(className))
			{
				elesGa[i].classList.add(className);

				if (icon || titleStatus)
				{
					var ele = document.createElement("i");
					
					if (icon)
					{
						ele.setAttribute("class", "sgh_fa fa fa-fw " + icon);
					}
					
					if (titleGame)
					{
						if (elesGa[i].hasAttribute("title"))
						{
							if (titleStatus)
							{
								ele.setAttribute("title", titleGame + " - " + titleStatus);
							}
							else
							{
								ele.setAttribute("title", titleGame);
							}
						}
					}
					else if (titleStatus)
					{
						if (elesGa[i].hasAttribute("title"))
						{
							ele.setAttribute("title", titleStatus);
						}
						else
						{
							elesGa[i].setAttribute("title", titleStatus);
						}
					}
					
					elesGa[i].appendChild(ele);
				}
			}
			
			if (titleGame && !elesGa[i].hasAttribute("title"))
			{
				if (titleStatus)
				{
					elesGa[i].setAttribute("title", titleGame + " - " + titleStatus);
				}
				else
				{
					elesGa[i].setAttribute("title", titleGame);
				}
			}
		}
	}
}

function main() 
{	
	var url = document.documentURI;
	var title = document.title;
	
	if (document.querySelector("header"))
	{
		GM_addStyle(" \
			/* SGH Modify CSS */ \
			header { position: fixed; top: 0px; left: 0px; right: 0px; z-index: 6001; } \
			body { padding-top: 39px; } \
		");
	}
	
	var urlSteam = "https://store.steampowered.com/";
	var urlSdb = "https://steamdb.info/";
	
	var detectorContentTemplate = ' \n\
		<a class="sidebar__navigation__item__link" %HREF%> \n\
			<div class="sidebar__navigation__item__name">%NAME%</div> \n\
			<div class="sidebar__navigation__item__underline"></div> \n\
			<div class="sidebar__navigation__item__count">%COUNT%</div> \n\
		</a> ';
		
	// Clean http
	{
		setTimeout(function()
		{
			var urlHttp = "http://www.steamgifts.com/";
			var urlHttps = "https://www.steamgifts.com/";
			
			var elesA = document.querySelectorAll("a[href^='http://www.steamgifts.com/']");
			for (var i = 0; i < elesA.length; i++)
			{
				var url = elesA[i].getAttribute("href");
				if (url.indexOf(urlHttp) === 0)
				{
					url = url.replace(urlHttp, urlHttps);
					elesA[i].setAttribute("href", url);
				}
			}
		}, 10);
	}
	
	// Add SteamDB links
	{
		var eleGas = document.querySelectorAll(".giveaway__icon[href*='://store.steampowered.com/'] \
			, .table__column__secondary-link[href*='://store.steampowered.com/']");
		for (var i = 0; i < eleGas.length; i++)
		{
			var isSteam = false;
			
			var urlNew = eleGas[i].getAttribute("href").replace(urlSteam, urlSdb);
			if (urlNew.indexOf("/sub/") > -1)
			{
				urlNew = urlNew + "apps/#apps";
				isSteam = true;
			}
			else if (urlNew.indexOf("/app/") > -1)
			{
				urlNew = urlNew + "subs/";
				isSteam = true;
			}
			
			if (isSteam)
			{
				var eleA = document.createElement("a");
				eleA.classList.add("sgh_icon_sdb");
				eleA.setAttribute("href", urlNew);
				eleA.setAttribute("target", "_blank");
				eleA.innerHTML = '<div class="sgh_icon_sdb_div"></div>';
					
				if (!eleGas[i].classList.contains("giveaway__icon"))
				{
					eleA.classList.add("sgh_icon_sdb_sec");
				}
				
				insertAfterElement(eleA, eleGas[i]);
			}
		}
	}
	
	// Reset cache before marking
	if (url.indexOf("/account/settings/profile") > -1 || url.indexOf("/giveaways/won") > -1)
	{
		if (GM_getValue(name_config_general_mark_owned_game) === 1)
		{
			resetProfileCacheTimestamp();
		}
	}
	
	// Reset cache when pressing F5
	if (GM_getValue(name_config_general_mark_owned_game) === 1)
	{
		document.addEventListener("keydown", function (e)
		{
			if (e.keyCode === 116 || e.code === "F5")
			{
				resetProfileCacheTimestamp();
				window.location.reload();
				e.preventDefault();
				return false;
			}
		}, true);
	}
	
	// Correct GA links
	{
		var rgxMarker = /[^a-z0-9]/ig;
		
		var elesGa = document.querySelectorAll("a[href*='steamgifts.com/giveaway/'], a[href^='/giveaway/']");
		for (var i = 0; i < elesGa.length; i++)
		{
			var isEdited = false;
			
			var strsHref = elesGa[i].href.split("/");
			if (strsHref.length >= 5)
			{
				if (rgxMarker.test(strsHref[4]) && strsHref[4].length > 5)
				{
					strsHref[4] = strsHref[4].replace(rgxMarker, "");
					isEdited = true;
				}
				
				if (strsHref.length == 5)
				{
					strsHref.push("");
					isEdited = true;
				}
			}
			
			if (isEdited)
			{
				elesGa[i].href = strsHref.join("/");
			}
		}
	}
	
	// Hilight owned games and dlcs
	if (GM_getValue(name_config_general_mark_owned_game) === 1)
	{	
		markOwned(":not(.table__column__heading) > .giveaway__icon[href*='store.steampowered.com/']", function(ele)
		{
			return ele.parentElement.parentElement.parentElement.parentElement;
		}, null, "sgh_rowOwned", "sgh_rowNotInterested", "sgh_rowWished");
	}
		
	// Mark owned GA
	if (GM_getValue(name_config_general_mark_owned_giveaway) === 1)
	{
		var elesGa = document.querySelectorAll(" \
			.comments a[href*='steamgifts.com/giveaway/'], .comments a[href^='/giveaway/'] \
			, .page__description a[href*='steamgifts.com/giveaway/'], .page__description a[href^='/giveaway/'] \
			, .comments a[href*='sgtools.info/giveaways/'], .page__description a[href*='sgtools.info/giveaways/'] \
			, .giveaway_box_list a[href^='/happy-holidays/'] ");

		if (elesGa.length > 0)
		{
			var markGaFromJson = function(dataResSteam)
			{
				if (!dataResSteam)
				{
					//console.log("markGaFromJson: empty");
					return;
				}
				
				if (typeof dataResSteam["rgOwnedApps"] === "undefined"
					|| dataResSteam["rgOwnedApps"].length === 0)
				{
					console.log("not logged in");
				}	
				else if (typeof dataResSteam["rgOwnedApps"] !== "undefined"
					&& typeof dataResSteam["rgOwnedPackages"] !== "undefined"
					&& typeof dataResSteam["rgIgnoredApps"] !== "undefined")
				{
					var rgxId = /[0-9]+/;
					var rgxApp = /:\/\/store\.steampowered\.com\/app\/[0-9]+/i;
					var rgxSub = /:\/\/store\.steampowered\.com\/sub\/[0-9]+/i;
					var rgxEnded = /Ended [0-9]+ [a-z]+ ago/i;
					
					var elesGa = document.querySelectorAll(" \
						.comments a[href*='steamgifts.com/giveaway/'] \
						, .comments a[href^='/giveaway/'] \
						, .page__description a[href*='steamgifts.com/giveaway/'] \
						, .page__description a[href^='/giveaway/'] \
						, .comments a[href*='sgtools.info/giveaways/'] \
						, .page__description a[href*='sgtools.info/giveaways/'] \
						, .giveaway_box_list a[href^='/happy-holidays/'] ");
					
					var gaCur = 0;
					var tmId = setInterval(function()
					{
						if (gaCur >= elesGa.length)
						{
							clearInterval(tmId);
						}
						else
						{
							var dataHref = elesGa[gaCur].href;
							if (dataHref)
							{
								var gaId = getGaId(dataHref);
								elesGa[gaCur].dataset.sghGaId = gaId;
								
								GM_xmlhttpRequest(
								{
									method: "GET",
									url: dataHref,
									onload: function(response) 
									{
										var isOwned = false;
										var isFound = true;
										var isHidden = false;
										var isLvlRequired = false;
										var isRegionRestricted = false;
										var isEntered = false;
										var textStatus = "Exists in Account";
										var textGame = "";
										
										var parser = new DOMParser();
										var dataRes = parser.parseFromString(response.responseText, "text/html");
										
										if (response.finalUrl.indexOf("/happy-holidays/") > -1)
										{
											var eleStatus = dataRes.querySelector(".giveaway_box_notification");
											if (eleStatus)
											{
												if (eleStatus.textContent.indexOf("since the game already exists in your account") > -1)
												{
													isOwned = true;
												}
											}
											
											if (isOwned)
											{
												var gaIdCur = getGaId(response.finalUrl);
												var className = "sgh_appOwned";
												
												for (var i = 0; i < elesGa.length; i++)
												{
													if (elesGa[i].dataset.sghGaId === gaIdCur)
													{
														if (className && !elesGa[i].classList.contains(className))
														{
															elesGa[i].classList.add(className);
															elesGa[i].title = "Owned";
														}
													}
												}
											}
										}
										else if (response.finalUrl === "https://www.steamgifts.com/")
										{
											textStatus = "Not found"
												
											console.log("GA: not found - " + dataHref);
											applyIcon(dataHref, elesGa
												, "sgh_gaNotFound", "fa-search-minus", textStatus, textGame);
										}
										else
										{
											var eleGame = dataRes.querySelector(".featured__heading__medium");
											if (eleGame)
											{
												textGame = eleGame.textContent.trim();
												
												var elePoint = dataRes.querySelector(".featured__heading__small");
												if (elePoint)
												{
													if (elePoint.nextElementSibling 
														&& elePoint.nextElementSibling.classList.contains("featured__heading__small"))
													{
														// Copies and Points
														elePoint = elePoint.nextElementSibling;
													}
													textGame += " " + elePoint.textContent.trim();
												}
											}
											
											var eleExist = dataRes.querySelector(".sidebar__error");
											if (eleExist)
											{
												textStatus = eleExist.textContent.trim();
												if (textStatus === "Exists in Account")
												{
													isOwned = true;
												}
												else if (textStatus.indexOf("Level") > -1)
												{
													isLvlRequired = true;
												}
												else if (textStatus.indexOf("Region") > -1)
												{
													isRegionRestricted = true;
												}
											}
											
											if (!isOwned)
											{
												var eleA = dataRes.querySelector(".global__image-outer-wrap[href*='store.steampowered.com/']");
												if (eleA)
												{
													var attrHref = eleA.href;
													var id = rgxId.exec(attrHref);
													if (id)
													{
														var valId = parseInt(id);
															
														if (rgxApp.test(attrHref))
														{
															if (dataResSteam["rgOwnedApps"].indexOf(valId) > -1)
															{
																isOwned = true;
															}
															else
															{
																//console.log("App: not owned - https://store.steampowered.com/app/" + id + "/");
															}
														}
														else if (rgxSub.test(attrHref))
														{								
															if (dataResSteam["rgOwnedPackages"].indexOf(valId) > -1)
															{
																isOwned = true;
															}
															else
															{
																//console.log("Sub: not owned - https://store.steampowered.com/sub/" + id + "/");
															}
														}
													}
												}
												else
												{
													var eleName = dataRes.querySelector(".featured__heading__medium");
													if (!eleName)
													{
														isFound = false;
													}
												}
												
												if (dataRes.querySelector(".featured__container") 
													&& !dataRes.querySelector(".featured__giveaway__hide"))
												{
													isHidden = true;
												}
											}
											
											if (isOwned)
											{
												textStatus = "Exists in Account";
												applyIcon(response.finalUrl, elesGa
													, "sgh_gaOwned", "fa-briefcase", textStatus, textGame);
											}
											else if (isHidden)
											{
												if (dataRes.querySelector(".sidebar__entry-delete:not(.is-hidden)"))
												{
													// Entered
													applyIcon(response.finalUrl
														, elesGa, "sgh_gaEntered", "fa-check-circle", textStatus + " - Entered", textGame);
												}
												else
												{
													console.log("GA: filtered - " + response.finalUrl);
													applyIcon(response.finalUrl, elesGa
														, "sgh_gaFiltered", "fa-eye-slash", "Your filtered game", textGame);
												}
											}
											else if (isLvlRequired)
											{
												console.log("GA: lvl required - " + response.finalUrl);
												applyIcon(response.finalUrl, elesGa
													, "sgh_gaLvlRequired", "fa-level-up", textStatus, textGame);
											}
											else if (isRegionRestricted)
											{
												console.log("GA: region restricted - " + response.finalUrl);
												applyIcon(response.finalUrl, elesGa
													, "sgh_gaRegionRestricted", "fa-exclamation-circle", textStatus, textGame);
											}
											else if (isFound)
											{											
												textStatus = "";
												
												var eleRemain = dataRes.querySelector(".featured__column");
												if (eleRemain)
												{
													textStatus = eleRemain.textContent.trim();
												}
												
												if (rgxEnded.test(textStatus))
												{
													// Ended
													applyIcon(response.finalUrl
														, elesGa, "sgh_gaEnded", "fa-calendar-times-o", textStatus, textGame);
												}
												else
												{							
													console.log("GA: not owned - " + response.finalUrl);
													
													if (dataRes.querySelector(".sidebar__entry-delete:not(.is-hidden)"))
													{
														// Entered
														applyIcon(response.finalUrl
															, elesGa, "sgh_gaEntered", "fa-check-circle", textStatus + " - Entered", textGame);
													}
													else
													{
														var eleErr = dataRes.querySelector(".sidebar__error.is-disabled");
														if (eleErr && eleErr.textContent.trim() === "Missing Base Game")
														{
															// DLC
															applyIcon(response.finalUrl
																, elesGa, "sgh_gaMissingBase", "fa-cubes", textStatus + " - Missing Base Game", textGame);
														}
														else
														{
															// Not owned
															applyIcon(response.finalUrl
																, elesGa, "sgh_gaNotOwned", "", textStatus, textGame);
														}
													}
												}
											}
											else
											{
												console.log("GA: unknown - " + response.finalUrl);
												
												textStatus = "Unknown information";
												
												var iconStatus = "fa-question-circle";
												
												var eleMsg = dataRes.querySelector(".table__row-outer-wrap:nth-child(2) .table__column--width-fill");
												if (eleMsg)
												{
													var textRaw = eleMsg.textContent.trim();
													if (textRaw.indexOf("creator's whitelist") > -1)
													{
														textStatus = "Whitelist only";
														iconStatus = "fa-heart";
													}
													else if (textRaw.indexOf("required Steam groups") > -1)
													{
														textStatus = "Steam groups only";
													}
													else if (textRaw.indexOf("following region") > -1)
													{
														textStatus = textRaw.replace(
															"This giveaway is restricted to the following region", "Region restricted");
													}
													else if (textRaw.indexOf("blacklisted the giveaway creator") > -1)
													{
														textStatus = "You have blacklisted GA creator";
													}
													else if (textRaw.indexOf("blacklisted by the giveaway creator") > -1)
													{
														textStatus = "You have been blacklisted by GA creator";
														iconStatus = "fa-ban";
													}
													else if (textRaw.indexOf("Deleted ") === 0)
													{
														textStatus = textRaw;
														iconStatus = "fa-trash";
													}
													else
													{
														textStatus = textRaw;
													}
												}
												else
												{
													var eleDes = dataRes.querySelector("body > div > .description");
													if (eleDes)
													{
														var textRaw = eleDes.textContent.trim();
														if (textRaw.indexOf("Page not found.") > -1)
														{
															textStatus = "Page not found";
														}
														else
														{
															textStatus = textRaw;
														}
													}
												}
												
												applyIcon(response.finalUrl, elesGa
													, "sgh_gaUnknown", iconStatus, textStatus, textGame);
											}
										}
										
									} // End onload
								});
							}
						}
						gaCur++
					}, 200);
				}
			}
			
			// Force mark from cache
			{
				setTimeoutCustom(function()
				{
					// Delay after script ran
					var profileJson = GM_getValue(name_profile_json, 0);
					markGaFromJson(profileJson);
				}, 300);
			}
			
			if (isProfileCacheExpired())
			{
				GM_xmlhttpRequest(
				{
					method: "GET",
					url: "https://store.steampowered.com/dynamicstore/userdata/?t=" + getUnixTimestamp(),
					onload: function(response) 
					{
						console.log("markOwnedGa: userdata " + response.responseText.length + " bytes");
						
						var dataRes = JSON.parse(response.responseText);
						
						setProfileCache(dataRes);				
						markGaFromJson(dataRes);
						
					} // End onload
				});
			}
		}
	}
		
	var eleMaintain = document.querySelector("body > div > .description");
	if (eleMaintain)
	{
		var text = eleMaintain.textContent;
		if (/(maintenance|database)/i.test(text))
		{
			console.log("autorefresh: maintenance in 3m");
			setTimeoutCustom(function()
			{
				reload();
			}, 180000);
		}
	}
	
	// Paging on top
	if (!/\/(giveaway|discussion|trade)\//i.test(url))
	{
		var eleHead = document.querySelector(".page__heading");
		var elePage = document.querySelector(".pagination:not(.sgh_page)");
		if (eleHead && elePage)
		{
			var elePageNew = elePage.cloneNode(true);
			elePageNew.classList.add("sgh_page");
			insertAfterElement(elePageNew, eleHead);
		}
	}
	
	if (url.indexOf("/giveaway/") > -1)
	{
		setTimeoutCustom(function()
		{
			var eleContainer = document.querySelector(".page__heading, body > div > .description");
			if (!eleContainer)
			{
				if (window === window.parent)
				{
					console.log("autorefresh: no content");
					reload();
				}
			}
		}, 10000);
		
		var eleSearch = document.querySelector(".sidebar__search-container");
		if (eleSearch)
		{
			var eleDttHead = document.createElement("h3");
			eleDttHead.classList.add("sidebar__heading");
			eleDttHead.classList.add("sgh_detector_header");
			eleDttHead.textContent = " Detector ";
			eleDttHead.style.display = "none";
			insertAfterElement(eleDttHead, eleSearch);
			
			var eleDttNav = document.createElement("ul");
			eleDttNav.classList.add("sidebar__navigation");
			eleDttNav.classList.add("sgh_detector_nav");
			eleDttNav.style.display = "none";
			insertAfterElement(eleDttNav, eleDttHead);
			
			var eleRttHead = document.createElement("h3");
			eleRttHead.classList.add("sidebar__heading");
			eleRttHead.classList.add("sgh_information_header");
			eleRttHead.textContent = " Information ";
			eleRttHead.style.display = "none";
			insertAfterElement(eleRttHead, eleDttNav);
			
			var eleRttNav = document.createElement("ul");
			eleRttNav.classList.add("sidebar__navigation");
			eleRttNav.classList.add("sgh_information_nav");
			eleRttNav.style.display = "none";
			insertAfterElement(eleRttNav, eleRttHead);
		}
		
		var warnOwned = function()
		{
			/*setTimeoutCustom(function()
			{
				var divDel = document.querySelector(".sidebar__entry-delete");
				if (divDel)
				{
					if (!divDel.classList.contains("is-hidden") 
						|| !document.querySelector(".featured__giveaway__hide"))
					{
						if (GM_getValue(name_config_ga_autoenter) === 1)
						{
							// Auto remove entry when owned
							divDel.click();
						}
					}
				}
			}, 3000);*/
			
			var eleNav = document.querySelector(".sgh_detector_nav");
			if (eleNav)
			{
				var ele = document.createElement("li");
				ele.classList.add("sidebar__navigation__item");
				
				var content = ' \n\
					<a class="sidebar__navigation__item__link" > \n\
						<div class="sidebar__navigation__item__name">Warning</div> \n\
						<div class="sidebar__navigation__item__underline"></div> \n\
						<div class="sidebar__navigation__item__count">Exists in Account</div> \n\
					</a> ';
					
				ele.innerHTML = content;
				eleNav.style.display = "";
				eleNav.previousElementSibling.style.display = "";
				eleNav.appendChild(ele);
			}
		};

		// Hilight owned
		if (GM_getValue(name_config_general_mark_owned_game) === 1)
		{
			if (!isVisible())
			{
				var eleApp = document.querySelector(".global__image-outer-wrap[href*='store.steampowered.com/']");
				if (eleApp)
				{
					eleApp.classList.add("sgh_noTransition");
				}
			}
			
			markOwned(".global__image-outer-wrap[href*='store.steampowered.com/']", function(eleTarget, markType)
			{
				if (markType === 1)
				{
					warnOwned();
				}
				
				return eleTarget;
			}, null, "sgh_appOwned", "sgh_appNotInterested", "sgh_appWished");
			
			
			markOwned(".page__description a[href*='store.steampowered.com/'], \
				.page__description a[href*='steamdb.info/'], \
				.comments a[href*='store.steampowered.com/'], \
				.comments a[href*='steamdb.info/']"
				, null, null, "sgh_linkOwned", "sgh_linkNotInterested", "sgh_linkWished");
		}
		
		// Enter GA
		if (url.indexOf("/entries") < 0 && url.indexOf("#") < 0)
		{
			var isIdle = function()
			{
				var eleText = document.querySelector("textarea[name='description']");
				return (!eleText || eleText.value === "") 
					&& !document.querySelector(".sgh_config.sgh_config_active");
			};
			
			if (document.querySelector(".featured__giveaway__hide"))
			{
				// Not in filtered
				
				var divIns = document.querySelector(".sidebar__entry-insert");
				if (divIns)
				{
					divIns.addEventListener("click", function()
					{
						// After click "Enter Giveaway"
						setTimeoutCustom(function()
						{
							var divLoad = document.querySelector(".sidebar__entry-loading:not(.is-hidden)");
							if (divLoad)
							{
								// Long loading
								
								console.log("autorefresh: long loading");
								setTimeoutCustom(function()
								{
									if(isIdle())
									{
										reload();
									}
								}, 1000);
							}
							else
							{
								var divErr = document.querySelector(".sidebar__error.is-disabled");
								if (divErr)
								{
									if (divErr.textContent.trim() === "Not Enough Points")
									{
										// "Not Enough Points"
										
										console.log("autorefresh: not enough points");
										setTimeoutCustom(function()
										{
											if(isIdle())
											{
												reload();
											}
										}, 1000);
									}
									else
									{
										console.log("autorefresh: error entered");
										setTimeoutCustom(function()
										{
											if(isIdle())
											{
												reload();
											}
										}, 1000);
									}
								}
							}
						}, 5000);
					});
					
					/*if (!divIns.classList.contains("is-hidden"))
					{
						setTimeoutCustom(function()
						{
							if (!document.querySelector(".sgh_appOwned"))
							{
								var divIns = document.querySelector(".sidebar__entry-insert");
								if (divIns)
								{
									if (!divIns.classList.contains("is-hidden"))
									{
										if (GM_getValue(name_config_ga_autoenter) === 1)
										{
											divIns.click();
										}
									}
								}
							}
						}, 2000);
					}*/
				}
				else
				{
					var divErr = document.querySelector(".sidebar__error.is-disabled");
					if (divErr)
					{
						if (divErr.textContent.trim() ===  "Not Enough Points")
						{
							// "Not Enough Points" when page is loaded
							
							setTimeoutCustom(function()
							{
								if (!document.querySelector(".sgh_appOwned"))
								{
									// wait for checking owned
									
									console.log("autorefresh: not enough points in 55s");
									setTimeoutCustom(function()
									{
										if(isIdle())
										{
											reload();
										}
									}, 55000);
								}
							}, 5000);
							
							divErr.classList.add("sgh_pointer");
							divErr.setAttribute("title", "Refresh");
							divErr.addEventListener("click", reload);
						}
					}
				}
			}
		}
		
		// Show points in title
		if (GM_getValue(name_config_ga_title) === 1)
		{
			// Show points if not owned
			// Add checked after entered
			// Add empty box if can enter
		
			var isOwned = false;
			
			var divErr = document.querySelector(".sidebar__error.is-disabled");
			if (divErr)
			{
				if (divErr.textContent.trim() === "Exists in Account")
				{
					isOwned = true;
				}
			}
			else
			{
				var divEntry = document.querySelector(".sidebar__entry-insert, .sidebar__entry-delete");
				if (!divEntry)
				{
					// Ended
					isOwned = true;
				}
			}
			
			if (!isOwned)
			{
				var point = "";
				
				var elePoint = document.querySelector(".featured__heading__small");
				if (elePoint)
				{
					if (elePoint.nextElementSibling
						&& elePoint.nextElementSibling.classList.contains("featured__heading__small"))
					{
						// Copies and Points
						elePoint = elePoint.nextElementSibling;
					}
					
					var execPoint = /[0-9]+P/.exec(elePoint.textContent);
					if (execPoint)
					{
						point = execPoint[0] + " ";
						document.title =  point + title;
					}
				}
				
				var addCheckedTitle = function()
				{
					var iconCheck = "☑️";	// ✔ ☑ ☑️
					var iconBox = "☐";		// ⎕ ☐
						
					var eleDel = document.querySelector(".sidebar__entry-delete");
					if (eleDel)
					{
						if (!eleDel.classList.contains("is-hidden"))
						{
							// Entered
							document.title = iconCheck + point + title;
						}
						else
						{
							var eleIns = document.querySelector(".sidebar__entry-insert:not(.is-hidden)");
							if (eleIns)
							{
								// Can enter
								document.title = iconBox + point + title;
							}
							else
							{
								var eleLoad = document.querySelector(".sidebar__entry-loading:not(.is-hidden)");
								if (eleLoad)
								{
									// Loading
									document.title = iconBox + point + title;
								}
								else
								{
									// Can't enter
									document.title = point + title;
								}
							}
						}
					}
					else
					{
						var eleErr = document.querySelector(".sidebar__error.is-disabled");
						if (eleErr)
						{
							// Not Enough Points 
							document.title = point + title;
						}
					}
				};
				
				addCheckedTitle();
				
				var eleDel = document.querySelector(".sidebar__entry-delete");
				if (eleDel)
				{
					var muTarget_form = eleDel.parentElement;
					if (muTarget_form.tagName === "FORM")
					{
						var muOb_form = new MutationObserver(function(mutations)
						{
							mutations.forEach(function(mutation)
							{
								//console.log(mutation.type + " " + mutation.target.getAttribute("class"));
								//if (mutation.type === "attributes" && mutation.target.tagName === "DIV")
								{
									addCheckedTitle();
								}
							});
						});
						
						var muCf_form = 
						{
							childList: true, 
							subtree: true, 
							attributes: true, 
							attributeFilter: ["class"] 
						};
						
						muOb_form.observe(muTarget_form, muCf_form);
					}
				}
			}
		}
		
		// Add SteamDB link
		{
			var eleCover = document.querySelector(".global__image-outer-wrap[href*='://store.steampowered.com/']");
			if (eleCover)
			{
				var urlNew = eleCover.getAttribute("href").replace(urlSteam, urlSdb);
				if (urlNew.indexOf("/sub/") > -1)
				{
					urlNew = urlNew + "apps/#apps";
				}
				else
				{
					urlNew = urlNew + "subs/";
				}
		
				var eleNav = null;
				var eleNavParent = null;
				
				var eleHeaders = document.querySelectorAll(".sidebar__heading");
				for (var i = 0; i < eleHeaders.length; i++)
				{
					eleNavParent = eleHeaders[i].parentElement;
					if (eleHeaders[i].textContent.trim() === "Stores")
					{
						eleNav = eleHeaders[i].nextElementSibling;
						break;
					}
				}
				
				if (eleNavParent && !eleNav)
				{
					var eleH3 = document.createElement("h3");
					eleH3.classList.add("sidebar__heading");
					eleH3.textContent = "Stores";
					
					eleNavParent.appendChild(eleH3);
					
					eleNav = document.createElement("ul");
					eleNav.classList.add("sidebar__navigation");
					
					eleNavParent.appendChild(eleNav);
				}
				
				if (eleNav && eleNav.classList.contains("sidebar__navigation"))
				{
					var eleNew = document.createElement("li");
					eleNew.classList.add("sidebar__navigation__item");
					eleNew.innerHTML = ' \n\
						<a class="sidebar__navigation__item__link" href="' + urlNew + '" rel="nofollow" target="_blank"> \n\
							<div class="sidebar__navigation__item__name">SteamDB</div> \n\
							<div class="sidebar__navigation__item__underline"></div> \n\
							<div class="sidebar__navigation__item__count sgh_icon_sdb_div"></div> \n\
						</a> ';
					eleNav.appendChild(eleNew);
				}
				
				// Add compatible with SG Add IsThereAnyDeal Data
				if (eleNav)
				{
					setTimeoutCustom(function(eleNav)
					{
						if (eleNav)
						{
							var eleIad = document.querySelector(".isthereanydeal_link");
							if (eleIad)
							{
								insertAfterElement(eleIad.parentElement, eleNav.lastElementChild);
							}
						}
					}, 100, eleNav);
				}
		
				// Add SteamDB box
				if (GM_getValue(name_config_ga_sdb) === 1)
				{
					var eleSide = document.querySelector(".sidebar");
					if (eleSide)
					{
						if (urlNew.indexOf("/sub/") > -1)
						{
							var eleDiv = document.createElement("div");
							eleDiv.classList.add("sgh_sdbBox");
							eleDiv.classList.add("sgh_hidden");
							eleSide.appendChild(eleDiv);
							
							GM_xmlhttpRequest(
							{
								method: "GET",
								url: urlNew,
								onload: function(response) 
								{
									var dataRes = (new DOMParser()).parseFromString(response.responseText, "text/html");
									
									var eleTable = dataRes.querySelector("#apps > .table");
									if (eleTable)
									{
										var eleTh = eleTable.querySelector("th:nth-child(2)");
										if (eleTh)
										{
											eleTh.textContent = "Type";
										}
										
										var elesA = eleTable.querySelectorAll("a");
										for (var i = 0; i < elesA.length; i++)
										{
											var href = elesA[i].getAttribute("href");
											if (href.indexOf("/app/") === 0)
											{
												elesA[i].setAttribute("href", urlSdb + href.substr(1));
											}
											else
											{
												var index = href.indexOf("?utm_source=");
												if (index > -1)
												{
													elesA[i].setAttribute("href", href.substr(0, index));
												}
											}
											
											elesA[i].setAttribute("target", "_blank");
										}
										
										var elesSpan = eleTable.querySelectorAll("span.octicon-globe");
										for (var i = 0; i < elesSpan.length; i++)
										{
											elesSpan[i].classList.add("fa");
											elesSpan[i].classList.add("fa-globe");
										}
										
										eleDiv.appendChild(eleTable);
										eleDiv.classList.remove("sgh_hidden");
									}
									
									if (GM_getValue(name_config_general_mark_owned_game) === 1)
									{
										markOwned(".sgh_sdbBox .table .app", null, function(ele)
										{
											return ele.getAttribute("data-appid");
										}, "owned", null, null, function(appCount, subCount, appOwned, subOwned)
										{
											if (appCount > 0)
											{
												var eleNav = document.querySelector(".sgh_information_nav");
												if (eleNav)
												{
													var ele = document.querySelector(".sgh_information_nav_owned");
													if (!ele)
													{
														ele = document.createElement("li");
														ele.classList.add("sidebar__navigation__item");
														ele.classList.add("sgh_information_nav_owned");
													}
													
													var content = detectorContentTemplate;
													content = content.replace("%NAME%", "App Owned");
													content = content.replace("%COUNT%", appOwned + " / " + appCount);
													content = content.replace("%HREF%", "");
													
													ele.innerHTML = content;
													eleNav.style.display = "";
													eleNav.previousElementSibling.style.display = "";
													eleNav.appendChild(ele);
												}
												
												if (appCount === appOwned)
												{
													var eleApp = document.querySelector(
														".global__image-outer-wrap[href*='store.steampowered.com/']");
													if (eleApp && !eleApp.classList.contains("sgh_appOwned"))
													{
														eleApp.classList.add("sgh_appOwned");
														warnOwned();
													}
												}
											}
										});
									}
									
								} // End onload
							});
						}
					}
				}
			}
		}
		
		// Open image
		{
			if (false)
			{
				setTimeoutCustom(function()
				{
					var eleImgs = document.querySelectorAll(".comment__toggle-attached");
					for (var i = 0; i < eleImgs.length; i++)
					{
						eleImgs[i].click();
					}
				}, 1000);
			}
		}
		
		// Train detector
		{
			var trainUrls = [];
			
			var eleDes = document.querySelector(".page__description");
			if (eleDes)
			{
				var parentGaId = getGaId(url);
				
				var eleAs = eleDes.parentElement.querySelectorAll("a[href*='/giveaway/']");
				for (var i = 0; i < eleAs.length; i++)
				{
					var href = eleAs[i].href;
					var gaId = getGaId(href);
					if (gaId !== parentGaId)
					{
						var arr = [gaId, href, eleAs[i].textContent.trim().toLowerCase(), eleAs[i]];
						trainUrls.push(arr);
					}
				}
				
				var des = "";
				
				if (trainUrls.length === 0)
				{
					var des = eleDes.textContent.trim().replace(/[^a-z0-9]/ig,"");
				}
				
				{
					var elesEm = eleDes.querySelectorAll("em");
					if (elesEm.length === 5)
					{
						var des = "";
						for (var i = 0; i < elesEm.length; i++)
						{
							des += elesEm[i].textContent.trim();
						}
					}
				}
				
				if (des.length === 5 && !/(enjoy|flash)/i.test(des))
				{
					var arr = [des, "https://www.steamgifts.com/giveaway/" + des + "/", "hidden", null];
					trainUrls.push(arr);
				
					var eleNew = document.createElement("a");
					eleNew.setAttribute("href", arr[0]);
					eleNew.setAttribute("title", "Auto Generated");
					eleNew.textContent = " Hidden: " + des;
					
					var eleMark = eleDes.querySelector(".markdown > p");
					if (eleMark)
					{
						eleMark.appendChild(document.createElement("br"));
						eleMark.appendChild(document.createElement("br"));
						eleMark.appendChild(eleNew);
					}
				}
			}
			
			trainUrls = normalizeArray2D(trainUrls);
			
			if (trainUrls.length > 0)
			{
				var rgxBack = /(back|prev|last|past|before|<|◄|⬱|←|⏮|⏪|«|⇦|⬅|↩|⇠|↤|⤶|🔽|◀️|👈)/i;
				var rgxNext = /(next|>|↪|⇢|↦|⤷|🔼|\+|▶️|👉)/i;
				var rgxNotNum = /[^0-9]/g;
				
				var trainUrl = "";
				var eleNext = null;
				var elePrev = null;
				
				if (trainUrls.length === 1)
				{
					if (!rgxBack.test(trainUrls[0][2]) || rgxNext.test(trainUrls[0][2]))
					{
						trainUrl = trainUrls[0][1];
						eleNext = trainUrls[0][3];
					}
				}
				else if (trainUrls.length === 2)
				{
					if (rgxBack.test(trainUrls[1][2]))
					{
						trainUrl = trainUrls[0][1];
						eleNext = trainUrls[0][3];
						elePrev = trainUrls[1][3];
					}
					else if (rgxBack.test(trainUrls[0][2]))
					{
						trainUrl = trainUrls[1][1];
						eleNext = trainUrls[1][3];
						elePrev = trainUrls[0][3];
					}
					else
					{
						if (trainUrls[0][3] && trainUrls[0][3].previousSibling)
						{
							var text = trainUrls[0][3].previousSibling;
							if (text.nodeType === 3)
							{
								if (rgxBack.test(text.textContent))
								{
									trainUrl = trainUrls[1][1];
									eleNext = trainUrls[1][3];
									elePrev = trainUrls[0][3];
								}
							}
						}
					}
					
					if (!trainUrl)
					{
						if (rgxNext.test(trainUrls[1][2]) && !rgxNext.test(trainUrls[0][2]))
						{
							trainUrl = trainUrls[1][1];
							eleNext = trainUrls[1][3];
							elePrev = trainUrls[0][3];
						}
						else if (rgxNext.test(trainUrls[0][2]) && !rgxNext.test(trainUrls[1][2]))
						{
							trainUrl = trainUrls[0][1];
							eleNext = trainUrls[0][3];
							elePrev = trainUrls[1][3];
						}
					}
					
					if (!trainUrl)
					{
						var num1 = trainUrls[0][2].replace(rgxNotNum, "");
						var num2 = trainUrls[1][2].replace(rgxNotNum, "");
						if (num1 && num2)
						{
							if (num1 - num2 === 2)
							{
								trainUrl = trainUrls[0][1];
								eleNext = trainUrls[0][3];
								elePrev = trainUrls[1][3];
							}
							else if (num1 - num2 === -2)
							{
								trainUrl = trainUrls[1][1];
								eleNext = trainUrls[1][3];
								elePrev = trainUrls[0][3];
							}
						}
					}
				}
				
				var eleNav = document.querySelector(".sgh_detector_nav");
				if (eleNav)
				{
					var ele = document.createElement("li");
					ele.classList.add("sidebar__navigation__item");
					
					var content = ' \n\
						<a class="sidebar__navigation__item__link" %HREF%> \n\
							<div class="sidebar__navigation__item__name">Train</div> \n\
							<div class="sidebar__navigation__item__underline"></div> \n\
							<div class="sidebar__navigation__item__count">%COUNT%</div> \n\
						</a> ';
					
					if (trainUrl !== "")
					{
						content = content.replace("%HREF%", 'href="' + trainUrl + '"');
					}
					else
					{
						content = content.replace("%HREF%", "");
					}
					
					if (trainUrls.length === 1 && trainUrl === "")
					{
						content = content.replace("%COUNT%", trainUrls.length + " End");
					}
					else
					{
						content = content.replace("%COUNT%", trainUrls.length);
					}
					
					ele.innerHTML = content;
					eleNav.style.display = "";
					eleNav.previousElementSibling.style.display = "";
					eleNav.appendChild(ele);
				}
				
				if (trainUrl !== "")
				{
					console.log("Train: " + trainUrl);
					
					var isSelf = false;
					
					var eleUser = document.querySelector(".nav__avatar-outer-wrap");
					if (eleUser)
					{
						var eleCreator = document.querySelector(".featured__columns .global__image-outer-wrap--avatar-small");
						if (eleCreator)
						{
							if (eleUser.getAttribute("href") === eleCreator.getAttribute("href"))
							{
								isSelf = true;
							}
						}
					}
					
					if (!isSelf)
					{
						setTimeoutCustom(function(trainUrl)
						{
							var isRide = false;
					
							var eleOwned = document.querySelector(".sgh_appOwned");
							if (eleOwned)
							{
								if (document.querySelector(".sidebar__error, .sidebar__entry-delete.is-hidden"))
								{
									// Skip owned
									isRide = true;
								}
								else 
								{
									var eleTime = document.querySelector("div.featured__column:nth-child(1)");
									if (eleTime && eleTime.textContent.indexOf("Begins in") > -1)
									{
										// Skip future
										isRide = true;
									}
								}
							}
							else
							{
								var divErr = document.querySelector(".sidebar__error.is-disabled");
								if (divErr)
								{
									if (divErr.textContent.trim() ===  "Exists in Account")
									{
										// Skip exists
										isRide = true;
									}
								}
							}
								
							if (!isRide 
								&& document.querySelector(".featured__container") 
								&& !document.querySelector(".featured__giveaway__hide")
								&& !document.querySelector(".sidebar__error[href^='/?login']"))
							{
								// Skip filtered
								isRide = true;
							}
							
							if (isRide)
							{
								if (GM_getValue(name_config_ga_train_rider) === 1
									&& !document.querySelector(".sgh_config.sgh_config_active"))
								{
									window.location = trainUrl;
								}
							}
						}, 3000, trainUrl);
					}
					
					if (eleNext)
					{
						eleNext.classList.add("sgh_train_next");
					}
					
					if (elePrev)
					{
						elePrev.classList.add("sgh_train_prev");
					}
					
					addKeyCtrl(document, eleNext, ["BracketRight", 221, 171]);	// ]
					addKeyCtrl(document, elePrev, ["BracketLeft", 219]);		// [
				}
			}
			
		}
		
		// Warning detector
		{
			var eleDes = document.querySelector(".page__description");
			if (eleDes)
			{
				var des = eleDes.textContent.trim();
				if (/(warn| not | only |n't |dont |doesnt )/i.test(des))
				{
					var eleNav = document.querySelector(".sgh_detector_nav");
					if (eleNav)
					{
						var ele = document.createElement("li");
						ele.classList.add("sidebar__navigation__item");
						
						var content = ' \n\
							<a class="sidebar__navigation__item__link"> \n\
								<div class="sidebar__navigation__item__name">Warning</div> \n\
								<div class="sidebar__navigation__item__underline"></div> \n\
								<div class="sidebar__navigation__item__count">Read Description</div> \n\
							</a> ';
						
						ele.innerHTML = content;
						eleNav.style.display = "";
						eleNav.previousElementSibling.style.display = "";
						eleNav.appendChild(ele);
					}
				}
			}
		}
		
		// Filtered detector
		{
			var eleDes = document.querySelector(".featured__giveaway__hide");
			if (!eleDes && !document.querySelector(".sidebar__error[href^='/?login']"))
			{
				var eleNav = document.querySelector(".sgh_detector_nav");
				if (eleNav)
				{
					var ele = document.createElement("li");
					ele.classList.add("sidebar__navigation__item");
					
					var content = ' \n\
						<a class="sidebar__navigation__item__link"> \n\
							<div class="sidebar__navigation__item__name">Warning</div> \n\
							<div class="sidebar__navigation__item__underline"></div> \n\
							<div class="sidebar__navigation__item__count">Filtered Game</div> \n\
						</a> ';
					
					ele.innerHTML = content;
					eleNav.style.display = "";
					eleNav.previousElementSibling.style.display = "";
					eleNav.appendChild(ele);
				}
			}
		}
		
		// Information detector
		{
			var eleNav = document.querySelector(".sgh_information_nav");
			if (eleNav)
			{
				var eleWhl = document.querySelector(".featured__column--whitelist");
				if (eleWhl)
				{
					var ele = document.createElement("li");
					ele.classList.add("sidebar__navigation__item");
					
					var content = detectorContentTemplate;
					content = content.replace("%NAME%", "Restriction");
					content = content.replace("%COUNT%", eleWhl.textContent.trim());
					content = content.replace("%HREF%", "");
					
					ele.innerHTML = content;
					eleNav.style.display = "";
					eleNav.previousElementSibling.style.display = "";
					eleNav.appendChild(ele);
				}
				
				var eleIvt = document.querySelector(".featured__column--invite-only");
				if (eleIvt)
				{
					var ele = document.createElement("li");
					ele.classList.add("sidebar__navigation__item");
					
					var content = detectorContentTemplate;
					content = content.replace("%NAME%", "Restriction");
					content = content.replace("%COUNT%", eleIvt.textContent.trim());
					content = content.replace("%HREF%", "");
					
					ele.innerHTML = content;
					eleNav.style.display = "";
					eleNav.previousElementSibling.style.display = "";
					eleNav.appendChild(ele);
				}
				
				var eleRgn = document.querySelector(".featured__column--region-restricted");
				if (eleRgn)
				{
					var ele = document.createElement("li");
					ele.classList.add("sidebar__navigation__item");
					
					var content = detectorContentTemplate;
					content = content.replace("%NAME%", "Region");
					content = content.replace("%COUNT%", "Restricted");
					content = content.replace("%HREF%", eleRgn.href ? ('href="' + eleRgn.href + '"') : "");
					
					ele.innerHTML = content;
					eleNav.style.display = "";
					eleNav.previousElementSibling.style.display = "";
					eleNav.appendChild(ele);
				}
				
				var eleGrp = document.querySelector(".featured__column--group");
				if (eleGrp)
				{
					var ele = document.createElement("li");
					ele.classList.add("sidebar__navigation__item");
					
					var content = detectorContentTemplate;
					content = content.replace("%NAME%", "Group");
					content = content.replace("%COUNT%", eleGrp.textContent.replace("Gifts for ", "").trim());
					content = content.replace("%HREF%", 'href="' + eleGrp.getAttribute("href") + '"');
					
					ele.innerHTML = content;
					eleNav.style.display = "";
					eleNav.previousElementSibling.style.display = "";
					eleNav.appendChild(ele);
				}
				
				var eleLvl = document.querySelector(".featured__column--contributor-level");
				if (eleLvl)
				{
					var ele = document.createElement("li");
					ele.classList.add("sidebar__navigation__item");
					
					var content = detectorContentTemplate;
					content = content.replace("%NAME%", "Level");
					content = content.replace("%COUNT%", eleLvl.textContent.replace("Level ", "").trim());
					content = content.replace("%HREF%", "");
					
					ele.innerHTML = content;
					eleNav.style.display = "";
					eleNav.previousElementSibling.style.display = "";
					eleNav.appendChild(ele);
				}
			}
		}
		
		// Show average
		{
			var rgxCopy = /[0-9,]+ Copies/;
			
			var eleHead = document.querySelector(".featured__heading__small");
			if (eleHead)
			{
				var arrCopy = rgxCopy.exec(eleHead.textContent);
				if (arrCopy)
				{						
					var copyStr = arrCopy[0].replace(" Copies", "");
					var copy = parseInt(copyStr.replace(/,/g, "")) || 1;
					
					var eleEntry = document.querySelector(".live__entry-count");
					if (eleEntry)
					{
						var entryStr = eleEntry.textContent;
						var entry = parseInt(entryStr.replace(/,/g, "")) || 0;
						
						var avg = (Math.round(entry / copy) || 1).toLocaleString("en-US");
						
						var ele = document.createElement("li");
						ele.classList.add("sidebar__navigation__item");
						
						var content = detectorContentTemplate;
						content = content.replace("%NAME%", "Average Entries");
						content = content.replace("%COUNT%", avg);
						content = content.replace("%HREF%", "");
						
						ele.innerHTML = content;
						
						insertAfterElement(ele, eleEntry.parentElement.parentElement);
					}
				}
			}
		}
		
		// Bigger buttons
		{
			if (GM_getValue(name_config_ga_bigger) === 1)
			{
				GM_addStyle
				(" \
					.sidebar__entry-insert, .sidebar__entry-delete, \
					  .sidebar__entry-loading, .sidebar__error { \
					    line-height: 64px; } \
				");
			}
		}
	}
	
	if (url === "https://www.steamgifts.com/" || url === "https://www.steamgifts.com" 
		|| url.indexOf("steamgifts.com/?") > -1 || url.indexOf("steamgifts.com?") > -1 
		|| url.indexOf("/giveaways/search") > -1)
	{
		var isInactive = getQueryByName("q") !== "" 
			|| getQueryByName("sub") !== "" 
			|| getQueryByName("app") !== ""
			|| GM_getValue(name_config_home_hide_entered) === 0;
		
		var eleLast = null;
		var eles = document.querySelectorAll(".giveaway__row-inner-wrap");
		for (var i = 0; i < eles.length; i++)
		{
			if (eles[i].classList.contains("is-faded"))
			{
				eles[i].parentElement.classList.add("sgh_rowHidden");
				if (isInactive)
				{
					eles[i].parentElement.classList.add("sgh_rowHidden_inactive");
				}
			}
			else
			{
				eles[i].parentElement.classList.add("sgh_rowShown");
				eleLast = eles[i];
			}
		}
		
		if (eleLast)
		{
			eleLast.parentElement.classList.add("sgh_rowLast");
		}
	
		// Toggle entered rows
		var eleSetting = document.querySelector(".page__heading a[href='/account/settings/giveaways']");
		if (eleSetting)
		{
			var expandTitle = "Toggle Entered Rows: ";
			
			var eleExpand = document.createElement("a");
			eleExpand.setAttribute("href", "");
			eleExpand.setAttribute("onclick", "return false;");
			eleExpand.setAttribute("data-mode", isInactive ? "hide" : "show");
			eleExpand.innerHTML = '<i class="fa fa-expand"></i>';
			eleExpand.title = expandTitle + (isInactive ? "Show" : "Hide");
			
			insertBeforeElement(eleExpand, eleSetting);
			
			eleExpand.addEventListener("click", function(ev)
			{
				var ele = ev.target;
				if (ele.tagName === "I")
				{
					ele = ele.parentElement;
				}
				
				console.log(ele.dataset.mode);
				
				if (ele.dataset.mode === "hide")
				{
					ele.title = expandTitle + "Hide";
					
					var elesRowShown = document.querySelectorAll(
						":not(.pinned-giveaways__inner-wrap) > .sgh_rowShown.sgh_rowShown_inactive");
					for (var i = 0; i < elesRowShown.length; i++)
					{
						elesRowShown[i].classList.remove("sgh_rowShown_inactive");
					}
					
					var elesRowHidden = document.querySelectorAll(
						":not(.pinned-giveaways__inner-wrap) > .sgh_rowHidden.sgh_rowHidden_inactive");
					for (var i = 0; i < elesRowHidden.length; i++)
					{
						elesRowHidden[i].classList.remove("sgh_rowHidden_inactive");
					}
					
					var eleRowLast = document.querySelector(
						":not(.pinned-giveaways__inner-wrap) > .sgh_rowLast.sgh_rowLast_inactive");
					if (eleRowLast)
					{
						eleRowLast.classList.remove("sgh_rowLast_inactive");
					}
					
					ele.dataset.mode = "show";
				}
				else if (ele.dataset.mode === "show")
				{
					ele.title = expandTitle + "Show";
					
					var elesRowHidden = document.querySelectorAll(
						":not(.pinned-giveaways__inner-wrap) > .sgh_rowHidden");
					for (var i = 0; i < elesRowHidden.length; i++)
					{
						elesRowHidden[i].classList.add("sgh_rowHidden_inactive");
					}
					
					var eleRowLast = document.querySelector(
						":not(.pinned-giveaways__inner-wrap) > .sgh_rowLast");
					if (eleRowLast)
					{
						eleRowLast.classList.add("sgh_rowLast_inactive");
					}
					
					ele.dataset.mode = "invert";
				}
				else // invert
				{
					ele.title = expandTitle + "Invert";
					
					var elesRowShown = document.querySelectorAll(
						":not(.pinned-giveaways__inner-wrap) > .sgh_rowShown");
					for (var i = 0; i < elesRowShown.length; i++)
					{
						elesRowShown[i].classList.add("sgh_rowShown_inactive");
					}
					
					ele.dataset.mode = "hide";
				}
				
				/*var eleWidget = document.querySelector(".page__heading");
				if (eleWidget)
				{
					eleWidget.scrollIntoView();
					window.scrollBy(0, -50);
				}*/
			});
		}
		
		var elePageCopy = document.querySelector(".sgh_page");
		if (elePageCopy)
		{
			elePageCopy.classList.add("sgh_page_border");
		}
		
		var eleSearchNew = document.querySelector(".sidebar__navigation__item__link[href='/giveaways/search?type=new']");
		if (eleSearchNew)
		{
			var eleNav = eleSearchNew.parentElement.parentElement;
			
			var eleNew;
			var eleHead;
			var eleUl;
			
			eleHead = document.createElement("h3");
			eleHead.classList.add("sidebar__heading");
			eleHead.textContent = "Filters";
			insertAfterElement(eleHead, eleNav);
			
			eleUl = document.createElement("ul");
			eleUl.classList.add("sidebar__navigation");
			insertAfterElement(eleUl, eleHead);

			eleNew = document.createElement("li");
			eleNew.classList.add("sidebar__navigation__item");
			eleNew.classList.add("sgh_region_1");
			eleNew.innerHTML = 
				'<a class="sidebar__navigation__item__link" href="/giveaways/search?region_restricted=true"> \n\
					<div class="sidebar__navigation__item__name">Region</div> \n\
					<div class="sidebar__navigation__item__underline"></div> \n\
					<div class="sidebar__navigation__item__count">Restricted</div> \n\
				</a>';
			eleUl.appendChild(eleNew);
			
			eleNew = document.createElement("li");
			eleNew.classList.add("sidebar__navigation__item");
			eleNew.classList.add("sgh_level_1");
			eleNew.innerHTML = 
				'<a class="sidebar__navigation__item__link" href="/giveaways/search?level_min=1"> \n\
					<div class="sidebar__navigation__item__name">Level</div> \n\
					<div class="sidebar__navigation__item__underline"></div> \n\
					<div class="sidebar__navigation__item__count">Min 1</div> \n\
				</a>';
			eleUl.appendChild(eleNew);
			
			eleNew = document.createElement("li");
			eleNew.classList.add("sidebar__navigation__item");
			eleNew.classList.add("sgh_copy_2");
			eleNew.innerHTML = 
				'<a class="sidebar__navigation__item__link" href="/giveaways/search?copy_min=2"> \n\
					<div class="sidebar__navigation__item__name">Copy</div> \n\
					<div class="sidebar__navigation__item__underline"></div> \n\
					<div class="sidebar__navigation__item__count">Min 2</div> \n\
				</a>';
			eleUl.appendChild(eleNew);
			
			eleNew = document.createElement("li");
			eleNew.classList.add("sidebar__navigation__item");
			eleNew.classList.add("sgh_point_0");
			eleNew.innerHTML = 
				'<a class="sidebar__navigation__item__link" href="/giveaways/search?point_max=0"> \n\
					<div class="sidebar__navigation__item__name">Point</div> \n\
					<div class="sidebar__navigation__item__underline"></div> \n\
					<div class="sidebar__navigation__item__count">Max 0</div> \n\
				</a>';
			eleUl.appendChild(eleNew);
			
			eleNew = document.createElement("li");
			eleNew.classList.add("sidebar__navigation__item");
			eleNew.classList.add("sgh_entry_100");
			eleNew.innerHTML = 
				'<a class="sidebar__navigation__item__link" href="/giveaways/search?entry_max=100"> \n\
					<div class="sidebar__navigation__item__name">Entry</div> \n\
					<div class="sidebar__navigation__item__underline"></div> \n\
					<div class="sidebar__navigation__item__count">Max 100</div> \n\
				</a>';
			eleUl.appendChild(eleNew);
			
			eleNew = document.createElement("li");
			eleNew.classList.add("sidebar__navigation__item");
			eleNew.classList.add("sgh_entry_500");
			eleNew.innerHTML = 
				'<a class="sidebar__navigation__item__link" href="/giveaways/search?entry_max=500"> \n\
					<div class="sidebar__navigation__item__name">Entry</div> \n\
					<div class="sidebar__navigation__item__underline"></div> \n\
					<div class="sidebar__navigation__item__count">Max 500</div> \n\
				</a>';
			eleUl.appendChild(eleNew);

			eleNew = document.createElement("li");
			eleNew.classList.add("sidebar__navigation__item");
			eleNew.classList.add("sgh_entry_1000");
			eleNew.innerHTML = 
				'<a class="sidebar__navigation__item__link" href="/giveaways/search?entry_max=1000"> \n\
					<div class="sidebar__navigation__item__name">Entry</div> \n\
					<div class="sidebar__navigation__item__underline"></div> \n\
					<div class="sidebar__navigation__item__count">Max 1000</div> \n\
				</a>';
			eleUl.appendChild(eleNew);

			eleNew = document.createElement("li");
			eleNew.classList.add("sidebar__navigation__item");
			eleNew.classList.add("sgh_entry_min_1000");
			eleNew.innerHTML = 
				'<a class="sidebar__navigation__item__link" href="/giveaways/search?entry_min=1000&amp;copy_max=1"> \n\
					<div class="sidebar__navigation__item__name">Entry</div> \n\
					<div class="sidebar__navigation__item__underline"></div> \n\
					<div class="sidebar__navigation__item__count">Over 1000</div> \n\
				</a>';
			eleUl.appendChild(eleNew);
			
			eleHead = document.createElement("h3");
			eleHead.classList.add("sidebar__heading");
			eleHead.textContent = "Discussions";
			insertAfterElement(eleHead, eleUl);
			
			eleUl = document.createElement("ul");
			eleUl.classList.add("sidebar__navigation");
			insertAfterElement(eleUl, eleHead);
			
			eleNew = document.createElement("li");
			eleNew.classList.add("sidebar__navigation__item");
			eleNew.innerHTML = 
				'<a class="sidebar__navigation__item__link" href="/discussions/search?q=train&h=end" target="_blank"> \n\
					<div class="sidebar__navigation__item__name">Trains</div> \n\
					<div class="sidebar__navigation__item__underline"></div> \n\
				</a>';
			eleUl.appendChild(eleNew);
			
			eleNew = document.createElement("li");
			eleNew.classList.add("sidebar__navigation__item");
			eleNew.innerHTML = 
				'<a class="sidebar__navigation__item__link" href="/discussions/deals" target="_blank"> \n\
					<div class="sidebar__navigation__item__name">Deals</div> \n\
					<div class="sidebar__navigation__item__underline"></div> \n\
				</a>';
			eleUl.appendChild(eleNew);
			
			var qCopyMin = getQueryByName("copy_min");
			var qEntryMax = getQueryByName("entry_max");
			var qEntryMin = getQueryByName("entry_min");
			var qRegion = getQueryByName("region_restricted");
			var qLevelMin = getQueryByName("level_min");
			var qPointMax = getQueryByName("point_max");
			
			
			if (qCopyMin === "2" || qEntryMax === "100" || qEntryMax === "500" || qEntryMax === "1000" 
				|| qEntryMin === "1000"|| qRegion === "true" || qLevelMin === "1" || qPointMax === "0")
			{
				var eleSelected = document.querySelector(".sidebar__navigation__item.is-selected .fa-caret-right");
				if (eleSelected)
				{
					eleSelected.parentElement.parentElement.classList.remove("is-selected");
					eleSelected.parentElement.removeChild(eleSelected);
					
					var sEntry = "";
					
					if (qCopyMin === "2")
					{
						sEntry = ".sgh_copy_2";
					}
					else if (qRegion === "true")
					{
						sEntry = ".sgh_region_1";
					}
					else if (qLevelMin === "1")
					{
						sEntry = ".sgh_level_1";
					}
					else if (qPointMax === "0")
					{
						sEntry = ".sgh_point_0";
					}
					else if (qEntryMin === "1000")
					{
						sEntry = ".sgh_entry_min_" + qEntryMin;
					}
					else
					{
						sEntry = ".sgh_entry_" + qEntryMax;
					}
					
					var eleEntry = document.querySelector(sEntry);
					if (eleEntry)
					{
						eleEntry.classList.add("is-selected");
						
						var eleI = document.createElement("i");
						eleI.classList.add("fa");
						eleI.classList.add("fa-caret-right");
						insertBeforeElement(eleI, eleEntry.firstElementChild.firstElementChild);
					}
				}
			}
		}
		
		// Move poll when voted
		{
			var elePoll = document.querySelector("div.homepage_heading");
			if (elePoll && elePoll.textContent.trim() === "Community Poll" 
				&& elePoll.parentElement.querySelector(".poll--enable-results"))
			{
				var eleParent = elePoll.parentElement.parentElement;
				insertAfterElement(eleParent, eleParent.nextElementSibling);
			}
		}
	}
	
	if (url.indexOf("/giveaways/search") > -1)
	{
		if (getQueryByName("page") !== "")
		{
			var eleWidget = document.querySelector(".page__heading");
			if (eleWidget)
			{
				if (document.querySelectorAll(".giveaway__row-outer-wrap:not(.sgh_rowHidden)").length > 2)
				{
					setTimeoutCustom(function()
					{
						eleWidget.scrollIntoView();
						window.scrollBy(0, -50);
					}, 300);
				}
			}
		}
	}
	
	if (url.indexOf("/user/") > -1)
	{
		var eleLevel = document.querySelector("div.featured__table__column:nth-child(2) \
			> div:nth-child(4) > div:nth-child(2) > span:nth-child(1)");
		if (eleLevel)
		{
			var tooltip = eleLevel.getAttribute("data-ui-tooltip");
			var json = JSON.parse(tooltip);
			if (json && json.rows[0].columns[0].name === "Contributor Level")
			{
				document.title = title + " - " + json.rows[0].columns[1].name;
			}
		}
	}
	
	if (url.indexOf("/account/settings/giveaways/filters") > -1)
	{
		if (GM_getValue(name_config_general_mark_owned_game) === 1)
		{
			markOwned(".table__column__secondary-link[href*='store.steampowered.com/']", function(eleTarget)
			{
				return eleTarget.parentElement.parentElement
					.parentElement.parentElement;
			}, null, "sgh_rowEnterOwned", "sgh_rowEnterNotInterested", "sgh_rowEnterWished");
		}
	}
	
	if (url.indexOf("/giveaways/created") > -1 
		|| url.indexOf("/giveaways/entered") > -1 
		|| url.indexOf("/giveaways/wishlist") > -1 
		|| url.indexOf("/giveaways/won") > -1 
		|| url.indexOf("/account/steam/games") > -1 
		|| url.indexOf("/account/steam/wishlist") > -1 
		|| url.indexOf("/bundle-games") > -1 )
	{
		if (GM_getValue(name_config_general_mark_owned_game) === 1)
		{
			markOwned(".global__image-inner-wrap", function(eleTarget)
			{
				return eleTarget.parentElement.parentElement.parentElement.parentElement;
			}, function(eleTarget)
			{
				return eleTarget.style.backgroundImage;
			}, "sgh_rowEnterOwned", "sgh_rowEnterNotInterested", "sgh_rowEnterWished");
			
			markOwned(".table_image_thumbnail", function(eleTarget)
			{
				return eleTarget.parentElement.parentElement.parentElement;
			}, function(eleTarget)
			{
				return eleTarget.style.backgroundImage;
			}, "sgh_rowEnterOwned", "sgh_rowEnterNotInterested", "sgh_rowEnterWished");
		}
		
		if (url.indexOf("/giveaways/entered") > -1)
		{
			// Show average
			{
				var rgxCopy = /[0-9,]+ Copies/;
				
				var elesHead = document.querySelectorAll(".table__column__heading");
				for (var i = 0; i < elesHead.length; i++)
				{
					var arrCopy = rgxCopy.exec(elesHead[i].textContent);
					if (arrCopy)
					{						
						var copyStr = arrCopy[0].replace(" Copies", "");
						var copy = parseInt(copyStr.replace(/,/g, "")) || 1;
						
						var eleEntry = elesHead[i].parentElement.parentElement.parentElement
							.lastElementChild.previousElementSibling.previousElementSibling;
						var entryStr = eleEntry.textContent;
						var entry = parseInt(entryStr.replace(/,/g, "")) || 0;
						
						eleEntry.innerHTML = entryStr
							+ " <br/> Avg: " + (Math.round(entry / copy) || 1).toLocaleString("en-US");
						
					}
				}
			}
		}
		else if (url.indexOf("/giveaways/won") > -1)
		{
			var elesIcon = document.querySelectorAll(".icon_to_clipboard");
			for (var i = 0; i < elesIcon.length; i++)
			{
				elesIcon[i].addEventListener("click", function(ev)
				{
					GM_setClipboard(ev.target.getAttribute("data-clipboard-text"));
				});
			}
			
			var eleHead = document.querySelector(".widget-container .page__heading__breadcrumbs");
			if (eleHead)
			{			
				var eleA = document.createElement("a");
				eleA.setAttribute("href", "https://store.steampowered.com/account/registerkey");
				eleA.innerHTML = '<i class="fa fa-key"></i>';
				eleA.title = "Activate product key on Steam";
				eleA.setAttribute("target", "_blank");
				
				insertAfterElement(eleA, eleHead);
			}
		}
	}
	
	// Deprecated
	if (url.indexOf("/sales/") > -1)
	{
		if (GM_getValue(name_config_general_mark_owned_game) === 1)
		{
			markOwned(".global__image-inner-wrap", 
				function(eleTarget)
				{
					return eleTarget.parentElement.parentElement
						.parentElement.parentElement;
				},
				function(eleTarget)
				{
					return eleTarget.style.backgroundImage;
				}, "sgh_rowEnterOwned", "sgh_rowEnterNotInterested", "sgh_rowEnterWished");
		}
	}
	
	if (url.indexOf("/discussion/") > -1 || url.indexOf("/trade/") > -1)
	{
		if (GM_getValue(name_config_general_mark_owned_game) === 1)
		{
			markOwned("a[href*='store.steampowered.com/'], a[href*='steamdb.info/']", function(eleTarget, markType)
			{
				var isRow = false;
				
				var eleLabel = eleTarget.parentElement.parentElement;
				
				if (eleLabel.tagName !== "TR")
				{
					eleLabel = eleLabel.parentElement;
				}
				if (eleLabel.tagName !== "TR")
				{
					eleLabel = eleLabel.parentElement;
				}
				if (eleLabel.tagName === "TR")
				{
					isRow = true;
					if (markType === 1)
					{
						eleLabel.classList.add("sgh_rowEnterOwned");
					}
					else if (markType === 2)
					{
						eleLabel.classList.add("sgh_rowEnterNotInterested");
					}
					else if (markType === 3)
					{
						eleLabel.classList.add("sgh_rowEnterWished");
					}
				}
				
				if (!isRow)
				{
					if (markType === 1)
					{
						eleTarget.classList.add("sgh_linkOwned");
					}
					else if (markType === 2)
					{
						eleTarget.classList.add("sgh_linkNotInterested");
					}
					else if (markType === 3)
					{
						eleTarget.classList.add("sgh_linkWished");
					}
				}
			}, null, "", "", "");
		}
		
		var eleContent = document.querySelector(".comment__display-state");
		if (eleContent)
		{
			// Show hidden GA
			{
				var hidden = "";
				var elesHidden = eleContent.querySelectorAll("strong");
				if (elesHidden.length === 5)
				{
					for (var i = 0; i < elesHidden.length; i++)
					{
						hidden += elesHidden[i].textContent.trim();
					}
				}
				
				if (hidden.length === 5)
				{
					var eleNew = document.createElement("a");
					eleNew.setAttribute("href", "https://www.steamgifts.com/giveaway/" + hidden + "/");
					eleNew.setAttribute("title", "Auto Generated");
					eleNew.textContent = " Hidden: " + hidden;
					
					var elePLast = eleContent.querySelector(".comment__description > p:last-child");
					if (elePLast)
					{
						var elePNew = document.createElement("p");
						elePNew.appendChild(eleNew);
						
						insertAfterElement(elePNew, elePLast)
					}
				}
			}
		
			// Detect GA
			{
				var elesA = eleContent.querySelectorAll("a");
				for (var i = 0; i < elesA.length; i++)
				{
					if (elesA[i].getAttribute("href").length === 5)
					{
						elesA[i].setAttribute("href", "https://www.steamgifts.com/giveaway/" 
							+ elesA[i].getAttribute("href") + "/");
					}
				}

				var elesGa = eleContent.querySelectorAll("a[href*='steamgifts.com/giveaway/'], a[href^='/giveaway/']");
				var elesTl = eleContent.querySelectorAll("a[href*='sgtools.info/giveaways/']");
				var elesPz = eleContent.querySelectorAll("a[href*='itstoohard.com/puzzle/'], a[href*='jigidi.com/']");
				
				function countUrl(eles)
				{
					var urls = [];
					
					for (var i = 0; i < eles.length; i++)
					{
						urls.push(eles[i].getAttribute("href"));
					}
					
					urls = normalizeArray(urls);
					
					return urls.length;
				}
				
				var countGa = countUrl(elesGa);
				var countTl = countUrl(elesTl);
				var countPz = countUrl(elesPz);
				
				if (countPz + countTl + countGa > 0)
				{
					var eleSide = document.querySelector(".sidebar__search-container");
					if (eleSide)
					{
						var eleH = document.createElement("h3");
						eleH.classList.add("sidebar__heading");
						eleH.classList.add("sgh_detector_header");
						eleH.textContent = " Detector ";
						insertAfterElement(eleH, eleSide);
						
						var eleNav = document.createElement("ul");
						eleNav.classList.add("sidebar__navigation");
						eleNav.classList.add("sgh_detector_nav");
						insertAfterElement(eleNav, eleH);
						
						if (countGa > 0)
						{
							var ele = document.createElement("li");
							ele.classList.add("sidebar__navigation__item");
							
							var content = detectorContentTemplate;
							content = content.replace("%NAME%", "Giveaway");
							content = content.replace("%COUNT%", countGa);
							
							if (countGa === 1)
							{
								content = content.replace("%HREF%", 'href="' + elesGa[0].getAttribute("href") + '"');
							}
							else
							{
								content = content.replace("%HREF%", "");
							}
							
							ele.innerHTML = content;
							eleNav.appendChild(ele);
						}
						
						if (countTl > 0)
						{
							var ele = document.createElement("li");
							ele.classList.add("sidebar__navigation__item");
							
							var content = detectorContentTemplate;
							content = content.replace("%NAME%", "SGTools");
							content = content.replace("%COUNT%", countTl);
							
							if (countTl === 1)
							{
								content = content.replace("%HREF%", 'href="' + elesTl[0].getAttribute("href") + '"');
							}
							else
							{
								content = content.replace("%HREF%", "");
							}
							
							ele.innerHTML = content;
							eleNav.appendChild(ele);
						}
						
						if (countPz > 0)
						{
							var ele = document.createElement("li");
							ele.classList.add("sidebar__navigation__item");
							
							var content = detectorContentTemplate;
							content = content.replace("%NAME%", "Puzzle");
							content = content.replace("%COUNT%", countPz);
							
							if (countPz === 1)
							{
								content = content.replace("%HREF%", 'href="' + elesPz[0].getAttribute("href") + '"');
							}
							else
							{
								content = content.replace("%HREF%", "");
							}
							
							ele.innerHTML = content;
							eleNav.appendChild(ele);
						}
					}
				}
			}
		}
		
		// Add GA shortcut
		if (url.indexOf("/discussion/") > -1)
		{
			var eleSide = document.querySelector(".sidebar");
			if (eleSide)
			{
				var eleForm = document.createElement("form");
				eleForm.classList.add("sgh_ga_shortcut_form");
				eleForm.setAttribute("onsubmit", "return false;");
				
				var eleDiv = document.createElement("div");
				eleDiv.classList.add("sidebar__search-container");
				eleForm.appendChild(eleDiv);
				
				var eleInput = document.createElement("input");
				eleInput.classList.add("sgh_ga_shortcut_input");
				eleInput.setAttribute("type", "text");
				eleInput.setAttribute("placeholder", "Insert GA ID here...");
				eleInput.setAttribute("value", "");
				eleDiv.appendChild(eleInput);
				
				eleInput.addEventListener("keyup", function(e)
				{
					e.target.value = e.target.value.replace(/[^a-z0-9]/ig, "");
					
					if (e.keyCode === 13)
					{
						var eleLink = document.querySelector(".sgh_ga_shortcut_link");
						if (eleLink)
						{
							var val = e.target.value;
							if (val.length === 5)
							{
								eleA.setAttribute("href", "https://www.steamgifts.com/giveaway/" + val + "/");
								eleA.click();
							}
						}
					}
				});
				
				var eleA = document.createElement("a");
				eleA.classList.add("sgh_ga_shortcut_link");
				eleA.setAttribute("target", "_blank");
				eleA.setAttribute("href", "");
				eleDiv.appendChild(eleA);
				
				var eleI = document.createElement("i");
				eleI.classList.add("fa");
				eleI.classList.add("fa-gift");
				eleDiv.appendChild(eleI);
				
				eleSide.appendChild(eleForm);
			}
		}
		
		// Change GA code to url
		{
			var rgxGa = /(https:\/\/www\.steamgifts\.com\/giveaway\/|https?:\/\/www\.sgtools\.info\/giveaways\/)[^ )}]+/ig;
			
			var elesCode = document.querySelectorAll(".comment__description > pre > code, .comment__description > p > code");
			for (var i = 0; i < elesCode.length; i++)
			{
				var resGa = elesCode[i].textContent.match(rgxGa);
				if (resGa)
				{
					var gaIdArr = [];
					
					var elesAGa = elesCode[i].parentElement.parentElement.querySelectorAll(" \
						a[href*='steamgifts.com/giveaway/'] \
						, a[href^='/giveaway/'] \
						, a[href*='sgtools.info/giveaways/'] ");
					for (var j = 0; j < elesAGa.length; j++)
					{
						gaIdArr.push(getGaId(elesAGa[j].href));
					}
					
					gaIdArr = normalizeArray(gaIdArr);
				
					var elePre = null;
					var countShow = 0;
					
					for (var j = 0; j < resGa.length; j++)
					{
						var urlGa = resGa[j];
						var gaId = getGaId(urlGa);
						
						if (gaId.length > 0)
						{
							if (!elePre)
							{
								elePre = document.createElement("pre");
								insertAfterElement(elePre, elesCode[i].parentElement);
							}
							
							var eleA = document.createElement("a");
							eleA.setAttribute("href", urlGa);
							eleA.textContent = urlGa;
							elePre.appendChild(eleA);
							elePre.appendChild(document.createElement("br"));
							
							if (gaIdArr.indexOf(gaId) > -1)
							{
								eleA.classList.add("sgh_hidden");
								eleA.nextElementSibling.classList.add("sgh_hidden");
							}
							else
							{
								countShow++;
							}
						}
					}
					
					if (countShow < 1)
					{
						elePre.classList.add("sgh_hidden");
					}
				}
			}
		}
		
	}
	
	if (url.indexOf("/discussions/search") > -1)
	{
		if (getQueryByName("h") === "end")
		{
			var rgxEnd = /[^a-z](ended|expired|finished|over)[^a-z]/i;
			var elesHead = document.querySelectorAll(".table__column__heading");
			for (var i = 0; i < elesHead.length; i++)
			{
				if (rgxEnd.test(" " + elesHead[i].textContent + " "))
				{
					elesHead[i].parentElement.parentElement.parentElement.parentElement.classList.add("sgh_rowHidden");
				}
			}
		}
	}
	
	// Hide owned GA
	if (GM_getValue(name_config_general_mark_owned_giveaway) === 1)
	{
		if (url.indexOf("/giveaway/") > -1 || url.indexOf("/discussion/") > -1)
		{
			var eleHead = document.querySelector(".widget-container .page__heading__breadcrumbs");
			
			var eleHide = document.createElement("a");
			eleHide.setAttribute("href", "");
			eleHide.setAttribute("onclick", "return false;");
			eleHide.setAttribute("data-mode", "hide");
			eleHide.innerHTML = '<i class="fa fa-expand"></i>';
			eleHide.title = "Toggle Hide Owned GA";
			
			insertAfterElement(eleHide, eleHead);
			
			eleHide.addEventListener("click", function(ev)
			{
				var ele = ev.target;
				if (ele.tagName === "I")
				{
					ele = ele.parentElement;
				}
				
				var eleStyle = document.querySelector("#sgh_style_hide_owned_ga");
				if (!eleStyle)
				{
					eleStyle = document.createElement("style");
					eleStyle.id = "sgh_style_hide_owned_ga";
					eleStyle.setAttribute("type", "text/css");
					document.head.appendChild(eleStyle);
				}
				
				if (ele.dataset.mode === "hide")
				{
					eleStyle.textContent = " .sgh_gaOwned { visibility: hidden; } ";
					ele.dataset.mode = "show";
				}
				else
				{
					eleStyle.textContent = "";
					ele.dataset.mode = "hide";
				}
			});
		}
	}
	
	var eleLogout = document.querySelector(".nav__row.js__logout");
	if (eleLogout)
	{
		var eleRight = document.querySelector(".nav__right-container > .nav__button-container");
		if (eleRight)
		{
			var eleEnt = document.createElement("div");
			eleEnt.setAttribute("class", "nav__button-container nav__button-container--notification")
			eleEnt.innerHTML = '<a title="Giveaways Entered" class="nav__button" \n\
				href="/giveaways/entered"><i class="fa fa-tag"></i></a>';
			
			insertBeforeElement(eleEnt, eleRight);
		}
	}
	
	var divBtn = document.querySelectorAll(".nav__button-container--inactive");
	for (var i = 0; i < divBtn.length; i++)
	{
		divBtn[i].classList.remove("nav__button-container--inactive");
	}
			
	// Move Ads
	{
		var eleAdsSide = document.querySelector(".sidebar__mpu");
		if (eleAdsSide)
		{
			eleAdsSide.parentElement.appendChild(eleAdsSide);
		}
		
		var elePat = document.querySelector("a[href*='://www.patreon.com/steamgifts']");
		if (elePat)
		{
			elePat.parentElement.parentElement.appendChild(elePat.parentElement);
		}
		
		var eleHb = document.querySelector(".humble_block");
		if (eleHb)
		{
			eleHb.parentElement.parentElement.appendChild(eleHb.parentElement);
		}
		
		var eleAdsBar = document.querySelector("div:not(.sidebar__mpu) > div[id^='div-gpt-ad-']");
		if (eleAdsBar)
		{
			eleAdsBar.parentElement.parentElement.appendChild(eleAdsBar.parentElement);
		}
	}
	
	setTimeout(function()
	{
		if (window === window.parent)
		{
			document.body.classList.add("sgh_body");
			if (document.querySelector(".SGv2-Dark-button:not(.light)"))
			{
				document.body.classList.add("sgh_SGv2Dark");
			}
		}
	}, 100);
	
	window.addEventListener("beforeunload", function(e) 
	{
		clearTimeoutAll();
		clearIntervalAll();
	});
}

var name_config_sgh_welcome = "sgh_config_sgh_welcome";
var name_config_sgh_active = "sgh_config_sgh_active";
var name_config_general_mark_owned_game = "sgh_config_general_mark_owned_game";
var name_config_general_mark_owned_giveaway = "sgh_config_general_mark_owned_giveaway";
var name_config_home_hide_entered = "sgh_config_home_hide_entered";
//var name_config_ga_autoenter = "sgh_config_ga_autoenter";
var name_config_ga_title = "sgh_config_ga_title";
var name_config_ga_train_rider = "sgh_config_ga_train_rider";
var name_config_ga_bigger = "sgh_config_ga_bigger";
var name_config_ga_sdb = "sgh_config_ga_sdb";

var name_profile_json = "sgh_profile_json";
var name_profile_time = "sgh_profile_time";

function initAllConfig()
{
	// Short-circuit evaluation
	GM_getValue(name_config_sgh_welcome, -1) === -1 && GM_setValue(name_config_sgh_welcome, 0);
	
	GM_getValue(name_config_sgh_active, -1) === -1 && GM_setValue(name_config_sgh_active, 1);
	GM_getValue(name_config_general_mark_owned_game, -1) === -1 && GM_setValue(name_config_general_mark_owned_game, 1);
	GM_getValue(name_config_general_mark_owned_giveaway, -1) === -1 && GM_setValue(name_config_general_mark_owned_giveaway, 1);
	GM_getValue(name_config_home_hide_entered, -1) === -1 && GM_setValue(name_config_home_hide_entered, 1);
	//GM_getValue(name_config_ga_autoenter, -1) === -1 && GM_setValue(name_config_ga_autoenter, 0);
	GM_getValue(name_config_ga_title, -1) === -1 && GM_setValue(name_config_ga_title, 1);
	GM_getValue(name_config_ga_train_rider, -1) === -1 && GM_setValue(name_config_ga_train_rider, 1);
	GM_getValue(name_config_ga_bigger, -1) === -1 && GM_setValue(name_config_ga_bigger, 0);
	GM_getValue(name_config_ga_sdb, -1) === -1 && GM_setValue(name_config_ga_sdb, 1);
}

function updateConfigAll()
{
	updateConfigBool(name_config_sgh_active);
	updateConfigBool(name_config_general_mark_owned_game);
	updateConfigBool(name_config_general_mark_owned_giveaway);
	updateConfigBool(name_config_home_hide_entered);
	//updateConfigBool(name_config_ga_autoenter);
	updateConfigBool(name_config_ga_title);
	updateConfigBool(name_config_ga_train_rider);
	updateConfigBool(name_config_ga_bigger);
	updateConfigBool(name_config_ga_sdb);
}

function clearAllConfig()
{
	var keep = [];
	var config = GM_listValues();
	debug("clearAllConfig: " + config.length);
	for (var i = 0; i < config.length; i++)
	{
		if (keep.indexOf(config[i]) < 0)
		{
			GM_deleteValue(config[i]);
		}
	}
}

function getConfigQuery(name)
{
	return ".sgh_config input[name='" + name + "']";
}

function createConfigBool(number, heading, name, enabled, description)
{
	enabled = (typeof enabled === "undefined") ? GM_getValue(name) : enabled;
	enabled = (enabled === 1 || enabled === true);
	
	description = (typeof description === "string") ? description : "";
	
	var content = ' \n\
		<div class="form__row"> \n\
			<div class="form__heading"> \n\
				<div class="form__heading__number">' + number + '.</div> \n\
				<div class="form__heading__text">' + heading + '</div> \n\
			</div> \n\
			<div class="form__row__indent"> \n\
				<div>' + description + '</div> \n\
				<div> \n\
					<input name="' + name + '" value="'+ (enabled ? 1 : 0) +'" type="hidden"> \n\
					<div data-checkbox-value="1" class="form__checkbox \n\
						' + (enabled ? "is-selected" : "is-disabled") + '"> \n\
						<i class="form__checkbox__default fa fa-circle-o"></i> \n\
						<i class="form__checkbox__hover fa fa-circle"></i> \n\
						<i class="form__checkbox__selected fa fa-check-circle"></i> Yes \n\
					</div> \n\
					<div data-checkbox-value="0" class="form__checkbox \n\
						' + (!enabled ? "is-selected" : "is-disabled") + '"> \n\
						<i class="form__checkbox__default fa fa-circle-o"></i> \n\
						<i class="form__checkbox__hover fa fa-circle"></i> \n\
						<i class="form__checkbox__selected fa fa-check-circle"></i> No \n\
					</div> \n\
				</div> \n\
			</div> \n\
		</div> \n\
		';
	return content;
}

function updateConfigBool(name, enabled)
{
	enabled = (typeof enabled === "undefined") ? GM_getValue(name) : enabled;
	enabled = (enabled === 1 || enabled === true);
	
	var eleInput = document.querySelector(getConfigQuery(name));
	if (eleInput)
	{
		eleInput.value = (enabled ? 1 : 0);
		eleInput.nextElementSibling.classList.add(enabled ? "is-selected" : "is-disabled");
		eleInput.nextElementSibling.classList.remove(!enabled ? "is-selected" : "is-disabled");
		eleInput.nextElementSibling.nextElementSibling
			.classList.add(!enabled ? "is-selected" : "is-disabled");
		eleInput.nextElementSibling.nextElementSibling
			.classList.remove(enabled ? "is-selected" : "is-disabled");
	}
}

function mainConfig()
{	
	GM_addStyle
	(" \
		/* SGH Config CSS */ \
		.sgh_config { opacity: 0; visibility: hidden; position: fixed; z-index: 9997; \
		  transition: visibility 0.3s, opacity 0.3s; } \
		.sgh_config.sgh_config_active { opacity: 1; visibility: visible; } \
		.sgh_config_bg { display: block; background-color: #3C424D; position: fixed; \
		  top: 0px; bottom: 0px; left: 0px; right: 0px; opacity: 0.85; z-index: 9998; } \
		.sgh_config_detail { display: block; opacity: 1; z-index: 9999; \
		  position: fixed; top: 20px; bottom: 20px; width: 600px; left: 50%; margin-left: -300px; \
		  padding: 20px 20px; background-color: #f0f2f5; border-radius: 4px; \
		  text-align: center; text-shadow: 1px 1px rgba(255,255,255,0.94); } \
		.sgh_SGv2Dark .sgh_config_detail { background-color: #181816; text-shadow: none; } \
		.sgh_config .popup__description { font-weight: 300; font-size: 12px; \
		  max-width: 400px; margin: 0 auto; overflow: auto; \
		  position: absolute; left: 0px; right: 0px; top: 86px; bottom: 50px; } \
		.sgh_config .popup__actions { margin: 0 auto; \
		  position: absolute; left: 0px; right: 0px; bottom: 0px; height: 40px; } \
		.sgh_config .label { cursor: pointer; } \
		.sgh_config input[type='checkbox'] { width: auto; } \
		.sgh_config .form__row__indent { text-align: left; } \
		.sgh_config .form__checkbox { border-bottom: 1px dotted #d2d6e0; \
		  display: inline-block; min-width: 70px; margin-right: 10px; } \
		.sgh_config .popup__actions > :not(first-child) { margin-left: 15px; } \
		.sgh_config .popup__actions > * { margin-right: 0px; } \
		.sgh_SGv2Dark .sgh_config .form__rows { margin-top: 0px; padding-top: 8px !important; } \
		.sgh_SGv2Dark .sgh_config .form__rows > div { min-width: auto !important; } \
	");
	
	var eleOptionHeader = null;
	var eleLogout = document.querySelector(".nav__row.js__logout");
	if (eleLogout)
	{
		eleOptionHeader = document.createElement("a");
		eleOptionHeader.classList.add("nav__row");
		eleOptionHeader.setAttribute("href", "");
		eleOptionHeader.innerHTML = ' \n\
			<i class="icon-grey fa fa-fw fa-cogs"></i> \n\
			<div class="nav__row__summary"> \n\
				<p class="nav__row__summary__name">SteamGifts Helper</p> \n\
				<p class="nav__row__summary__description">Customize your options.</p> \n\
			</div> ';
		insertAfterElement(eleOptionHeader, eleLogout);
	}
	else
	{
		var divRight = document.querySelector(".nav__right-container > .nav__button-container");
		if (divRight)
		{
			eleOptionHeader = document.createElement("div");
			eleOptionHeader.setAttribute("class", "nav__button-container nav__button-container--notification")
			eleOptionHeader.innerHTML = '<a title="SteamGifts Helper - Customize your options." class="nav__button" \n\
				href=""><i class="fa fa-cogs"></i></a>';
			
			insertBeforeElement(eleOptionHeader, divRight);
		}
	}
	
	if (eleOptionHeader)
	{
		eleOptionHeader.addEventListener("click", function(e)
		{
			e.preventDefault();
			
			var eleOption = document.querySelector(".sgh_config");
			if (eleOption)
			{
				updateConfigAll();
				
				eleOption.classList.add("sgh_config_active");
			}
		});
		
		var eleOption = document.createElement("div");
		eleOption.classList.add("sgh_config");
		document.body.appendChild(eleOption);
		
		var eleOptionBg = document.createElement("div");
		eleOptionBg.classList.add("sgh_config_bg");
		eleOption.appendChild(eleOptionBg);
		
		eleOptionBg.addEventListener("click", function(e)
		{
			var eleOption = document.querySelector(".sgh_config");
			if (eleOption)
			{
				eleOption.classList.remove("sgh_config_active");
			}
		});
		
		var eleOptionOption = document.createElement("div");
		eleOptionOption.classList.add("sgh_config_detail");
		eleOption.appendChild(eleOptionOption);
		
		var numOption = 0;
		
		eleOptionOption.innerHTML = ' \n\
			<p class="popup__heading"> \n\
				<span class="popup__heading__bold">Welcome to SteamGifts Helper</span> \n\
				<br> \n\
				Here you can customize your options. \n\
			</p> \n\
			<div class="popup__description"> \n\
				<div class="form__rows"> \n\
					<div class="page__heading"><div class="page__heading__breadcrumbs">General</div></div> <div> \n'
					+ createConfigBool(++numOption, "Enable SteamGifts Helper?"
						, name_config_sgh_active, false) 
					+ createConfigBool(++numOption, "Mark owned Steam games?"
						, name_config_general_mark_owned_game, false) 
					+ createConfigBool(++numOption, "Mark owned giveways?"
						, name_config_general_mark_owned_giveaway, false) 
					+ ' </div> \n\
					<div class="page__heading"><div class="page__heading__breadcrumbs">Home Pages</div></div> <div> \n'
					+ ((numOption = 0) || " ")
					+ createConfigBool(++numOption, "Hide entered giveaways?"
						, name_config_home_hide_entered, false) 
					+ ' </div> \n\
					<div class="page__heading"><div class="page__heading__breadcrumbs">Giveaway Pages</div></div> <div> \n'
					+ ((numOption = 0) || " ")
					/*+ createConfigBool(++numOption, "Enable auto enter giveaways?"
						, name_config_ga_autoenter, false)*/
					+ createConfigBool(++numOption, "Show points in giveaway titles?"
						, name_config_ga_title, false)
					+ createConfigBool(++numOption, "Enable train rider?"
						, name_config_ga_train_rider, false, "Use Ctrl+] and Ctrl+[ to go next and previous wagons.") 
					+ createConfigBool(++numOption, "Enable bigger entry buttons?"
						, name_config_ga_bigger, false) 
					+ createConfigBool(++numOption, "Show SteamDB box for Steam subs?"
						, name_config_ga_sdb, false) 
					+ ' </div> \n\
				</div> \n\
			</div> \n\
			<div class="popup__actions"> \n\
				Please refresh pages after changed your options.  \n\
				<span class="b-refresh">Refresh</span> \n\
				<span class="b-close">Close</span> \n\
			</div> \n\
			';
		
		var eleOptionRefresh = document.querySelector(".sgh_config .b-refresh");
		if (eleOptionRefresh)
		{
			eleOptionRefresh.addEventListener("click", function(e)
			{
				reload();
			});
		}
		
		var eleOptionClose = document.querySelector(".sgh_config .b-close");
		if (eleOptionClose)
		{
			eleOptionClose.addEventListener("click", function(e)
			{
				var eleOption = document.querySelector(".sgh_config");
				if (eleOption)
				{
					eleOption.classList.remove("sgh_config_active");
				}
			});
		}
		
		// Welcome
		{
			if (GM_getValue(name_config_sgh_welcome) !== 1)
			{
				GM_setValue(name_config_sgh_welcome, 1);
				
				updateConfigAll();
				
				eleOption.classList.add("sgh_config_active");
			}
			
		}
	
		// Config observer
		{
			var muTarget_config = document.querySelector(".sgh_config");
			if (muTarget_config)
			{
				var muOb_config = new MutationObserver(function(mutations)
				{
					mutations.forEach(function(mutation)
					{
						if (mutation.type === "attributes" && mutation.target.tagName === "INPUT")
						{
							var eleInput = mutation.target;
							var nameInput = eleInput.getAttribute("name");
							var enabled = (eleInput.value === "1") ? 1 : 0;
							if (GM_getValue(nameInput) !== enabled)
							{
								GM_setValue(nameInput, enabled);
							}
						}
					});
				});
				
				var muCf_config = { childList: true, subtree: true, attributes: true, attributeFilter: ["value"] };
				muOb_config.observe(muTarget_config, muCf_config);
			}
		}
	}
}

//clearAllConfig();

if (GM_getValue(name_config_ga_sdb, -1) === -1)
{
	initAllConfig();
	
	// Force show config when new config added
	//GM_setValue(name_config_sgh_welcome, 0);
}

if (GM_getValue(name_config_sgh_active) === 1)
{
	if (window !== window.parent)
		return;
	
	attachOnReady(initStyle);
	attachOnReady(main);
}

attachOnReady(mainConfig);

})();

// End