CS:GO Lounge Live

A csgolounge.com betting tool and enhancer.

当前为 2015-04-08 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name          CS:GO Lounge Live
// @namespace     CSGOLoungeLive
// @author        soma
// @description   A csgolounge.com betting tool and enhancer.
// @include       http://csgolounge.com/
// @include       http://csgolounge.com/#
// @exclude       http://*.csgolounge.com/
// @include       http://dota2lounge.com/
// @include       http://dota2lounge.com/#
// @exclude       http://*.dota2lounge.com/
// @require       http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js
// @version       0.2.3.3
// @icon          http://img11.hostingpics.net/pics/365638LIVE.png
// @grant         GM_addStyle
// @grant         GM_getValue
// @grant         GM_setValue
// @grant         GM_xmlhttpRequest
// @grant         GM_getResourceText
// ==/UserScript==

/* Note: You are ALLOWED to edit and/or modify this script if belonging credits are given and you have informed the author BEFORE publishing the modified version.
 *       You are NOT ALLOWED to sell whole or any parts of this script.
 *       (cl) 2015 - soma.
 *       For further information contact soma @steam id: "somq" or on reddit.
 * */
GM_addStyle(' \
body {background-image: none;}\
.shownotav-btn:active { text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3); text-decoration: none; background-color: #eeeeee; border-color: #cfcfcf; color: #d4d4d4; } \
.shownotav-btn:hover, .button:focus, #switchmainviewa:hover, #switchmainviewa:hover { background-color: #f6f6f6; color:#999;} \
.shownotav-btn { letter-spacing: 5px; font-size: 16px; height: 50px; line-height: 40px; border-radius: 4px; background-color: #eeeeee; border: medium none; box-sizing: border-box; color: #666666; cursor: pointer; transition-duration: 0.3s; transition-property: all;; float: left; height: 40px; text-align: center; } \
.shownotav { width: 100%; padding: 0 50px; } \
main section.box {width: 68%;};\
.smallfont {font-size: 12px;} a.smallfont:hover {color:#666;}.teamadetails {width: 45%; float: left; text-align: center} .teambdetails{width: 45%; float: left; text-align: center} \
.vsdetails{width: 10%; float: left; text-align: center;font-size: 16px;} .detailsbox {float: left; margin: 16px 2%; width: 78%;font-size: 14px;}.teamtext {font-size:16px} \
.c-loading {background-image: url("http://img4.hostingpics.net/pics/5276773011.gif"); height: 100px; position: absolute; width: 100px;}\
.matchleft {min-height: 70px;box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.5) inset, 0 1px 1px 0 rgba(255, 255, 255, 0.5); border-radius: 8px; padding: 5px 0;max-width:1555px; width:63%;} section.box {width:98%; max-width:1430px;} .matchctn{float:left;width: 98%;} \
#c-overlay { background-color: rgba(0, 0, 0, 0.5); height: 100%; left: 0; position: absolute; top: 0; width: 100%; z-index: 10; }\
#switchmainview {float: right; display:none;}\
#mainloadingbar li {margin-left: auto; margin-right: auto; width: 260px;}\
.progress { box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.5) inset, 0 1px 1px 0 rgba(255, 255, 255, 0.5); margin: 0 auto; width:200px; background: none repeat scroll 0 0 #ebebeb; border-left: 1px solid transparent; border-radius: 10px; border-right: 1px solid transparent; height: 20px;}\
.progress > span {background: linear-gradient(to bottom, #f0f0f0, #dbdbdb 70%, #cccccc) repeat scroll 0 0 #cccccc; border-color: #bfbfbf #b3b3b3 #9e9e9e; border-image: none; border-radius: 10px; border-style: solid; border-width: 1px; box-shadow: 0 1px rgba(255, 255, 255, 0.3) inset, 0 1px 2px rgba(0, 0, 0, 0.2); float: left; height: 18px;line-height: 4px; margin: 0 -1px; min-width: 30px; position: relative;text-align: right;} \
.progress > span > span { line-height: 17px; color: rgba(0, 0, 0, 0.7); font-size: 11px; font-weight: bold; padding: 0 8px; text-shadow: 0 1px rgba(255, 255, 255, 0.4);} \
.mb-loading { height: 25px;text-align: center; background: url("http://img11.hostingpics.net/pics/279433ajaxloader3.gif") no-repeat scroll center center rgba(0, 0, 0, 0);} \
.rounded-btn1{ display: block;width:40px; height:40px; border-top:2px solid #fff; border-radius:50%; background-color:#EEEEEE; background: linear-gradient(#EDEAE1,#CDC8B5); text-align:center; box-shadow: 0 5px 2px 3px rgba(158, 158, 158, 0.4), 0 3px 5px #B7B6B6, 0 0 0 2px #BBB7AE, inset 0 -3px 1px 2px rgba(186, 178, 165, 0.5), inset 0 3px 1px 2px rgba(246, 245, 241, 0.3); cursor:pointer; } .rounded-btn1:active{border-radius:50%; border-top:none; border:1px solid #BAB7AE; background-color:#EEEEEE; text-align:center; color:#BAB7AE; text-shadow: 0 1px 1px white, 0 1px 1px #BAB7AE; box-shadow: 0 0 0 0 #BBB7AE; } .rounded-btn1 span { font-size:30px; color:#666; text-shadow:2px 2px 0 rgba(255, 255, 255, 0.9);}\
.feeds {text-shadow: 1px 1px 0 #e5e5e5;margin: 16px 1%; font-size:14px;}\
#feedsbox { width:30%; display: block; float: left; margin: 10px 0.5%;}\
.feeds-header {background: url("http://img11.hostingpics.net/pics/396420iconrssgrey.png") no-repeat scroll 0 0 / 33px auto rgba(0, 0, 0, 0)}\
.feedbox-title-inner { float:left; padding: 0 40px;}\
.feedstitle { height: 46px; opacity: 0.7; padding: 1%; text-align: center; text-decoration: underline; }\
#hltvfeed .feedstitle {background: url("http://img15.hostingpics.net/pics/49901496Zhddu.jpg") no-repeat scroll 50% center rgba(0, 0, 0, 0);}\
#redditfeed .feedstitle {background: url("http://img15.hostingpics.net/pics/464286reddit.png") no-repeat scroll 50% center rgba(0, 0, 0, 0);}\
#gosugamersfeed .feedstitle {background: url("http://img15.hostingpics.net/pics/241137gglogo.png") no-repeat scroll 50% center rgba(0, 0, 0, 0);}\
.feeds li { box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.5) inset, 0 1px 1px 0 rgba(255, 255, 255, 0.5); padding: 1%; } \
.feedslinks-box {margin: 0 2% 16px;padding-top: 5px;}\
.feedlink a {display: block;}\
.feedlink a:hover {border-radius: 2px; box-shadow: 1px 0px 0px 1px #999; display: block; opacity: 0.8; transition: 0.5s;}\
.main-feedbox {  background-color: #bbb;border-radius: 5px;float: left;box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.5) inset, 0 1px 1px 0 rgba(255, 255, 255, 0.5);width: 100%;}\
.line2a { padding-left: 10px; text-align: center;font-size: 14px;}\
.line2b { padding-right: 10px; text-align: center;font-size: 14px;}\
.matchbox-summary { float: left; font-size: 12px; margin: 16px 0; width: 15%;}\
.expandmatch-btn { color: #ddd; position:absolute; height: 20px; padding-left: 7px; font-size:20px;}\
.expmatchbtn-ctn { float: right; height: 25px; width: 25px;}\
.infosbelow-lr {width: 35%; float: left;}\
.infosbelow-center { float: left; font-size: 14px; text-align: center; width: 30%; } \
.sumbox {text-align: center; background: #bababa; border-radius: 4px; float: left; margin: 2px 0; opacity: 0.9; padding: 4px 4px 4px 20px; border: 1px solid #9b9b9b;}\
.suminfo {}\
.suminfo-info{background: url("http://img11.hostingpics.net/pics/344354iconinfov3.png") no-repeat scroll 2px center / 14px auto #ababab}\
.suminfo-bet{background: url("http://img15.hostingpics.net/pics/666500Dice.png") no-repeat scroll 2px center / 16px auto #ababab}\
a .suminfo-info:hover { background: url("http://img11.hostingpics.net/pics/344354iconinfov3.png") no-repeat scroll 2px center / 14px auto #D7D7D7; transition: 0.5s; opacity: 0.9;}\
a .suminfo-bet:hover { background: url("http://img15.hostingpics.net/pics/666500Dice.png") no-repeat scroll 2px center / 16px auto #D7D7D7; transition: 0.5s; opacity: 0.9;}\
.feedloading {background: url("http://img4.hostingpics.net/pics/356667712.gif") no-repeat scroll 3px center transparent; height: 30px; width: 30px; display: block; position: absolute; margin-left: 23%; margin-top: 1%;}\
aside#submenu {float:left;opacity: 0.9;border-radius: 0 0 10px;}\
main {padding-right:0;}\
#submenutoggle { background: none repeat scroll 0 0 #252525; float: right; font-size: 30px; height: 40px; opacity: 1; text-align: center; width: 200px; }\
aside#submenu > nav {margin:0}\
#shortsmb {  background: none repeat scroll 0 0 #252525; border-radius: 0 0 6px; float: left; font-size: 20px; opacity: 0.7; padding: 5px 10px 10px 5px; text-align: center;}\
#shortsmblink { color: #ff8a00;}\
.matchloading { background: url("http://img4.hostingpics.net/pics/5276773011.gif") no-repeat scroll 0 0 / 40px auto #cbcbcb; border-radius: 20px; height: 40px; left: 2%; margin: 5px; opacity: 0.6; width: 40px; }\
.matchloading-ctn { float: left; height: 50px; margin: 5px; position: absolute; width: 50px; }\
#infobox-wrapper {  background: none repeat scroll 0 0 #eee; border-radius: 5px 5px 0 0; bottom: 0; opacity: 0.9; padding: 15px 15px 10px; position: fixed; right: 50px; width: 430px; }\
.infobox-ctn {  background: none repeat scroll 0 0 #fff; border: 1px solid #ccc; border-radius: 3px; padding: 10px; text-align: center; }\
#settings-aliases {padding:5px 0;}\
 label { margin-left: 5px; float:right; font-size: 8px;background: none repeat scroll 0 0 rgb(138, 138, 138); border-radius: 14px; box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.1) inset, 0 -1px 0 0 rgba(0, 0, 0, 0.1) inset; color: #fff; cursor: pointer; display: inline-block; font-style: normal; font-weight: bold; height: 20px; line-height: 20px; position: relative; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); transition: all 1s ease-in 0s; width: 50px; } \
 label i { background: none repeat scroll 0 0 rgb(255, 255, 255); border-radius: 20px; box-shadow: 0 -3px 3px 0 rgba(0, 0, 0, 0.1) inset, 0 -1px 1px 0 rgba(255, 255, 255, 0.4) inset, 0 2px 0 0 rgba(0, 0, 0, 0.2); display: block; height: 20px; position: absolute; right: 30px; top: 0px; transition: all 100ms ease 0s; width: 20px;} \
 label i:before {  background: none repeat scroll 0 0 rgb(239, 239, 239); border-radius: 12px; box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.1) inset; content: ""; display: block; height: 8px; left: 50%; margin: -4px 0 0 -4px; position: absolute; top: 50%; width: 8px;} \
 label:active i:before { box-shadow: inset 0 1px 0 0 rgba(0, 0, 0, 0.3); } \
 label:before { content: "off"; margin-left: 20px; text-transform: uppercase; transition: all 200ms ease; } \
 input[type=checkbox]:checked ~ label:before { content: "on"; text-transform: uppercase; margin-right: 30px; margin-left: 5px; } \
 input[type=checkbox]:checked ~ label{ background: rgb(141,173,51); background: radial-gradient(center, ellipse cover, rgba(141,173,51,1) 0%, rgba(146,178,55,1) 24%, rgba(157,187,64,1) 55%, rgba(166,194,78,1) 100%); } \
 input[type=checkbox]:checked ~ label i { right: 0px; } \
 input[type=checkbox] { display:none; }\
 .matchmain { text-shadow: 0 1px 1px #ffffff; }\
.match {box-shadow:1px 2px 2px 2px #888;}\
.title { color: #999; float: left; position: relative; width: 98%;padding: 1% 1% 0;margin-left:0;text-transform: none;} \
.title:hover a {color: #999; text-shadow: none;}\
.title a{ color: #999; text-shadow: none;} \
#mainheader a:hover{ color: #777; text-shadow: none;} \
#mainheader { font-weight: 300; line-height: 16px;min-height: 40px;float:left; color: #777;font-size: 12px;width: 100%;border: 1px solid #ccc;}\
#mainheader .nomatchesfound {text-align:center;}\
#mainheader li { margin: 3px; padding: 2px;}\
.mainheader-c {}\
 .bets-header {background:url("http://cdn.csgolounge.com/img/bets.png") no-repeat;}\
 .mh-boxes {}\
 .mh-left {width:20%;float:left;padding:2px;}\
 .mh-center {width:50%;padding: 0 2px; margin:0 auto; text-align:center;max-height: 90px;}\
 .mh-right {width:175px;float:right;padding: 0 2px;}\
 #matchescount li {margin: 3px 0 0;}\
 #current-matchescount {font-weight:bold;}\
li.sticker { background: none repeat scroll 0 0 #e0e0e0; border-radius: 3px; box-shadow: 1px 1px 1px 1px #ccc; text-shadow: 0 1px 0px #fff;} \
.austatus { font-weight: bold; text-align: center;}\
.austatus-inner { font-weight: normal; text-align:left; margin-top: 5px;}\
.numofm {font-weight:bold;}\
.au-lasttime { float:right; font-weight:bold;color: #8a8a8a;}\
.au-timeleft { float:right; font-weight:bold;color: #8a8a8a;}\
.scriptinfo-header {}\
#scriptinfo-box {font-size:12px;opacity:0.9;overflow-y:auto; max-height:80px}\
#scriptinfo-box .linfo {background: url("http://img15.hostingpics.net/pics/169315info16x16.png") no-repeat 2px center scroll rgba(0, 0, 0, 0);}\
#scriptinfo-box .lwarning {background: url("http://img15.hostingpics.net/pics/701001warning16x16.png") no-repeat 2px center scroll rgba(0, 0, 0, 0);}\
#scriptinfo-box .lerror {background: url("http://img15.hostingpics.net/pics/477689error16x16.png") no-repeat scroll 2px center rgba(0, 0, 0, 0);}\
.timenow {float: left; margin-left: 20px;}\
.matchheader { background: #ccc; border-radius: 10px; border-top: 1px solid #ccc; float: left; font-size: 12px; line-height: 12px; margin-bottom: 4px; text-shadow: 1px 1px 0 #e5e5e5; color: #555;}\
.timeleft { color: #666; font-size: 13px; font-weight:bold}\
.timeRaw {font-size: 10px;}\
.eventm { color: #333; float: right; font-size: 12px; }\
.matchheader-spacer:after { content: "|"; }\
.matchheader span { float: left;} \
.matchheader-spacer { color: #777; font-size: 6px; margin: 0 10px; }\
.matchstatus .matchislive {color: #72A326; text-shadow: 1px 1px 0px #4A7010; font-weight: bold;font-size: 12px;}\
.matchstatus .matchisclosed {font-weight: bold; color: #D12121;font-size: 12px;}\
#force-refresh-ctn {float:right;}\
#force-refresh-ctn .fr-loading{ background-image: url("http://img15.hostingpics.net/pics/932558refreshanim.gif"); background-size: 16px auto; display: block; height: 16px; width: 16px; }\
#force-refresh-ctn .fr-notloading{ background-image: url("http://img15.hostingpics.net/pics/707861refreshfixed.png"); background-size: 16px auto; display: block; height: 16px; width: 16px;}\
');
// Grey scheme: Foreground color = #333333 // Background color = #bbbbbb

var scriptVersion = GM_info.script.version;
//console.log(version);
var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
console.log('@Greasemonkey/@Tampermonkey settings:', GM_info);
console.log('@JQuery: ', $.fn.jquery);
console.log('@CSGLounge Live version:', scriptVersion);

// Global settings
var settings = {
    "debug": {
        "global": false, // activates _log
        "feeds": "0",
        "autoUpdate": false // activate detailed autoupdate logging
    },
    "matchBoxStatus": "0", // Main view, boxes open, closed. feature disabled.
    "mainMenuStatus": "0", // 1 Show, 0 Hide main menu
    "updateDelay": "300000", // 5 mins = 300 seconds (*1000)
    "defaultTimeout": "10000", // 10 seconds
    "switches": {
        "completeinit": true,
        "feeds": true,
        "autoupdate": true
    },
    "isNewVersion": {
        "oldVersion": "",
        "newVersion": "",
        "status": false
    }
};
// debug (forces settings rewrite)
//localStorage.setItem("csglLiveSettings", JSON.stringify(settings));

/* Check for a newer version not elegant at all, will do that in a proper way later*/
var scriptVersionChecker = (localStorage.getItem('csgllive_lastversion') != scriptVersion);
if (scriptVersionChecker) {
    var currentVersion = localStorage.getItem('csgllive_lastversion');
    localStorage.setItem("csgllive_lastversion", scriptVersion);
    settings.isNewVersion.oldVersion = currentVersion;
    settings.isNewVersion.newVersion = scriptVersion;
    settings.isNewVersion.status = true;
    localStorage.removeItem("csglLiveSettings");
    localStorage.setItem("csglLiveSettings", JSON.stringify(settings));
}

var globalJobStatus = []; // global status for job to track if they are finished or not.
var globalData = {};
if (localStorage.getItem("csglLiveSettings") !== null) {
    settings = JSON.parse(localStorage.getItem("csglLiveSettings"));
    console.log('@CSGLounge Live settings:', localStorage.getItem('csglLiveSettings'));
}


// get base url in ff.
if (!is_chrome) {
    var baseUrl = window.location.href;
    var regexp = /.*\/(.*?)$/;
    var match = regexp.exec(baseUrl);
    if (match[1] === '#') {
        var baseUrl = baseUrl.replace('#', '');
    }
} else {
    var baseUrl = "http://csgolounge.com/";
}

/*********************/
/* DEBUG AND HELPERS */
/*********************/
// debug log if activated
if (!is_chrome) {
    _log = (function (undefined) { // if firefox
        var Log = Error; //  proper inheritance...?
        Log.prototype.write = function (args) {

            var lineNum = extractLineNumberFromStack(this.stack);
            var lineNumberStr = [[lineNum]];
            args = args.concat(lineNumberStr);
            args = sortArray(args);
            //                console.log(args);
            if (console && console.log) {
                if (console.log.apply) {
                    console.log.apply(console, args);
                } else {
                    console.log(args);
                } // nicer display in some browsers
            }
        };
        var extractLineNumberFromStack = function (stack) {

            var lineNum = stack.split('\n')[1];
            var lineNum = lineNum.split(' (')[0].substring(0, lineNum.length - 1);
            var lineNum = lineNum.split(':')[3].substring(0, lineNum.length - 1);
            return lineNum;
        };
        var sortArray = function (arrayTosort) { // swap 1st and last value.
            argsNew = [];
            for (var i = 0; i < arrayTosort.length; i++) {
                var j = i + 1;
                argsNew[j] = arrayTosort[i];
            }

            var lastItem = argsNew.pop();
            argsNew[0] = lastItem;
            return argsNew;
        };
        return function (params) {

            if (typeof settings.debug.global !== undefined || settings.debug.global)
                return;
            Log().write(Array.prototype.slice.call(arguments, 0));
        };
    })();
} else {
    _log = function (args) {
        if(settings.debug.global) { console.log(args); }
    };
}
pLog = _log;
auLog = function (args) {
//        console.log(['AU:'],' ', args);
    console.log(['AU:'], ' ', Array.prototype.slice.call(arguments, 0));
};
/* log tool */
window.log = function () {
    log.history = log.history || []; // store logs to an array for reference
    log.history.push(arguments);
    if (this.console && settings.debug.global) {
        console.log(Array.prototype.slice.call(arguments));
    }
};
l = function (args) {
    console.log(args);
};
_l = function (args) {
    console.log(args);
};

/****************/
/* SCRIPT START */
/****************/
/* Global Class - wrap basically every workers jobs - process detailled below... */
function globalClass(worker) {
    var self = this;
    this.worker = worker;
    this.job = {};
    this.job.init = true;
    this.job.done = false;
    this.job.update = false;
    this.job.retrieveMissing = false;
    this[this.worker] = {"data": []};
    console.log("Initializing INSTANCE for worker", this.worker, '', this[this.worker]);
    // matches ajax req errors & loading
    this.loading = {};
    this.loading.matchdiv = '<div class="matchloading-ctn"><div class="matchloading"></div></div>';
    // If error on retrieve is returned by matches ajax request: // errors.JOB.STRING
    this.errors = {};
    this.errors.match = {};
    this.errors.feeds = {};
    this.errors.match.toAppendFirstPart = '<div class="detailsbox error">There was an error retrieving the data (';
    this.errors.match.toAppendLastPart = ')...<a href="#" class="maindata-retrieve">Retrieve manually</a></div>';
    this.errors.match.aborted = this.errors.match.toAppendFirstPart + 'Aborted' + this.errors.match.toAppendLastPart;
    this.errors.match.timedOut = this.errors.match.toAppendFirstPart + 'Timed out' + this.errors.match.toAppendLastPart;
    this.errors.match.error = this.errors.match.toAppendFirstPart + 'Error' + this.errors.match.toAppendLastPart;
    this.errors.match.RetrieveFailedMatches = " item(s) failed to load. <a href='#' class='retrieve-failedmatches'>Retrieve missing item(s)</a> ";
    this.errors.feeds.timeout = "Feeds api didn't respond in time, please try again in one minute...";
    this.errors.feeds.abort = "Abort error, please try again later...";
    this.errors.feeds.errors = "There was an error, feeds api might be empty at the moment, please try again later...";
    this.liveNow = '<span class="matchislive">&nbsp; Live !</span>';
    this.feeds = {
        "data": [
            "reddit", "hltv"
        ],
        "feedsDatas": {
            "reddit": {
                "url": "https://vast-harbor-8484.herokuapp.com/api?feed=reddit",
                "datas": ""
            },
            "hltv": {
                "url": "https://vast-harbor-8484.herokuapp.com/api?feed=hltv",
                "datas": ""
            }
        }
    };
    this.feedbox = '<section id="feedsbox"><div class="title"><div id="secondheader" class="feeds-header mainheader-c">&nbsp;<div class="feedbox-title-inner"><strong>Feeds</strong> </div></div></div></section>';
    this.propsContainers = {
        "bestOf": ".infosbelow-center",
        "dateRaw": ".dateRaw",
        "ipstatus": "",
        "itemplaced": "",
        "mainstream": "",
        "matchNameA": ".teamtext:eq(0) b",
        "matchNameB": ".teamtext:eq(1) b",
        "msstatus": "",
        "peopleItemsNum": ".peopleItemsNum",
        "teamAReward": ".infosbelow-lr span:eq(0)",
        "teamAperc": ".teamtext:eq(0) i",
        "teamBReward": ".infosbelow-lr span:eq(1)",
        "teamBet": "",
        "teamBperc": ".teamtext:eq(1) i",
        "timeLeft": ".timeleft",
        "timeRaw": ".timeRaw",
        "valueBetA": "",
        "valueBetB": ""
    };
    // build an array containing all properties.
    var buildPropList = function (propsContainers) {
        var propsList = [];
        for (var properties in propsContainers) {
            propsList.push(properties);
        }
        return propsList;
    };
    this.propList = buildPropList(this.propsContainers);
    this.arrow = {};
    this.arrow.up = '<span style="color: green;">&#8593;</span>';
    this.arrow.down = '<span style="color: red;">&#8595;</span>';
    this.arrow.equal = '&nbsp;';
    this.arrow.err = '&nbsp;';
} /* ! globalClass(worker)*/


globalClass.prototype.initGlobalProcess = function () {
    _log('*** Global INIT for worker ' + this.worker + ' ***');
    var dfd = new jQuery.Deferred();
    return dfd.resolve(this);
}; // !initGlobalProcess

/*
 * monitorWorker method
 * @param {type} jobStatus = error || success
 * @param {type} container
 * @param {type} jobType = view || request
 * @param {type} id
 * @param {type} errorType = error details - eq. timeout, abort etc...
 * @feedsObj :
 loadingStatus.
 "index": 0,
 "totalItemsToLoad": dataLength,
 "globalMonitor": {
 "error": {"view" : 0, "request" : 0, "IDs" : [], "ctn" : []},
 "success": {"view" : 0, "request" : 0, "IDs" : [], "ctn" : []},
 "mustRetry": []
 }
 */
globalClass.prototype.monitorWorker = function (jobStatus, jobType, container, id, errorType) { // jobStatus = error || success, jobType = view || request, errorType = error details - eq. timeout, abort etc...
    _log('... currently monitoring "' + this.worker + '" worker ...');
    // monitor global responses status to count how many succeed and failed.
    var globalMonitor = this[this.worker].loadingStatus.globalMonitor; // example. this.initialization.loadingStatus.globalMonitor
//    console.log('MONITOR', globalMonitor[jobStatus][jobType], jobType)

    globalMonitor[jobStatus].IDs.push(id);
    globalMonitor[jobStatus].ctn.push(container);
    globalMonitor[jobStatus][jobType]++; // example. currentObj.success.view = 6.

    if (jobType === "view") { // update loading status when append are done.
        this[this.worker].loadingStatus.index = (++this[this.worker].loadingStatus.index);
    }
//    if(jobStatus === "error") { // send error to errorHandling method
//        this.errorHandling(jobStatus, jobType, container, id, "global");
//    }

};
globalClass.prototype.errorHandling = function (jobStatus, jobType, container, id, errorType) {
    var globalMonitor = this[this.worker].loadingStatus.globalMonitor; // example. this.initialization.loadingStatus.globalMonitor

    if (this.worker === "initialization" && jobType === "request") { // error
        $('#scriptinfo-box').prepend('<li class="lerror sticker"><span class="timenow">' + this.tools() + '</span>An error occured (' + errorType + ') while requesting match #' + id + '.</li>');
        container.find('.matchloading-ctn').remove();
        container.append(this.errors.match[errorType]);
    }

    if (errorType === "done") {
        $('#scriptinfo-box').prepend('<li class="lerror sticker"><span class="timenow">' + this.tools() + '</span>' + globalMonitor.error.request + this.errors.match.RetrieveFailedMatches);
    }

};
globalClass.prototype.done = function () {
    console.log('ALLDONE: worker ', this.worker, ' has finished his jobs. obj:', this);
    var globalMonitor = this[this.worker].loadingStatus.globalMonitor; // example. this.initialization.loadingStatus.globalMonitor

    // init is done
    if (this.worker === "initialization" && this.job.init && !this.job.retrieveMissing) {
        // store data in globalData obj
        globalData.currentData = {};
        globalData.currentData = this[this.worker].data;
        // check for errors
        if (globalMonitor.error.request > 0) {
            this.errorHandling("error", "", "", "", "done");
        }
        if (globalMonitor.error.request === 0) {
            $('#scriptinfo-box').prepend('<li class="linfo sticker"><span class="timenow">' + this.tools() + '</span> ' + this.worker + ' done successfully.');
        }
        if (settings.isNewVersion.status) {
            if (currentVersion === null) {
                $('#scriptinfo-box').prepend('<li class="linfo sticker"><span class="timenow">' + this.tools() + '</span> Welcome to CSGL Live version ' + scriptVersion + ', everything loaded successfully. Enjoy !</li>');
            } else if(typeof currentVersion !== "undefined") {
                $('#scriptinfo-box').prepend('<li class="linfo sticker"><span class="timenow">' + this.tools() + '</span> CSGL Live has updated from version ' + currentVersion + ' to ' + scriptVersion + ' successfully.</li>');
                settings.isNewVersion.status = false;
                localStorage.setItem("csglLiveSettings", JSON.stringify(settings));
            }

        }
    }
    var dfd = new jQuery.Deferred();
    return dfd.resolve(this);
};
globalClass.prototype.initPageView = function () {
    _log('*** init Page View ***');
    var self = this;
    /* MAIN STYLE*/
    var mainStyle = $('head link[type="text/css"]').attr('href');
    if (typeof mainStyle != "undefined") {
        var mainStyle = mainStyle.replace(/\d+$/, '');
        if (mainStyle != '//cdn.csgolounge.com/css/gray.min.css?') {
            $.ajax({
                method: 'GET',
                url: 'ajax/setSkin?skin=1',
                success: function (response) {
                    console.log(response);
                }
            });
            $('head link[type="text/css"]').attr('href', "//cdn.csgolounge.com/css/gray.min.css?");
        }
    }
    // logo
    $('body').find('header a:eq(0)').html('<img id="logo" alt="CS:GO Marketplace" src="http://img11.hostingpics.net/pics/797445csgllivelogo4.png">');
    /* 
     * http://img11.hostingpics.net/pics/797445csgllivelogo4.png
     * http://img11.hostingpics.net/pics/501830csgllivelogo.png
     * http://img11.hostingpics.net/pics/926464csgllivelogo2.png
     * http://img11.hostingpics.net/pics/357697csgllivelogo3.png
     */

    // Main view, boxes open, closed.
    if (settings.matchBoxStatus === '0') {
//        localStorage.setItem('matchBoxStatus', settings.matchBoxStatus);
        initialization.matchBoxStatus = ' style="display:none;"';
        var btnMatchBoxStatus = '+';
    } else if (settings.matchBoxStatus === '1') {
//        localStorage.setItem('matchBoxStatus', settings.matchBoxStatus);
        initialization.matchBoxStatus = ' style="display:block;"';
        initialization.btnMatchBoxStatus = '-';
    } else {
        initialization.matchBoxStatus = ' style="display:block;"';
    }

    // hide main trade box
    $('#tradelist').parent().hide();
    $('#tradelist').hide();
    // Hide not available, add button
    var firstna = $('.matchmain .notavailable:first').parent();
    firstna.nextAll().andSelf().wrapAll("<div id='sh-na' style='display:none;'></div>")
            .parent().before('<a href="#" class ="shownotav-btn shownotav"><span>Show closed matches</span></a>');
    $("body").on("click", "a.shownotav-btn", function (e) {
        $('a.shownotav-btn').remove();
        $('#sh-na').slideDown('slow');
        e.preventDefault();
    });
    // Page Header
    $('.title, #bets').removeAttr('style');
    //matchheader
    $('.title:eq(1)').html('<div id="mainheader" class="bets-header mainheader-c"></div>');
    $('#mainheader').append('<div class="mh-boxes mh-left"><ul></ul> </div>');
    $('#mainheader').append('<div class="mh-boxes mh-right"><ul></ul></div></div>');
    $('#mainheader').append('<div class="mh-boxes mh-center"><ul id="scriptinfo-box"></ul></div>');
    $('.mh-left ul').append('<li class="sticker matchesav"></li>');
    if (settings.switches.autoupdate) {
        $('.mh-left ul').append('<li class="sticker austatus"><ul class="austatus-title"><li>Auto-Update Status<span id="force-refresh-ctn"><a id="force-refresh" class="fr-notloading" title="Force a page refresh"href="#"></a></span></li></ul><span class="austatus-inner"><ul><li>Last update: <span class="au-lasttime">-</span></li><li>Next update in: <span class="au-timeleft">-</span></li></ul></span>');
    }
    $('.mh-center').prepend('<span class="scriptinfo-header">CS:GL Live version: ' + scriptVersion + ' <a href="#">reddit</a> - <a target="_blank" href="https://steamcommunity.com/tradeoffer/new/?partner=81839980&token=VqSHKQT0" title="support the cause !">steam donation</a></span>');
    //matchheader
    $('.mh-right ul').append('<li>Matches Infos: <input type="checkbox" id="completeinit-switch" /> <label for="completeinit-switch" > <i></i> </label></li>');
    $('.mh-right ul').append('<li>Feeds: <input type="checkbox" id="feeds-switch" /> <label for="feeds-switch" > <i></i> </label></li>');
    $('.mh-right ul').append('<li>Auto Update: <input type="checkbox" id="autoupdate-switch" /> <label for="autoupdate-switch"> <i></i> </label></li>');
    // Switches status
    $('#completeinit-switch').attr('checked', settings.switches.completeinit);
    $('#feeds-switch').attr('checked', settings.switches.feeds);
    $('#autoupdate-switch').attr('checked', settings.switches.autoupdate);
    $("#mainheader").on("click", "input#completeinit-switch", function (e) {
        if ($('input#completeinit-switch').is(":checked")) {
            settings.switches.completeinit = true;
            $('#scriptinfo-box').prepend('<li class="linfo sticker"><span class="timenow">' + self.tools() + '</span>Matches infos have been activated.</li>');
        } else {
            if (settings.switches.autoupdate) {
                $('#scriptinfo-box').prepend('<li class="linfo sticker"><span class="timenow">' + self.tools() + '</span>Auto update disable have been forced.</li>');
            }
            settings.switches.completeinit = false;
            settings.switches.autoupdate = false;
            $('#autoupdate-switch').attr('checked', settings.switches.autoupdate);
            $('#scriptinfo-box').prepend('<li class="linfo sticker"><span class="timenow">' + self.tools() + '</span>Matches infos have been disabled.</li>');
        }
        localStorage.setItem("csglLiveSettings", JSON.stringify(settings));
    });
    $("#mainheader").on("click", "input#feeds-switch", function (e) {
        settings.switches.feeds = $('input#feeds-switch').is(":checked") ? true : false;
        localStorage.setItem("csglLiveSettings", JSON.stringify(settings));
        if (!settings.switches.feeds) {
            $('#scriptinfo-box').prepend('<li class="linfo sticker"><span class="timenow">' + self.tools() + '</span>Feeds have been disabled.</li>');
        }
        if (settings.switches.feeds) {
            $('#scriptinfo-box').prepend('<li class="linfo sticker"><span class="timenow">' + self.tools() + '</span>Feeds have been activated.</li>');
        }
    });
    $("#mainheader").on("click", "input#autoupdate-switch", function (e) {
        if ($('input#completeinit-switch').is(":checked") === false) {
            $('#autoupdate-switch').attr('checked', false);
            alert('Turn on "matches infos" first.');
            $('#scriptinfo-box').prepend('<li class="linfo sticker"><span class="timenow">' + self.tools() + '</span>Please turn on matches infos first if you want to enable auto-update.</li>');
        } else {
            settings.switches.autoupdate = $('input#autoupdate-switch').is(":checked") ? true : false;
            localStorage.setItem("csglLiveSettings", JSON.stringify(settings));
            if (!settings.switches.autoupdate) {
                clearInterval(window.autoUpdate);
                clearInterval(window.autoUpdateTimer);
                $('.au-timeleft').html('-');
                $('#scriptinfo-box').prepend('<li class="linfo sticker"><span class="timenow">' + self.tools() + '</span>Auto update has just been stopped and disabled.</li>');
            }
            if (settings.switches.autoupdate) {
                $('#scriptinfo-box').prepend('<li class="linfo sticker"><span class="timenow">' + self.tools() + '</span>Auto update has been activated, please refresh the page to initialize it.</li>');
            }
        }


    });
    // Big Main Switch Button
    //$('#mainheader').append('<div id="switchmainview"><a href="#" id="switchmainviewa" class="rounded-btn1"><span>' + btnMatchBoxStatus + '</span></a></div>')

    $("#switchmainview").on("click", "a#switchmainviewa", function (e) {
        $(".detailsbox").slideToggle("fast", function () {
            $("#switchmainviewa span").text($('.detailsbox').is(':visible') ? "-" : "+");
        });
        e.preventDefault();
    });
    // Boxes expander
    $("#bets").on("click", "a.expandmatch-btn-a", function (e) {
        var $alinktext = $(e.target);
        var $detailsbox = $(e.target).parents().eq(2).find('.detailsbox');
        $detailsbox.slideToggle("fast", function () {
            $alinktext.text($detailsbox.is(':visible') ? "-" : "+");
        });
        e.preventDefault();
    });
    // SubMenu
    $('aside#submenu').prepend('<a id="submenutoggle"><span href="#" id="submenutogglelink">&#8592;</span></a>');
    $("#submenu").after('<a id="shortsmb" style="display:none;"><span id="shortsmblink" href="#">&#8600;</span></a>');
    if (settings.mainMenuStatus == '0') {
        $('aside#submenu').hide();
        $('#shortsmb').show();
    }

    $("body").on("click", "a#shortsmb", function (e) {
        $('#shortsmb').hide('fast');
        $("aside#submenu").show("slide");
        settings.mainMenuStatus = '1';
        localStorage.setItem("csglLiveSettings", JSON.stringify(settings));
    });
    $("#submenu").on("click", "a#submenutoggle", function (e) {
        $("aside#submenu").hide("slide", function () {
            $('#shortsmb').show();
            settings.mainMenuStatus = '0';
            localStorage.setItem("csglLiveSettings", JSON.stringify(settings));
        });
    });
    // Error link when a matchbox has failed to retrieve matchInfos
    // NOTE: USE initialization worker FOR THIS
    $(".match").on("click", "a.maindata-retrieve", function (e) {
        self.job.retrieveMissing = true;
        self.job.init = false;
        var selector = $(this).closest('.matchmain');
        selector.find('.error').remove();
        CompleteInitialization.call(self, self.worker, selector);
        e.preventDefault();
    });
    $("#error-matchesload").on("click", "a.retrieve-failedmatches", function (e) {
        var selector = self[self.worker].loadingStatus.globalMonitor.error.ctn;
        $('#error-matchesload').empty();
        $(selector).each(function (index, value) {
            value.find('.error').remove();
        });
        CompleteInitialization.call(self, this.worker, selector);
        e.preventDefault();
    });
    $("#force-refresh-ctn").on("click", "a#force-refresh", function (e) {
        console.log('refreshing auto update..');
        $('#scriptinfo-box').prepend('<li class="linfo sticker"><span class="timenow">' + self.tools() + '</span>Forcing a page refresh...</li>');
        $('#force-refresh').removeClass('fr-notloading').addClass('fr-loading');
//        clearInterval(window.autoUpdate);
//        clearInterval(window.autoUpdateTimer);
//        self.autoUpdateTimers();
//        UpdateInitialization();
//        window.autoUpdate = setInterval(function () {
//            self.autoUpdateTimers();
        UpdateInitialization();
//        }, settings.updateDelay);
        e.preventDefault();
    });
    // infobox
    $('main').append('<div id="infobox-wrapper" style="display: none;"><div class="infobox-ctn"></div></div>');
    // show trades
    $('#menu').append('<a href="#" class="showtrades"><img alt="Show trades" src="//cdn.csgolounge.com/img/my_trades.png">Show trades</a>');
    $("#menu").on("click", "a.showtrades", function (e) {
        $('.box:eq(1)').toggle(); // matchbox
        $('.box:eq(0)').fadeToggle('slow'); // trade box
        $('.box:eq(0) #tradelist').toggle(); // tradebox inner
        e.preventDefault();
    });
    // arrows containers
    var matchmainCtn = $('body').find('.matchmain .match').not('.notavailable').parent();
    $.each(matchmainCtn, function (i, v) {

        var teamTextA = $(v).find('.teamtext').eq('0');
        var teamTextB = $(v).find('.teamtext').eq('1').find('i');
        teamTextA.append('<span class="arrow-teama"></span>');
        teamTextB.before('<span class="arrow-teamb"></span>');
    });
    _log('-init page view done.');
    var dfd = new jQuery.Deferred();
    return dfd.resolve(this);
};
/* Loop through dom .matchmain and retrieve infos */
globalClass.prototype.parseMainPage = function (selector, rawData) {
    _log('*** parse Main Page ***');
    var data = (typeof rawData !== "undefined") ? rawData : 'body';
    if (typeof selector !== 'undefined' && selector !== "") {
        var matchesCtn = selector;
    } // If user has clicked to manually retrieve infos of a specific match
    else {
        var matchesCtn = $(data).find('.matchmain .match').not('.notavailable').parent();
    } //if not, selector is every match available on the page
    var csgl = {"data": []}; // global object, containing basically every data for every match.

    if (matchesCtn.length >= 1) {   // iterate through every matchmain box, find data, store it in csgl obj.
        $(matchesCtn).each(function (index, value) {

            var matchUrlDest = $(this).find('a').attr('href');
            var matchId = matchUrlDest.replace('match?m=', '').replace("predict?m=", "");
            var matchUrl = baseUrl + matchUrlDest;
            var matchCtn = $(this).find('a[href="match?m=' + matchId + '"]').closest('.match');
            var matchPercA = $(this).find('a[href="match?m=' + matchId + '"] div.teamtext:eq(0) i').text();
            var matchPercB = $(this).find('a[href="match?m=' + matchId + '"] div.teamtext:eq(1) i').text();
            var matchNameA = $(this).find('a[href="match?m=' + matchId + '"] div.teamtext:eq(0) b').text();
            var matchNameB = $(this).find('a[href="match?m=' + matchId + '"] div.teamtext:eq(1) b').text();
            matchCtn.append('<div class="matchloading-ctn"><div class="matchloading"></div></div>'); // init loading display

            var csglMatchData = {
                matchUrl: matchUrl,
                matchId: matchId,
                matchCtn: matchCtn,
                teamAperc: matchPercA,
                teamBperc: matchPercB,
                matchNameA: matchNameA,
                matchNameB: matchNameB
            };
            csgl.data.push(csglMatchData);
        }); // matches basic data retrieving has finished.

        this[this.worker].data = csgl.data; // Obj = this.worker.data[matches]

        // success
        _log('-parseMainPage success', this[this.worker].data);
        var dfd = new jQuery.Deferred();
        return dfd.resolve(this);
    } else {
        // escaped
        _log('parseMainPage escaped, no matches found'); // No matches has been found, append a message and retrieve the feed
//        updateLoading('', '1'); // Set progress bar to 100%
        $('#mainheader').append('<div class="nomatchesfound"><br />There are currently no matches to bet on ! ;( <br /> Try checking later...</div>');
    }

};
// gather and append global infos
globalClass.prototype.globalInfos = function () {
    _log('*** global infos ***');
    var numberOfMatchesS = $('body').find('.matchmain .match').not('.notavailable').parent().length; // ??!

    var dfd = new jQuery.Deferred();
    return dfd.resolve(this);
};
globalClass.prototype.initLoading = function () {    // init loading
    _log('... Init Loading ...');
    console.log("obj this[this.worker]:", this.worker, this[this.worker]);
    var data = this[this.worker].data;
    if (data === "undefined" || data === 0) {
        dataLength = 1;
    }

    if (typeof data === "object") {
        var dataLength = (Object.getOwnPropertyNames(data).length) - 1;
    } // USEFUL 'TILL I FIX THE WORKER OBJ FORMAT ?
    else {
        var dataLength = data.length;
    }

    this[this.worker].loadingStatus = {// loading vars
        "index": 0,
        "totalItemsToLoad": dataLength,
        "globalMonitor": {
            "error": {"view": 0, "request": 0, "IDs": [], "ctn": []},
            "success": {"view": 0, "request": 0, "IDs": [], "ctn": []},
            "mustRetry": []
        }  // index to monitor how many ajax requests succeed
    };
    // VIEW
    if (this.worker === "feeds") { // append feeds container and init loading gif
        $('main').append(this.feedbox);
        $.each(data, function (index, value) {
            $('main #feedsbox').append('<article id="' + value + 'feed-ctn" class="feeds standard"> <div class="main-feedbox" id="' + value + 'feed"><span id="' + value + '-loading" class="feedloading" style="display:none;"></span><div class="feedstitle"> </div> <div class="feedslinks-box"><ul></ul></div> </div> </article>');
        });
        $('.feedloading').fadeIn('fast');
    } else if (this.worker === "initialization" || this.worker === "basicInit") {    // matches count and loading bar
        if ($('#matchescount').length === 0) {
            $('#mainheader .mh-center ul').append('<li id="matchescount">loading: <span id="current-matchescount">0</span> / <span id="total-matchescount"></span></li>');
            $('#mainheader .mh-center ul').append('<li id="mainloadingbar"><div class="progress"><span style="width: 0%;"><span>0%</span></span></div></li>');
        }
        // matchescount
        var numberOfMatchesS = $('body').find('.matchmain .match').not('.notavailable').parent().length;
        $('.matchesav').html('<span class="numofm"> ' + numberOfMatchesS + '</span> matches available.'); // dot = &#149;
        $('#mainheader #matchescount #total-matchescount').html(numberOfMatchesS);
    } else {    // any worker VIEW

    }
    console.log("initloadingEND", this[this.worker].loadingStatus);
    var dfd = new jQuery.Deferred();
    return dfd.resolve(this);
};
// Ajax requests prototype, do the worker requests, parse the data, return whatever needed
globalClass.prototype.ajaxCalls = function (worker, job, url, id, container, timeout) {
    _log('... ajaxCalls ...');
    _log("Request sent for worker:", worker, " url: ", url, " id: ", id, " container: ", container);
    if (typeof timeout === "undefined") {
        timeout = settings.defaultTimeout;
    }

    this.genericCall = function () {
        var self = this;
        _log('ajax req for: ', worker, ' @: ', url, container);
        return $.ajax({
            method: 'GET',
            url: url,
            timeout: timeout,
            success: function (data) {   // Request complete, parse data
//                _log('request complete for: url:', url, ' id: ', id,' container:', container, 'RESULT=', data);
                _log("response received for worker:", worker, "url;", url);
            },
            onabort: function (data) {
                _log('onabort error throwed for request=> url:', url, ' id: ', id, ' container:', container, 'RESULT=', data);
            },
            ontimeout: function (data) {
                _log('ontimeout error throwed for request=> url:', url, ' id: ', id, ' container:', container, 'RESULT=', data);
            },
            onerror: function (data) {
                _log('onerror error throwed for request=> url:', url, ' id: ', id, ' container:', container, 'RESULT=', data);
            }
        });
    };
//    if (worker === 'initialization' || worker === 'feeds') { // if there are other requests type to add, keep this worker in a condition statement...
    return this.genericCall();
//    }

};
// Global INIT Parse each match page request
globalClass.prototype.parseMatchPageData = function (worker, job, url, id, container, data) {
    console.log('*!* parsing... ', id);
    _log('... parseMatchPageData ...');
    _log('parsing data for url:', url, ' id: ', id, ' container:', container);
    var self = this;
    var $d = $(data);
    var tar = '.box-shiny-alt:eq(0) .full .half:eq(0)';
    var tar = $d.find(tar);
    var teamAReward = tar.length > 0 ? tar.html().split("<br>")[1] : '';
    var tbr = '.box-shiny-alt:eq(0) .full .half:eq(1)';
    var tbr = $d.find(tbr);
    var teamBReward = tbr.length > 0 ? tbr.html().split("<br>")[1] : '';
    var vba = '.box-shiny-alt:eq(0) .full .half:eq(0)';
    var vba = $d.find(vba);
    var valueBetA = vba.length > 0 ? vba.html().split("<br>")[2] : '';
    var vbb = '.box-shiny-alt:eq(0) .full .half:eq(1)';
    var vbb = $d.find(vbb);
    var valueBetB = vbb.length > 0 ? vbb.html().split("<br>")[2] : '';
    var tl = '.box-shiny-alt:eq(0) .half:eq(0)';
    var tl = $d.find(tl);
    var timeLeft = tl.length > 0 ? tl.text() : '';
    var bo = '.box-shiny-alt:eq(0) .half:eq(1)';
    var bo = $d.find(bo);
    var bestOf = bo.length > 0 ? bo.text() : '';
    var t = '.box-shiny-alt:eq(0) .half:eq(2)';
    var t = $d.find(t);
    var time = t.length > 0 ? t.text() : '';
    var d = 'section.box:eq(0) .box-shiny-alt .half:eq(2)';
    var d = $d.find(d);
    var date = d.length > 0 ? d.attr("title") : '';
    var pin = 'section.box:eq(1) div.box-shiny-alt .full:eq(0)';
    var pin = $d.find(pin);
    var peopleItemsNum = pin.length > 0 ? pin.text() : '';
//            var matchDateFull = convertCsglDate(date, time);
//            var matchDateHuman = matchDateFull[1];
//            var matchDateRobot = matchDateFull[0];

    // Optional (itemplaced, mainstream)
    var ip = '.box-shiny-alt .full:eq(2)';
    var tb = '.box-shiny-alt a.active';
    if ($d.find(ip).length) {
        var itemplaced = $d.find(ip).html();
        var teamBet = $d.find(tb).index();
        if (teamBet == '1') {
            teamBet = 'a';
        }
        if (teamBet == '3') {
            teamBet = 'b';
        }
        var ipstatus = '1';
    } else {
        var itemplaced = 'No bet placed.';
        var ipstatus = '0';
        var teamBet = '0';
    }
    var ms = '#stream #mainstream';
    if ($d.find(ms).length) {
        var mainstream = $d.find(ms).html();
        var msstatus = '1';
    } else {
        var mainstream = 'No stream available';
        var msstatus = '0';
    }

    $(self[self.worker].data).each(function (index, value) {
        if (value.matchId === id) {
            value.teamAReward = teamAReward;
            value.teamBReward = teamBReward;
            value.valueBetA = teamAReward;
            value.valueBetB = teamBReward;
            value.peopleItemsNum = $.trim(peopleItemsNum);
            value.timeLeft = timeLeft;
            value.bestOf = bestOf;
            value.timeRaw = $.trim(time);
            value.dateRaw = date;
//                        value.matchDateRobot = matchDateRobot;
//                        value.matchDateHuman = matchDateHuman;
            value.ipstatus = ipstatus;
            value.itemplaced = itemplaced;
            value.teamBet = teamBet;
            value.msstatus = msstatus;
            value.mainstream = mainstream;
        }

    });
    _log(self.worker + ' OBJ: ', self[self.worker]);
    // retrieve the object with data for the current "id"
    var result = $.grep(self[self.worker].data, function (e) {
        return e.matchId == id;
    });
    var data = result[0];
    _log('parseMatchPageData worker', worker, 'done for', url);
    var dfd = new jQuery.Deferred();
    return dfd.resolve(self, data, this);
//  dfd.resolve()
//  return dfd.promise(self, data, this);
};
globalClass.prototype.dothestuff = function (a) {
    console.log('*#*#* parseData ***');
    var xxxx = $.Deferred();
    console.log('*#*#* called processItem ***');
    xxxx.resolve();
    return xxxx.promise();
};
globalClass.prototype.ended = function (a) {
    console.log('*#*#* finito! ***');
};
globalClass.prototype.appendEachMatch = function (worker, job, url, id, container, data) {
    _log('*** appendEachMatch ***');
//    console.log("Appending match #",id, 'data:', data, this);

    if (typeof (data.teamAReward) !== "undefined" && (data.teamAReward).length > 0) { // todo: und && length var checker
        //GATHER INFOS TO APPEND
        var nobetplaced = data.ipstatus === '0' ? data.itemplaced : '&nbsp;';
        var placedbet = data.ipstatus === '1' ? data.itemplaced : '&nbsp;';
        // infos Below TeamA vs TeamB
        var infosbelow = '<div class="infosbelow-lr infosbelow-tb"> <div class="line2a"><span title="csgolounge bet reward value">' + data.teamAReward + '</span></div> </div> <div class="infosbelow-center">' + data.bestOf + '</div> <div class="infosbelow-lr infosbelow-tb"> <div class="line2b"> <span title="csgolounge bet reward value">' + data.teamBReward + '</span> </div>';
        // Match box header (eg. time left, date cup etc...)
//        var mDataHeaderSpacer = '<div class="matchheader-spacer">-</div>';
//        var matchDataheader1 = ('<div class="whenm"> - <span class="dateRaw">' + data.dateRaw + '</span> - <span class="timeRaw">' + data.timeRaw + '</span></div>');
//        var matchDataheader2 = ('<div class="whenm"><span class="peopleItemsNum">' + data.peopleItemsNum + '</span></div>');

        var mDataHeaderSpacer = '<span class="matchheader-spacer"></span>';
        var headerDTimeLeft = '<span class="timeleft">' + data.timeLeft + '</span>';
        var headerDMatchStatus = '<span class="matchstatus"></span>';
        var headerDTimeRaw = '<span class="timeRaw">&nbsp;&nbsp;(' + data.timeRaw + ')</span>';
        var headerDDateRaw = '<span class="dateRaw">' + data.dateRaw + '</span>';
        var headerDPItemNum = '<span class="peopleItemsNum">' + data.peopleItemsNum + '</span>';
        var headerDEvent = '<span class="eventm">CCS</span>';
        $('.matchheader .whenm').remove();
        // matchheader (time left, date, additionnal info, cup)
        var $w = $('body').find('a[href="match?m=' + id + '"]').parents().eq(2).find('.matchheader .whenm');
        var $w2 = $('body').find('a[href="match?m=' + id + '"]').parents().eq(2).find('.matchheader');
        // APPEND
        // matchheader
//        $w2.append(matchDataheader1 + mDataHeaderSpacer + matchDataheader2);
        $w2.append(headerDTimeLeft + headerDMatchStatus + headerDTimeRaw + mDataHeaderSpacer + headerDDateRaw + mDataHeaderSpacer + headerDPItemNum);
        if ((data.timeLeft).indexOf('ago') > -1) {
            var msCtn = $('body').find('.matchstatus');
            msCtn.html(this.liveNow);
        }
        // Infos below the TeamA vs TeamB part
        data.matchCtn.find('a:first').append(infosbelow);
        // SummaryBox (labels eg. "No bet placed" "hltv link" "reddit link" etc..."
        data.matchCtn.append('<div class="matchbox-summary"></div>');
        if (data.ipstatus == '0') {
            data.matchCtn.find('.matchbox-summary').append('<span class="sumbox suminfo-bet">No bet placed.</span>');
        } else {
            data.matchCtn.find('.matchbox-summary').append('<span class="sumbox suminfo-bet">A bet has been placed.</span>');
        }
        // Expand button
        data.matchCtn.append('<div class="expmatchbtn-ctn"><a class="expandmatch-btn-a"><span class="expandmatch-btn">+</span></a></div>');
        // DetailsBox (box to expand)
        data.matchCtn.append('<div class="detailsbox"' + initialization.matchBoxStatus + '>' + placedbet + '</div>');
        // MAINSTREAM
        // if (data.msstatus == '1') {
        // data.matchCtn.append('<div class="detailsbox"><div class="mainstream-btn"><a href="#" > class="sh-stream">SHOW HIDE STREAM</a></div><div class="mainstream" style="display: none;">'+data.mainstream+'</div>')
        // }
        // $('.sh-stream').click(function(){
        // var $t = $(this).parents().eq(2);
        // alert($t.find('.mainstream'))
        // return false;
        // });

        console.log('append done for id:', id);
    }
    // loading display
    data.matchCtn.find('.matchloading-ctn').remove();
    var dfd = new jQuery.Deferred();
    return dfd.resolve(this, container, id);
};
globalClass.prototype.updateLoading = function (loadingStatus) {
    var loadingStatus = this[this.worker].loadingStatus;
    if (this.worker === "feeds") {
        if (loadingStatus.index + 1 === loadingStatus.totalItemsToLoad) {  // feeds have finished loading
            $('.feedloading').fadeOut('fast');
        }
    } else if (this.worker === "initialization") { // status bar render for worker initialization
        var status = loadingStatus.index;
        var total = loadingStatus.totalItemsToLoad;
        var part = (100 / total);
        var currentPart = part * status;
        var newPart = part + currentPart;
        var newPartShow = Math.round(newPart);
        $('.progress > span').css('width', newPart + '%');
        $('.progress > span > span').text(newPartShow + '%');
        if (status + 1 === total) {
            $('.progress > span').css('width', '100%');
            $('.progress > span > span').text('100%');
            $('#mainloadingbar').fadeOut('slow');
            $('#matchescount').fadeOut('slow');
        }
        $('#mainheader #matchescount #current-matchescount').html(loadingStatus.index); // loading counter "X"/y
    } else { // any worker
    }
};
/* *********** Feed Jobs *********** */

globalClass.prototype.appendEachFeed = function (worker, job, url, id, container, data) {
    _log('*** appendEachFeed ***');
    var self = this;
//    var data = JSON.parse(data.response);
    var data = data.datas.feedProperties;
    $.each(data, function (index, value) {
        var feedUrl = typeof value.feedUrls !== "undefined" ? value.feedUrls.reddit : value.feedUrl;
        container.append('<li><a href="' + feedUrl + '" target="_blank" title="' + value.feedCup + '">' + value.feedMatchname + ' - ' + value.feedDate + '</li>');
    });
    var dfd = new jQuery.Deferred();
    return dfd.resolve(this, this[this.worker].loadingStatus);
};
/* *********** Update Page *********** */

globalClass.prototype.getMainPageDistant = function () {
    _l('*** Initialization of Update Page Data  ***');
//    globalData.currentData = globalClass.initialization.data;    // store local infos retrieved with initialization worker
    console.log("getMainPageDistant", "this", this, this.worker);
    var dfd = new jQuery.Deferred();
    return dfd.resolve(this);
};
globalClass.prototype.compareData = function () {
    /* CurrentData = data on the page before the update
     * NewData = data on the DISTANT page
     * DiffData = currentData (+ add - rem from newData)
     *            result of currentData and newData comparison (add&rem) => will use it to compare current props (diffData[]) with new props (newData[])
     */
    _log('*** Compare Page Data ***');
    console.log('*** Compare Page Data ***');
    //COMPARE
    var currentData = globalData.currentData;
    var newData = this[this.worker].data;
    console.log(this.tools(), 'globalData.currentData - compareData START', globalData.currentData);
    console.log(this.tools(), 'newData - compareData START', newData);
//    console.log(JSON.stringify(currentData))
//    console.log(JSON.stringify(newData))

    var globalMonitor = this[this.worker].loadingStatus.globalMonitor;
    if (globalMonitor.error.request > 0) { // if there was at least 1 req error in match pages requests.
        for (var i = 0; i < globalMonitor.error.IDs; i++) {

        }
    }

    /* DEBUG */
    // rem
//    newData.splice(1, 1) // completely removes item 1 of array until next item (1 item for 1 time)
    // add
//    var editThat = [];
//    newData.forEach(function (obj) { // cloning diffData with currentData
//        var clonedObj = {};
//        var clonedObj = jQuery.extend(true, {}, obj);
//        editThat.push(clonedObj);
//    });
//    editThat[1].matchId = "9999";
//    editThat[1].matchUrl = "http://csgolounge.com/match?m=9999";
//    var last = newData.length;
//    newData[last] = editThat[1];
    /* DEBUG */

    var propsToUpdate = []; // we are building this array a bit below, containing all properties to update.

    var diffData = []; // result of currentData and newData comparison (add&rem) => will use it to compare current props (diffData[]) with new props (newData[])

// WRONG WAY TO CLONE.
//    currentData.forEach(function (obj) { // cloning diffData with currentData
//        diffData.push(obj);
//    });
    currentData.forEach(function (obj) { // cloning diffData with currentData
        var clonedObj = {};
        var clonedObj = jQuery.extend(true, {}, obj); // deep dopy
        diffData.push(clonedObj);
    });
    // matches to add & to remove.
    function dataDifferenceADD(currentData, newData) {
        var x = {};
        currentData.forEach(function (obj) {
            x[obj.matchId] = obj;
        });
        return newData.filter(function (obj) {
            return !(obj.matchId in x);
        });
    }
    function dataDifferenceREM(currentData, newData) {
        var x = {};
        newData.forEach(function (obj) {
            x[obj.matchId] = obj;
        });
        return currentData.filter(function (obj) {
            return !(obj.matchId in x);
        });
    }
    var toAdd = dataDifferenceADD(currentData, newData);
    console.log('add', toAdd);
    var toRem = dataDifferenceREM(currentData, newData);
    console.log('rem', toRem);
//    console.log("toAdd", JSON.stringify(toAdd))
//    console.log("newData", JSON.stringify(newData))
    toAdd.forEach(function (obj) { //add
        diffData.push(obj); // push toAdd to diffData OBJ
        propsToUpdate.push(obj);
    });
    toRem.forEach(function (obj) { //rem
        var index = diffData.map(function (x) {
            return x.matchId;
        }).indexOf(obj.matchId); // grep index of toRem matchId in currentData
        if (index > -1) {
            diffData.splice(index, 1); // remove toRem element(s) in diffData
        }
    });
    this.remAndAdd = {};
    this.remAndAdd.rem = toRem;
    this.remAndAdd.add = toAdd;
//    console.log("diffData", JSON.stringify(diffData))
//    console.log("newData", JSON.stringify(newData))

    /*
     #1 props checks
     - loop through each prop of newData
     => check if current prop is in diffData
     - if yes => compare values => if diff => update dom & obj
     - if no => update dom & obj
     */

    for (var i = 0; i < newData.length; i++) {
        var newValuesObj = newData[i];
        var matchId = newValuesObj.matchId; // GET MATCHID
        var currentValues = $.grep(diffData, function (element, index) { // Grep matchId in diffData
            return element.matchId === matchId;
        });
        console.log('@compareData: --------- Checking matchID: ', matchId, ' ---------');
        if (typeof currentValues !== "undefined" && currentValues.length !== 0) {
            var currentValuesObj = currentValues[0]; // item of diffData array with current/old values (eg. {matchId: 2185, matchCtn: "div"...})

            //console.log('currentValuesObj', currentValuesObj)

            // build a list of properties for each array of values
            var currentArrayOfProps = Object.getOwnPropertyNames(currentValuesObj);
            var newArrayOfProps = Object.getOwnPropertyNames(newValuesObj);
//                    console.log('allvars', newValuesObj, matchId, currentValuesObj, currentArrayOfProps, newArrayOfProps)

            percStatus = {}; // percentage status: up, down, equal, err status
            for (var j = 0; j < newArrayOfProps.length; j++) { // iterate over the props array from newData

                /* Results */
                // newValuesObj = obj from newData (eg. Object { matchUrl="http://csgolounge.com/match?m=3022",  matchId="3022",  matchCtn={...},  plus...})
                // currentValuesObj = obj from diffData (eg. Object { matchUrl="http://csgolounge.com/match?m=3022",  matchId="3022",  matchCtn={...},  plus...})
                // propNameToCheck / newArrayOfProps[j] = teamBReward
                // newValuesPropValue / newValuesObj[propNameToCheck] = 5.4 for 1
                /* !Results */

                var propNameToCheck = newArrayOfProps[j];
                var newValuesPropValue = newValuesObj[propNameToCheck];
                var currentValuesPropValue = currentValuesObj[propNameToCheck];
                if (settings.debug.autoUpdate) {
                    console.log('propNameToCheck', propNameToCheck);
                    console.log('newValuesObj', newValuesObj);
                    console.log('currentValuesObj', currentValuesObj);
                    console.log('newValuesPropValue', newValuesPropValue);
                    console.log('currentValuesPropValue', currentValuesPropValue);
                    console.log('newArrayOfProps', newArrayOfProps);
                    console.log('currentArrayOfProps', currentArrayOfProps);
                    console.log('newValuesPropValue', newValuesPropValue);
                    console.log('currentValuesPropValue', currentValuesPropValue);
                }
                if ((currentValuesPropValue !== newValuesPropValue) && typeof newValuesPropValue != "undefined") { // prop is different in newDatas & currentData, newData prop is defined.
                    if (settings.debug.autoUpdate) {
                        console.log('#' + matchId, 'currentValuesPropValue', currentValuesPropValue, 'newValuesPropValue', newValuesPropValue);
                    }
                    // we populate an array (propsToUpdate) containing objects with props to update. We set obj at the array id it was in newData.
                    // eg. newData[2] = { "matchId": "2789", "prop" : "value" ... } => propToUpdate[2] = { "matchId": "2789", "propXToUpdate" : "valueXToUpdate" ...}

                    if (propNameToCheck === "teamBperc" || propNameToCheck === "teamAperc") { // percentage status. Let's check if percentage goes up, down, stays equal or is in err. Access example: propsToUpdate[index].percStatus.teamAperc
                        percStatus[propNameToCheck] = currentValuesPropValue < newValuesPropValue ? "up" : currentValuesPropValue > newValuesPropValue ? "down" : currentValuesPropValue == newValuesPropValue ? "equal" : "err";
                    }

                    var elementPos = propsToUpdate.map(function (x) { // Checking if we have already an obj for this matchId in propsToUpdate
                        return x.matchId;
                    }).indexOf(newValuesObj.matchId); // id in array

                    if (elementPos === -1) { // we've no obj, creating it.
                        var objToPush = {// basic obj containing matchId.
                            "matchId": newValuesObj.matchId
                        };
                    }
                    // setting objToPush properties
                    objToPush[propNameToCheck] = newValuesPropValue; // populating current prop in our obj
                    if (typeof percStatus[propNameToCheck] !== "undefined" && percStatus[propNameToCheck].length > 0) { // add percStatus if we've it.
                        objToPush.percStatus = percStatus;
                    }
                    // pushing obj or updating propsToUpdate array.
                    if (elementPos === -1) {
                        propsToUpdate.push(objToPush); // pushing obj containing prop, or prop + matchId.
                    } else {
                        propsToUpdate[elementPos] = objToPush; // pushing obj containing prop, or prop + matchId.
                    }
                }

            } // !for loop (newArrayOfProps, properties list from newData)
        }
    } // !for loop (newData)

    console.log(this.tools(), 'newData - compareData END', newData);
    console.log(this.tools(), 'diffData - compareData END', diffData);
    console.log(this.tools(), 'propsToUpdate - compareData END', propsToUpdate);
    globalData.currentData = newData; // update globalData Object
    this.propsToUpdate = propsToUpdate; // public prop, will be used by updateData to generate the VIEW
//    console.log(JSON.stringify(propsToUpdate))

    var dfd = new jQuery.Deferred();
    return dfd.resolve(this);
};
globalClass.prototype.updateData = function () {
//    _l('*** Update Page Data  ***');
    console.log('*** Update Page Data  ***', this.propsToUpdate);
    var self = this;
    // UPDATE
    /* 1) grep matchId
     * 2) find container in dom
     * 3) find props containers in matchmain container
     * 4) update containers
     */
//    var propsToUpdate = [{"matchId": "2904", "peopleItemsNum": "\n                20026 people placed 57614 items.\n                                "}, {"matchId": "2907", "teamBReward": "1.3 for 1", "valueBetB": "1.3 for 1", "peopleItemsNum": "\n                15373 people placed 44126 items.\n                                "}, {"matchId": "2905", "teamAReward": "3.24 for 1", "valueBetA": "3.24 for 1", "peopleItemsNum": "\n                11275 people placed 31350 items.\n                                "}, {"matchId": "2908", "teamBReward": "3.54 for 1", "valueBetB": "3.54 for 1", "peopleItemsNum": "\n                1279 people placed 3564 items.\n                                "}, {"matchId": "2911", "teamBReward": "3.71 for 1", "valueBetB": "3.71 for 1", "peopleItemsNum": "\n                722 people placed 1842 items.\n                                "}, {"matchId": "2910", "peopleItemsNum": "\n                894 people placed 2420 items.\n                                "}, {"matchId": "2909", "teamAReward": "1.91 for 1", "valueBetA": "1.91 for 1", "peopleItemsNum": "\n                567 people placed 1472 items.\n                                "}]
//    console.log(propsToUpdate.length)

    // ADD && REM TO DOM
    // REMOVES
    var addedMatchesCtn = []; // container to pass as selector to CompleteInitialization.call(that, worker, selector) for props loading
    var toAdd = this.remAndAdd.add;
    var toRem = this.remAndAdd.rem;
    // TO ADD DEBUG
//    var m = [];
//    $.each($('body').find('.matchmain .match').not('.notavailable').parent(), function (i, v) {
//      m.push(v)
//    });
//    console.log('v', m)
//    var toAdd = [m[1], m[3]]

    // TO REM DEBUG
//    var toRem = [{"matchUrl": "http://csgolounge.com/match?m=3058", "matchId": "3058", "matchCtn": {"0": {}, "length": 1, "prevObject": {"0": {}, "length": 1, "prevObject": {"0": {}, "context": {}, "length": 1}, "context": {}, "selector": "a[href=\"match?m=2957\"]"}, "context": {}}, "teamAperc": "84%", "teamBperc": "16%", "matchNameA": "A51", "matchNameB": "Incursion", "teamAReward": "0.05 to 0.19 for 1", "teamBReward": "5.14 for 1", "valueBetA": "0.05 to 0.19 for 1", "valueBetB": "5.14 for 1", "peopleItemsNum": "\n                37891 people placed 109923 items.\n                                ", "timeLeft": "1 hour from now", "bestOf": "Best of 3", "timeRaw": "\n                04:30 CEST            ", "dateRaw": "Thursday 2nd April 2015", "ipstatus": "0", "itemplaced": "No bet placed.", "teamBet": "0", "msstatus": "0", "mainstream": "No stream available"}];
//    var matchCtnx = $('body').find('a[href="match?m=3058"]').closest('.match').parent();    // debug
//    console.log(matchCtnx);
//    console.log(toRem);
//    toRem[0].matchCtn = matchCtnx;    // debug
    if (toRem.length > 0) {
        $('.numofm').html((globalData.currentData).length).delay(50).fadeOut().fadeIn('slow');
    }
    if (toAdd.length > 0) {
        // detach all containers
        var matchmainCtn = $('body').find('.matchmain .match').not('.notavailable').parent();
        var detachedMM = [];
        $.each(matchmainCtn, function (i, v) { // detach all matches containers in detachedMM array
            var matchUrlDest = $(v).find('a').attr('href');
            var matchId = matchUrlDest.replace('match?m=', '').replace('predict?m=', '');
            //detached.push($(v).detach())
            var detachedMatches = {
            };
            detachedMatches.matchCtn = $(v).detach();
            detachedMatches.matchId = matchId;
            detachedMM.push(detachedMatches);
        });
        console.log('detachedMM', detachedMM);
        // rebuld the page with reattached matches containers and added match containers
        $.each(globalData.currentData, function (i, v) { // loop through newData (updated in the prev. step globaData.currentData object), for each entry, check if ctn is in DOM or in newData obj
            //   check if v.matchId is in a 'toAdd' match, if yes, grep matchCtn in newData, else attach current matchCtn
            var matchToAdd = $.grep(toAdd, function (element, index) { // check if match is in toAdd
                return element.matchId === v.matchId;
            });
            //var matchToAdd = matchToAdd[0];

            // matchIsNew so toAdd: yes, no.
            var matchIsNew = (matchToAdd.length > 0) ? true : false;
            if (matchIsNew) { // current matchId is also in toAdd.
                console.log('matchIsNew TRUE', matchToAdd[0].matchCtn);
                if (typeof matchToAdd[0].matchCtn !== 'undefined') {
                    $(matchToAdd[0].matchCtn).parent().insertBefore('.shownotav').delay(50).fadeOut().fadeIn('slow');
                    console.log('added new match:', v.matchCtn, v);
                    addedMatchesCtn.push($(matchToAdd[0].matchCtn).parent());
                    $('#scriptinfo-box').prepend('<li class="linfo sticker"><span class="timenow">' + self.tools() + '</span>A new match has been added (#' + v.matchId + ') !</li>');
                    $('.numofm').html((globalData.currentData).length).delay(50).fadeOut().fadeIn('slow');
                }
            }
            if (!matchIsNew) { // matchCtn is in detachedMatches
                var matchToReAppend = $.grep(detachedMM, function (element, index) {
//                    console.log('matchIsNOTNew', detachedMM, element, v.matchId);
                    //return element.matchId === v.matchId;
                    return element.matchId === v.matchId;
                });
                var matchToReAppend = matchToReAppend[0];
//                console.log('matchToReAppend, matchIsNOTNew ', matchToReAppend)
                if (typeof matchToReAppend.matchCtn !== 'undefined') {
                    $(matchToReAppend.matchCtn).insertBefore('.shownotav');
                }
            }
        });
    }
    // Properties update
    var propsToUpdate = this.propsToUpdate;
    function getPropValue(obj, prop) {
        var toRet;
        $.each(obj, function (propl, val) {
            if (propl === prop) {
                toRet = val;
                return false;
            }
        });
        return toRet;
    }
    var debugAU = false;
    for (var x = 0; x < propsToUpdate.length; x++) { // loop through propsToUpdate
        var obj = propsToUpdate[x]; // obj in propsToUpdate array
        var matchId = obj.matchId;
//        if (matchId === "9999") {
//            var matchId = "3051"
//            var a = $('body').find('a[href="match?m=3051"]').closest('.match').parent();
//            var container = a['1'];
//            var container = $(container);
//        } else {
        var subContainer = $('body').find('a[href="match?m=' + matchId + '"]').closest('.match'); // .match ctn
        var container = subContainer.parent(); // .matchmain ctn
//        }
        if (debugAU) {
            console.log(['AU:'], ' ', '-------- check matchId:', matchId, ' ------');
            console.log(['AU:'], ' ', 'var x in propsToUpdate', 'container', container, 'obj', obj, 'prop', prop, 'dest', destCtn, 'destSel', destCtnSel);
        }
        for (var prop in obj) { // browse each prop of the obj
            if (debugAU) {
                console.log(['AU:'], ' ', '(var prop in obj)', 'prop', prop);
            }
            if (prop !== "matchId" || prop !== "teamBperc" || prop !== "teamAperc" || prop !== "percStatus" || prop !== "matchCtn") {
                var destCtnSel = getPropValue(this.propsContainers, prop); // where to append the prop
                var destCtn = container.find(destCtnSel);
                if (destCtn.length > 0) {
                    var newValue = obj[prop];
                    destCtn.html(newValue).delay(100).fadeOut().fadeIn('slow');
                    console.log('Updated matchId:', matchId, ' prop:', prop, ' with value:', newValue, 'in container:', destCtn);
                }
            }
            if (prop === "timeLeft") { // Live !, Postponed, Closed etc...
                console.log("PROPTIMELEFT:", prop, obj[prop], this, container, msCtn, this.liveNow, obj[prop].indexOf('ago'));
                if (obj[prop].indexOf('ago') > -1) {
                    var msCtn = container.find('.matchstatus');
                    msCtn.html(this.liveNow);
                }
            }

            if (prop === "percStatus") { // arrows
                if (typeof obj.percStatus.teamAperc !== "undefined") {
                    var destCtn = container.find('.arrow-teama');
                    if (typeof destCtn !== "undefined" && destCtn.length > 0) {
                        destCtn.html(this.arrow[obj.percStatus.teamAperc]).delay(100).fadeOut().fadeIn('slow');
                    }
                }
                if (typeof obj.percStatus.teamBperc !== "undefined") {
                    var destCtn = container.find('.arrow-teamb');
                    if (typeof destCtn !== "undefined" && destCtn.length > 0) {
                        destCtn.html(this.arrow[obj.percStatus.teamBperc]).delay(100).fadeOut().fadeIn('slow');
                    }
                }
            }
            if (prop === "teamBperc" || prop === "teamAperc") {
                var destCtnSel = getPropValue(this.propsContainers, prop); // where to append the prop
                var destCtn = container.find(destCtnSel);
                if (destCtn.length > 0) {
                    if (debugAU) {
                        console.log(['AU:'], ' ', 'prop', prop, 'dest', destCtn, 'destSel', destCtnSel);
                    }
                    var newValue = obj[prop];
                    destCtn.html(newValue).delay(100).fadeOut().fadeIn('slow');
                }
            }

        }   // for (var prop in obj)
    }   // for (var x in propsToUpdate)



    var dfd = new jQuery.Deferred();
    return dfd.resolve(this, toAdd, toRem);
};
globalClass.prototype.autoUpdateTimers = function () {
    var today = new Date();
    var hh = today.getHours();
    var mm = today.getMinutes();
    var ss = today.getSeconds();
    if (ss <= 9)
        ss = "0" + ss;
    if (mm <= 9)
        mm = "0" + mm;
    var timeNow = hh + ':' + mm + ':' + ss;
    $('.au-lasttime').html(timeNow);
//    var mins = settings.updateDelay;
    var secs = settings.updateDelay / 1000;
    var currentSeconds = 0;
    var currentMinutes = 0;
    if (typeof window.autoUpdateTimer != "undefined") {
        clearInterval(window.autoUpdateTimer);
    }

    window.autoUpdateTimer = setInterval(function () {
        auCountDown();
    }, 1000);
    function auCountDown() {
        currentMinutes = Math.floor(secs / 60);
        currentSeconds = secs % 60;
        if (currentSeconds <= 9)
            currentSeconds = "0" + currentSeconds;
        secs--;
        $('.au-timeleft').html(currentMinutes + "m " + currentSeconds + "s");
        if (secs === -1) {
            clearInterval(window.autoUpdateTimer);
            $('.au-timeleft').html('updating...');
        }
    }


};
/* *********** join Matches And Feed *********** */
globalClass.prototype.compareMatchesWithFeed = function () {
    _log('*** Compare Matches With Feeds ***');
};
globalClass.prototype.appendFeedToMatches = function () {
    _log('*** Append Feed to Matches ***');
};
globalClass.prototype.tools = function () {
    _log('*** tools ***');
    var today = new Date();
    var hh = today.getHours();
    var mm = today.getMinutes();
    var ss = today.getSeconds();
    if (ss <= 9)
        ss = "0" + ss;
    if (mm <= 9)
        mm = "0" + mm;
    var timeNow = hh + ':' + mm + ':' + ss;
    return timeNow;
};
function CompleteInitialization(worker, selector) {
//    var initGlobal = new globalClass('initialization'); // wrap init + get each match infos + appends
    var selector = (typeof selector === "undefined") ? "" : selector;
    this.job.retrieveMissing = (typeof selector != "undefined" && selector.length > 0) ? true : false;
    console.log('this (CompleteInitialization)', this, worker, selector, this.job.retrieveMissing);
    $.when(this.parseMainPage(selector)).then(function (that) {
        pLog('DONE:', 'parseMainPage', that);
        return that.globalInfos();
    }).then(function (that) {
        pLog('DONE:', 'globalInfos', that);
        return that.initLoading();
    }).then(function (that) {    // Get Match Infos LOOP
        var promisesCompleteInit = [];
        var data = that[that.worker].data;
        $.each(data, function (index, matchUrl) {
            var matchUrl = data[index].matchUrl;
            var matchId = data[index].matchId;
            var matchCtn = data[index].matchCtn;
            _log('curr =', matchUrl, that);
            var p = that.ajaxCalls(that.worker, that.job, matchUrl, matchId, matchCtn, settings.defaultTimeout); //
            promisesCompleteInit.push(p);
            p.done(function (data, textStatus, jqXHR) {
                var responseData = jqXHR.responseText;
                that.monitorWorker("success", "request", matchCtn, matchId); // monitor global responses status to count how many succeed and failed.

                // when request is done, process the data.
                $.when(that.parseMatchPageData(that.worker, that.job, matchUrl, matchId, matchCtn, responseData)).then(function (that, data) {
                    return that.appendEachMatch(that.worker, that.job, matchUrl, matchId, matchCtn, data);
                }).then(function (that, matchCtn, matchId) {
                    pLog('DONE: CompleteInitialization, appendEachMatch', that);
                    that.monitorWorker("success", "view", matchCtn, matchId); // monitor global responses status to count how many succeed and failed.
                    return that.updateLoading(that[that.worker].loadingStatus); // send each request status individually to updateLoading
                });
            });
            p.fail(function (jqXHR, stringStatus, exceptionObj) { // exceptionObj: "abort", "timeout", "No Transport".
                if (exceptionObj) {
                    switch (exceptionObj) {
                        case 'abort':
                            var errorType = 'abort';
                            that.errorHandling("error", "request", matchCtn, matchId, errorType);
                            that.monitorWorker("error", "request", matchCtn, matchId); // monitor global responses status to count how many succeed and failed.
                            break;
                        case 'timeout':
                            var errorType = 'timeout';
                            that.errorHandling("error", "request", matchCtn, matchId, errorType);
                            that.monitorWorker("error", "request", matchCtn, matchId); // monitor global responses status to count how many succeed and failed.
                            break;
                        case 'No Transport':
                            var errorType = 'No Transport';
                            that.errorHandling("error", "request", matchCtn, matchId, errorType);
                            that.monitorWorker("error", "request", matchCtn, matchId); // monitor global responses status to count how many succeed and failed.
                            break;
                    }
                } else {
                    var errorType = 'error';
                    that.errorHandling("error", "request", matchCtn, matchId, errorType);
                    that.monitorWorker("error", "request", matchCtn, matchId); // monitor global responses status to count how many succeed and failed.
                }
                pLog('Failed to retrieve a match in CompleteInitialization', errorType, matchUrl);
            });
        }); // each ended.

        $.when.apply($, promisesCompleteInit)
                .always(function () {
                    that.done();
                    pLog('DONE: CompleteInitialization ajax req and appends have just finished.');
                    if (settings.switches.autoupdate) {
                        console.log('Initializing Update in ' + settings.updateDelay / 1000 / 60 + ' minutes');
//                    console.log('GLOBALOBJ',that.initialization.data)
//                    console.log('GLOBALOBJ',globalData.currentData )
                        that.autoUpdateTimers();
                        window.autoUpdate = setInterval(function () {
                            console.log('UpdateInitialization');
                            that.autoUpdateTimers();
                            UpdateInitialization();
                        }, settings.updateDelay);
                    }
                })
                .done(function () {
                    console.log('Fired all methods for worker init were done without errors.');
                })
                .fail(function () {
                    console.log('Fired all methods for worker init were done WITH ERRORS.');
                });
    });
}
/*
 * @CompleteInitialization()
 "parseMainPage",
 "globalInfos",
 "initLoading",
 "getMatchInfos", // WRAPPED THIS DIRECTLY IN CompleteInitialization function.
 "ajaxCalls",
 "parseMatchPageData",
 "appendEachMatch",
 "updateLoading"
 */

function UpdateInitialization() {   // (AU = Auto Update)
    pLog('UpdateInitialization fired !');
    var initUpdate = new globalClass('updatePage'); // init page view only
    $.when(initUpdate.getMainPageDistant())
            .then(function (that) {
                var AUmainpage = initUpdate.ajaxCalls(initUpdate.worker, "updatePage", baseUrl, "", "", settings.defaultTimeout);
                AUmainpage.done(function (data, textStatus, jqXHR) {
                    pLog('req ', baseUrl, ' done.');
                    $.when(that.parseMainPage("", data))
                            .then(function (that) {
                                pLog('DONE:', 'globalInfos', that);
                                return that.initLoading();
                            })
                            /* ---------------- */
                            .then(function (that, data) {    // Get Match Infos LOOP
                                _log('parseMainPage DONE', that[that.worker]);
                                var promisesUpdateInit = [];
                                var promisesUpdateParsing = [];
                                var dataG = that[that.worker].data;
                                $.each(dataG, function (index, matchUrl) {
                                    var matchUrl = dataG[index].matchUrl;
                                    var matchId = dataG[index].matchId;
                                    var matchCtn = dataG[index].matchCtn;
                                    //console.log('curr =', matchUrl, that);
                                    var px = that.ajaxCalls(that.worker, that.job, matchUrl, matchId, matchCtn, settings.defaultTimeout); //
                                    promisesUpdateInit.push(px);
                                    px.done(function (data, textStatus, jqXHR) {    // ajax request is complete and has success status.
                                        var responseData = jqXHR.responseText;
                                        pLog('DONE', that.worker, that.job, matchUrl, matchId, matchCtn);
                                        that.monitorWorker("success", "request", matchCtn, matchId); // monitor global responses status to count how many succeed and failed.
                                        promisesUpdateParsing.push(that.parseMatchPageData(that.worker, that.job, matchUrl, matchId, matchCtn, responseData)); // Parse the data.
                                        if (promisesUpdateParsing.length === dataG.length) {    //  wait for all parsing promises returned by parseMatchPageData method.
                                            $.when.apply($, promisesUpdateParsing).then(
                                                    function (status) {
                                                        $.when(that.compareData())
                                                                .then(function (that) {
                                                                    return that.updateData();
                                                                }, function () {
                                                                    console.log('E R R O R');
                                                                })
                                                                .then(function (that, toAdd, toRem) { // datas append when a new match has been added.
                                                                    console.log('UPDATEDATADONE:', toAdd);
                                                                    if (typeof toAdd != "undefined" && toAdd.length > 0) {
                                                                        console.log('UPDATEDATADONE:', toAdd);
                                                                        for (var i = 0; i < toAdd.length; i++) {
                                                                            console.log('appending shit to a new ctn:', toAdd[i]);
                                                                            that.appendEachMatch(that.worker, that.job, toAdd[i].matchUrl, toAdd[i].matchId, toAdd[i].matchCtn, toAdd[i]);
                                                                        }
                                                                    }
                                                                    // when a match has been removed.
                                                                    console.log('UPDATEDATADONE:', toRem);
                                                                    if (typeof toRem != "undefined" && toRem.length > 0) {
                                                                        console.log('UPDATEDATADONE:', toRem);
                                                                        for (var i = 0; i < toRem.length; i++) {
                                                                            var matchUrl = toRem[i].matchUrl;
                                                                            var matchId = toRem[i].matchId;
                                                                            console.log('appending shit to a new ctn:', toAdd[i]);
                                                                            console.log("TOREMOVE", toRem.length);
                                                                            console.log('toRem[i].matchCtn', toRem[i].matchCtn);
                                                                            // find, detach and append match ctn to shna
                                                                            var toRemCtn = $('body').find('a[href="match?m=' + matchId + '"]').parents().eq(2);
                                                                            var detachedToRemCtn = toRemCtn.detach();
                                                                            detachedToRemCtn.appendTo('#sh-na').find('.match').addClass('notavailable');
                                                                            console.log('detached', matchId, detachedToRemCtn, 'and appended to #sh-na');
                                                                            // ajax call the match page to get the match result or status (winner/loser or postponed, closed etc...)
                                                                            $.when(that.ajaxCalls(that.worker, that.job, matchUrl, matchId, detachedToRemCtn, settings.defaultTimeout))
                                                                                    .done(function (data, textStatus, jqXHR) {
                                                                                        console.log('REMOVEDONE:', textStatus, jqXHR, matchUrl, matchId);
                                                                                        var data = $(data);
                                                                                        var resultSel = data.find('.box-shiny-alt:eq(0)');
                                                                                        var teamARes = resultSel.find('b:eq(0)');
                                                                                        var teamBRes = resultSel.find('b:eq(1)');
                                                                                        var teamARes = teamARes.text().trim();
                                                                                        var teamBRes = teamBRes.text().trim();
                                                                                        console.log('teamARes', teamARes);
                                                                                        console.log('teamBRes', teamBRes);
                                                                                        var wonImg = '<img style="position: relative; left: 40px; top: -12px;" src="http://cdn.csgolounge.com/img/won.png">';
                                                                                        if (teamARes.indexOf('WIN') > -1 || teamBRes.indexOf('WIN') > -1) {
                                                                                            var matchResult = teamARes + ' vs ' + teamBRes;
                                                                                            var checkStatus = "lerror";
                                                                                            if (teamARes.indexOf('(win)') > -1) {
                                                                                                var ta = detachedToRemCtn.find('.teamtext');
                                                                                                var ta = ta.next();
                                                                                                ta.prev().html(wonImg);
                                                                                            }
                                                                                            if (teamARes.indexOf('(win)') > -1) {
                                                                                                var tb = detachedToRemCtn.find('teamtext');
                                                                                                var tb = tb.prev();
                                                                                                tb.prev().html(wonImg);
                                                                                            }
                                                                                        }

                                                                                        console.log('tatb', ta, tb);
                                                                                        var msSel = $('body').find('.box-shiny-alt div:eq(4)');
                                                                                        var matchStatus = msSel.text().trim();
                                                                                        console.log('matchStatus', matchStatus);
                                                                                        if (matchStatus !== "") {
                                                                                            var matchResult = matchStatus;
                                                                                            var checkStatus = "lerror";
                                                                                        }
                                                                                        if (typeof matchResult === "undefined") {
                                                                                            var matchResult = '<a href="' + matchUrl + '" target="_blank">Could not find result for match #' + matchId + ', check it by clicking here</a>';
                                                                                            var checkStatus = "lwarning";
                                                                                        }
                                                                                        // apppend match status and prepend info
                                                                                        $('#scriptinfo-box').prepend('<li class="' + checkStatus + ' sticker"><span class="timenow">' + that.tools() + '</span>A match has just been closed:<br /> ' + matchResult + '</li>');

                                                                                    })
                                                                                    .fail(function (jqXHR, stringStatus, exceptionObj) { // exceptionObj: "abort", "timeout", "No Transport".
                                                                                        console.log('REMOVEFAIL:', jqXHR, stringStatus, exceptionObj);
                                                                                    });
                                                                            // append status to ctn and info
                                                                        }
                                                                    }
                                                                }, function () {
                                                                    console.log('E R R O R');
                                                                });
                                                    });
                                        }
                                    });
                                    px.fail(function (jqXHR, stringStatus, exceptionObj) { // exceptionObj: "abort", "timeout", "No Transport".
                                        var dfd = new jQuery.Deferred();
                                        promisesUpdateParsing.push(dfd.resolve()); // resolve the item that should have been parsed by promisesUpdateParsing anyway, we need to feed promisesUpdateParsing array to know all available  data have been parsed by parseMatchPageData.

                                        if (exceptionObj) {
                                            switch (exceptionObj) {
                                                case 'abort':
                                                    var error = 'abort';
                                                    break;
                                                case 'timeout':
                                                    var error = 'timeout';
                                                    break;
                                                case 'No Transport':
                                                    var error = 'No Transport';
                                                    break;
                                            }
                                        } else {
                                            var error = 'error';
                                        }
                                        that.monitorWorker("error", "request", matchCtn, matchId); // monitor global responses status to count how many succeed and failed.
                                        console.log('REQUESTFORAUFAILED:', that.worker, that.job, matchUrl, matchId, matchCtn, jqXHR, stringStatus, exceptionObj);
                                        var msg = ' There was an error while retrieving match #' + matchId + ' datas. Could not update it for now, trying again in ~' + settings.updateDelay / 1000 / 60 + ' minutes...';
                                        $('#scriptinfo-box').prepend('<li class="lerror sticker"><span class="timenow">' + that.tools() + '</span>' + msg + '</li>');
                                    });
                                }); // each ended.

                                $.when.apply($, promisesUpdateInit)
                                        .done(function (that) {
                                            console.log('Fired all methods for worker UPDATEPAGE, all done without errors.');
                                            $('#force-refresh').removeClass('fr-loading').addClass('fr-notloading');
                                        })
                                        .fail(function (that) {
                                            console.log('Fired all methods for worker UPDATEPAGE, all done WITH ERRORS.');
                                            $('#force-refresh').removeClass('fr-loading').addClass('fr-notloading');
                                        });
                            });
                    /* ---------------- */
                });
                AUmainpage.fail(function (jqXHR, stringStatus, exceptionObj) { // exceptionObj: "abort", "timeout", "No Transport".
                    $('#scriptinfo-box').prepend('<li class="lerror sticker"><span class="timenow">' + that.tools() + '</span> Main page request for auto update failed. Site might be overloaded ? If many tries fail again, please disable auto update until site trafic downs.');
                    console.log('Main page request for auto update failed.');
                });
            });
}
/*
 * @UpdateInitialization()
 *
 getMainPageDistant
 ajaxCalls
 parseMainPage
 initLoading
 each dataG
 ajaxCalls
 monitorWorker
 parseMatchPageData
 compareData
 if add => appendEachMatch
 */


function FeedsInitialization() {
    var initFeeds = new globalClass('feeds'); // Turn on feeds
    $.when(initFeeds.initGlobalProcess()).then(function (that) {
        pLog('DONE:', 'initGlobalProcess', that);
        return that.globalInfos();
    }).then(function (that) {
        pLog('DONE:', 'globalInfos', that);
        return that.initLoading();
    }).then(function (that) {
        pLog('DONE:', 'initLoading', that);
        that[that.worker] = that.feeds;
        // ask ajaxCalls to request each feeds
        $.each(that.feeds.data, function (index, feedName) {
            var url = that.feeds.feedsDatas[feedName].url;
            var feedContainer = $("#" + feedName + "feed .feedslinks-box ul");
            var job = feedName;
            _log('feedName', that.worker, that.job, url, feedName, feedContainer);
            $.when(that.ajaxCalls(that.worker, that.job, url, feedName, feedContainer, 30000))
                    .done(function (data, textStatus, jqXHR) {
                        var responseData = jqXHR.responseJSON;
                        _log('AJAX CALL DONE', data, textStatus, jqXHR);
                        that.monitorWorker("success", "request", feedContainer, feedName);
                        // when request is done, process the data.
                        $.when(that.appendEachFeed(that.worker, that.job, url, feedName, feedContainer, responseData)).then(function (that, data) {
                            that.monitorWorker("success", "view", feedContainer, feedName);
                            return that.updateLoading(that.worker, that.job, url, feedName, feedContainer, data);
                        });
                    })
                    .fail(function (jqXHR, stringStatus, exceptionObj) { // exceptionObj: "abort", "timeout", "No Transport".
                        if (exceptionObj) {
                            switch (exceptionObj) {
                                case 'abort':
                                    var error = 'abort';
                                    if (feedName === "hltv") {
                                        $('#hltvfeed .feedslinks-box').append('<li>' + that.errors.feeds.abort + '</li>');
                                    }
                                    if (feedName === "reddit") {
                                        $('#redditfeed .feedslinks-box').append('<li>' + that.errors.feeds.abort + '</li>');
                                    }
                                    break;
                                case 'timeout':
                                    if (feedName === "hltv") {
                                        $('#hltvfeed .feedslinks-box').append('<li>' + that.errors.feeds.timeout + '</li>');
                                    }
                                    if (feedName === "reddit") {
                                        $('#redditfeed .feedslinks-box').append('<li>' + that.errors.feeds.timeout + '</li>');
                                    }
                                    var error = 'timeout';
                                    break;
                                case 'No Transport':
                                    if (feedName === "hltv") {
                                        $('#hltvfeed .feedslinks-box').append('<li>' + that.errors.feeds.errors + '</li>');
                                    }
                                    if (feedName === "reddit") {
                                        $('#redditfeed .feedslinks-box').append('<li>' + that.errors.feeds.errors + '</li>');
                                    }
                                    break;
                            }
                        } else {
                            var error = 'error';
                        }
                        that.monitorWorker("error", "request", feedContainer, feedName); // monitor global responses status to count how many succeed and failed.
                        pLog('Feeds failed to retrieve data', error, feedName, feedContainer);
                    });
        });
    }).done(function (that) {
        pLog('DONE:', 'ajaxCalls', that);
        pLog('done all.');
        initFeeds.done();
    });
}
/*
 * @Feeds()
 "initGlobalProcess",
 "globalInfos",
 "initLoading",
 "getFeeds",
 "ajaxCalls",
 "appendEachFeed",
 "updateLoading"
 */

function initialization(initType) {
//    var initGlobal = new globalClass('basicInit'); // init page view only
    var worker = 'initialization'; // default
    switch (initType) {
        case "complete":
            var worker = 'initialization';
            break;
        case "basic":
            var worker = 'basicInit';
            break;
    }
    var initGlobal = new globalClass(worker); // init page view only
    $.when(initGlobal.initGlobalProcess()).then(function (that) {
        pLog('DONE:', 'initGlobalProcess', that);
        return that.initPageView();
    }).then(function (that) {
        pLog('DONE:', 'initPageView', that);
    }).done(function (that) {
        pLog('DONE:', 'BasicInitialization', that);
        if (initType === "basic") { // a basic Init has been requested, finishing.
            return initGlobal.done();
        } else {    // a complete init has been requested, continueing.
            CompleteInitialization.call(initGlobal);
        }
    });
}
/*
 * @BasicInitialization()
 "initGlobalProcess",
 "initPageView"
 */
settings.switches.completeinit ? initialization('complete') : initialization('basic');
if (settings.switches.feeds) {
    FeedsInitialization();
}

//UpdateInitialization();



//var initGlobal = new globalClass('basicInit'); // init page view only
//var initGlobal = new globalClass('UpdatePage'); // wrap init + get each match infos + appends

//var initGlobal = new globalClass('initialization'); // wrap init + get each match infos + appends
//initGlobal.initGlobalProcess();
//var initFeeds = new globalClass('feeds');
//initFeeds.initGlobalProcess();
//
//var initUpdatePage = new globalClass('UpdatePage'); // init updateData worker
//initUpdatePage.initGlobalProcess();
//