Friday, February 4, 2011

FB MafiaWars Addon


// ==UserScript==
// @name           FB MafiaWars Addon
// @copyright      2010 - David Cabrera
// @version        0.3.1.4
// @description    Facebook MafiaWars Tools.
// @include        http://userscripts.org/scripts/source/90615.meta.js*
// @include        http://apps.facebook.com/inthemafia/*
// @include        http://facebook.mafiawars.com/mwfb/remote/html_server.php*
// @include        http://www.connect.facebook.com/widgets/serverfbml.php*
// @exclude        http://facebook.mafiawars.com/mwfb/*#*
// @exclude        http://facebook.mafiawars.com/mwfb/remote/html_server.php?xw_controller=requests*
// @exclude        http://facebook.mafiawars.com/mwfb/remote/html_server.php?xw_controller=freegifts*
// ==/UserScript==

const DEBUG_MODE = false;

if (typeof(unsafeWindow) == 'undefined') {
    unsafeWindow = window;
}

var scriptAppInfo = 
{
    appName: 'FB MafiaWars Addon',
    appTag: 'FBMafiaWarsAddon_',
    appVer: '0.3.1.4',
    appUrl: 'http://userscripts.org/scripts/show/90615',
    appMeta: 'http://userscripts.org/scripts/source/90615.meta.js',
    appUpdateInterval: 6
};

var Base64 = function () {
    var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    /**
     * private method for UTF-8 encoding
     * @private
     * @param {String} string
     * @return {String}
     */
    var _utf8_encode = function(string) {
        string = string.replace(/\r\n/g, "\n");
        var utftext = "";
        
        for (var n = 0; n < string.length; n++) {
        
            var c = string.charCodeAt(n);
            
            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if ((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }
        }
        return utftext;
    };
    /**
     * private method for UTF-8 decoding
     * @private
     * @param {String} utftext
     * @return {String}
     */
    var _utf8_decode = function(utftext) {
        var string = "";
        var i = 0;
        var c = 0, c1 = 0, c2 = 0, c3 = 0;
        
        while (i < utftext.length) {
        
            c = utftext.charCodeAt(i);
            
            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            }
            else if ((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i + 1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            }
            else {
                c2 = utftext.charCodeAt(i + 1);
                c3 = utftext.charCodeAt(i + 2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }
        }
        return string;
    };  
    /**
     * Public method for encode
     * @param {String} input
     */
    this.encode = function(input) {
        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;
        
        input = _utf8_encode(input);
        
        while (i < input.length) {
        
            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);
            
            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;
            
            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            }
            else if (isNaN(chr3)) {
                enc4 = 64;
            }
            
            output = output +
            _keyStr.charAt(enc1) +
            _keyStr.charAt(enc2) +
            _keyStr.charAt(enc3) +
            _keyStr.charAt(enc4);
            
        }
        return output;
    };
    /**
     * Public method for decode
     * @param {String} input
     */
    this.decode = function(input) {
        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;
        
        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
        
        while (i < input.length) {
        
            enc1 = _keyStr.indexOf(input.charAt(i++));
            enc2 = _keyStr.indexOf(input.charAt(i++));
            enc3 = _keyStr.indexOf(input.charAt(i++));
            enc4 = _keyStr.indexOf(input.charAt(i++));
            
            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;
            
            output = output + String.fromCharCode(chr1);
            
            if (enc3 != 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 != 64) {
                output = output + String.fromCharCode(chr3);
            }
            
        }
        output = _utf8_decode(output);
        return output;
    };
    
    return this;
}

/**
 * Creates a Config object that save/load data in json string format.
 * @constructor
 * @param {String} name Used for set/get from elements (element.id = name + defOptions.var_name) 
 * @param {Array} defOptions Array of key => value pairs.
 * @return {Config}
 */
var Config = function(name, _default) {
    var options = _default;
    var elementKey = name;
    var appPath = scriptAppInfo.appTag + name;
    var _this = this;
    
    var toGood = function(value, def) {
        switch (typeof(def)) {
            case 'string'  : return String(value);
            case 'number'  : return isNaN(value) === false  ? parseInt(value) : def;
            case 'boolean' : return value === true;
            default: 
                if (typeof(value) !== typeof(def)) {
                    return def;
                }
                else {
                    return value;
                }
        }
    };
    var loadOptions = function(str) {
        if (str == null)
            return;
        
        var tempOpt = $.parseJSON(str);
        $.each(tempOpt, function(name, value){
            if (typeof(options[name]) !== 'undefined') {
                options[name] = toGood(value, options[name]);
            }
        });
    };
    this.each = function(fn) {
        $.each(options, fn);
    };
    this.get = function(key) {
        return options[key];
    };
    this.set = function(key, new_value) {
        options[key] = toGood(new_value, options[key]);
    };
    this.save = function(callback) {
        setTimeout(function() {
            //log$('saving: ('+appPath+')'+$.toJSON(options));
            GM_setValue(appPath, $.toJSON(options));
            if (typeof callback == 'function')
                callback.apply(_this);
        }, 0);
    };
    this.load = function(callback) {
        setTimeout(function() {
            loadOptions(GM_getValue(appPath, null));
            //log$('loaded ('+appPath+'): '+GM_getValue(appPath, 'null'));
            if (typeof callback == 'function')
                callback.apply(_this);
        }, 0);
    };
    this.toDomElements = function() {
        $.each(options, function(name, value) {
            _this.setToElement(name);
        });
    };
    this.fromDomElements = function() {
        $.each(options, function(name, value) {
            _this.getFromElement(name);
        });
    };  
    this.setToElement = function(name) {
        var elem = e$('#' + elementKey +'_'+ name.toLowerCase());
        if (elem == null) 
            return;
            
        if (elem.is('input:checkbox')) {
            elem[0].checked = this.get(name);
        }
        else if (elem.is('select[multiple]')) {
            elem.empty();
            $.each(this.get(name), function(name, value) {
                elem.append(c$('option', 'value:'+name).text(value));
            });
        }
        else {
            elem.val(this.get(name));
        }
        
    };
    this.getFromElement = function(name) {
        var elem = e$('#' + elementKey +'_'+ name.toLowerCase());
        if (elem == null) 
            return;
        
        if (elem.is('input:checkbox')) {
            this.set(name, elem.get(0).checked);
        }
        else if (elem.is('select[multiple]')) {
            var arr = {};
            elem.children().each(function(index,opt){
                arr[opt.value] = $(opt).text();
            });
            this.set(name, arr);
        }
        else {
            this.set(name, elem.val());
        }
    };
    return this;
};

/**
 * Global variables
 */
var global = {
    /** @type String */ USER_ID      : '',
    /** @type String */ PERSON_ID    : '',
    /** @type Base64 */ Base64       : null,
    /** @type Config */ options      : null,
    /** @type Object */ popups       : new Object(),
    /** @type String */ zGraphicsURL : 'http://mwfb.static.zynga.com/mwfb/graphics/',
    /** @type String */ fbAuthUrl    : 'https://graph.facebook.com/oauth/authorize?client_id=10979261223&redirect_uri=http://apps.facebook.com/inthemafia/index.php&type=user_agent&display=popup',
    /** @type String */ href         : '',
    /** @type String */ uri_tmpcb    : '',
    
    pages: {
        'story_controller': jobPage,
        'job_controller': jobPage,
        'map_controller': jobMapPage,
        'freegifts_controller': giftPage,
        'socialmission_controller': missionPage,
        'collection_controller': collectionPage,
        'stats_controller': statsPage
    },
    
    cities: {
        1: 'New York',
        2: 'Cuba',
        3: 'Moscow',
        4: 'Bangkok',
        5: 'Las Vegas',
        6: 'Italy'
    },
    
    userStats: {
        'health': function() {
            return unsafeWindow.User.health;
        },
        'max_health': function() {
            return unsafeWindow.User.max_health;
        },
        'energy': function() {
            return unsafeWindow.User.energy;
        },
        'max_energy': function() {
            return unsafeWindow.User.max_energy;
        },
        'stamina': function() {
            return unsafeWindow.User.stamina;
        },
        'max_stamina': function() {
            return unsafeWindow.User.max_stamina;
        },
        'exp_to_next_level': function() {
            return $('#exp_to_next_level').text();
        },
        'healthpercent': function() {
            return parseFloat((unsafeWindow.User.health * 100) / unsafeWindow.User.max_health);
        }
    }
};

// =========================================================
// CONSOLE LOG (DEBUG)
// =========================================================
/**
 * Send text to window console.
 * @param {String} msg
 */
function log$(message) {
    if (DEBUG_MODE === false)
        return;
        
    try {
        (console||unsafeWindow.console).log('FBMWAddon (DEBUG): ' + message);
    } 
    catch (e) {
        // EMPTY
    }
}
/**
 * 
 * @param {Object} err
 */
function logErr$(err) {
    var sStack   = '';
    var sMessage = '';
    try {
        sMessage = err.message + '. ';
        sStack = err.stack.split('\n')[1];
    }
    catch(e) {
        sMessage = err;
    }
    try {
        (console||unsafeWindow.console)
        .log('FBMWAddon (ERROR): ' + sMessage + '\n' + sStack);
    } 
    catch (e) {
        // EMPTY
    }
}

// =========================================================
// SELECTORS
// =========================================================
/**
 * Get a jQuery with at least 1 element, otherwise null.
 * @param {Object} selector
 * @param {Object} context
 * @return {jQuery}
 */
function e$(selector, context) {
    var j = $(selector, context);
    if (j.length > 0) {
        return j;
    }
    
    return null;
}

/**
 * Create a jQuery from a HTML text.
 * @param {String} htmlText
 * @return {jQuery}
 */
function h$(htmlText) {
    var elem = c$('div');
    elem[0].innerHTML = htmlText;
    return elem;
}

/**
 * Create a new element.<br><br>
 * NAME can be an element, jquery or string.<br>
 * script and style tag are supported.<br>
 * input elements can set the type in format "input:text" for example.<br><br>
 * ATTR String format is: "name1:value1 , name2:value2" etc...
 * @param {String, jQuery, Element} name The new element to create.
 * @param {Object, String} attr Attributes to set to the new jquery element 
 * @return {jQuery}
 */
function c$(name, attr) {
    var inputRegex = /^input:(\w+)$/i;
    var obj, r, a;
    // create the object
    if (typeof(name) !== "string") {
        obj = $(name);
    }
    else if ((r = inputRegex.exec(name))) {
        obj = $('<input type="' + r[1] + '">');
    }   
    else {
        if (name == 'style') {
            obj = $('<' + name + ' type="text/css">');
        }
        else if (name == 'script') {
            obj = $('<' + name + ' type="text/javascript">');
        }
        else {
            obj = $('<' + name + '>');
        }
    }
    // return undefined if no object is created 
    if (obj.length < 1) 
        return null;
        
    // apply attributes
    if (typeof(attr) === "string") 
    {
        if ((r = attr.split(',')).length > 1) {
            for (var i = 0; i < r.length; i++) {
                if ((a = r[i].split(':')).length == 2) {
                    obj.attr($.trim(a[0]), $.trim(a[1]));
                }
            }
        }
        else if ((a = attr.split(':')).length == 2) {
            obj.attr($.trim(a[0]), $.trim(a[1]));
        }
        else {
            obj.attr('id', $.trim(attr));
        }
    }
    else if (typeof(attr) === "object") {
        obj.attr(attr);
    }
    
    return obj;
}

/**
 * Get a Element from an evaluated expression.
 * @param {Object} selector
 * @param {Object} context
 * @return {Element}
 */
function x$(selector, context) {
    context = context || document;
    return document.evaluate(selector, context, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
}

/**
 * Return an Array of Node Elements
 * @param {Object} selector
 * @param {Object} context
 * @return {Array}
 */
function a$(selector, context) {
    context = context || document;
    var elem, elements = [];
    var result = document.evaluate(selector, context, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
    while ((elem = result.iterateNext())) {
        if (elem.nodeType) 
            elements.push(elem);
    }
    return elements;
}

// =========================================================
// INIT FUNCTIONs
// =========================================================
function initStorage() {

    if (typeof GM_deleteValue == 'undefined')
    {
        log$('Greasemonkey api don\'t found. using localStorage...');
        if (typeof(localStorage) == 'undefined' || typeof(localStorage.getItem) == 'undefined') 
        {
            if (!(localStorage = unsafeWindow.localStorage)) {
                log$('localStorage is undefined, using a temporal storage.');
                localStorage = new (function() {
                    var tmp_array= [];
                    this.setItem= function(name, value){
                        tmp_array[name] = value;
                    },
                    this.getItem = function(name) {
                        return tmp_array[name] || null;
                    },
                    this.removeItem = function(name) {
                        tmp_array[name] = null;
                    }
                    return this;
                })();
            }
        }
        /**
         * Sets the named preference to the specified value.
         * @param {String} name The name preference.
         * @param {String, Number, Boolean} value Must be strings, booleans, or integers.
         */
        GM_setValue = function(name, value) {
            localStorage.setItem(name, value);
        };
        /**
         * Returns the named preference, or defaultValue if it does not exist
         * @param {String} name The name preference.
         * @param {String, Number, Boolean} defaultValue To return if it does not exist.
         * @return {String, Number, Boolean}
         */
        GM_getValue = function(name, defaultValue) {
            var value = localStorage.getItem(name);
            return value || defaultValue;
        };
        /**
         * deletes the named preference or subtree
         * @param {String} name The name preference to delete.
         */
        GM_deleteValue = function(name) {
            localStorage.removeItem(name);
        };
    }
}
function initjQuery(accessToken) {
    
    if (typeof(unsafeWindow.$) == 'undefined' || typeof(unsafeWindow.FB) == 'undefined') {
        log$('Failed to load jQuery/facebook. Try again in 3 second.');
        setTimeout(initjQuery, 3000);
    }
    else {
        log$('jQuery is loaded.');
        
        if (typeof($) == 'undefined') {
            $ = unsafeWindow.$;
        }
        if (typeof(do_ajax) == 'undefined') {
            do_ajax = unsafeWindow.do_ajax;
        }
        if (typeof(FB) == 'undefined') {
            FB = unsafeWindow.FB;
        }
        // add regex selector to jQuery 
        $.expr[":"].regex = function(a, i, m, r) 
        {
            var p, s_expr, s_member;
            // get member and expr
            if ((p = m[3].split(',')).length > 1) {
                s_member = $.trim(p[0]);
                s_expr = $.trim(p[1]);
            }
            else {
                s_member = 'html';
                s_expr = $.trim(m[3]);
            }
            // create regex expr
            var r = new RegExp(s_expr, 'i');
            
            // is a jQuery member
            if ($(a)[s_member]) {
                return r.test($(a)[s_member]());
            }               
            // is a element member
            if (a[s_member]) {
                return r.test(a[s_member]);
            }
            return false;   
        };
        
        if (!(global.USER_ID = getUserID())) {
            alert('MWAddon: Error, no user id found. Aborting load.');
            return;
        }
        // get person ID
        global.PERSON_ID = String(global.USER_ID).match(/(\d+)/)[1];
        
        // create Base64 Object
        global.Base64 = new Base64();
        
        // create default global options
        global.options = new Config('main', {
            privacy              : {'value': 'ALL_FRIENDS'},
            useFacebookGraphApi  : true,
            access_token         : '',
            appLastUpdateCheck   : 0,
            api_bit_ly_login     : '',
            api_bit_ly_key       : '',
            opt_PlayerStats      : true,
            opt_JobRates         : true,
            opt_GiftPage         : true,
            opt_MissionPage      : true,
            opt_CollectionPage   : true,
            menu_timers          : {}
        });
        
        global.options.load(function() 
        {
            if (accessToken) {
                global.options.set('access_token', accessToken);
                global.options.set('useFacebookGraphApi', true);
                global.options.save();
            }
            // Add iframe Updater
            setTimeout(function() {
                var now = new Date().getTime();
                var uInt = scriptAppInfo.appUpdateInterval * 60 * 60 * 1000;
                if (now > (global.options.get('appLastUpdateCheck') + uInt)) {
                    var el = document.createElement('iframe');
                    el.setAttribute('style', 'display: none;');
                    el.setAttribute('src', scriptAppInfo.appMeta + '?' + now);
                    document.getElementsByTagName('body')[0].appendChild(el);
                    global.options.set('appLastUpdateCheck', now);
                    global.options.save();
                }
            }, 6000);
            // ;
            
            // for handle page loadings
            $('#mainDiv').ajaxComplete(function(e, r, o) {
                update_tmpcb(o.url);
                
                modMenu();
                setTimeout(modUserStats, 20);
                
                if (o.url.match('xw_action=share_loot')) {
                    setTimeout(function() {
                        secretStash(r.responseText);
                    }, 500);
                    return;
                }
                var metadata = /<!--\s*Current\s*Page:\s*(\w+)/.exec(r.responseText);
                metadata && loadController(metadata[1], r.responseText);
            });
            
            // this is the first load so...
            modMenu();
            modUserStats();
            update_tmpcb(global.href);
            loadController(getCurrentPageName());
        });
    }
}

/**
 * Check for updates at the userscripts metadata iframe.
 * @param {Object} metadata
 */
function updateCheck (metadata) {
    var lastVer = metadata.match(/@version\s*(.+)/)[1];
    var metaName = metadata.match(/@name\s*(.+)/)[1];
    if (metaName == scriptAppInfo.appName && scriptAppInfo.appVer !== lastVer) {
        if (confirm('There is a new version for ' + scriptAppInfo.appName + '.\n\nURL: ' +
            scriptAppInfo.appUrl +  '\n\nDo you want to update now?')) 
        {
            unsafeWindow.open(scriptAppInfo.appUrl, '_blank');
        }
    }
}

/**
 * Load the specified controller for the current page.
 * @param {String} name Controller name
 * @param {Object} responseText Response HTML of page.
 */
function loadController(name, responseText) 
{
    if (typeof global.pages[name] == 'function') {
        log$('loading: ' + name);
        setTimeout(function() {
            global.pages[name].apply(document, [responseText]);
        }, 500);
    }
    else 
        log$('No handled: ' + name);
}
// =========================================================
// DOM OBJECTS
// =========================================================
/**
 * Create a popup with the specified options.<br>
 * The options members are:<br><br>
 * - {String} <b>title</b> To set popup title.<br>
 * - {Number} <b>top</b> To set popup top.<br>
 * - {Boolean} <b>autoOpen</b> Once created, show it up.<br>
 * - {Function} <b>onclose</b> On close event.<br>
 * - {Array} <b>buttons:</b><br>
 * --- {String} <b>label</b> to set the button text.<br>
 * --- {Function} <b>onclick</b> On click event.
 * @constructor
 * @param {String} id
 * @param {Object} options
 * @return {domPopupObject}
 */
var domPopupObject = function(id, options) {
    
    if (typeof(id) !== 'string') {
        if (typeof id == 'object') {
            options = id;
        }
        id = 'mwaddon_popup';
    }
    if (typeof options !== 'object') 
        options = {};
    
    if (typeof options.title !== 'string') {
        options.title = undefined;
    }
    if (typeof options.top !== 'number') 
        options.top = 80;
    
    if (options.autoOpen !== true) 
        options.autoOpen = false;
    
    if (typeof options.center !== 'boolean') 
        options.center = true;
    
    if (typeof options.type !== 'string') 
        options.type = 'normal';
    
    if (typeof options.appendTo == 'undefined')
        options.appendTo = e$('#fbmw_addon_popup'); 
    
    switch(options.type) {
        case 'simple': options.popclass = 'simpleWithTitle'; break;
        case 'rob'   : options.popclass = 'pop_rob'; break;
        case 'help'  : options.popclass = 'cash_help_box'; options.center = false; break;
        default      : options.popclass = ''; break;
    }

    //
    var self = this;
    
    // get an id for this popup
    var pid = Math.round(new Date().getTime() / 100);
    var fodderElt = (options.appendTo || c$('div', 'fbmw_addon_popup').prependTo('#final_wrapper'));
    var divElt = c$('div', 'pop_' + pid).appendTo(fodderElt).addClass(options.popclass);
    var bgElt = c$('div', 'pop_bg_' + pid).appendTo(divElt).addClass('pop_bg');
    var popupElt = c$('div', 'pop_box_' + pid).appendTo(divElt).addClass('pop_box');
    
    if (options.zIndex) {
        popupElt.css('z-index', options.zIndex + 1);
        bgElt.css('z-index', options.zIndex);
    }

    var onclose = function() {
        bgElt.hide();
        popupElt.fadeOut(200, function() {
            if (typeof(options.onclose) == 'function') {
                options.onclose.apply(this);
            }
            if (options.type !== 'persistent') {
                self.destroy();
            }
        });
        $('#content_row, #inner_page').height('auto');
        return false;
    };  
    
    var closeAfterClick = function() {
      if (options.closeAfterClick === true) {
        onclose();
      }
      return false;
    };   
    
    // apply ccs style?
    if (typeof(options.css) !== 'undefined') {
        popupElt.css(options.css);
    }
    else if (parseInt(options.top)) {
        popupElt.css('top', options.top);
    }
    
    // close button
    c$('a').appendTo(popupElt).addClass('pop_close').bind('click', onclose);
    
    // header
    /**
     * @type {jQuery}
     */
    this.header = c$('div').css('padding-top', 20).appendTo(popupElt);
    
    if (typeof(options.title) !== 'undefined') {
        this.header.append(
            c$('div').addClass('title').html(options.title)
            .css('border-bottom', '2px solid #4F4F4F')
        ).css({
            'height': 40,
            'text-align': 'center',
            'font-weight': 'bold',
            'color': 'rgb(255, 255, 255)'
        });
    }
    /**
     * @type {jQuery}
     */
    this.content = c$('div', id).appendTo(popupElt).addClass('clearfix');
    
    if (options.content) {
        this.content.append(options.content);
    }
    if (options.center) {
        this.content.css('text-align', 'center');
    }
    
    // add buttons
    var bDiv = c$('div').css('padding', '10px 5px').appendTo(popupElt);
    
    if (options.buttons instanceof Array) {
        bDiv.css({
            'border-top': '2px solid #1F1F1F',
            'background-color': 'transparent',
            'text-align': 'center'
        });
        for (var i = 0; i < options.buttons.length; i++) {
            var obutton = options.buttons[i] || {};
            if (typeof obutton.label !== 'string') 
                obutton.label = 'undefined';
            if (typeof obutton.onclick !== 'function') {
                obutton.onclick = onclose;
            }
            b$(obutton.label).appendTo(bDiv).addClass(obutton.addClass)
            .css('margin-left', 5).click(closeAfterClick).click(obutton.onclick);
        }
    }
    /**
     * Close the popup, fires onclose event.
     */
    this.close = function() {
        onclose();
    };
    /**
     * Show the popup.
     */
    this.show = function() {
        bgElt.show();
        popupElt.show();
        $('#inner_page').height(Math.max(parseInt(popupElt.height()) + 100, $('#inner_page').height()));
    };
    /**
     * Add Style element to popup from a base64 encoded string.
     * @param {String} base64String An String encoded in base64
     */
    this.addBase64Style = function(base64String) {
        c$('style').prependTo(popupElt).append(global.Base64.decode(base64String));
    };
    /**
     * Add Script element to popup from a base64 encoded string.
     * @param {String} base64String An String encoded in base64
     */
    this.addBase64Script = function(base64String) {
        c$('script').prependTo(popupElt).append(global.Base64.decode(base64String));
    };
    
    this.destroy = function() {
        divElt.remove();
        delete global.popups[id], this;
    };
    
    if (options.type == 'persistent') {
        global.popups[id] = this;
    }
    
    // auto open
    if (options.autoOpen) 
        this.show();
    
    return this;
};
/**
 * Create a new DOM Tabs layout.
 * @constructor
 * @param {Element, jQuery} appendTo The Object where the tabs is append.
 * @param {String} id the string id of this dom object.
 * @param {Array} tabNames Array of all tabs Names.
 * @param {Object} height Optional height of tab Layout.
 * @param {Object} width Optional width of tab Layout.
 * @return {domTabObject}
 */
var domTabObject = function(appendTo, id, tabNames, height, width, backgroundLayer) 
{
    /**
     * Show a tab. 
     * @param {String, Number} id Can be the tab name (string) or tab index (integer).
     */
    this.showTab = function(id) 
    {
        var tabID = ( isNaN(id) ? layerKeys[id] : id  );
        var elt = e$('#' + layerID + '_tab_' + tabID);
        if (elt)
            elt.click();
    }
    /**
     * Get the specified layout. 
     * @param {String, Number} id Can be the tab name (string) or tab index (integer)
     * @return {jQuery}
     */
    this.getLayout = function(id) 
    {
        var tabID = (isNaN(id) ? layerKeys[id] : id  );
        return e$('#' + layerID + '_tab_' + tabID + '_layout');
    }
    /**
     * Add html code to the right of all tabs.
     * @param {String} innerHTML
     */
    this.tabClear = function(innerHTML) 
    {
        (e$('.tab_clear', headerLayout) || 
         c$('div').addClass('tab_clear').appendTo(headerLayout)).html(innerHTML);
    }
    if (tabNames.length < 1) 
        return null;
    var layerID = id, layerKeys = [];
    var mainLayout =  c$('div', layerID).appendTo(appendTo);
    var headerLayout = c$('div').addClass('tab_box_header').height(35).appendTo(mainLayout);    
    var tab_click = function(){
        $('div[id*="layout"]', '#' + layerID).hide();
        $('div[id^="' + layerID + '_tab_"]', headerLayout).removeClass().addClass('tab tab_inactive_op');
        $('#' + this.id + '_layout').show();
        $(this).removeClass().addClass('tab tab_active_op');
    };
    if (width)  
        mainLayout.width(width);
    for (var i = 0; i < tabNames.length; i++) {
        var tab = c$('div', layerID + '_tab_' + i).appendTo(headerLayout)
        .addClass('tab tab_inactive_op').click(tab_click).css({
            'margin-right': 3,
            'cursor': 'pointer',
            'padding-top': 8
        });
        c$('div').addClass('tab_start').html('&nbsp;').appendTo(tab);
        c$('div').addClass('tab_middle').html(tabNames[i]).appendTo(tab);
        c$('div').addClass('tab_end').html('&nbsp;').appendTo(tab);
        // add the tab layouts.
        var layout = c$('div','id:'+layerID+'_tab_'+i+'_layout,class:tab_box_content').appendTo(mainLayout).hide();
        if (height)
            layout.height(height);
        if (backgroundLayer)
            layout.css('background-color', backgroundLayer);
        // To parse tab name keys
        layerKeys[tabNames[i]] = i;
    }
    // show up the tab layer.
    this.showTab(0);
    return this;
}
/**
 * Create a new DOM table object.
 * @constructor
 * @param {Element, jQuery} appendTo The oject where the table is append.
 * @param {Number} rows Amount of rows in table.
 * @param {Number} columns Amount of columns in table.
 * @param {Object} [styleCSS] Optional style sheet for the table.
 * @return {domTableObject} 
 */
var domTableObject = function(appendTo, rows, columns, styleCSS) 
{
    var row_array = [], cell_array = [];
    
    this.table = c$('table', 'cellspacing:0').appendTo(appendTo);
    this.tbody = c$('tbody').appendTo(this.table);
    
    if (styleCSS) {
        this.table.css(styleCSS);
    }
    for (var r = 0; r < rows; r++) {
        row_array[r] = c$('tr').appendTo(this.tbody);
        cell_array[r] = [];
        for (var c = 0; c < columns; c++) {
            cell_array[r][c] = c$('td').appendTo(row_array[r]);
        }
    }
    /**
     * @param {Number} x
     * @return {jQuery}
     */
    this.row = function(x) 
    {
        return row_array[x];
    };
    /**
     * @param {Number} x
     * @param {Number} y
     * @return {jQuery}
     */
    this.cell = function(x, y) 
    {
        return cell_array[x][y];
    };
    return this;
};
// =========================================================
// POPUPS
// =========================================================

/**
 * Display a modal message popup.<br>
 * Usage:<br><br>
 * <b>icon</b>: {String} Can be info or error.<br>
 * <b>title</b>: {String} the title of the new popup.<br>
 * <b>message</b>: {String} message sent to user.<br>
 * <b>buttons</b>: {Array} optional buttons. 
 * @param {Object} options
 */
function showHelpPopup(options) {
    var icons = {
        'info': global.resource.info_icon,
        'error': global.resource.ajax_error
    };
    var helpPopup = new domPopupObject({
        type: 'help',
        top: options.top,
        autoOpen: true,
        zIndex: 99999,
        closeAfterClick: true,
        buttons: options.buttons,
        content: c$('div').css({'text-align': 'left','margin': '5px 30px'})
            .append(c$('img').css('float', 'left').attr('src', icons[options.icon]))
            .append(c$('h3').css('padding', '3px 28px').html(options.title))
            .append(c$('div').css('margin-top', 10).html(options.message))
    });
    if (typeof(options.top) == 'undefined') {
        $('#TopField').focus();
    } 
}
/**
 * Display a modal popup asking user for text.
 * @param {String} message
 * @param {String} defaultText
 * @param {Function} callback
 */
function showPromptPopup(message, defaultText, callback) {
    if (typeof(message) !== 'string') {
        return;
    }
    var inputElt = c$('textarea', 'rows:12,cols:72').val(defaultText||'');
    var popupElt = new domPopupObject({
        type     : 'simple',
        autoOpen : true,
        zIndex   : 99999,
        buttons  : [
            {
             label   : 'Accept',
             onclick : function() {
           popupElt.close();
           callback && callback(inputElt.val());
           return false;
          }
                
            },{ label: 'Cancel' }
        ],
        content: c$('div').css('margin-top', 10)
                 .append(c$('h3').css('margin', 0).text(message||'write a text:'))
                 .append(inputElt)
    });
}
/**
 * Display a modal popup showing text to user.
 * @param {String} message
 * @param {String} text
 */
function showTextPopup(message, text) {
    if (!message || !text) {
        return;
    }
    var inputElt = c$('textarea', 'readonly:readonly,rows:12,cols:72').val(text);
    var popupElt = new domPopupObject({
        type     : 'simple',
        autoOpen : true,
        zIndex   : 99999,
        buttons  : [{
            label    : 'Select All',
            addClass : 'short white',
            onclick  : function() {inputElt.select(); return false;}
        }],
        content: c$('div').css('margin-top', 10)
                 .append(c$('h3').css('margin', 0).text(message))
                 .append(inputElt)
    });
}

function loadingOverlay(message) {
    $('#fbmw_menu').mouseleave();
    
    if (message == 'hide') {
        return $('#overlay_pop').hide();
    }
    
    if (e$('#overlay_pop') !== null) {
        $('#loaderText', '#overlay_pop').text(message);
        return $('#overlay_pop').show();
    }
    
    var divElt = c$('div', 'id:overlay_pop').hide()
    .appendTo(e$('#fbmw_addon_popup') || c$('div', 'fbmw_addon_popup').prependTo('#final_wrapper'));
    
    c$('div', 'id:overlay_pop_bg,class:pop_bg').appendTo(divElt).show();
    c$('div', 'id:overlay_pop_box,class:socialMissionTryAgain')
    .appendTo(divElt).css('top', 100).show()
    .append(c$('div', 'loaderText').text(message))
    .append(
        c$('div').append(
            c$('img').attr('src', 
            'http://mwfb.static.zgncdn.com/mwfb/graphics/socialmissions/ajax-loader.gif')
        )
    );
    
    return divElt.show();
}

// =========================================================
// UTILS
// =========================================================

/**
 * Apply the specified options to an select element.
 * @param {Object} options
 * @param {Object} context
 */
function applySelectOptions(options, context) {
    $.each(options, function(id, opt) {
        var elem = $('#' + id, context);
        $.each(opt, function(value, name) {
            elem.append(c$('option', 'value:'+value).text(name));
        });
    });
}


/**
 * Return an object with all url parameters
 * @param {String} url
 * @return {Object}
 */
function splitUrl(url) {
    if (typeof(url) !== 'string') {
        return {};
    }
    var spl, n, sUrl = {};  
    var s_url = url.replace(/&amp;/g, '&');
    
    if ((spl = s_url.split('?')).length == 2) {
        s_url = spl[1];
    }
    if ((spl = s_url.split('&')).length > 0) {
        for (var i = 0; i < spl.length; i++) {
            if ((n = spl[i].split('=')).length == 2) {
                sUrl[n[0]] = unescape(n[1]);
            }
        }
    }
    return sUrl;
};

/**
 * Set a timerInterval to an element.
 * @param {String, Element, jQuery} selector the dom element to apply text.
 */
var timerMessage = function(selector) {
    var timerId;
    var self = this;
    /**
     * Start the timer with the specified options.<br>
     * - text must contain %N% tag to be replaced by the countwown delay
     * @param {String} text Text to apply.
     * @param {Number} delay Countdown in seconds.
     * @param {Function} callback function to be executed when delay is 0
     * @param {Array} [params] Optional array of parameters for callback.
     */
    this.start = function(text, delay, callback, params) {
        if (e$(selector) == null) {
            return 0;
        }
        self.clear();
        
        $(selector).html(text.replace('%N%', delay));
        
        timerId = setInterval(function() {
            
            $(selector).html(text.replace('%N%', delay--));
            
            if (delay < 0) {
                self.clear();
                callback.apply(self, params);
            }
            
        }, 1000);
        
        return timerId;
    };
    /**
     * Clear the timer.
     */
    this.clear = function() {
        if (timerId) {
            clearInterval(timerId);
        }
    };
    
    return this;
};

// =========================================================
// METHODS
// =========================================================

/**
 * Do an ajax request.
 * @param {Object} options
 * @param {Function} [callback]
 */
function ajaxRequest(options, callback) 
{
    var _overlay;
    
    try {
        if (typeof(options) == 'string' && typeof(callback) == 'function') {
            var sUrl = options;
            options = {
                url: sUrl,
                success: callback
            };
        }
        if (typeof(options) !== 'object') {
            throw ReferenceError('options is not defined.');
        }
        
        if (typeof(options.success) !== 'function') {
            if (typeof(callback) == 'function') {
                options.success = callback; 
            }
            else {
                throw ReferenceError('callback is not defined.');
            }
        }
        
        if (typeof(options.url) !== 'string') {
            throw ReferenceError('url is not defined.');
        }
        
        if (options.liteLoad !== 1) {
            options.liteLoad = 0;
        }
        
        var params = {
            'ajax': 1,
            'liteload': options.liteLoad,
            'sf_xw_user_id': global.USER_ID,
            'sf_xw_sig': unsafeWindow.local_xw_sig
        };
        
        var connector = (options.url.indexOf('?') == -1) ? '?' : '&';
        var url = (/http/.test(options.url) 
        ? '' 
        : 'http://facebook.mafiawars.com/mwfb/') + options.url;
        
        if (typeof(options.data) == 'object') {
            $.each(options.data, function(name, value) {
                params[name] = value;
            });
        };
        
        if (typeof(options.message) == 'string') {
            _overlay = loadingOverlay(options.message);
        }
        
        $.ajax({
            type: "POST",
            url: url + connector + 'xw_client_id=8',
            data: params,
            global: false,
            timeout: 30000,
            success: function(htmlText) {
                update_tmpcb(htmlText);
                _overlay && _overlay.hide();
                options.success.apply(document, new Array(htmlText));
            },
            error: function() {
                // EMPTY
            },
            complete: function(xmlRequest, textStatus) {
                if (textStatus !== 'success') {
                    throw Error('bad ajaxRequest response.');        
                }
            }
        });
    }
    catch(err) {
        logErr$(err);
        _overlay && _overlay.hide();
        callback && callback(err.message);
    }
}

/**
 * Do a Json request.
 * @param {String} url
 * @param {Function} callback
 */
function jsonRequest(url, callback) 
{
    if (typeof(callback) !== 'function') {
        logErr$(ReferenceError('Callback argument missed.'));
        return;
    }
    var params = {
        'ajax': 1,
        'liteload': 1,
        'sf_xw_user_id': global.USER_ID,
        'sf_xw_sig': unsafeWindow.local_xw_sig
    };
    var connector = (url.indexOf('?') == -1) ? '?' : '&';
    var url = (/http/.test(url) ? '' : 'http://facebook.mafiawars.com/mwfb/') + url;
    
    $.ajax({
        type: "POST",
        dataType: "json",
        url: url + connector + 'xw_client_id=8',
        data: params,
        global: false,
        success: function(jsonData) {
            try {
                unsafeWindow.user_fields_update(jsonData.user_fields);
                unsafeWindow.user_info_update(jsonData.user_fields, jsonData.user_info);
            } 
            catch (err) {
                logErr$(err);
            }
            callback.apply(document, [jsonData]);
        }
    });
}

/**
 * Show an error message about server http request response.
 */
function badServerResponse() {
    showHelpPopup({
        icon: 'error',
        title: 'Bad server response',
        message: 'There is an error in the server response. Try again later.'
    });
}

/**
 * Search scripts that matches the specified regexText in htmlText.
 * @param {String} htmlText
 * @param {String} regexText
 * @param {Boolean} b_innerText
 * @return {Object}
 */
function getScripts(htmlText, regexText, b_innerText) {
    var output = {}, r1, r2;
    var scriptRegex = /<script[^>]*?>((.|\n|\r|\t)*?)<\/script>/g;
    var searchRegex = new RegExp(regexText, 'i');
    try {
        while ((r1 = scriptRegex.exec(htmlText))) {
            if (r2 = searchRegex.exec(r1[1])) {
                if (typeof(output[r2[0]]) !== 'string') {
                    output[r2[0]] = '';
                }
                if (b_innerText === true) {
                    output[r2[0]] += r1[1];
                }
                else {
                    output[r2[0]] += r1[0];
                }
            } 
        }
    }
    catch(err) {
        logErr$(err);
    }    
    return output;
}

/**
 * Execute a Regular expresion and return and object.
 * @param {RegExp} rgx
 * @param {String} text
 */
function doRegex(rgx, text) {
    var output = {}
    var result = rgx.exec(String(text));
    if (result) {
        for (var i = 0; i < result.length; i++) {
            output['$'+ i] = result[i];
        }
    }
    return output
}

/**
 * Update "tmp" and "cb" uri components.
 * @param {String} text
 */
function update_tmpcb(text) {
    var tmp, cb;
    if ((tmp = /tmp=([0-9a-fA-F]+)/.exec(text)) && (cb = /cb=([0-9a-fA-F]+)/.exec(text))) 
    {
        global.uri_tmpcb = '&tmp='+tmp[1]+'&cb='+cb[1];
    }
}
/**
 * Evaluate a Mafia Wars HTML text response to make sure it's fine.
 * @param {String} responseText
 */
function mw_updater(htmlText) 
{
    try {
        var script = h$(htmlText).find('script:regex(text,local_xw_sig =|var user_fields)');
        
        if (script.length > 0) {
            $('#sf_updater').append(script);
            return true;
        }
    }
    catch(err) {
        logErr$(err);
    }
    return false;
}
/**
 * Get user ID from script code.
 * @return {Number}
 */
function getUserID() 
{
    var match = /'sf_xw_user_id':\s?'([^']+)'/.exec($('body').html());
    if (match) {
        log$('USER ID: ' + unescape(match[1]));
        return unescape(match[1]);
    }
    return null;
}

/**
 * Return a valid internal Mafia wars url.
 * @param {String} controller Default is "index".
 * @param {String} action Default is "view".
 * @param {Number} city To force city ID, otherwise the current city is used.
 * @return {String}
 */
function getIntURL(controller, action, city) 
{
    var params = [
        'xw_controller=' + (controller || 'index'),
        'xw_action=' + (action || 'view'),
        'xw_city=' + (city || getCurrentCity()),
        'xw_person=' + global.PERSON_ID
    ];
    return 'html_server.php?' + params.join('&') + global.uri_tmpcb;
}

/**
 * Return a valid external Mafia Wars url.
 * @param {String} controller Default is "index".
 * @param {String} action Default is "view".
 * @param {Object} params {Name => Value} pairs.
 * @return {String}
 */
function getExtURL(controller, action, params) 
{
    var url = 'http://apps.facebook.com/inthemafia/track.php?';
    
    if (typeof(params) !== 'object') {
        params = {};
    }
    
    url += 'next_controller=' + (controller || 'index');
    url += '&next_action=' + (action || 'view');
    
    $.each(params, function(name, value) {
        if (name == 'next_params') {
            value = escape( $.toJSON(value) ); 
        }
        if (name != 'next_controller' && name != 'next_action') {
            url += ('&' + name + '=' + value);
        }
    });
    
    return url;
}

/**
 * Return the profile url of the user id
 * @param {String} user_id
 * @return {String}
 */
function getProfileLink(user_id) 
{
    var id = global.Base64.encode(String(user_id) || global.USER_ID); 
    return 'http://apps.facebook.com/inthemafia/profile.php?id='+escape('{"user":"'+id+'"}');
}

/**
 * Deposit the amount of cash specified..
 * @param {Number} city city id where to deposit 
 * @param {Number, String} amount cash to deposit
 * @param {Function} callback return server response or undefined.
 */ 
function bankDeposit(city, amount, callback) {
    var cityNames = {
        1: 'new_york',
        2: 'cuba',
        3: 'moscow',
        4: 'bangkok',
        5: 'vegas',
        6: 'italy'
    };
    var url = 'remote/'; 
    if (city == 5) {
        url += getIntURL('propertyV2', 'doaction');
        url += '&doaction=ActionBankDeposit&building_type=6&city='+city;
    }
    else {
        url += getIntURL('bank', 'deposit_all') + '&city=' + cityNames[city];
    }
    jsonRequest(
        url + '&amount=' + amount, 
        function(jsonData) 
        {
            var result = jsonData.deposit_message;
            if (typeof(result) == 'undefined') {
                result = $.parseJSON(jsonData.data).success_message;
            }
            callback(result);
        }
    );
}

/**
 * Travel to the specified city. 
 * @param {Number} destination city id for destiny
 * @param {String} div selector
 * @param {Function} callback return true if success.
 */
function travelToCity(destination, div, callback) {
    var cityRegex = /current_city_id'.\s*=\s*parseInt."(\d)".;/i;
    var loadMessage = 'Traveling to '+global.cities[destination]+'...';
    
    if (typeof(div) == 'function') {
        callback = div;
        div = null;
    }
    ajaxRequest({
        url: 'remote/' + getIntURL('travel', 'travel'),
        liteLoad: 1,
        data: {
            'destination' : destination || 1,
            'from'        : 'index',
            'zone'        : 1,
            'nextParams'  : ''
        },
        message:  (div ? loadMessage : null), 
        success: function(htmlText) {
            var cityId = doRegex(cityRegex, htmlText).$1 || 0;
            if (mw_updater(htmlText)) {
                if (div) {
                    $('#'+div).html(htmlText);
                }
            }
            log$('travelToCity: '+ cityId);
            callback && callback(parseInt(cityId));
        }
    });
} 

/**
 * Return a valid gift link.<br><br>
 * Usage: <br>
 * {Number} <b>giftId </b> to set the gift ID.<br>
 * {Number} <b>giftCat</b> to set the gift Category.<br>
 * {String} <b>message</b> to show overlay message.<br>
 * @param {Object} options 
 */
function getGiftLink(options) 
{
    try {
        if (typeof(options) !== 'object') {
            throw ReferenceError('options is not defined.');
        }
        if (typeof(options.success) !== 'function') {
            throw ReferenceError('callback is not defined.');
        }
        // do the request
        ajaxRequest({
            url: 'remote/' + getIntURL('requests', 'friend_selector'),
            liteLoad: 1,
            message: options.message,
            data: {
                'req_controller' : 'freegifts',
                'free_gift_id'   : options.giftId || 0,
                'free_gift_cat'  : options.giftCat || 1
            },
            success: function(htmlText) {
                options.success( (doRegex(/<fb:req-choice url='([^']+)'/, htmlText).$1 || 'Error') );
            }
        }); 
    }
    catch(err) {
        logErr$(err);
    }
}
/**
 * Convert a long url to a new short url.
 * @param {String} longURL The long url to be shorter.
 * @param {Function} callback The function to be executed after finish -> callback(shortURL).
 */
function getShortURL(longURL, callback) 
{
    try {
        if (typeof(callback) !== 'function') {
            throw ReferenceError('callback is not defined.');
        }
        if (typeof(longURL) !== 'string' || !/http/.test(longURL)) {
            throw ReferenceError('longURL is not defined.');
        }
        // default api set to json-tinyurl
        var _api = {
            url: 'http://json-tinyurl.appspot.com/?callback=?',
            data: { url: longURL }
        };
        // if api.bit.ly available, use it.
        if (global.options.get('api_bit_ly_login') && global.options.get('api_bit_ly_key')) {
            _api = {
                url: 'http://api.bit.ly/v3/shorten?callback=?',
                data: {
                    longUrl: longURL,
                    format: 'json',
                    login: global.options.get('api_bit_ly_login'),
                    apiKey: global.options.get('api_bit_ly_key')
                }
            };
        }
        $.ajax({
            url: _api.url,
            dataType: 'jsonp',
            timeout: 30000,
            global: false,
            data: _api.data,
            success: function(jsonData)
            {
                if (jsonData.status_code == 200) {
                    callback(jsonData.data.url);
                }  
                else if (jsonData.ok) {
                    callback(jsonData.tinyurl);
                } 
                else {
                    throw Error('unexpected json response.');
                }
            },
            error: function(a, b) {
                alert(b);
            }
        });
    }
    catch(err) {
        logErr$(err);
        callback && callback('Error');
    }
}
/**
 * Get the current city ID.
 * @return {Number}
 */
function getCurrentCity() 
{
    try {
        var cityId = doRegex(/\D+(\d)/, $('#mw_city_wrapper').attr('class')).$1;
        if (parseInt(cityId) < 1) {
            throw Error('unexpected cityId value.');
        }
        return parseInt(cityId);
    } 
    catch (err) {
        logErr$(err);
        return 1;
    }
}

/**
 * get the current Page name.
 * @return {String}
 */
function getCurrentPageName() 
{
    return $('#inner_page').attr('class');
}

/**
 * Return the Date String from the giving milliseconds Number.
 * @param {Number} ms
 * @return {String}
 */
function millisecondsToDateString(ms) 
{
    var pad = function(n) {
        return (n > 9 ? n : '0' + n);
    };
    var dateText = '',s,m,h,d;
    
    s = Math.floor(ms / 1000);
    m = Math.floor(s / 60);
    h = Math.floor(m / 60);
    d = Math.floor(h / 24);
    
    dateText += (d > 0 ? d+'d ' : '');
    dateText += ((h=h%24) > 0 ? pad(h) : '00') + 'h ';
    dateText += ((m=m%60) > 0 ? pad(m) : '00') + 'm ';
    dateText += ((s=s%60) > 0 ? pad(s) : '00') + 's';
    
    return dateText
}
/**
 * Return a new jQuery with the new sexy style button.
 * @param {String} label
 * @param {String} attr
 * @return {jQuery}
 */
function b$(label, attr) {
    var spanElt = c$('span').append(c$('span').html(label));
    return c$('a', attr).addClass('sexy_button_new').append(spanElt);
}

// =========================================================
// FACEBOOK CALLS.
// =========================================================
var facebook = {
    validate: function(response, callback) {
        log$($.toJSON(response));
        
        if (response && (response.error_code == 101 || response.error_code == 190)) 
        {
            showHelpPopup({
                icon: 'error',
                title: 'Invalid facebook key',
                message: 'You need to update your Facebook access key.<br>'+
                    'Click "Update" to reload Mafia Wars to get a new valid key.<br>'+
                    'Click "Offline permission" to get an endpoint long-lived key.<br>',
                    
                buttons: [{
                    label: 'Update',
                    onclick: this.updateAccessToken
                }, {
                    label: 'Offline permission',
                    onclick: this.endpointAccessToken
                }, {
                    label: 'Cancel'
                }]
            });
        }
        else if (response && response.error_code == 200) 
        {
            showHelpPopup({
                icon: 'error',
                title: 'Error: (#'+response.error_code+')',
                message: response.error_msg,
                buttons: [{
                    label: 'Give permissions',
                    onclick: this.addStandardPermissions
                }]
            });
        }
        else if (response && response.error_code && response.error_msg) 
        {
            showHelpPopup({
                icon: 'error',
                title: 'Error: (#'+response.error_code+')',
                message: response.error_msg
            });
        }
        else if (typeof(callback) == 'function') {
             callback(response); 
        }
    },
    graphApi: function(user, method, callback, data) {
        if (typeof(data) !== 'object') {
            data = {};
        }
        data['format'] = 'json';
        data['access_token'] = global.options.get('access_token');
        $.ajax({
            url      : 'https://graph.facebook.com/'+ user + '/' + method + '?callback=?',
            dataType : 'jsonp',
            global   : false,
            data     : data,
            success  : callback
        });
    },
    restApi: function(method, callback, data) {
        if (typeof(data) !== 'object') {
            data = {};
        }
        data['format'] = 'json';
        data['access_token'] = global.options.get('access_token');
        $.ajax({
            url      : 'https://api.facebook.com/method/' + method + '?callback=?',
            dataType : 'jsonp',
            global   : false,
            data     : data,
            success  : function(res) 
            {
                facebook.validate(res, callback);
            }   
        });
    },
    
    graphHasPermission: function(ext_perm, callback) {
        this.restApi('users.hasAppPermission', callback, {
            'ext_perm': ext_perm
        });
    },
    
    // PUBLISHING METHODS
    graphPublish: function(privacy, attachment, actionLinks, target, callback) {
        this.restApi('stream.publish', callback, {
            'target_id'    : target,
            'privacy'      : parseFloat(target) > 0 ? '' : $.toJSON(privacy),
            'attachment'   : $.toJSON(attachment),
            'action_links' : $.toJSON(actionLinks)
        });
    },
    graphCreateNote: function(title, content, callback) {
        this.restApi('notes.create', callback, {
            'title'    : title,
            'content'  : content
        });
    },
    graphEditNote: function(note_id, title, content, callback) {
        this.restApi('notes.edit', callback, {
            'note_id'  : note_id,
            'title'    : title,
            'content'  : content
        });
    },
    graphAddLike: function(post_id, callback) {
        this.restApi('stream.addLike', callback, {
            'post_id': post_id
        });
    },
    graphAddComment: function(post_id, comment, callback) {
        this.restApi('stream.addComment', callback, {
            'post_id': post_id,
            'comment': comment
        });
    },
    friendListGet: function(callback) {
        this.graphApi('me', 'friendlists', callback);
    },
    friendListCreate: function(name, callback) {
        this.graphApi('me', 'friendlists', callback, {
            'method': 'post',
            'name': name
        });
    },
    friendListAddUsers: function(listId, userId, callback) {
        this.graphApi(listId, 'members/' + userId, callback, {
            'method': 'post'
        });
    },
    
    
    // RETRIEVAL METHODS
    graphGetGroups: function(callback) {
        this.restApi('groups.get', callback);
    },
    
    
    // JAVASCRIPT CONNECT METHODS
    oldPublishMethod: function(text, attach, aLinks, target, c, callback) {
        FB.Connect.forceSessionRefresh(function() {
            FB.Connect.streamPublish(text, attach, aLinks, target, c, function(r) {
                return callback && callback(r && r.post_id);
            });
        });
    },
    
    hasAppPermission: function(permission, callback) {
        FB.Facebook.apiClient.users_hasAppPermission(permission, function(has_perms) {
            callback && callback(has_perms == 1);
        });
    },
    getPermission: function(permission, callback) {
        // read_stream publish_stream user_groups offline_access
        FB.Connect.showPermissionDialog(permission, function(perms) {
            callback && callback(perms == permission);
        });
    },
    needPermission: function(permission, callback) {
        facebook.hasAppPermission(permission, function(success) {
            if (success == true) {
                callback && callback(true);
                return;
            } 
            facebook.getPermission(permission, callback);
        });
    },
    
    getNewsFeed: function(callback) {
        var sql = '';
        sql += 'SELECT strip_tags(attachment), post_id, created_time, source_id, target_id, permalink, actor_id';
        sql += ' FROM stream WHERE app_id=10979261223 ';
        sql += 'AND source_id in (SELECT target_id FROM connection WHERE source_id=me()) ';
        sql += 'AND filter_key = "nf" AND is_hidden = 0 AND (source_id = actor_id OR target_id = me())';
        FB.Connect.forceSessionRefresh(function() {
            FB.Facebook.apiClient.fql_query(sql, callback);
        });
    },
    
    streamPublish: function(options, callback) {
        var targetId = (options.target ? String(parseFloat(options.target)) : '');
        var attachment = {
            'media': [{
                'type': 'image',
                'src': options.pic,
                'href': options.url
            }],
            'description': options.description,
            'name': options.name,
            'href': options.url
        };
        var actionLinks = [{
            'text': options.actionText,
            'href': options.url
        }];
        var privacy = global.options.get('privacy');
        
        if (global.options.get('useFacebookGraphApi')) {
            this.graphPublish(privacy, attachment, actionLinks, targetId, callback);
        }
        else {
            this.oldPublishMethod("", attachment, actionLinks, targetId, null, callback);
        }
    },
    
    getInfo: function(uids, callback) {
        FB.Facebook.apiClient.users_getInfo(uids, 'name', function(result) {
            callback(result);
        });
    },
    
    getFriends: function(callback) {
        if (global.options.get('useFacebookGraphApi')) {
            this.restApi('friends.get', callback);
            return;
        }
        var sql = 'SELECT uid, name FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1 = me())';
        FB.Facebook.apiClient.fql_query(sql, function(result) {
            var a = [];
            for (var i= 0; i < result.length; i++) {
                a.push(result[i].uid1);
            }
            callback(a);
        });
    },
    
    // Permissions and Access 
    addStandardPermissions: function() {
        facebook.getPermission('read_stream,publish_stream,user_groups');
    },
    addOfflinePermissions: function() {
        facebook.getPermission('offline_access', function(success) {
            if (success == true) {
                unsafeWindow.open(global.fbAuthUrl, '_top');
            }
        });
    },
    updateAccessToken: function() {
        unsafeWindow.open(global.fbAuthUrl, '_top');
    },
    endpointAccessToken: function() {
        facebook.needPermission('offline_access', function(success) {
            if (success === true) {
                updateAccessToken();
            }
        });
    }
};

// =========================================================
// CONFIG POPUP
// =========================================================
/**
 * Create a new popup with global config options
 */
function appConfig() {
    
    if (typeof(global.popups['config_popup']) !== 'undefined') {
        global.popups['config_popup'].show();
        return;
    }
    
    var checkboxes = [
        {id:'main_opt_playerstats',    label:'Modify player stats to show energy/stamita/global ratios.'},
        {id:'main_opt_jobrates',       label:'Modify jobs stats to show energy/stamita ratios.'},
        {id:'main_opt_giftpage',       label:'Modify gift page to show new gifts and options.'},
        {id:'main_opt_missionpage',    label:'Modify social mission page to show ShortURL buttons.'},
        {id:'main_opt_collectionpage', label:'Modify Collection Page to use Multi Gifter popup for send gifts.'}
    ];
    var popupElt = new domPopupObject('config_popup', {
        title: scriptAppInfo.appName + ' v'+ scriptAppInfo.appVer,
        type: 'persistent',
        center: false,
        css: {
            'top': 100,
            'background': 'none repeat scroll 0% 0% black'
        },
        buttons: [{
            label: 'Save configuration'
        }],
        onclose: function() {
            var value = $('option[selected]', '#privacy').val();
            if (value !== 'CUSTOM') {
                global.options.set('privacy', {'value':value});
            }
            else {
                global.options.set('privacy', {
                    'value': value,
                    'friends': 'SOME_FRIENDS',
                    'allow': $('option[selected]', '#privacy_fl').val()
                });
            }
            global.options.fromDomElements();
            global.options.save();
        }
    });
    var option_click = function() {
        var isfor = $(this).attr('isfor');
        var elem = $('#'+isfor).get(0);
        
        // throggle checked
        elem.checked = elem.checked !== true;
        $(this).toggleClass('checked',elem.checked);
    };
    var privacy_change = function() {
        var self = this;
        var pflElt = $('#privacy_fl', popupElt.content);
        var selected = this.options[this.selectedIndex].value;
        var privacy = global.options.get('privacy');
        
        if(selected == 'CUSTOM') {
            facebook.needPermission('read_friendlists', function(success) {
                if(!success) {
                    self.selectedIndex = 1;
                    return;
                }
                facebook.friendListGet(function(list) {
                    var data = list.data, opt;
                    if (data.length < 1) {
                        showHelpPopup({
                            icon: 'error',
                            title: 'friendlist length',
                            message: 'Seem that you haven\'t friendlists.'
                        });
                    }
                    pflElt.empty();
                    for(var i = 0; i < data.length; i++) {
                        opt = c$('option', 'value:'+data[i].id).text(data[i].name);
                        pflElt.append(opt);
                        if (privacy && privacy.allow == data[i].id) {
                            opt.attr('selected', 'selected');
                        }
                    }
                    pflElt.show();
                });
            });
        }
        else {
            pflElt.hide();
        }
        return false;
    };
    
    function checkBoxOption (forid, text)
    {
        var checked = $('#'+forid).attr('checked') ? 'checked ' : '';
        c$('div', 'isfor:'+forid).appendTo(popupElt.content)
            .addClass('checkbox '+checked+'clearfix').text(text).click(option_click);
    }
    function hideInputElements() 
    {
        var inpdiv = c$('div').appendTo(popupElt.content).hide();
        for (var i = 0; i < checkboxes.length; i++) {
            inpdiv.append(c$('input:checkbox', checkboxes[i].id));
        }
    }
    function shortUrlApi()
    {
        var apiDiv = c$('div', 'class:frame_box').appendTo(popupElt.content)
        .append(c$('span').text('You can use bit.ly service for short url:'));
        // table
        var tb = new domTableObject(apiDiv, 2, 2);
        
        tb.cell(0, 0).css('text-align', 'right').append(c$('span').text('Login name: '));
        tb.cell(0, 1).append(c$('input:text', 'id:main_api_bit_ly_login, class:black_box'));
        
        tb.cell(1, 0).css('text-align', 'right').append(c$('a').text('Your api key: ').attr({
            'href': "http://bit.ly/a/your_api_key",
            'target': "_black"
        }));
        tb.cell(1, 1).append(c$('input:text', 'id:main_api_bit_ly_key, class:black_box'));
    }
    
    function addGraphApi() 
    {
        c$('div', 'class:frame_box').appendTo(popupElt.content)
        .append(c$('span').text('To Activate some Facebook features you need to '))
        .append(c$('a', 'href:#').text('give permissions.').click(facebook.addStandardPermissions))
        .append('<br /><br />')
        .append(c$('label', 'for:main_access_token').text('Here is your Facebook api key:'))
        .append(c$('input:text', 'id:main_access_token, class:black_box'))
        .append('<br />')
        .append(c$('span').text('Key expire after a time. You can '))
        .append(c$('a').text('update your key').attr({'href': global.fbAuthUrl,'target': '_top'}))
        .append(c$('span').text(' or get an '))
        .append(c$('a', 'href:#').text('endpoint long-lived key.').click(facebook.addOfflinePermissions));
    } 
    function addPrivacyOptions() {
        var elem;
        var privacy = global.options.get('privacy');
        var privacyOpts = {
            'Everyone'            : 'EVERYONE',
            'All friends'         : 'ALL_FRIENDS',
            'Friends of friends'  : 'FRIENDS_OF_FRIENDS',
            'Myself'              : 'SELF',
            'From friend list'    : 'CUSTOM'
        };
        c$('div', 'class:frame_box').appendTo(popupElt.content).height(50)
        .append(c$('span').text('You can select who will see your wall post:'))
        .append('<br />')
        .append(
            elem = c$('select', 'id:privacy,class:black_box').width(200)
            .css({'float':'left','margin-right':10}).change(privacy_change)
        )
        .append(
            c$('select', 'id:privacy_fl,class:black_box')
            .css('float','left').width(200).hide()
        );
        
        $.each(privacyOpts, function(name, value) {
            var opt = c$('option', 'value:'+value).text(name);
            elem.append(opt);
            if (privacy && privacy.value == value) {
                opt.attr('selected', 'selected');
            }
        });
        elem.change();
    } 
    // add style
    popupElt.addBase64Style(
        'I2NvbmZpZ19wb3B1cCAuYmxhY2tfYm94IHsNCgl3aWR0aDogNDAwcHg7DQoJZm9udC13ZWlnaHQ6IGJvbGQ7IA0KCWNvbG9yOiBy'+
        'Z2IoMjA4LCAyMDgsIDIwOCk7IA0KCWJvcmRlcjogMXB4IHNvbGlkIHJnYigxNTMsIDE1MywgMTUzKTsgDQoJYmFja2dyb3VuZC1j'+
        'b2xvcjogYmxhY2s7IA0KCWZvbnQtc2l6ZTogMTRweDsNCn0NCiNjb25maWdfcG9wdXAgLmZyYW1lX2JveCB7DQoJYm9yZGVyOiAx'+
        'cHggc29saWQgIzFGMUYxRjsNCgltYXJnaW4tYm90dG9tOiAyMHB4Ow0KCXBhZGRpbmc6IDVweDsNCgl0ZXh0LWFsaWduOiBsZWZ0'+
        'Ow0KfQ0KI2NvbmZpZ19wb3B1cCBkaXYuY2hlY2tib3ggew0KCWJhY2tncm91bmQ6IHVybCgiaHR0cDovL213ZmIuc3RhdGljLnp5'+
        'bmdhLmNvbS9td2ZiL2dyYXBoaWNzL2ZsYWdzL213X21lc3NhZ2Vib3hfY2hlY2tib3gyX25vcm1hbGl6ZWQuZ2lmIikgbm8tcmVw'+
        'ZWF0IHNjcm9sbCAwJSAwJSB0cmFuc3BhcmVudDsNCgl0ZXh0LWFsaWduOiBsZWZ0Ow0KCW1hcmdpbi10b3A6IDEwcHg7DQoJbWlu'+
        'LWhlaWdodDogMjBweDsNCgl3aWR0aDogYXV0bzsgDQoJcGFkZGluZy1sZWZ0OiAzMHB4OyANCgloZWlnaHQ6IDIwcHg7DQoJY3Vy'+
        'c29yOiBwb2ludGVyOw0KfQ0KI2NvbmZpZ19wb3B1cCBkaXYuY2hlY2tib3guY2hlY2tlZCB7DQoJYmFja2dyb3VuZDogdXJsKCJo'+
        'dHRwOi8vbXdmYi5zdGF0aWMuenluZ2EuY29tL213ZmIvZ3JhcGhpY3MvZmxhZ3MvbXdfbWVzc2FnZWJveF9jaGVja2JveDFfbm9y'+
        'bWFsaXplZC5naWYiKSBuby1yZXBlYXQgc2Nyb2xsIDAlIDAlIHRyYW5zcGFyZW50Ow0KfQ=='
    );
    
    // add hide elements and api config
    hideInputElements();
    addGraphApi();
    addPrivacyOptions();
    shortUrlApi();
    
    global.options.load(function() {
        global.options.toDomElements();
        // add checkbox elements
        popupElt.content.css('padding', '10px 50px');
        for (var i = 0; i < checkboxes.length; i++) {
            checkBoxOption(checkboxes[i].id, checkboxes[i].label);
        }
        
        c$('a', 'target:_black').appendTo(c$('center').css('margin',5).appendTo(popupElt.content))
        .attr('href', 'https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CQVWPSUMDKW5N')
        .append(c$('img').attr('src', 'https://www.paypal.com/en_US/i/btn/btn_donate_SM.gif'));
    
        // show popup
        popupElt.show();
    });
} 

// =========================================================
// MODS
// =========================================================

/**
 * Add the top header menu.
 */
function modMenu()
{
    var menu_container = (e$('#fbmw_menu_container') || 
        c$('div', 'fbmw_menu_container').prependTo('#final_wrapper'));
    
    var menuOptions = {
        'FBMWAddon Options'        : {'click': appConfig           , 'main': true               },
        'Home Feed Center'         : {'click': homeFeedCenter      , 'timer':'homeFeedCenter'   },
        'Gifts Page (Short Links)' : {'click': tofreegiftsPage     , 'timer':'freegifts'        },
        'Operations Page (Links)'  : {'click': toOperationsPage                                 },
        'News Helper'              : {'click': newsHelper          , 'timer':'newsHelper'       },
        'Collect All Cities'       : {'click': collectAllCities    , 'timer':'collectAllCities' },
        'Battlefield!'             : {'click': battlefield                                      },
        'Craft Manager'            : {'click': craftManager        , 'timer':'craftManager'     },
        'Inventory Analizer'       : {'click': InventoryAnalizer                                },
        'Multi Gifter'             : {'click': multiGifter                                      },
        'My Links'                 : {'click': userLinks                                        },
        'Mafia Wiper'              : {'click': mafiaWiper                                       },
        'Go Atlantic City!'        : {'click': toAtlanticCity      , 'timer':'AtlanticCity'     }
    };
    
    var setTimerClick = function() {
        var timers = global.options.get('menu_timers');
        timers[$(this).attr('timer')] = (new Date()).getTime();
        global.options.save();
    };
    var lastExecution = function() {
        var sName  = $(this).text();
        var sTimer = $(this).attr('timer');
        var nNow   = (new Date()).getTime();
        var nTime  = global.options.get('menu_timers')[sTimer];
        
        if (nTime) {
            $(this).attr('title', 'You run '+sName+' '+millisecondsToDateString(nNow - nTime)+' ago.');
            return false;
        }
        return false;
    };
        
    (function() {
        
        if (e$('#fbmw_menu_arrow') == null) {
            c$('div', 'fbmw_menu_arrow').prependTo(menu_container).css({
                'position': 'absolute',
                'z-index': 25,
                'top': 10,
                'left': 2,
                'width': 40,
                'height': 40,
                'background-color': 'transparent',
                'background-image': 'url("' + global.resource.menu_arrow + '")'
            }).mouseenter(function() {
                $('#fbmw_menu').stop().animate({
                    'left': '0px'
                }, 'normal');
            });
        }
        
        if (e$('#fbmw_menu') !== null) {
            return;
        }
        
        var menuElt = c$('div', 'fbmw_menu').prependTo(menu_container).css({
            'position': 'absolute',
            'z-index': 30,
            'top': 10,
            'left': -178,
            'width': 180,
            'border': '1px solid #CDCDCD',
            'border-left-width': '0px',
            'border-right-width': '2px',
            'border-right-color': 'yellow',
            'font-size': 12,
            'font-weight': 'bold'
        }).mouseleave(function() {
            $('#fbmw_menu').stop().animate({
                'left': '-178px'
            }, 'normal');
        });
        
        $.each(menuOptions, function(name, menu) {
            var a = c$('a', 'class:sexy_destination').appendTo(menuElt).html(name);
            
            a.click(menu.click);
            
            if (menu.main) {
                a.css('border-bottom', '1px solid white');
            }
            if (typeof(menu.timer) == 'string') {
                a.click(setTimerClick).mouseenter(lastExecution).attr('timer', menu.timer);
            }
        });
        
    })();
}

/**
 * Update the user stats with ratios.
 */
function modUserStats()
{
    if (!global.options.get('opt_PlayerStats')) {
        return;
    }
    var fixedInt = function(n){
        if (n == 'Infinity') {
            return 0;
        }
        else {
            return n.toFixed(Math.abs(n) < 10 ? 2 : 0);
        }
    };
    try {
        var energy = global.userStats.energy(), stamina = global.userStats.stamina();
        var expNeedtoLevel = global.userStats.exp_to_next_level();
        var energyRatio = fixedInt(expNeedtoLevel / energy);
        var staminaRatio = fixedInt(expNeedtoLevel / stamina);
        var globalRatio = fixedInt(expNeedtoLevel / (energy + stamina));
        
        var statElt = $('#user_stats').find('.stat');
        if (e$('.experience > strong', statElt) !== null) 
            $('.experience > strong', statElt).hide().appendTo(statElt);
        $('.experience', statElt).html('Exp Need: <span class="energy_highlight">' + expNeedtoLevel + '</span>');
        
        var tooltips = {
            'energy_ratio': 'You need to gain {0} experience points for each one energy point to level up.',
            'stamita_ratio': 'You need to gain {0} experience points for each one stamita point to level up.',
            'global_ratio': 'You need to gain {0} experience points for each one energy and stamita point to level up.'
        };
        var applyTag = function(str, tag_array) {
            for (var t in tag_array) {
                str = str.replace('{' + t + '}', tag_array[t]);
            }
            return str;
        };
        
        $('.level_stat', '#user_stats').width(70);
        
        (e$('#energy_ratio') ||
        c$('span', 'energy_ratio').addClass('energy').appendTo(statElt).css({
            'padding-right': 5,
            'font-size': 12
        }))
        .attr('title', applyTag(tooltips['energy_ratio'], {0:energyRatio})).text(energyRatio + ' -');
        
        (e$('#stamita_ratio') ||
        c$('span', 'stamita_ratio').addClass('energy').appendTo(statElt).css({
            'padding-right': 5,
            'font-size': 12,
            'background': 'url("http://mwfb.static.zynga.com/mwfb/graphics/icon_stamina_16x16_01.gif") no-repeat scroll 0pt 50% transparent'
        }))
        .attr('title', applyTag(tooltips['stamita_ratio'], {0:staminaRatio})).text(staminaRatio + ' -');
        
        (e$('#global_ratio') ||
        c$('span', 'global_ratio').addClass('more_in').appendTo(statElt).css('font-size', 12))
        .attr('title', applyTag(tooltips['global_ratio'], {0:globalRatio})).text(globalRatio);
    } 
    catch (err) {
        logErr$(err);
    }
}

/**
 * Add a no-frame link to the Top of Mafia Wars canvas iframe. 
 */
function modNoCanvasFrame() 
{
    var canvas_iframe = x$('//iframe[@class="canvas_iframe_util"]');
    
    if (canvas_iframe !== null) {
        var divElt = document.createElement('div');
        
        divElt.innerHTML = '<span style="font-weight: bold; font-size: 14px;">'+
            scriptAppInfo.appName + ' v' + scriptAppInfo.appVer + '&nbsp;|&nbsp;' +
            '<a href="'+ scriptAppInfo.appUrl + '">Check Updates</a>&nbsp;|&nbsp;'+
            '<a href="' + canvas_iframe.getAttribute('src') + '">'+
            'Load No-Frame MafiaWars Game.</a></span>';
            
        canvas_iframe.parentNode.insertBefore(divElt, canvas_iframe);
    }
}
// =========================================================
// PAGES.
// =========================================================
function toAtlanticCity() {
    var popupElt = new domPopupObject({
        type: 'simple',
        title: 'Atlantic City',
        autoOpen: true,
        content: c$('iframe').attr({
            'width': 550,
            'height': 450,
            'src': 'http://m.mafiawars.com/mobileweb'
        })
    });
}
function tofreegiftsPage() {
    do_ajax('mainDiv', 'remote/' + getIntURL('freegifts', 'view'), 0, 1);
    return false;
}
function toOperationsPage() {
    do_ajax('inner_page', 'remote/' + getIntURL('socialmission', 'view'), 1, 1);
    return false;
}

function statsPage() {
    if (e$('#addtowhitelistbutton') !== null) {
        return false; 
    }
    var eMember = e$('a:regex(href,xw_controller=group&xw_action=remove),.tutorial_text');
    var eCenter = c$('center', 'addtowhitelistbutton').insertAfter('.stats_title:first');
    
    if (eMember == null) {
        b$('Add this user to WhiteList!', 'class:medium green').appendTo(eCenter)
        .css('margin', 5).click(function() {
            battlefield($('#inner_page'), 'whiteList');
        }); 
        b$('Add this user to BlackList!', 'class:medium red').appendTo(eCenter)
        .css('margin', 5).click(function() {
            battlefield($('#inner_page'), 'blackList');
        }); 
    }
}

/**
 * Add auto helper to index page.
 */
function newsHelper() {
    
    if (typeof(global.popups['newshelper_popup']) !== 'undefined') {
        global.popups['newshelper_popup'].show();
        return false;
    }
    
    const ERROR_SUCCESS = 0;
    const ERROR_BAD_RESPONSE = 1;
    const ERROR_UNKNOW_ACTION = 2;
    
    var myfeedNews = {};
    var options = new Config('newshelper', {
        lastNewsTime: 0
    });
    var popupElt = new domPopupObject('newshelper_popup', {
        title: 'News Helper',
        type: 'persistent',
        top: 30,
        center: false,
        onclose: function() {
            options.save();
        }
    });
    // ACTIONS
    var _Actions = {
        'goWar': {
            repeat  : 'a:regex(href,xw_action=attack)',
            success : /(You won the fight[^<]*|This war is already[^<]*|You have already[^<]*)/i
        },
        'goPage': function(htmlText, callback) {
            popupElt.close();
            
            setTimeout(function() {
                callback(ERROR_SUCCESS);
                checkNewsCount();
                
                var metadata = doRegex(/<!--\s*Current\s*Page:\s*(\w+)/, htmlText).$1;
                
                $('#inner_page').html(htmlText).removeClass().addClass(metadata);
                
                c$('p').prependTo('#inner_page').css({
                    'border': '2px solid #8F8F8F',
                    'margin': 0,
                    'padding': 8
                }).text('You\'re here from News Helper, ').append(
                    c$('a', 'href:#').text('click here open the popup again.').click(newsHelper)
                );
                loadController(metadata);
                
            }, 500);
        },
        'whitelist': function(htmlText, callback) {
            battlefield(htmlText, 'whiteList', callback);
            return false;  
        }
    };
    // ENVENTS
    var _Event = {
        showAllEvents_click: function() {
            $('#more_events', $(this).parent().parent()).show();
            $(this).remove();
            return false;
        },
        refresh_click: function() {
            showDiv('loading', 'body');
            loadNews(function() {
                genFeedListDom();
                showDiv('newslist', 'body');
            });
            return false;
        },
        reset_click: function() {
            options.set('lastNewsTime', 0);
            _Event.refresh_click();
            return false;
        },
        filterType_change: function() {
            var selected = $('option[selected]', this).val();
            
            if (selected == 'all') {
                $('.update_item', popupElt.content).show();
                return false;
            }
            $('.update_item', popupElt.content).each(function(index, elem) {
                if ($(elem).attr('tp') == selected) {
                    $(elem).show();
                }
                else {
                    $(elem).hide();
                }
            });
            return false;
        },
        help_click: function() {
            if ($(this).attr('disabled')) {
                return false;
            }
            $(this).attr('disabled', 'disabled').css('opacity', 0.4);
            
            var self   = this;
            var parent = $(self).parent().parent();
            var id     = parent.attr('newid');
            var feed   = myfeedNews.feeds[id].feed;
            var action = _Util.getAction(feed.type);
            
            log$(feed.type);
            
            doHelp(feed.action_url, action, function(text) {
                if (text == ERROR_SUCCESS) {
                    parent.remove();
                    return false;
                }
                if (text == ERROR_BAD_RESPONSE) {
                    badServerResponse();
                    log$('newsHelper, doHelp: '+ feed.action_url);
                    $(self).removeAttr('disabled').css('opacity', 1);
                    return false;
                }
                if (text == ERROR_UNKNOW_ACTION) {
                    text = 'I don\'t know how to do it.';
                }
                b$('Clear', 'id:clearbtn,class:medium white')
                .appendTo($(self).parent().empty()).click(_Event.remove_click);
                
                $('.update_txt:first', parent).html(text);
            });
            
            return false;
        },
        remove_click: function() {
            var elem = $(this).parent().parent();
            elem.fadeOut(500, function() {
                elem.remove();
                checkNewsCount();
            });
        }
    };
    
    var _Util = {
        /**
         * @param {jQuery} obj
         */
        getUrl: function(obj) 
        {
            if (!obj.length || !obj.attr) 
                return '';
                
            var url = obj.attr('href');
            
            if (typeof(url) == 'string' && url.match('http')) {
                return url;
            }
            return doRegex(/['"](remote[^'"]*)/, obj.attr('onclick')).$1;
        },
        clean: function(data) 
        {
            var obj = $('<div>'+ data.replace(/<div[^>]*>/g, '<div>') +'</div>');
            $('img, .sexy_button_new, br, div:empty', obj).remove();
            return obj.html();
        },
        getActor: function(id) {
            var act, url;
            if (myfeedNews.users && (act = myfeedNews.users[id])) {
                return '<a href="'+getProfileLink(act.user_id)+'" target="_black">'+act.user_name+'</a>';
            }
            return '';
        },
        getAction: function(name, bForAutoMode) {
            if (name.match('War - Help Needed|War - Declared')) {
                return _Actions.goWar;
            }
            if (name.match('Attacked|Robbery|Hitlist|Snuffed')) {
                return _Actions.whitelist;
            }
            if (name.match('War|Fight|Operation|Mastery Boost|Boss Defeated|helped')) {
                return _Actions.goPage;
            }
            return {};
        }
    };
            
    function doHelp(url, action, callback) 
    {
        ajaxRequest({
            url: url,
            liteLoad: 1,
            success: function(htmlText) 
            {
                var getElem;
                
                if (!mw_updater(htmlText)) {
                    callback(ERROR_BAD_RESPONSE);
                    return;
                }
                if (typeof(action) == 'function') {
                    action(htmlText, callback);
                    return;
                }
                if (action.repeat && (getElem = e$(action.repeat, htmlText))) {
                    doHelp(_Util.getUrl(getElem), action, callback);
                    return;
                }
                if (action.success && action.success.exec && (getElem = action.success.exec(htmlText))) {
                    callback( getElem[1] );
                    return;
                }
                if ((getElem = $('.message_body:last,#mbox_generic_1 tr:eq(1)', htmlText)).length > 0) {
                    callback( _Util.clean(getElem.eq(0).html()) );
                }
                else {
                    callback(ERROR_UNKNOW_ACTION);
                }
            }
        });
    }
    
    function showDiv(name, type, ms, fn) {
        $('*[id*=_'+type+']', popupElt.content).hide();
        $('#' + name + '_' + type, popupElt.content).show(ms, fn);
    }
    
    function genFeedListDom() {
        var i, ulElt = $('.player_updates', popupElt.content).empty();
        var types = {}, lastAddedTime = options.get('lastNewsTime');
        
        var toTimePosted = function(sec) {
            var now = (new Date()).getTime();
            return millisecondsToDateString(now - (sec*1000)) + ' ago:';
        };
        
        function addEvent(elem, s_body) {
            var eventsElt = e$('#more_events', elem);
            
            if (eventsElt == null) {
                eventsElt = c$('div', 'id:more_events').appendTo($('.update_txt', elem)).hide();
                c$('center', 'class:update_txt').appendTo(elem).append(
                    c$('a', 'href:#').text('Show all events').click(_Event.showAllEvents_click)
                );
            }
            
            eventsElt.append(c$('div').html(s_body));
        }


        function addFeed(id, stream) 
        {
            lastAddedTime = Math.max(stream.time_posted, lastAddedTime);
            
            var actor_name  = _Util.getActor(stream.actor_id);
            var s_body      = String(stream.body_text).replace(/\{\*actor\*\}/g, actor_name);
            var existsElem  = e$('div[uid='+stream.actor_id+'][tp=Attacked]', ulElt);
            
            if (existsElem !== null) {
                addEvent(existsElem, s_body);
                return;
            }
            var attr        = 'newid:'+ id +',tp:' + stream.type + ',uid:'+stream.actor_id;
            var updateItem  = c$('div', attr + ',class:update_item').prependTo(ulElt);
            var bhasAction  = /xw_action/.test(stream.action_url);
            
            c$('div', 'class:update_timestamp').appendTo(updateItem).html(toTimePosted(stream.time_posted));
            
            c$('div', 'class:update_icon').appendTo(updateItem).append(
                c$('img', {
                'width': 40,
                'height': 40,
                'src': stream.feed_image
            }));
            
            c$('div', 'class:update_txt').appendTo(updateItem).html(s_body);
            
            c$('div', 'class:update_buttons').appendTo(updateItem).append(
                b$(bhasAction?'Help':'Clear', 'class:medium white,title:'+stream.action_text)
                .click(bhasAction ? _Event.help_click : _Event.remove_click)
            )
            .append(c$('a', 'href:#,class:ignore').text('ignore').click(_Event.remove_click));
            
            types[stream.type] = true;
        }
        
        for (var i = 0, feed = myfeedNews.feeds; i < feed.length; i++) {
            if (feed[i].feed.time_posted > options.get('lastNewsTime')) {
                addFeed(i, feed[i].feed);
            }   
        }
        
        options.set('lastNewsTime', lastAddedTime);
        options.save();
        
        var filterElt = $('#filter_type', popupElt.content).empty()
        .append(c$('option', 'value:all').text('ALL'));
        
        $.each(types, function(name) {
            filterElt.append(c$('option', 'value:'+name).text(name));
        });
        
        checkNewsCount();
    }
    
    function checkNewsCount() {
        var updatesElt = $('.player_updates', popupElt.content);
        if (updatesElt.children().length < 1) {
            c$('center').css('padding', 10).appendTo(updatesElt).html(
                'No news after last load.<br>'+
                'Click "Refresh" to show most recent news.<br>'+
                'Click "Reset and Refresh" to get all news (included old ones).'
            );
        }
    }
    
    function genMainDom() {
        
        c$('div', 'class:frame_box').appendTo(popupElt.content)
        .append(c$('label', 'for:filter_type').text('You can filter your news by: '))
        .append(c$('select', 'id:filter_type,class:black').width(200).change(_Event.filterType_change))
        .append(b$('Refresh', 'class:short white').click(_Event.refresh_click))
        .append(b$('Reset and Refresh', 'class:short white').click(_Event.reset_click));
        
        c$('div').css('border-top', '1px solid #6F6F6F').appendTo(popupElt.content)
        .append(c$('div', 'id:newslist_body,class:player_updates').height(500))
        .append(
            c$('center', 'id:loading_body').height(475).css('padding-top',25)
            .append(c$('img').attr('src', global.zGraphicsURL+'socialmissions/ajax-loader.gif'))
        );
    }
    
    function loadNews(callback) {
        jsonRequest(
            'remote/'+ getIntURL('news','load')+'&lastupdate=0', 
            function(jsonData) 
            {
                var data = $.parseJSON(jsonData.data);
                if (data.json_data) {
                    myfeedNews = data.json_data;
                }
                callback && callback();
            }
        );
    }
    
    function Initialize() {
        var obj = loadingOverlay('Loading News...');
        genMainDom();
        loadNews(function() {
            obj.hide();
            genFeedListDom();
            showDiv('newslist', 'body');
            // show popup
            popupElt.show();            
        });
    }
    
    popupElt.addBase64Style(
        'I25ld3NoZWxwZXJfcG9wdXAgLmJsYWNrIHsNCglmb250LXdlaWdodDogYm9sZDsgDQoJY29sb3I6IHJnYigyMDgsIDIwOCwgMjA4'+
        'KTsgDQoJYm9yZGVyOiAxcHggc29saWQgcmdiKDE1MywgMTUzLCAxNTMpOyANCgliYWNrZ3JvdW5kLWNvbG9yOiBibGFjazsgDQoJ'+
        'Zm9udC1zaXplOiAxNHB4Ow0KfQ0KI25ld3NoZWxwZXJfcG9wdXAgLmZyYW1lX2JveCB7DQoJYm9yZGVyOiAxcHggc29saWQgIzFG'+
        'MUYxRjsNCgltYXJnaW4tYm90dG9tOiA1cHg7DQoJcGFkZGluZzogMTBweDsNCgl0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KI25ld3No'+
        'ZWxwZXJfcG9wdXAgLmZyYW1lX2JveCBhIHsNCgltYXJnaW4tbGVmdDogNXB4DQp9DQojbmV3c2hlbHBlcl9wb3B1cCAudXBkYXRl'+
        'X2J1dHRvbnMgew0KCWZsb2F0OiByaWdodDsNCglmb250LXNpemU6IDEwcHg7DQoJZm9udC13ZWlnaHQ6IGJvbGQ7DQoJbWFyZ2lu'+
        'OiAwcHg7DQoJdGV4dC1hbGlnbjogcmlnaHQ7DQoJd2lkdGg6IDYwcHg7DQp9DQojbmV3c2hlbHBlcl9wb3B1cCAudXBkYXRlX2J1'+
        'dHRvbnMgLmlnbm9yZSB7IA0KCXRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7DQp9DQojbmV3c2hlbHBlcl9wb3B1cCAudXBkYXRl'+
        'X2l0ZW0gew0KCXdpZHRoOiA5OSU7DQoJbWluLWhlaWdodDogNzVweDsNCn0NCiNuZXdzaGVscGVyX3BvcHVwIC51cGRhdGVfdHh0'+
        'IHsNCgl3aWR0aDogNDUwcHg7DQp9'
    );
    
    // load options and Initialize.
    options.load(Initialize);
}

/**
 * Update missions to add getShortURL buttons.
 */
function missionPage(responseText) 
{
    if (!global.options.get('opt_MissionPage') || $('.socialMission').length < 1) {
        return;
    }
    var missions_links = [], socialMissions = [];
    var linkRegex  = /'href':'([^']+)'\+targetUrlParam};/g;
    var keyRegex   = /"feed_key":"(\d*)"/;
    var insRegex   = /"instance_id":"([^"]*)"/;
    var numRegex   = /"mission_num":"(\d*)"/;
    var userRegex  = /taskDoJob_[^_]*_(\d+)/;
    
    var options = new Config('operations', {
        groups       : {'0': 'My wall'},
        defaultGroup : 0,
        today        : 0,
        todayOps     : {},
        todayLinks   : {}
    });
    var getPic = function(s_background) {
        try {
            return String(/url\(([^\)]+)\)/.exec(s_background)[1]).replace(/["']/g,'');
        }
        catch(err) {
            logErr$(err);
            return '';
        }
    };
    var addMissionLink = function(url) {
        try {
            if (!insRegex.test(url)) {
                throw TypeError('Cant read "instance_id" from url.');
            }
            if (!keyRegex.test(url)) {
                throw TypeError('Cant read "feed_key" from url.');
            }
            if (!numRegex.test(url)) {
                throw TypeError('Cant read "mission_num" from url.');
            }
            return missions_links[insRegex.exec(url)[1]] = {
                key: keyRegex.exec(url)[1],
                num: numRegex.exec(url)[1]
            };
        }
        catch(err) {
            logErr$(err);
            return {key:0, num:0};
        }
    };
    var newSocialMission = function(instance_id) {
        var id = '#socialMission_' + instance_id;
        var i, j = $('*[id^=taskDoJob_' + instance_id + '_]');
        var leader_path = '.missionLeader > div:eq(1) > div:eq(1) > div:eq(0)';

        var sm = socialMissions[instance_id] = {
            owner:      e$('.missionLeader', id) == null,
            name:       $.trim($('.missionName', id).text()),
            difficulty: $.trim($('.missionDifficulty > span', id).text()),
            slots:      {total:0,free:0},
            id:         global.USER_ID.match(/(\d+)/)[1],
            instance:   instance_id,
            key:        missions_links[instance_id].key,
            num:        missions_links[instance_id].num,
            missionPic: getPic($('.missionPic', id).attr('style'))
        };
        if (!sm.owner) {
            sm.id = (i = userRegex.exec(j.attr('id'))) ? i[1] : 0;
            sm.leader = $(leader_path, id).text();
        }
        // get free slots
        $('.missionTaskBox', id).each(function(i, elt) {
            sm.slots.total++;
            if (e$('.missionTaskImage > div', elt) == null) {
                sm.slots.free++;
            }
        });
        return sm;
    };
    var createValidUrl = function(m) {
        return getExtURL('socialmission', 'joinMission', {
            'zy_track'    : 'feed',
            'sendtime'    : Math.round(new Date().getTime() / 100),
            'friend'      : 'p|' + m.id,
            'next_params' : {
                'owner_id'    : 'p|' + m.id,
                'feed_key'    : m.key,
                'instance_id' : m.instance,
                'mission_num' : m.num
            }
        });
    };
    var getGroups = function(callback) {
        facebook.needPermission('user_groups', function(success) {
            if (success !== true) {
                callback && callback();
                return;
            }
            var list = {'0': 'My wall'};
            facebook.graphGetGroups(function(groups) {
                for (var i = 0; i < groups.length; i++) {
                    list[groups[i].gid] = groups[i].name;
                }
                options.set('groups', list)
                options.save(callback);
            });
        });
    };
    var updateGroups = function() {
        var elt = $('#op_groups').empty();
        $.each(options.get('groups'), function(id, name) {
            elt.append(c$('option', 'value:'+id).text(name));
        });
    };
    var getShortLinkInfo = function(m) {
        return '['+m.difficulty+' ('+m.slots.free+'/'+m.slots.total+')] ' +
               '"' + m.name + (m.owner === false ? '" from: '+m.leader : '"') + ' => ';
    };
    var getPublishInfo = function(m) {
        return '['+m.difficulty+' ('+m.slots.free+'/'+m.slots.total+')] ' + m.name;
    };
    var _Event = {
        refreshGroups_click: function() {
            var self = this;
            if ($(this).attr('enabled')) {
                return false;
            }
            $(this).attr('enabled', true).css('opacity', 0.4);
            getGroups(function() {
                updateGroups();
                $(self).removeAttr('enabled').css('opacity', 1);
            });
            return false;
        },
        setDefault_click: function() {
            options.set('defaultGroup', $('option[selected]', '#op_groups').val());
            options.save();
            showHelpPopup({
                icon: 'info',
                title: 'Default group',
                message: 'The selected group has been saved as default.'
            });
            return false;
        },
        publish_click: function() {
            if ($(this).attr('enabled')) {
                return false;
            }
            $(this).attr('disable', true).css('opacity', 0.4);
            publishOperation(this);
            return false;
        },
        addShortLink_click: function() {
            if ($(this).attr('disable')) {
                return;
            }
            $(this).attr('disable', true).css('opacity', 0.4);
            addShortLink(this);
            return false;
        },
        publishRemember_click: function() {
            showHelpPopup({
                top: $(this).offset().top - 200,
                icon: 'info',
                title: 'Operation published',
                message: 'You will be able to publish this operation when time is out.'
            });
            return false;
        },
        showLinks_click: function() {
            var outStr = '';
            $.each(options.get('todayLinks'), function(instance, m) {
                outStr += (m.info + m.url + '\n');
            });
            var inputElt = c$('textarea', 'readonly:readonly,rows:8,cols:70').val(outStr);
            var popupElt = new domPopupObject({
                title: 'Operation Links',
                type: 'simple',
                autoOpen: true,
                buttons: [{
                    label: 'Select All',
                    addClass: 'short white',
                    onclick: function() {
                        inputElt.select(); 
                        return false;
                    }
                }, {
                    label: 'Close and Reset',
                    addClass: 'short red',
                    onclick: function() {
                        options.set('todayLinks', {});
                        options.save();
                        popupElt.close();
                        return false;
                    }
                }, {
                    label: 'Close but keep',
                    addClass: 'short green'
                }],
                content: c$('div').css('margin-top', 10).append(inputElt)
            });
            return false;
        }
    };

    function publishOperation(self) 
    {
        var id = $(self).attr('mid');
        var mission = socialMissions[id];
        var target = $('option[selected]', '#op_groups').val();
        var sFrom = (mission.owner === false ? ' from "'+mission.leader+'"' : '');
        
        if (parseFloat(target) < 1) {
            target = '';
        }
        facebook.streamPublish({
            'target': target,
            'name': getPublishInfo(mission),
            'description': 'Join me on this operation' + sFrom + ' and find out what we loot.',
            'pic': mission.missionPic,
            'url': createValidUrl(mission),
            'actionText': 'Join now!'
        }, 
        function(response) {
            $('span > span', self).text('Link Published!');
            options.get('todayOps')[mission.instance] = (new Date()).getTime() + (5*60*1000);
            options.save();
        });
    }
    
    function addShortLink(self) 
    {
        var id         = $(self).attr('mid');
        var nTop       = $(self).offset().top - 200;
        var mission    = socialMissions[id];
        var url        = createValidUrl(mission);
        var savedLink  = options.get('todayLinks')[mission.instance];
        var inputElt   = c$('textarea', 'readonly:readonly,rows:4,cols:70');
        
        if (savedLink && savedLink.info && savedLink.url) {
            savedLink.info = getShortLinkInfo(mission);
            options.save();
            $('span > span', self).text('Link Updated!');
            return;
        }
        getShortURL(url, function(shortURL) {
            if (shortURL !== 'Error') {
                options.get('todayLinks')[mission.instance] = {
                    'info': getShortLinkInfo(mission),
                    'url': shortURL
                }
                options.save();
                $('span > span', self).text('Link Added!');
            }
            else {
                $(self).removeAttr('disable').css('opacity', 1);
                showHelpPopup({
                    top: nTop,
                    icon: 'error',
                    title: 'Error creating short url link',
                    message: 'You can open a new Tab to get the short link.',
                    buttons: [{
                        label: 'Open a new Tab',
                        addClass: 'short white',
                        onclick: function() {
                            unsafeWindow.open(
                                'http://tinyurl.com/create.php?url=' + escape(url)
                            );
                        }
                    }, {
                        label: 'Close' 
                    }]
                });
            }
        });
    }
    
    function genSettingsDom() 
    { 
        c$('style').insertBefore('#socialMissionContent').append(global.Base64.decode(
            'I29wZXJhdGlvbnNfc2V0dGluZ3MgLmJsYWNrIHsNCglmb250LXdlaWdodDogYm9sZDsNCgljb2xvcjog'+
            'cmdiKDIwOCwgMjA4LCAyMDgpOyANCglib3JkZXI6IDFweCBzb2xpZCByZ2IoMTUzLCAxNTMsIDE1Myk7'+
            'IA0KCWJhY2tncm91bmQtY29sb3I6IGJsYWNrOyANCglmb250LXNpemU6IDE0cHg7DQp9DQojb3BlcmF0'+
            'aW9uc19zZXR0aW5ncyB7DQoJYm9yZGVyOiAxcHggc29saWQgIzRGNEY0RjsNCgloZWlnaHQ6IDEyMHB4'+
            'Ow0KCW1hcmdpbi1ib3R0b206IDEwcHg7DQoJcGFkZGluZzogMTBweDsNCgl0ZXh0LWFsaWduOiBsZWZ0'+
            'Ow0KfQ=='
        ));
        
        var linksElt = c$('div').css('margin-top', 10)
        .append(c$('h3').css('margin', 0).text('To handle all my operations links:'))
        .append(
            c$('center').css('margin-top', 2)
            .append(b$('Show All Links', 'class:short green').click(_Event.showLinks_click))
        );
        
        c$('div', 'id:operations_settings').insertBefore('#socialMissionContent')
        .append(c$('h3').css('margin', 0).text('Operations will be published in:'))
        .append(c$('div').text('Remember that some groups have a limit of post per day.'))
        .append(c$('select', 'id:op_groups,class:black').css('margin-right',5).width(480))
        .append(c$('a', 'href:#').text('Set as default').click(_Event.setDefault_click))
        .append(b$('Refresh groups', 'class:short white').css('float','right').click(_Event.refreshGroups_click))
        .append(linksElt);
    }
    
    function genOperationsDom() 
    {
        var rgx;
        // we need instance_id, feed_key and mission_num for every link.
        while ((rgx = linkRegex.exec(responseText))) {
            if (/joinMission/.test(rgx[1])) {
                addMissionLink(unescape(rgx[1]));
            }
        }
        // look all missions and try to add getShortUrl button. 
        $('.socialMission').each(function(index, domElement) {
            if (!domElement.id || domElement.id.length < 14) {
                return;
            }
            var instance = domElement.id.substring(14);
            var curr, m_action = e$('.missionAction > a', '#socialMission_' + instance);
            var m_boxLeft = $('.missionBoxLeft', '#socialMission_' + instance);
            
            if (typeof(missions_links[instance]) !== 'undefined') {
                curr = newSocialMission(instance);
            }
            if (typeof(curr) !== 'undefined' && e$('#buttons_' + instance) == null) {
                if (curr.slots.free > 0) {
                    addButtons(m_boxLeft, instance);
                }
            }
        });
        
        function addButtons(div, instance) {
            var boxElt = c$('div', 'buttons_'+ instance).appendTo(div);
            var pDate = options.get('todayOps')[instance];
            var now = (new Date()).getTime();
            
            if (typeof(pDate) == 'undefined' || now > pDate) {
                b$('Publish', 'class:medium white,mid:' + instance).appendTo(boxElt)
                .click(_Event.publish_click);
            }
            else {
                b$(millisecondsToDateString(pDate-now), 'class:medium white,mid:' + instance)
                .appendTo(boxElt).click(_Event.publishRemember_click).css('opacity', 0.6);
            }
            boxElt.append('<br>');
            b$('Add Link', 'class:medium white,mid:' + instance).appendTo(boxElt)
            .css('margin-top',5).click(_Event.addShortLink_click);
        }
    }
    
    options.load(function() {
        var n_today = new Date().getDay();
        
        // reset stored data if need
        if (options.get('today') !== n_today) 
        {
            options.set('today', n_today);
            options.set('todayOps', {});
            options.set('todayLinks', {});
            options.save();
        }
        
        // Add setting box and buttons
        genSettingsDom();
        genOperationsDom();
        
        // update groups
        updateGroups();
        
        $('option[value='+options.get('defaultGroup')+']', '#op_groups')
        .attr('selected','selected');
    });

}

/**
 * Update the gift page adding a checkbox to each gift box and buttons for get links.
 */
function giftPage() 
{
    if (!global.options.get('opt_GiftPage') || e$('.freegift_grid') == null)
        return;
        
    var n_giftCat = 1;
    var freegift_buttons = $('.freegift_buttons').first().height(40).empty();
    
    var fixedGifts = {
        400: { name:'Secret Drop'         , img:'icon_atk_75x75_01.png'                    , title:'MYSTERY REWARD' , isnew:true},
        401: { name:'Italian Hardwood'    , img:'huge_item_italianhardwood_01.png'         , title:'ITALY'          , isnew:true},
        402: { name:'Marble Slab'         , img:'huge_item_marbleslab_01.png'              , title:'ITALY'          , isnew:true},
        422: { name:'Exotic Animal Feed'  , img:'huge_item_exoticanimalfeed_01.png'        , title:'ITEM PART'      , isnew:true},
        423: { name:'Time Capsule'        , img:'huge_item_timecapsule_01.png'             , title:'MYSTERY REWARD' , isnew:true},
        434: { name:'Coffin'              , img:'huge_item_coffinclosed_01.png'            , title:'MYSTERY REWARD' , isnew:true},
        189: { name:'Special Part'        , img:'huge_item_parts_01.png'                   , title:'ITEM PART'      , isnew:true},  
        417: { name:'Aquarium'            , img:'huge_item_aquarium_01.png'                , title:'PRIVATE ZOO'    , isnew:true},
        418: { name:'Big Cage'            , img:'huge_item_bigcage_01.png'                 , title:'PRIVATE ZOO'    , isnew:true},
        419: { name:'Bird Cage'           , img:'huge_item_birdcage_01.png'                , title:'PRIVATE ZOO'    , isnew:true},
        420: { name:'Feeding Trough'      , img:'huge_item_feedingtrough_01.png'           , title:'PRIVATE ZOO'    , isnew:true},
        421: { name:'Terrarium'           , img:'huge_item_terrarium_01.png'               , title:'PRIVATE ZOO'    , isnew:true},
        181: { name:'Hammer'              , img:'huge_item_hammer_01.png'                  , title:'ARMORY' },
        182: { name:'Rivet'               , img:'huge_item_rivets_01.png'                  , title:'ARMORY' },
        183: { name:'Furnace'             , img:'huge_item_furnace_01.png'                 , title:'ARMORY' },
        184: { name:'Vice'                , img:'huge_item_vice_01.png'                    , title:'ARMORY' },
        185: { name:'Anvil'               , img:'huge_item_anvil_01.png'                   , title:'ARMORY' },
        75 : { name:'Arc Welder'          , img:'huge_item_arcwelder_01.gif'               , title:'WEAPONS DEPOT' },
        76 : { name:'Buzzsaw'             , img:'huge_item_electronicwhetstone_01.gif'     , title:'WEAPONS DEPOT' },
        77 : { name:'Gunpowder'           , img:'huge_item_gunpowder_01.gif'               , title:'WEAPONS DEPOT' },
        78 : { name:'Gun Drill'           , img:'huge_item_gundrill_01.gif'                , title:'WEAPONS DEPOT' },
        79 : { name:'Forge'               , img:'huge_item_forge_01.gif'                   , title:'WEAPONS DEPOT' },
        70 : { name:'Cement Block'        , img:'huge_item_cinderblock_01.png'             , title:'CHOP SHOP' },
        71 : { name:'Power Tool'          , img:'huge_item_powertools_01.png'              , title:'CHOP SHOP' },
        72 : { name:'Car Lift'            , img:'huge_item_carlift_01.png'                 , title:'CHOP SHOP' },
        73 : { name:'Acetylene Torch'     , img:'huge_item_acetylenetorches_01.png'        , title:'CHOP SHOP' },
        74 : { name:'Shipping Container'  , img:'huge_item_shippingcontainers_01.png'      , title:'CHOP SHOP' },   
        161: { name:'Cinder Block'        , img:'huge_item_Cinderblock_01.gif'             , title:'CASINO' },
        162: { name:'Steel Girder'        , img:'huge_item_buildcasino_steelgirders_01.gif', title:'CASINO' },
        163: { name:'Concrete'            , img:'huge_item_Concrete_01.gif'                , title:'CASINO' },
        164: { name:'Construction Tool'   , img:'huge_item_constructiontools_01.png'       , title:'CASINO' },
        169: { name:'Security Camera'     , img:'huge_item_securitycamera_01.png'          , title:'VAULT' },
        170: { name:'Reinforced Steel'    , img:'huge_item_reinforcedsteel_01.png'         , title:'VAULT' },
        171: { name:'Deposit Box'         , img:'item_depositbox_01.png'                   , title:'VAULT' },
        172: { name:'Motion Sensor'       , img:'item_motionsensor_01.png'                 , title:'VAULT' },
        173: { name:'Magnetic Lock'       , img:'huge_item_magneticlock_01.png'            , title:'VAULT' }
    };
        
    var options = new Config('giftpage', {
        lastNoteId: -1,
        useShortUrl: true,
        checkedGifts: [],
        ignoreGifts: []
    });
    
    var _Gift = {
        isValid: function(id, url) {
            if (url.indexOf('gift_event') !== -1) {
                return true;
            }
            var u = splitUrl(url);
            return u.ztrack_subcategory.toLowerCase().indexOf(fixedGifts[id].name.toLowerCase()) !== -1;
        },
        getNameFromTag: function(tag) {
            return tag.substring(tag.lastIndexOf('_') + 1);
        },
        getImageUrl: function(name) {
            if (/http/.test(name)) {
                return name;
            }
            else {
                return global.zGraphicsURL + name;
            }
        },
        getCat: function(giftID) {
            var cat = 1;
            try {
                cat = unsafeWindow.self.allCats[giftID] || 1;
            } 
            catch (e) {
                return 1;
            }
            return cat;
        }
    };
    
    var _Event = {
        useShortUrl_click: function() {
            options.fromDomElements();
            options.save();
            return false;
        },      
        checkbox_click: function() {
            var checkbox = $('input:checkbox', this).get(0);
            checkbox.checked = checkbox.checked !== true;
            $(this).css('background-color',checkbox.checked ? 'grey' : 'transparent')
            .find('span').text(checkbox.checked ? 'CHECKED' : 'UNCHECKED');
            return false;
        },
        category_click: function() {
            var text = $(this).text();
            var checked = $('input:checkbox', $(this).parent()).get(0).checked !== true;
            
            $('div[giftcat='+text+']', '#gift_container').each(function(index, elem) {
                var checkbox = $('input:checkbox', elem).get(0);
                if (checkbox.checked !== checked) {
                    $('.freegift_box_stats', elem).click();
                }
            });
            return false;
        },
        publish: function() {
            var selectedElem = e$('.freegift_box_selected');
            var self = this;
            
            if (selectedElem == null) {
                showHelpPopup({
                    icon: 'info',
                    title: 'Select a gift to publish.',
                    message: 'Click in the image of a gift to make it selected<br>Then try again.',
                    buttons: [{
                        label: 'Accept'
                    }]
                });
                return false;
            }
            
            var giftName = $('.freegift_box_itemname', selectedElem).text();
            var id = selectedElem.attr('id').substring(13);
            var sPicture = global.zGraphicsURL + 'freegifts/MW_art_request_02.png';
            var imgElt = e$('.freegift_box_image img', selectedElem);
            
            if (imgElt) {
                sPicture = imgElt.attr('src');
            }
            
            getGiftLink({
                giftId: id,
                giftCat: _Gift.getCat(id),
                message: 'Obtaining the gift link...',
                success: function(url) 
                {
                    if (url !== 'Error') {
                        facebook.streamPublish({
                            'name': 'I have a ' + giftName,
                            'description': 'I want to gift you a ' + giftName + ', be sure to collect it now.',
                            'pic': sPicture,
                            'url': url,
                            'actionText': 'Collect it'
                        }, 
                        function(post_id) {
                            if (global.options.get('useFacebookGraphApi')) {
                                showHelpPopup({
                                    icon: 'info',
                                    title: 'The Gift has been Published!',
                                    buttons: [{
                                        label: 'Accept'
                                    }]
                                });
                            }
                        });
                        $(self).remove();
                    }
                    else {
                        showHelpPopup({icon:'error', title:'Can\'t get gift url, try again later.'});
                    }
                }
            });
            return false;
        },
        reset_click: function() {
            options.set('ignoreGifts', []);
            options.save(tofreegiftsPage);
            return false;
        },
        help_click: function() {
            showHelpPopup({
                icon: 'info',
                title: 'HOW TO SELECT GIFTS?',
                message: 'To get gifts links, check anyone and click "Get Checked gifts".<br>' +
                '- Click top part (Green) to check/uncheck ALL gifts of same type.<br>' +
                '- Click bottom part of box to Check/Uncheck a single gift.<br><br>' +
                'To publish a gift, select it and click in "Publish Selected gift".<br>' +
                '- Click in gift image to select the single gift.'
            });
            return false;
        },
        shortHelp_click: function() {
            showHelpPopup({
                icon: 'info',
                title: 'HOW TO USE SHORT URL SERVICE?',
                message: 'You can get automatic short links by checking "Use Short Url".<br>' +
                'By default, short links will be get with TinyUrl api.<br><br>' +
                'If TinyUrl api fail and you get errors, try using bit.ly api.<br>' +
                '- To use bit.ly api you need to be registered and configurate it ' +
                'in the configuration popup.'
            });
            return false;
        }
    };
    
    function genGiftDom() 
    {
        var gift, giftId, checked;
        var tab = new domTabObject(
            c$('div').insertAfter('.freegift_grid'),
            'gift_container', ['New Gifts', 'Old Gifts'], 845, 695
        );
        
        $('.freegift_grid').parent().height('auto');
        $('.freegift_grid').remove();
        $('#gift_container').css('margin',0);
        
        tab.tabClear(
            '<input type="checkbox" id="giftpage_useshorturl">'+
            '<label for="giftpage_useshorturl">Use Short URL</label>'+
            '<div style="margin-left: 20px; float: right;">'+
            '<a style="text-decoration: none;"id="show_help" href="#">'+
            '<img src="http://mwfb.static.zgncdn.com/mwfb/graphics/icon-help.gif"> '+
            'Select gifts?</a>'+
            '<a style="margin-left: 20px; text-decoration: none;"id="show_shorthelp" href="#">'+
            '<img src="http://mwfb.static.zgncdn.com/mwfb/graphics/icon-help.gif"> '+
            'Short url?</a>'+           
            '<a style="margin-left: 20px; text-decoration: none;"'+
            'id="reset_ignored" href="#">Reset Ignored Gifts</a>'+
            '</div>'
        );
        
        if (options.get('ignoreGifts').length > 0) {
            $('#reset_ignored').click(_Event.reset_click).show();
        }
        else {
            $('#reset_ignored').hide();
        }
        
        $('#show_help').click(_Event.help_click);
        $('#show_shorthelp').click(_Event.shortHelp_click);
        $('#giftpage_useshorturl').click(_Event.useShortUrl_click);
        
        for (var id in fixedGifts) 
        {
            if (!((gift = fixedGifts[id]) && gift.name) || options.get('ignoreGifts').indexOf(id) !== -1)
                continue;
                
            try {
                checked = options.get('checkedGifts').indexOf(id) !== -1;
                giftId = 'freegift_box_' + id;
                
                c$('div', 'giftcat:'+gift.title+',id:'+giftId)
                .appendTo(tab.getLayout(gift.isnew?0:1)).css('margin', '8px 9px')
                .addClass('freegift_box freegift_box_unselected freegift_box_unlocked')
                .append(
                    c$('div','class:freegift_box_tag').css('cursor','pointer')
                    .attr('title','Click here to Check/Uncheck all '+gift.title.toLowerCase()+' gifts.')
                    .click(_Event.category_click).html(gift.title||'')
                )
                .append(
                    c$('div', 'freegift_box_inner_' + id)
                    .append(
                        c$('div','class:freegift_box_image').css('cursor','pointer').append(
                            c$('img', {
                                'style' : 'width: 75px; height: 75px; border: 0px none;',
                                'src'   : _Gift.getImageUrl(gift.img),
                                'alt'   : gift.name,
                                'title' : 'Click here to Select this gift.'
                            })
                        )
                    )
                    .append(c$('div').addClass('freegift_box_itemname').html(gift.name))
                    .append(
                        c$('div', {
                            'title': 'Click here to Check/Uncheck this gift',
                            'class': 'freegift_box_stats',
                            'style': 'cursor: pointer; background-color: '+(checked?'grey;':'transparent;')
                        })
                        .append(c$('span').text(checked ?'CHECKED':'UNCHECKED'))
                        .append(
                            c$('input:checkbox', {
                                'id'      :'freegift_box_input_' + id,
                                'name'    :'freegift_box_input',
                                'checked' : checked,
                                'value'   : id
                            }).hide()
                        )
                        .click(_Event.checkbox_click)
                    )
                );
                
                $('.freegift_box_image', '#freegift_box_inner_' + id).get(0).setAttribute(
                    'onclick',
                    "$('div[id^=freegift_box_]').removeClass('freegift_box_selected').addClass('freegift_box_unselected');"+
                    "$('#"+giftId+"').removeClass('freegift_box_unselected').addClass('freegift_box_selected');"+
                    "selectedGift = " + id + ";"+
                    "giftCat = allCats[selectedGift]; return false;"
                );
                
            }
            catch (err) {
                logErr$(err);
            }
            
        }
    }
    
    function getNewGifts() 
    {
        $('.freegift_grid').children().each(function(index, elem) {
            if (!(elem.id && elem.onclick && e$('.freegift_box_stats', elem) !== null))
                return;
            
            var id = parseInt(elem.id.substring(13));
            if (fixedGifts[id]) {
                fixedGifts[id].isnew = true;
                return;
            }
            
            var tag = $('.freegift_box_tag',elem);
            
            fixedGifts[id] = {
                isnew : true,
                name  : $('.freegift_box_itemname',elem).text(),
                img   : $('.freegift_box_image img',elem).attr('src'),
                title : (tag.text() || _Gift.getNameFromTag(tag.attr('class'))).toUpperCase()
            };
        }); 
    }
    
    // get all the checked links
    function getLinks() 
    {
        var gifts_array = [];
        
        // Get checked gifts
        $('input:checkbox[name=freegift_box_input]', '#gift_container')
        .each(function(index, domElement) {
            if (domElement.checked) {
                gifts_array.push(domElement.value);
            } 
        });
        
        // save checked gifts
        options.set('checkedGifts', gifts_array.slice());
        options.save();
        
        if (!gifts_array.length) return;
        
        freegift_buttons.children().hide();
        
        // Start
        var workDiv = c$('center').appendTo(freegift_buttons);
        var b_ignoredGifts = false;
        var giftLog = [];
        
        showNormalMessage();
        getGift();
        // ;
        
        
        function showLinks() 
        {
            var groupList = [], title = '', i, t, item;
            var s_date = (new Date()).toDateString();
            var s_outText = s_date + '\n';
            var s_noteContent = '<ul>';
            var s_title = 'Check it to edit a old published note instead of create a new one.';
            
            var popup = new domPopupObject({
                title: 'Gift Links',
                type: 'simple',
                top: 150,
                onclose: function() {
                    delete popup, gifts_array, giftLog;
                    if (b_ignoredGifts) {
                        tofreegiftsPage();
                    }
                }
            });
            var publishNote = function() {
                var self = this;
                if ($(self).attr('disabled')) {
                    return false;
                }
                $(self).attr('disabled', true).css('opacity', 0.4);
                
                var sTitle = 'Mafia Wars Free Gift Links ('+s_date+')';
                var note_id = options.get('lastNoteId');
                
                var finish = function(new_note) {
                    if (parseInt(new_note) > 0) {
                        options.set('lastNoteId', parseInt(new_note));
                        options.save();
                    }
                    $(self).parent().empty().append(c$('h3').text('Note published!'));
                    return false;
                };
                
                s_noteContent = s_noteContent +'</ul>';
                
                if ($(self).attr('action') == 'edit') {
                    facebook.graphEditNote(note_id, sTitle, s_noteContent, finish);
                }
                else {
                    facebook.graphCreateNote(sTitle, s_noteContent, finish);
                }
                return false;
            };
             
            for (i = 0; i < giftLog.length; i++) {
                title = fixedGifts[giftLog[i].id].title;
                if (typeof(groupList[title]) == 'undefined') {
                    groupList[title] = [];
                }
                groupList[title].push({
                    name : fixedGifts[giftLog[i].id].name,
                    url  : giftLog[i].url,
                    lUrl : giftLog[i].long_url,
                    img  : _Gift.getImageUrl(fixedGifts[giftLog[i].id].img)
                })
            }
            
            for (t in groupList) {
                s_outText += ('\n'+ t + ':\n').toUpperCase();
                s_noteContent += '</ul><b>'+ String(t).toUpperCase() + ':</b><ul>';
                for (i = 0; i < groupList[t].length; i++) {
                    item = groupList[t][i];
                    s_outText += item.name + ' => '+ item.url + '\n';
                    s_noteContent += '<li><a href="'+item.url+'">'+item.name+'</a></li>'
                }
            }

            c$('textarea', 'readonly:readonly,rows:15,cols:60')
            .appendTo(popup.content).get(0).innerHTML = s_outText;
            
            c$('center', 'id:publish,class:clearfix').css('margin-top',20).appendTo(popup.content)
            .append(b$('Publish New Note', 'action:new,class:medium white').click(publishNote))
            .append(
                b$('Edit old Note', 'action:edit,class:medium white')
                .css('margin-left',10).click(publishNote)
            );
            
            if (b_ignoredGifts) {
                showIgnoredAlert('Click ok to continue.');
            }
            popup.show();
        }
        
        function showNormalMessage() 
        {
            var elt = c$('div').css('padding-top',7).appendTo(workDiv.empty());
            
            c$('img').attr('src',global.resource.ajax_loader).appendTo(elt).css('vertical-align', 'middle');
            
            c$('span', 'message_info').appendTo(elt).css({
                'margin-left': 10,
                'font-weight': 'bold'
            });
        }
        
        function showRetryMessage(name, retry_callback, skip_callback) 
        {
            var elt = c$('div').appendTo(workDiv.empty());
            
            c$('img').attr('src',global.resource.ajax_error).appendTo(elt).css('vertical-align', 'middle');
            
            c$('span').css('margin-left', 5).appendTo(elt)
            .text('Can\'t get gift link for ' + name + '.');
            
            b$('Retry').css('margin-left', 5).addClass('medium white freegift_send_button')
            .appendTo(elt).click(function() {
                showNormalMessage();
                retry_callback();
            });
                
            b$('Skip').css('margin-left', 5).addClass('medium white freegift_send_button')
            .appendTo(elt).click(function() {
                showNormalMessage();
                skip_callback();
            });
        }
        
        function showManualLink(id, url, callback) 
        {
            var elt = c$('div').appendTo(workDiv.empty());
            
            c$('span').text('Click:').appendTo(elt);
            
            b$('Get Tiny').css('margin', '0px 5px').appendTo(elt)
            .addClass('medium white freegift_send_button')
            .click(function() {
                unsafeWindow.open('http://tinyurl.com/create.php?url=' + escape(url));
            });
            
            c$('label', 'for:tinyurl_link').text('and paste the link:').appendTo(elt);
            
            c$('input:text', 'tinyurl_link').appendTo(elt).css({
                'width': 180,
                'margin-left': 5
            });
            
            b$('OK').css('margin-left', 5).appendTo(elt).addClass('medium white freegift_send_button')
            .click(function() {
                url = $('#tinyurl_link').val();
                if (/http:\/\/tinyurl.com\//.test(url)) {
                    addGift(id, url);
                }
                else {
                    
                }
                showNormalMessage();
                callback();
            });
        }
        
        function showIgnoredAlert(lastMessage) {
            showHelpPopup({
                icon: 'info',
                title: 'Gifts ignored',
                message: 'Some gifts has been ignored because i get invalid link.\n' + 
                    'They are now in "ignored list" and will be hidden.\n\n' + lastMessage
            });     
        }
        
        function nextGift() {
            gifts_array.splice(0, 1);
            getGift();
        }
        
        function ignoreGift(id) {
            options.get('ignoreGifts').push(id);
            options.save();
            b_ignoredGifts = true;
        }
        
        function addGift(id, short_url, long_url) {
            giftLog.push({
                id: id,
                url: short_url,
                long_url: long_url
            });
        }
        
        // get first link.
        function getGift() 
        {
            if (gifts_array.length > 0) 
            {
                var giftName = fixedGifts[gifts_array[0]].name;
                
                $('#message_info')
                .text('Trying to get url link for '+giftName+' gift...');
                
                // long url
                getGiftLink({
                    giftId: gifts_array[0],
                    giftCat: _Gift.getCat(gifts_array[0]),
                    success: function(url) 
                    {
                        if (!_Gift.isValid(gifts_array[0], url)) {
                            ignoreGift(gifts_array[0]);
                            nextGift();
                            return;
                        }
                        if ($('#giftpage_useshorturl').get(0).checked) {
                            getShortURL(url, function(shortURL) {
                                if (shortURL == 'Error') {
                                    showRetryMessage(giftName, getGift, nextGift);
                                }
                                else {
                                    addGift(gifts_array[0], shortURL, url);
                                    nextGift();
                                }
                            });
                        }
                        else if (/http/.test(url)) {
                            showManualLink(gifts_array[0], url, nextGift);
                        }
                        
                    }
                });
            }
            else // Finish all links
            {   
                workDiv.remove();
                freegift_buttons.children().show();
                
                if (giftLog.length > 0) {
                    showLinks();
                }
                else if (b_ignoredGifts) {
                    showIgnoredAlert('Click ok to refresh gift page.');
                    tofreegiftsPage();
                }
                else {
                    showHelpPopup({icon:'info', title:'No gifts to show.'});
                }
            }
        }
    }
    
    // Get links button
    b$('Get checked links').appendTo(freegift_buttons).click(getLinks)
    .addClass('medium white sexy_send_gift_new').css('margin-right',10);
    
    // Publish button
    b$('Publish selected gift').appendTo(freegift_buttons).click(_Event.publish)
    .addClass('medium white sexy_announce_gray').css('margin-right',10);
    
    if (e$('#freegift_ask_button_bottom') !== null) {
        $('#freegift_ask_button_bottom').get(0)
        .setAttribute('onclick', 'getGiftFeed(); return false;');
    }
        
    // load options
    options.load(function() {
        getNewGifts();
        genGiftDom();
        options.toDomElements();
    });
    // ;
}
/**
 * Add Energy ratios to Jobs.
 */
function jobPage() 
{
    if (!global.options.get('opt_JobRates'))
        return;
    if (e$('.job_list') !== null) {
        // Normal jobs  
        $('tr', 'table[class=job_list]').each(function(index, domElement){
            try {
                var reward = parseInt($('td[class*="job_reward"] > span.bold_number', domElement).text());
                var energy = parseInt($('td[class*="job_energy"] > span.bold_number', domElement).text());
                if (reward && energy) {
                    var elem = $('td[class*="job_energy"]', domElement);
                    (e$('#job_energy_ratio', elem) || 
                     c$('div', 'job_energy_ratio').appendTo(elem))
                    .html((reward / energy).toFixed(2) + ' Ratio').css({
                        'color': 'green',
                        'font-weight': 'bold'
                    });
                }
            } 
            catch (err) {
                logErr$(err);
            }
        });
    }
    else if (e$('#new_user_jobs') !== null) {
        // Started jobs
        $('div[id^="job_"]', '#new_user_jobs').each(function(index, domElement){
            try {
                var reward = parseInt($('dd.experience', domElement).text());
                var energy = parseInt($('dd.energy', domElement).text());
                if (reward && energy) {
                    var elem = $('dd.energy', domElement).parent();
                    (e$('#job_energy_ratio', elem) || 
                     c$('dt', 'job_energy_ratio').appendTo(elem))
                    .html('('+(reward / energy).toFixed(2)+')').css({
                        'color': 'green',
                        'font-weight': 'bold'
                    });
                }
            } 
            catch (err) {
                logErr$(err);
            }
        });
    }
}
/**
 * Add Energy ratios to new city Jobs.
 */
function jobMapPage()
{
    if (!global.options.get('opt_JobRates'))
        return; 
    if (e$('#job_panel') !== null) {
        // Started jobs
        $('.job_container', '#job_panel').each(function(index, domElement){
            try {
                var reward = e$('dd.experience', domElement);
                var energy = e$('dd.energy', domElement) || e$('dd.stamina', domElement);
                if (reward && energy) {
                    var elem = energy.parent();
                    (e$('#job_energy_ratio', elem) || 
                     c$('dd', 'job_energy_ratio').appendTo(elem))
                    .html('('+(parseInt(reward.text()) / parseInt(energy.text())).toFixed(2)+')')
                    .css({
                        'color': 'green',
                        'font-weight': 'bold'
                    });
                }
            } 
            catch (err) {
                logErr$(err);
            }
        });
    }   
}
/**
 * Modify gift buttons to open Multi Gifter.
 */
function collectionPage()
{
    if (!global.options.get('opt_CollectionPage')) {
        return;
    }
    var giftButton_click = function() {
        var u = splitUrl($(this).attr('href'));
        multiGifter(u.gift_category, u.gift_id);
        $('#TopField').focus();
        return false;
    };
    $('a:regex(href,gift_id)').each(function(index,elem) {
        if (elem.href && elem.href.indexOf('xw_controller=gift') !== -1) {
            $(elem).removeAttr('onclick').click(giftButton_click);
        }
    });
}
// =========================================================
// CONTROLLERS.
// =========================================================

function InventoryAnalizer() {
    
    var Groups = ['Weapons', 'Armor', 'Vehicles', 'Animals'];
    var Indexes = {'1':0, '2':1, '3':2, '8': 3};
    var Qualities, Wishlist;
    var Filter = function() {
        return {
            'top_offense'   : new Array(),
            'top_defense'   : new Array(),
            'top_combined'  : new Array(),
            'weak_offense'  : new Array(),
            'weak_defense'  : new Array(),
            'weak_combined' : new Array(),
            'get_offense'   : new Array(),
            'get_defense'   : new Array(),
            'get_combined'  : new Array(),
            'give_away'     : new Array()
        };
    };
    var Inventory = {
        all        : new Array(),
        Weapons    : Filter(),
        Armor      : Filter(),
        Vehicles   : Filter(),
        Animals    : Filter(),
        Qualities  : null,
        ItemTypes  : null,
        Locations  : null,
        global     : {
            'Weapons_offense'    : 0,
            'Weapons_defense'    : 0,
            'Weapons_combined'   : 0,
            'Armor_offense'      : 0,
            'Armor_defense'      : 0,
            'Armor_combined'     : 0,
            'Vehicles_offense'   : 0,
            'Vehicles_defense'   : 0,
            'Vehicles_combined'  : 0,
            'Animals_offense'    : 0,
            'Animals_defense'    : 0,
            'Animals_combined'   : 0,
            'Total_offense'      : 0,
            'Total_defense'      : 0,
            'Total_combined'     : 0,
            'Qualities'          : {
                'Total': 0,
                '1': 0,
                '2': 0,
                '3': 0,
                '4': 0,
                '5': 0
            }
        }
    };
    
    var popupElt = new domPopupObject('invAnalizer_popup', {
        title: 'Inventory Analizer',
        css: {
            'width': 700,
            'left': 27,
            'top': 40
        },
        onclose: function() {
            delete Inventory;
        }
    });
    
    var _Event = {
        remWishlist_click: function() {
            var id = $(this).attr('wid');
            var url = 'remote/' + getIntURL('wishlist', 'remove');
            
            jsonRequest(url + '&isajax=1&retwl=1&wid='+id, setWishlist);
            
            return false;
        },
        addWishlist_click: function() {
            var id = $(this).attr('itemid');
            for(var i = 0; i < Wishlist.length; i++) {
                if(parseInt(id) === parseInt(Wishlist[i].id)) {
                    return false;
                }                
            }
            var sText = $(this).text();
            var url = 'remote/' + getIntURL('wishlist', 'add');
            
            $(this).replaceWith(c$('span').text(sText));
            jsonRequest(url + '&isajax=1&retwl=1&gift_category=1&gift_id='+id, setWishlist);
            
            return false;
        },
        item_click: function() {
            var sName   = String($('#type_filter option[selected]', popupElt.content).val());
            var sFilter = String($('#show_filter option[selected]', popupElt.content).val());
            
            $('.item_list li.selected', popupElt.content).toggleClass('selected', false);
            $(this).toggleClass('selected', true);
            
            genSelectedItemDom(Inventory[sName][sFilter][$(this).attr('idx')]);
        },
        genTable_click: function() {
            var sOutput = 'data:text/html;base64,';
            sOutput += global.Base64.encode(genHTMLTable());
            unsafeWindow.open(sOutput, '_black');
        }
    };
    
    var sortBy = {
        attack   : function(a, b) { return b.attack - a.attack; },
        defense  : function(a, b) { return b.defense - a.defense; },
        combined : function(a, b) { return (b.attack+b.defense) - (a.attack+a.defense); },
        quantity : function(a, b) { return b.quantity - a.quantity; }
    };
    
    var getInventoryData = function(html) {
        var Items, ItemTypes, Subtypes, Locations, Qualities, Wl; 
        var nStartIndex = html.indexOf('var Items');
        var nLastIndex = html.indexOf('</script>', nStartIndex)-1;
        
        eval(html.substr(nStartIndex, nLastIndex - nStartIndex));
        
        Inventory.ItemTypes = ItemTypes.data;
        Inventory.Locations = Locations.data;
        Inventory.Qualities = Qualities.data;
        Inventory.Subtypes  = Subtypes.data;
        
        nStartIndex = html.indexOf('var Wishlist');
        nStartIndex = html.indexOf('data:', nStartIndex)
        nLastIndex  = html.indexOf('],', nStartIndex)+1;
        
        eval(html.substr(nStartIndex, nLastIndex - nStartIndex).replace('data:', 'Wl=') + ';');
        
        Wishlist = Wl;
        
        return Inventory.all = Items.data;
    };
    
    function genHTMLTable() {
        var sOutput = '<html><head></head><body><table cellspacing="1" border="1" style="text-align:center;"><tbody>';
        var eList = $('.item_list', popupElt.content).clone();
        var eHeader = $('.header', popupElt.content).clone();
        
        eList.find('.space').remove();
        eHeader.find('.space').remove();
        
        eList.find('img').replaceWith(function() {
            var rgx;
            var sTitle = $(this).attr('title');
            var sUrl = $(this).attr('src');
            var sSpan = '<span title="' + sTitle + '">';
            
            if (/active-icon/.test(sUrl)) {
                return sSpan + 'A</span>';
            }
            if (/inactive-icon/.test(sUrl)) {
                return sSpan + 'N</span>';
            }
            if ((rgx = /Quality:\s*(\w)\w+/.exec(sTitle))) {
                return sSpan + rgx[1] + '</span>';
            }
            return '';
        });
        
        var sList = eList.html();
        var sHeader = eHeader.html();
        
        sList = sList.replace(/<li[^>]*>/g, '<tr>').replace(/<\/li>/g, '</tr>');
        sList = sList.replace(/<div[^>]*>/g, '<td>').replace(/<\/div>/g, '</td>');
        sHeader = sHeader.replace(/<div[^>]*>/g, '<th>').replace(/<\/div>/g, '</th>');
        
        sOutput += '<tr>' + sHeader + '</tr>' + sList;
        
        return sOutput + '</tbody></table></body></html>';
    }
    
    function setWishlist(jsonData) {
        try {
            var data = $.parseJSON(jsonData.data);
            if (data.wlstatus !== 'error') {
                Wishlist = data.wldata;
                updateWishlist();                
            }
            else {
                showHelpPopup({
                    icon: 'error',
                    title: 'Error adding item to wishlist',
                    message: data.wlmsg
                });
            }
        }
        catch(err) {
            logErr$(err);
        }
    }
    
    function updateWishlist() {
        var sRemImgSrc = global.zGraphicsURL + 'inventory/ItemCard/icons/Inventory-wishlist2-icon.png';
        var elem = $('#wishlist').empty();
        
        $.each(Wishlist, function(index, item) {
            c$('div', 'class:wl_item,title:'+item.name)
            .append(c$('img', 'class:remove,wid:'+index).attr('src', sRemImgSrc).click(_Event.remWishlist_click))
            .append(c$('img').attr('src', item.image).width(50).height(50))
            .append(c$('div', 'class:attack_defense').html(
                '<span class="attack">'+item.attack+
                '</span><span class="defense">'+item.defense+'</span>'
            ))
            .appendTo(elem);
        });         
    }
    
    function genListDom() {
        var sName      = String($('#type_filter option[selected]', popupElt.content).val());
        var sFilter    = String($('#show_filter option[selected]', popupElt.content).val());
        var bNeed      = /get/.test(sFilter);
        var sHtmlText  = '';
        
        if (/line/.test(sFilter)) {
            return;
        }
        if (sName == 'global') {
            genGlobalStats();
            return;
        }
        
        var iElt = $('#info_table').empty();
        
        var sQTitle = bNeed ? 'Items needed' : 'Item quantity';
        var sATitle = bNeed ? 'Attack gained if equipped' : 'Items equipped in attack';
        var sDTitle = bNeed ? 'Defense gained if equipped' : 'Items equipped in defense';
        var sCTitle = bNeed ? 'Combined gained if equipped' : 'Items equipped in tournaments';
        var sGATitle = bNeed ? 'Attack gained if total equipped' : 'Total attack from this item';
        var sGDTitle = bNeed ? 'Defense gained if total equipped' : 'Total defense from this item';
        var sGCTitle = bNeed ? 'Combined gained if total equipped' : 'Total combined from this item';
        
        c$('div', 'class:header')
        .append(c$('div', 'class:quality').html('A'))
        .append(c$('div', 'class:space'))
        .append(c$('div', 'class:quality').html('Q'))
        .append(c$('div', 'class:space'))
        .append(c$('div', 'class:item_name').html('Item Name'))
        .append(c$('div', 'class:space'))
        .append(c$('div', 'class:number quantity,title:'+sQTitle).html('QT'))
        .append(c$('div', 'class:space'))
        .append(c$('div', 'class:number,title:'+sATitle).html(bNeed?'+A':'EA'))
        .append(c$('div', 'class:number,title:'+sDTitle).html(bNeed?'+D':'ED'))
        .append(c$('div', 'class:number,title:'+sCTitle).html(bNeed?'+C':'ET'))
        .append(c$('div', 'class:space'))
        .append(c$('div', 'class:number').html('AT'))
        .append(c$('div', 'class:number').html('DF'))
        .append(c$('div', 'class:number').html('CB'))
        .append(c$('div', 'class:space'))
        .append(c$('div', 'class:total,title:'+sGATitle).html(bNeed?'GA':'TA'))
        .append(c$('div', 'class:total,title:'+sGDTitle).html(bNeed?'GD':'TD'))
        .append(c$('div', 'class:total,title:'+sGCTitle).html(bNeed?'GC':'TC'))
        .appendTo(iElt);
        
        // List of items
        $.each(Inventory[sName][sFilter], function(index, item) {
            
            var nCombined       = item.attack + item.defense;
            var nTotalAttack    = item.attack * item.quantity;
            var nTotalDefense   = item.defense * item.quantity;
            var nTotalCombined  = nCombined * item.quantity;
            var sImageQuality   = (Inventory.Qualities[String(item.quality)] || {}).image;
            var sImgActiveSrc   = 'http://mwfb.static.zgncdn.com/mwfb/graphics/inventory/ItemCard/icons/';
            var sImageActive    = item.active ? 'Inventory-active-icon.png' : 'Inventory-inactive-icon.png';
            var sActiveTitle    = item.active 
                ? 'Active item - Your Mafia is using this item in fights/robs.' 
                : 'Inactive item - Your Mafia is not using this item in fights/robs.';
            
            sHtmlText += '<li idx="'+index+'"><div class="quality">';
            sHtmlText += '<img title="'+sActiveTitle+'" style="margin-top: 1px;"';
            sHtmlText += 'src="'+sImgActiveSrc+sImageActive+'"></div>';
            sHtmlText += '<div class="quality">'+sImageQuality+'</div>';
            sHtmlText += '<div class="space"></div>';
            sHtmlText += '<div class="item_name">'+item.name+'</div>';
            sHtmlText += '<div class="space"></div>';
            
            if (bNeed) {
                var index = sFilter.lastIndexOf('_'); 
                sHtmlText += '<div class="number quantity">'+item['need'+sFilter.substr(index)]+'</div>';
            }
            else {
                sHtmlText += '<div class="number quantity">'+item.quantity+'</div>';
            }
            
            sHtmlText += '<div class="space"></div>';
            
            if (bNeed) {
                sHtmlText += '<div class="number">+'+item.gain_offense+'</div>';
                sHtmlText += '<div class="number">+'+item.gain_defense+'</div>';
                sHtmlText += '<div class="number">+'+item.gain_combined+'</div>';
            }
            else {
                sHtmlText += '<div class="number">'+item.equipped_offense+'</div>';
                sHtmlText += '<div class="number">'+item.equipped_defense+'</div>';
                sHtmlText += '<div class="number">'+item.equipped_combined+'</div>';
            }
            
            sHtmlText += '<div class="space"></div>';
            sHtmlText += '<div class="number">'+item.attack+'</div>';
            sHtmlText += '<div class="number">'+item.defense+'</div>';
            sHtmlText += '<div class="number">'+nCombined+'</div>';
            sHtmlText += '<div class="space"></div>';
            
            if (bNeed) {
                sHtmlText += '<div class="total">+'+item.gained_offense+'</div>';
                sHtmlText += '<div class="total">+'+item.gained_defense+'</div>';
                sHtmlText += '<div class="total">+'+item.gained_combined+'</div></li>';
            }
            else {
                sHtmlText += '<div class="total">'+nTotalAttack+'</div>';
                sHtmlText += '<div class="total">'+nTotalDefense+'</div>';
                sHtmlText += '<div class="total">'+nTotalCombined+'</div></li>';                
            }

        });
        
        c$('ul', 'class:item_list').html(sHtmlText).appendTo(iElt).find('li').click(_Event.item_click);
    }
    
    function genSelectedItemDom(item) {
        
        if (typeof(item) == 'undefined') {
            $('#item_info', popupElt.content).empty()
            .append(c$('div').text('Select an item to show extended info.'));
            return; 
        }
         // selected item info
        var infoElt, sSearchUrl = 'http://mafiawars.wikia.com/index.php?title=Special:Search&search=';
        var iLocation = Inventory.Locations[item.location];
        var sType = [];
        
        if (item.subtypes && item.subtypes.length) {
            $.each(item.subtypes, function(i, index) {
                var subtype = Inventory.Subtypes[String(index)];
                
                if(typeof(subtype) !== 'undefined') {
                    sType.push(subtype.name); 
                }
            });
        }
        
        $('#item_info', popupElt.content).empty()
        .append(c$('div', 'class:imagen').html(item.image))
        .append(infoElt = c$('div', 'class:info'));
        
        if (sType.length > 0) {
            c$('div').css({'float':'left','margin-right':5})
            .html('Item type: '+sType.join(', ') + ' ').appendTo(infoElt);
        }
        
        if (item.favor_id > 0 && parseInt(item.rp_price) > 0) {
            c$('div').appendTo(infoElt).css({'float':'left','color':'green'}).html('('+item.rp_price + ' RP)')
            //.html('<img src="'+global.zGraphicsURL+'v3/icon-gf-coin.gif">'+item.rp_price + ' RP');
        }
        else if (item.pawn_shop > 0 && parseInt(item.lp_price) > 0) {
            c$('div').appendTo(infoElt).css({'float':'left','color':'green'}).html('('+item.lp_price + ' LP)')
            //.html('<img src="'+global.zGraphicsURL+'crm/CRM_LP-icon-s.png">'+item.lp_price + ' LP');
        }
        else if (item.purchasable && parseInt(item.cash_price) > 0) {
            c$('div').appendTo(infoElt).css({'float':'left','color':'green'}).html('(buy: '+item.cash_price+')');
        }
        
        c$('div').css('clear', 'both').html('You can search it at ').appendTo(infoElt)
        .append(c$('a', 'target:_black').attr('href', sSearchUrl+String(item.name).replace(/\s+?/g,'+')).text('wikia'));
        
        if (item.tradeable > 0) {
            c$('div').html('This item can be added to ').appendTo(infoElt)
            .append(c$('a', 'href:#,itemid:'+item.id).text('wishlist')
            .click(_Event.addWishlist_click));
        }
        
        if (iLocation && iLocation.link && iLocation.name) {
            c$('div').html('You can get this item in ').appendTo(infoElt)
            .append(c$('a', 'target:_black').attr('href', iLocation.link).text(iLocation.name));
        }
    }
    
    function genMainDom() {
        var cSelectOptions = {
            'type_filter': {
                'Weapons'  : 'Weapons',
                'Armor'    : 'Armor',
                'Vehicles' : 'Vehicles',
                'Animals'  : 'Animals'
            },
            'show_filter': {
                'top_offense'         : 'Top offense',
                'top_defense'         : 'Top defense',
                'top_combined'        : 'Top combined',
                'line0'               : '-------------------',
                'weak_offense'        : 'Weak offense',
                'weak_defense'        : 'Weak defense',
                'weak_combined'       : 'Weak combined',
                'line1'               : '-------------------',
                'get_offense'         : 'Need for offense',
                'get_defense'         : 'Need for defense',
                'get_combined'        : 'Need for tournament',
                'line2'               : '-------------------',
                'give_away'           : 'To given away.'
            }
        };
        
        // filter
        c$('div', 'class:frame_box').appendTo(popupElt.content)
        .append(c$('label', 'for:show_filter').text('Show: '))
        .append(c$('select', 'id:type_filter,class:black').width(150).change(genListDom))
        .append(c$('select', 'id:show_filter,class:black').change(genListDom))
        .append(b$('Generate Table', 'class:short white').css('float', 'right').click(_Event.genTable_click));
        
        c$('div', 'class:frame_box').height(80).appendTo(popupElt.content)
        .append(c$('div', 'item_info').text('Select an item to show extended info.'))
        .append(c$('div', 'wishlist'));
          
        // List
        var divElt = c$('div', 'info_table').appendTo(popupElt.content).css({
            'margin': 2,
            'padding': 2
        });
        
        function buildStrengthBox(title, type) {
            var elem = c$('div', 'class:mafia_strength')
            .append(c$('div', 'class:total_title').append(c$('span').text(title)));
            
            $.each(['Weapons', 'Armor', 'Vehicles', 'Animals', 'Total'], function(index, name) {
                var nQuantity = Inventory.global[name+'_'+type];
                var sClassFix = (type == 'offense') ? 'attack' : type;
                
                c$('div', 'class:mafia_strength_spacing').appendTo(elem)
                .append(c$('div', 'class:stat_name').text(name + ':'))
                .append(c$('span','class:text_positioning '+sClassFix).text(nQuantity));
            });
            
            return elem;
        }
        
        function buildQualitiesBox() {
            var cQualities = Inventory.global.Qualities;
            var elem = c$('div', 'class:mafia_strength qualities')
            .append(c$('div', 'class:total_title').append(c$('span').text('Qualities equipped')));
            
            $.each(Inventory.Qualities, function(name, cQuality) {
                var nQuantity = cQualities[name];
                c$('div', 'class:mafia_strength_spacing').appendTo(elem)
                .append(c$('div').css('float', 'left').html(cQuality.image).css('margin-left',5))
                .append(c$('div', 'class:stat_name').text(cQuality.name + ':'))
                .append(c$('span','class:text_positioning').text(nQuantity));
            });
            
            c$('div', 'class:mafia_strength_spacing').appendTo(elem)
            .append(c$('div', 'class:stat_name').text('Total:'))
            .append(c$('span','class:text_positioning').text(cQualities['Total']));
            
            return elem;
        }
        
        // global stats
        c$('div', 'class:frame_box').height(200).appendTo(popupElt.content)
        .append(buildStrengthBox('Attack Strength', 'offense'))
        .append(buildStrengthBox('Defense Strength', 'defense'))
        .append(buildStrengthBox('Combined Strength', 'combined'))
        .append(buildQualitiesBox());
        
        // apply options
        applySelectOptions(cSelectOptions, popupElt.content);
    }
    
    function Initialize(htmlText) {
        if (mw_updater(htmlText) !== true) {
            popupElt.destroy();
            badServerResponse();
            return;
        }
        var Items = getInventoryData(htmlText);
        
        // get all items
        $.each(Items, function(id, obj) {
            var sInventory;
            var cQualities   = Inventory.global['Qualities'];
            var nGroupIndex  = Indexes[String(obj.type)];
            var bEquipped    = (obj.equipped_offense + obj.equipped_defense) > 0;
            var nEquipped    = Math.max(obj.equipped_offense, obj.equipped_defense);
            var bValid       = (obj.attack + obj.defense) > 0;
            var bAvailable   = (
                (obj.location != 7 && obj.location != 10 && obj.location != 16 
                && obj.location != 9 && obj.specialAbility.length < 1) 
                || obj.favor_id != -1 || obj.vc_available == true
            );
            try {
                if (typeof(sInventory = Inventory[Groups[nGroupIndex]]) !== 'undefined') 
                {
                    // add new stats
                    obj['equipped_combined'] = 0;
                    obj['need_offense']      = 0;
                    obj['need_defense']      = 0;
                    obj['need_combined']     = 0;
                    obj['gained_offense']    = 0;
                    obj['gained_defense']    = 0;
                    obj['gained_combined']   = 0;
                    obj['need_total']        = 0;
                    obj['gain_offense']      = 0;
                    obj['gain_defense']      = 0;
                    obj['gain_combined']     = 0;
                    obj['combined']          = obj['attack'] + obj['defense'];
                    obj['offense']           = obj['attack'];
                    
                    // add equiped items
                    if (bEquipped) {                        
                     cQualities[obj.quality] += nEquipped;
                     cQualities['Total'] += nEquipped;
                        sInventory['top_combined'].push(obj);
                        if(obj.equipped_offense > 0) {
                            sInventory['top_offense'].push(obj);
                        }
                        if(obj.equipped_defense > 0) {
                            sInventory['top_defense'].push(obj);
                        }
                    }
                    // add owned items
                    else if(!bEquipped && bValid && obj.quantity > 0) {
                        sInventory['top_combined'].push(obj); 
                        if(obj.attack > obj.defense) {
                            sInventory['weak_offense'].push(obj); 
                        }
                        else {
                            sInventory['weak_defense'].push(obj);
                        }
                    }
                    // add needed items
                    if(bValid && bAvailable) {
                        sInventory['get_combined'].push(obj);
                        sInventory['get_offense'].push(obj);
                        sInventory['get_defense'].push(obj);
                    }
                }
            }
            catch(err) {
                logErr$(err);
            }
        });
        
        // calculate all 
        $.each(Groups, function(index, groupTag) {
            Inventory[groupTag]['top_offense'].sort(sortBy.attack);
            Inventory[groupTag]['top_defense'].sort(sortBy.defense);
            Inventory[groupTag]['top_combined'].sort(sortBy.combined);
            Inventory[groupTag]['weak_offense'].sort(sortBy.attack);
            Inventory[groupTag]['weak_defense'].sort(sortBy.defense);
            
            // calculate combined
            var top_combined = [];
            var nMaxCombined = 501;
            
            $.each(Inventory[groupTag]['top_combined'], function(index, item) {
                if (nMaxCombined > 0) {
                    top_combined.push(item);
                    nMaxCombined -= item['quantity'];
                    item['equipped_combined'] = item['quantity'];
                    if (nMaxCombined < 0) {
                        item['equipped_combined'] += nMaxCombined;
                    }
                }
                else {
                    Inventory[groupTag]['weak_combined'].push(item);
                }
            });
            
            (Inventory[groupTag]['top_combined'] = top_combined).sort(sortBy.combined);
            Inventory[groupTag]['weak_combined'].sort(sortBy.combined);
            
            // calculate need, gain, total, etc..
            var getList = {'get_offense':[], 'get_defense':[], 'get_combined':[]};
            
            $.each(['offense', 'defense', 'combined'], function(index, tagName) {
                var sTag = 'get_' + tagName;
                
                $.each(Inventory[groupTag][sTag], function(index, Item) {
                    
                    var top = Inventory[groupTag]['top_' + tagName];
                    var nMax = 501, nGain = 0;
                    var tag = {
                        gain     : 'gain_' + tagName,
                        needed   : 'need_' + tagName,
                        gained   : 'gained_' + tagName,
                        equipped : 'equipped_' + tagName
                    };
                    
                    for (var i = 0; i < top.length; i++) {
                        nMax -= top[i][tag.equipped];
                        
                        if (Item[tagName] > top[i][tagName]) 
                        {
                            nGain = Item[tagName] - top[i][tagName];
                            Item[tag.needed] += top[i][tag.equipped];
                            Item[tag.gained] += (nGain * top[i][tag.equipped]);
                        }
                        if (nMax < 1) {
                            break;
                        }
                    }
                    
                    Item[tag.gain] = nGain;
                    
                    if (Item[tag.needed] > 0) {
                        Item['need_total'] = Math.max(Item['need_offense'] , Item['need_defense']);
                        Item['need_total'] = Math.max(Item['need_total']   , Item['need_combined']);
                        getList[sTag].push(Item);
                    }
                });
            });
            
            (Inventory[groupTag]['get_offense']  = getList['get_offense'] ).sort(sortBy.attack);
            (Inventory[groupTag]['get_defense']  = getList['get_defense'] ).sort(sortBy.defense);
            (Inventory[groupTag]['get_combined'] = getList['get_combined']).sort(sortBy.combined);
            
            var aMergedWeak = $.merge(Inventory[groupTag]['weak_offense'], Inventory[groupTag]['weak_defense']);
            var cItemsAdded = {};
            
            $.each($.merge(aMergedWeak, Inventory[groupTag]['weak_combined']), function(index, Item) {
                if (cItemsAdded[String(Item.id)] === true) {
                    return true;
                }
                if (Item['equipped_offense'] < 1 && 
                    Item['equipped_defense'] < 1 && 
                    Item['equipped_combined'] < 1)
                {
                    Inventory[groupTag]['give_away'].push(Item);
                    cItemsAdded[String(Item.id)] = true;
                }
            });
            
            Inventory[groupTag]['give_away'].sort(sortBy.quantity);

            $.each(['offense', 'defense', 'combined'], function(index, tagName) {
                var cGlobal = Inventory.global;
                var tags = {
                    top             : 'top_' + tagName,
                    equipped        : 'equipped_' + tagName,
                    groupStrength   : groupTag + '_' + tagName,
                    totalStrength   : 'Total_' + tagName
                 };
                
                $.each(Inventory[groupTag][tags.top], function(index, Item) {
                    var nAmount = Item[tagName] * Item[tags.equipped];
                    
                    cGlobal[tags.groupStrength] += nAmount;
                    cGlobal[tags.totalStrength] += nAmount;
                });
            });
        });
        
        genMainDom();
        
        genListDom();
        
        // add wishlist
        updateWishlist();
        
        // show popup
        popupElt.show();
    }
    
    popupElt.addBase64Style(
        'I2ludkFuYWxpemVyX3BvcHVwIC5ibGFjayB7DQoJd2lkdGg6IDI0MHB4Ow0KCW1hcmdpbi1sZWZ0OiA1cHg7DQoJZm9udC13ZWln'+
        'aHQ6IGJvbGQ7IA0KCWNvbG9yOiByZ2IoMjA4LCAyMDgsIDIwOCk7IA0KCWJvcmRlcjogMXB4IHNvbGlkIHJnYigxNTMsIDE1Mywg'+
        'MTUzKTsgDQoJYmFja2dyb3VuZC1jb2xvcjogYmxhY2s7IA0KCWZvbnQtc2l6ZTogMTRweDsNCn0NCiNpbnZBbmFsaXplcl9wb3B1'+
        'cCAuZnJhbWVfYm94IHsNCglib3JkZXI6IDFweCBzb2xpZCAjMkYyRjJGOw0KCW1hcmdpbjogNXB4Ow0KCW1pbi1oZWlnaHQ6IDI2'+
        'cHg7DQoJcGFkZGluZzogNXB4Ow0KCXRleHQtYWxpZ246IGxlZnQ7DQp9DQojaW52QW5hbGl6ZXJfcG9wdXAgZGl2LmhlYWRlciB7'+
        'DQoJYm9yZGVyOiAxcHggc29saWQgIzc3NzsNCgloZWlnaHQ6IDIwcHg7DQoJb3ZlcmZsb3c6IGhpZGRlbjsNCgl0ZXh0LWFsaWdu'+
        'OiBjZW50ZXI7DQoJcGFkZGluZzogMnB4Ow0KfQ0KI2ludkFuYWxpemVyX3BvcHVwIGRpdi5oZWFkZXIgZGl2Lml0ZW1fbmFtZSB7'+
        'DQoJdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KI2ludkFuYWxpemVyX3BvcHVwIHVsLml0ZW1fbGlzdCB7DQoJYm9yZGVyOiAxcHgg'+
        'c29saWQgIzk5OTsNCgloZWlnaHQ6IDM3NXB4Ow0KCWxpc3Qtc3R5bGUtdHlwZTogbm9uZTsNCgltYXJnaW46IDBweDsNCglvdmVy'+
        'Zmxvdy14OiBoaWRkZW47DQoJb3ZlcmZsb3cteTogYXV0bzsNCglwYWRkaW5nOiAwcHg7DQp9DQojaW52QW5hbGl6ZXJfcG9wdXAg'+
        'dWwuaXRlbV9saXN0IGxpIHsNCglib3JkZXI6IDFweCBzb2xpZCAjMzMzOw0KCWN1cnNvcjogcG9pbnRlcjsNCgloZWlnaHQ6IDE5'+
        'cHg7DQoJbWFyZ2luOiAxcHg7DQoJb3ZlcmZsb3c6IGhpZGRlbjsNCglwYWRkaW5nOiAxcHg7DQp9DQojaW52QW5hbGl6ZXJfcG9w'+
        'dXAgdWwuaXRlbV9saXN0IGxpLnNlbGVjdGVkIHsNCglib3JkZXI6IDFweCBzb2xpZCAjQ0MwOw0KfQ0KI2ludkFuYWxpemVyX3Bv'+
        'cHVwIGRpdi5udW1iZXIgew0KCWZsb2F0OiBsZWZ0Ow0KCW1heC13aWR0aDogMzBweDsNCgltaW4td2lkdGg6IDMwcHg7DQoJcGFk'+
        'ZGluZzogMXB4Ow0KCXdpZHRoOiBhdXRvOw0KfQ0KI2ludkFuYWxpemVyX3BvcHVwIGRpdi5udW1iZXIucXVhbnRpdHkgew0KCW1h'+
        'eC13aWR0aDogNDBweDsNCgltaW4td2lkdGg6IDQwcHg7DQp9DQojaW52QW5hbGl6ZXJfcG9wdXAgZGl2LnF1YWxpdHkgew0KCWZs'+
        'b2F0OiBsZWZ0Ow0KCW1heC13aWR0aDogMTZweDsNCgltaW4td2lkdGg6IDE2cHg7DQoJcGFkZGluZzogMXB4Ow0KCXdpZHRoOiBh'+
        'dXRvOw0KfQ0KI2ludkFuYWxpemVyX3BvcHVwIGRpdi50b3RhbCB7DQoJZmxvYXQ6IGxlZnQ7DQoJbWF4LXdpZHRoOiA1MHB4Ow0K'+
        'CW1pbi13aWR0aDogNTBweDsNCglwYWRkaW5nOiAxcHg7DQoJd2lkdGg6IGF1dG87DQp9DQojaW52QW5hbGl6ZXJfcG9wdXAgZGl2'+
        'LnNwYWNlIHsNCgliYWNrZ3JvdW5kLWNvbG9yOiAjM0YzRjNGOw0KCWZsb2F0OiBsZWZ0Ow0KCWhlaWdodDogMTlweDsNCgltYXgt'+
        'd2lkdGg6IDFweDsNCgltaW4td2lkdGg6IDFweDsNCgl3aWR0aDogMXB4Ow0KfQ0KI2ludkFuYWxpemVyX3BvcHVwIGRpdi5pdGVt'+
        'X25hbWUgew0KCWZsb2F0OiBsZWZ0Ow0KCW1heC13aWR0aDogMjIwcHg7DQoJcGFkZGluZzogMXB4Ow0KCXRleHQtYWxpZ246IGxl'+
        'ZnQ7DQoJd2lkdGg6IDIyMHB4Ow0KCXBhZGRpbmc6IDBweCA1cHg7DQp9DQojaW52QW5hbGl6ZXJfcG9wdXAgLmZyYW1lX2JveCBk'+
        'aXYjaXRlbV9pbmZvIHsNCglmbG9hdDogbGVmdDsNCgl3aWR0aDogMzc4cHg7DQp9DQojaW52QW5hbGl6ZXJfcG9wdXAgLmZyYW1l'+
        'X2JveCBkaXYuaW1hZ2VuIHsNCglib3JkZXI6IDFweCBzb2xpZCAjNUY1RjVGOw0KCWZsb2F0OiBsZWZ0Ow0KfQ0KI2ludkFuYWxp'+
        'emVyX3BvcHVwIC5mcmFtZV9ib3ggZGl2LmluZm8gew0KCWZsb2F0OiBsZWZ0Ow0KCWhlaWdodDogODBweDsNCgltYXJnaW4tbGVm'+
        'dDogNXB4Ow0KCW1heC1oZWlnaHQ6IDgwcHg7DQoJbWF4LXdpZHRoOiAyOTBweDsNCn0NCiNpbnZBbmFsaXplcl9wb3B1cCAuZnJh'+
        'bWVfYm94IGRpdiN3aXNobGlzdCB7DQoJZmxvYXQ6IGxlZnQ7DQoJd2lkdGg6IDMwMHB4Ow0KfQkNCiNpbnZBbmFsaXplcl9wb3B1'+
        'cCAuZnJhbWVfYm94IGRpdi53bF9pdGVtIHsNCglib3JkZXI6IDFweCBzb2xpZCAjNEY0RjRGOw0KCWZsb2F0OiBsZWZ0Ow0KCWhl'+
        'aWdodDogNzJweDsNCgltYXJnaW46IDFweDsNCglwYWRkaW5nOiAzcHg7DQoJdGV4dC1hbGlnbjogbGVmdDsNCgl3aWR0aDogOTBw'+
        'eDsNCn0NCiNpbnZBbmFsaXplcl9wb3B1cCAuZnJhbWVfYm94IGRpdi53bF9pdGVtIGltZy5yZW1vdmUgew0KCWZsb2F0OiByaWdo'+
        'dDsNCgljdXJzb3I6IHBvaW50ZXI7DQp9DQojaW52QW5hbGl6ZXJfcG9wdXAgLmZyYW1lX2JveCBkaXYud2xfaXRlbSAuYXR0YWNr'+
        'X2RlZmVuc2Ugew0KCW1hcmdpbjogMHB4Ow0KfQ0KI2ludkFuYWxpemVyX3BvcHVwIC5mcmFtZV9ib3ggZGl2LndsX2l0ZW0gLmF0'+
        'dGFja19kZWZlbnNlIC5kZWZlbnNlIHsNCgltYXJnaW4tbGVmdDogNXB4Ow0KfQ0KI2ludkFuYWxpemVyX3BvcHVwIC5tYWZpYV9z'+
        'dHJlbmd0aCB7DQoJYmFja2dyb3VuZDogdHJhbnNwYXJlbnQgdXJsKGh0dHA6Ly9td2ZiLnN0YXRpYy56Z25jZG4uY29tL213ZmIv'+
        'Z3JhcGhpY3MvaW52ZW50b3J5L3N1bW1hcnkvTWFmaWEtc3RyZW5ndGgtYm94LnBuZykgbm8tcmVwZWF0Ow0KCWZsb2F0OiBsZWZ0'+
        'Ow0KCWhlaWdodDogMjAwcHg7DQoJd2lkdGg6IDE2MHB4Ow0KCWZvbnQtc2l6ZTogMTJweDsNCn0NCiNpbnZBbmFsaXplcl9wb3B1'+
        'cCAubWFmaWFfc3RyZW5ndGggPiBkaXY6bGFzdC1jaGlsZCB7DQoJbWFyZ2luLXRvcDogMjBweDsNCn0NCiNpbnZBbmFsaXplcl9w'+
        'b3B1cCAubWFmaWFfc3RyZW5ndGgucXVhbGl0aWVzID4gZGl2Omxhc3QtY2hpbGQgew0KCW1hcmdpbi10b3A6IDE1cHg7DQp9DQoj'+
        'aW52QW5hbGl6ZXJfcG9wdXAgLm1hZmlhX3N0cmVuZ3RoIC50b3RhbF90aXRsZSB7DQoJZm9udC13ZWlnaHQ6IGJvbGQ7DQoJbWFy'+
        'Z2luLWJvdHRvbTogMjFweDsNCgltYXJnaW4tbGVmdDogYXV0bzsNCgltYXJnaW4tcmlnaHQ6IGF1dG87DQoJcGFkZGluZy10b3A6'+
        'IDEwcHg7DQoJcG9zaXRpb246IHJlbGF0aXZlOw0KCXRleHQtYWxpZ246IGNlbnRlcjsNCgl3aWR0aDogMTYwcHg7DQp9DQojaW52'+
        'QW5hbGl6ZXJfcG9wdXAgLm1hZmlhX3N0cmVuZ3RoLnF1YWxpdGllcyAudG90YWxfdGl0bGUgew0KCW1hcmdpbi1ib3R0b206IDEz'+
        'cHg7DQp9DQojaW52QW5hbGl6ZXJfcG9wdXAgLm1hZmlhX3N0cmVuZ3RoIC50b3RhbF90aXRsZSBzcGFuIHsNCgljb2xvcjogI0ZG'+
        'Q0QwMDsNCgl0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlOw0KfQ0KI2ludkFuYWxpemVyX3BvcHVwIC5tYWZpYV9zdHJlbmd0aCAu'+
        'bWFmaWFfc3RyZW5ndGhfc3BhY2luZyB7DQoJaGVpZ2h0OiAxOHB4Ow0KCW1hcmdpbi1sZWZ0OiAycHg7DQoJbWFyZ2luLXRvcDog'+
        'N3B4Ow0KfQ0KI2ludkFuYWxpemVyX3BvcHVwIC5tYWZpYV9zdHJlbmd0aC5xdWFsaXRpZXMgLm1hZmlhX3N0cmVuZ3RoX3NwYWNp'+
        'bmcgew0KCW1hcmdpbi10b3A6IDRweDsNCn0JDQojaW52QW5hbGl6ZXJfcG9wdXAgLnRleHRfcG9zaXRpb25pbmcgew0KCWNvbG9y'+
        'OiAjOTk5Ow0KCWZvbnQtc2l6ZTogMTFweDsNCn0NCiNpbnZBbmFsaXplcl9wb3B1cCAubWFmaWFfc3RyZW5ndGggLm1hZmlhX3N0'+
        'cmVuZ3RoX3NwYWNpbmcgLnN0YXRfbmFtZSB7DQoJZmxvYXQ6IGxlZnQ7DQoJbWFyZ2luLWxlZnQ6IDEwcHg7DQoJd2lkdGg6IDgw'+
        'cHg7DQp9'
    );
    
    ajaxRequest({
        url: 'remote/' + getIntURL('inventory'),
        message: 'Loading inventory data...',
        success: Initialize
    });
}

/**
 * Get feed stories and autohelp all 
 */
function homeFeedCenter() 
{
    const ERROR_BAD_RESPONSE = 'Bad server response, try it yourself.';
    
    var cancel_process = false;
    var feedStream = [];
    var inputSearchCalltimer;
    
    var options = new Config('feedstream', {
        maxLogLength               : 50,
        lastPostTime               : 0,
        autoClose                  : false,
        doGotoWar                  : true,
        doGiveSocialHelp           : true,
        doSocialMissions           : true,
        doClaimBonusAndReward      : true,
        doCollectLoot              : true,
        doPropertyHelp             : true,
        doGetBoost                 : true,
        doSendEnergyAndPhones      : true,
        doAcceptGiftEvent          : true,
        doHitlistBounty            : true, 
        helpDelay                  : 3,
        refreshDelay               : 15,
        joinMission                : 0,
        joinMissionAfter           : 0,
        diff_easy                  : false,
        diff_medium                : false,
        diff_hard                  : true,
        diff_event                 : false,
        maxFreeSlots               : 100,
        warFilter                  : false,
        warFilterText              : 'Attack: [5-9][2-9]\nDefense: [5-9][2-9]',
        socialHelpFilter           : false,
        socialHelpFilterText       : '',
        propertyHelpFilter         : false,
        propertyHelpFilterText     : '',
        collectLootFilter          : false,
        collectLootFilterText      : 'Railguns\nRange Finder Rifles\nMugati Sports'
    });
    // popup
    var popupElt = new domPopupObject('homefeedcenter_popup', {
        css: {
            'background': '#121212',
            'border': '4px solid white',
            '-webkit-border-radius': '8px 8px',
            '-moz-border-radius': '8px 8px',
            'border-radius': '8px 8px',
            'left': 10,
            'text-align': 'left',
            'top': 20,
            'width': 730,
            'z-index': '10001'
        },
        onclose: function() {
            cancel_process = true;
            options.fromDomElements();
            options.save();
            delete feedStream;
        }
    });
    
    var _Util = {
        toIntUrl: function(url) 
        {
            if (typeof(url) !== 'string' || url.indexOf('?') == -1) {
                return '';
            }
            var params = splitUrl(url), a, b;
            var sOutUrl = 'remote/' + getIntURL(params.next_controller, params.next_action);
            var unQuote = function(str) {
                var rgx;
                return (rgx = /"([^"]+)"/.exec(str)) ? rgx[1] : str;
            };
            for (var uri in params) {
                if (String(uri).indexOf('next_') == -1) {
                     sOutUrl += (typeof(params[uri]) == 'string' ?  '&'+uri+'='+params[uri] : '');
                }
            }
            if ((a = String(params.next_params).split(',')).length > 0) {
                for (var i = 0; i < a.length; i++) {
                    if ((b = String(a[i]).split(':')).length == 2) {
                        sOutUrl += ('&' + unQuote(b[0]) + '=' + unQuote(b[1]));
                    }
                }
            }

            return sOutUrl;
        },
        clean: function(data) 
        {
            if (typeof(data) !== 'string') {
                return data;
            }
            var obj = $('<div>'+ data.replace(/<div[^>]*>/g, '<div>') +'</div>');
            $('img, .sexy_button_new, br, div:empty', obj).remove();
            return obj.html();
        },
        getLength: function(obj) 
        {
            var len = 0;
            for (var i in obj) {
                len++;
            }
            return len;
        },
        getFixedLength: function(obj) 
        {
            var len = 0;
            for (var i in obj) {
                if (obj[i] !== undefined) len++;
            }
            return len;
        },
        getActionName: function(url) {
            if (typeof(url) == 'string' && /next_controller/.test(url)) {
                var u = splitUrl(url);
                return u.next_controller + '_' + u.next_action;
            }
            else {
                return '';
            }
        },
        urlFromStream: function(stream) {
            if (!(stream && stream.attachment)) {
                return '';
            }
            var att = stream.attachment;
            
            if (att.href) {
                return att.href;  
            }
            if (att.media[0] && att.media[0].href) {
                return att.media[0].href; 
            }
            return '';
        },
        /**
         * @param {jQuery} obj
         */
        getUrl: function(obj) {
            if (!obj.length || !obj.attr) 
                return '';
                
            var url = obj.attr('href');
            
            if (typeof(url) == 'string' && url.match('http')) {
                return url;
            }
            return doRegex(/['"](remote[^'"]*)/, obj.attr('onclick')).$1;
        },
        isChecked: function(selector, context) {
            if (typeof(selector) == 'undefined') {
                return true;
            }
            return $(selector, context).attr('checked');
        },
        filterText: function(optionName, filterName, text) {
            if (!options.get(optionName) || !options.get(filterName)) {
                return false;
            }
            
            var RegText = String(options.get(filterName)).replace(/\n+/g,'|');
            
            if ((new RegExp(RegText, 'i')).test(text)) {
                return false;
            }
            
            log$('filtered: ('+RegText+')\nIn: '+text);
            return 'This help has been filtered.';
        }
    };
    var groups = [
        'None',
        'Go to War',
        'Give Social Help',
        'Social Missions',
        'Claim Bonus And Reward',
        'Collect Loot',
        'Property Help',
        'Get Boost',
        'Send Energy And Phones',
        'Accept Gift Event',
        'Hitlist Bounty'
    ];
    
    var groupsFilters = {
        'doGiveSocialHelp': function(text) {
            return _Util.filterText('socialHelpFilter', 'socialHelpFilterText', text);
        },
        'doCollectLoot': function(text) {
            return _Util.filterText('collectLootFilter', 'collectLootFilterText', text);
        },
        'doPropertyHelp' : function(text) {
            return _Util.filterText('propertyHelpFilter', 'propertyHelpFilterText', text);
        }
    };
    
    // ACTIONS
    var _Actions = {
        hitlist_feed_hit               : {
            name       : 'Hitlist Bounty', 
            group      : 10,
            repeat     : '.message_body a:regex(href,xw_action=attack)',
            bad        : '.message_body:has(span.bad)'
        },
        war_view                       : {
            name       : 'Go to war', 
            group      : 1,
            repeat     : 'a:regex(href,xw_action=attack)',
            success    : /(You won the fight[^<]*|This war is already[^<]*|You have already[^<]*)/i,
            filter     : function(htmlText) {
                try {
                 if (options.get('warFilter')) {
                     var text = h$(htmlText).find('.helpers_rewards ul img').attr('title');
                     return _Util.filterText('warFilter', 'warFilterText', text);
                 }
                }
                catch(err) {
                    logErr$(err);
                }
                return false;
            }
        },
        war_share_reward_feed_click    : {
            name       : 'Claim war reward', 
            group      : 1,
            success    : /(<div\s*style=\\"color:\s*white;\s*font-size:\s*13px\\">[^<]+<\/div>|This\s*reward\s*is\s*invalid)/i
        },
        freegifts_acceptGiftEvent       : { 
            name       : 'Accept Gift Event',
            group      : 9,
            success    : /padding:\s*10px\s*20px;\s*margin:\s*5px\s*0px[^>]*>([^<]+)</i,
            skipif     : /You have already claimed the maximum/i
        },      
        index_ach_celeb                : {
            name       : 'Get archivement reward', 
            group      : 2,
            next       : '.message_body .sexy_button_new:regex(href,xw_action=ach_celeb)'
        },
        story_claim_boss_bonus         : {
            name       : 'Claim a boss bonus', 
            group      : 4,
            next       : '.message_body a:regex(href,xw_action=claim_boss_bonus)'
        },
        propertyV2_getBoost            : {
            name       : 'Get a property boost', 
            group      : 5,
            next       : '.message_body .sexy_button_new:regex(href,xw_action=getBoost)'
        },
        socialmission_joinMission      : {
            name       : 'Join in a mission', 
            group      : 3,
            enable     : '#feedstream_dosocialmissions',
            next       : doOperation
        },
        job_collect_loot                : {
            name       : 'Collect a loot', 
            group      : 5,
            skipif     : /have\s*to\s*wait/i 
        },
        propertyV2_itemFeedHelp         : {
            name       : 'Property item Help', 
            group      : 6,
            skipif     : /You\s*have\s*already\s*helped/i 
        },
        index_iced_boost_claim          : { 
            name       : 'Get iced boost', 
            group      : 7,
            skipif     : /You\s*can\s*only\s*receive/i 
        },
        // Generic helps
        job_give_help                   : { name: 'Give job help',               group: 2 },
        story_give_help_social          : { name: 'Give social help',            group: 2 },
        story_give_help_moscow_social   : { name: 'Give moscow help',            group: 2 },
        socialmission_rewardBrag        : { name: 'Claim social mission reward', group: 4 },
        map_mapboss_reward_claim        : { name: 'Claim boss reward',           group: 4 },
        quest_questFeedReward           : { name: 'Claim quest reward',          group: 4 },
        propertyV2_getCustomer          : { name: 'Get a customer',              group: 6 },
        propertyV2_cs_help_item         : { name: 'Property help',               group: 6 },
        propertyV2_cs_help_initial      : { name: 'Property initial help',       group: 6 },
        propertyV2_cs_help_final        : { name: 'Property final help',         group: 6 },
        index_levelup_boost_claim       : { name: 'Get levelup boost',           group: 7 },
        index_send_energy_mbox          : { name: 'Send energy',                 group: 8 },
        robbing_call_for_help_get_phone : { name: 'Get robbing phone',           group: 8 }
    };

    // EVENTS
    var _Event = {
        helpFeed_click: function() {
            if ($(this).attr('disabled') == true) {
                return false;
            }
            $(this).attr('disabled', true);
            
            var id      = $(this).attr('feed');
            var eParent = $(this).parent();
            var eText   = $('.body > p', '#feed_stream_' + id);
            var sHref   = _Util.urlFromStream(feedStream[id]);
            var action  = _Actions[_Util.getActionName(sHref)];
            
            var addClearButton = function() 
            {
                if (_Util.isChecked('#feedstream_autoclose')) {
                    setTimeout(function() {
                        _Event.deleteFeed_click.apply($('a.ignore', eParent).get(0));
                    }, 2000);
                }
                else {
                    b$('Clear', 'id:clearbtn,class:medium white,feed:'+id)
                      .appendTo(eParent).click(_Event.deleteFeed_click);
                }
            };
            
            log$(_Util.getActionName(sHref));
            eParent.children().fadeOut(200);
            
            if (action && _Util.isChecked(action.enable)) {
                eText.html('<img style="vertical-align: middle;" src="'+
                global.resource.ajax_loader+'">'+'<span style="margin-left: 5px;">Loading...</span>');
                
                doHelp(_Util.toIntUrl(sHref), action, function(data) {
                    eText.hide().html(_Util.clean(data)).fadeIn(500, addClearButton);
                });
            }
            else {
                eText.hide().html('I can\'t do it.<br>But you can still help by '+
                '<a href="'+sHref+'" target="_black">open it in a new tab.</a>')
                .fadeIn(500, addClearButton);
            }
            return false
        },
        deleteFeed_click: function() {
            var id = $(this).attr('feed');
            
            $('#feed_stream_'+id).fadeOut(500, function(){
                $('#feed_stream_'+id).remove();
            });
            feedStream[parseInt(id)] = undefined;
            $('#total_feeds', '#feed_center_header').html(_Util.getFixedLength(feedStream));
            return false
        },
        skip_click: function() {
            showDiv('control', 'panel', 500, function(){
                $('#status_panel').empty();
            });
        },
        refresh_click: function() {
            showDiv('ajaxloader', 'body');
            
            $('#status_panel').empty()
            .append(c$('div').css('padding-top',12).text('Loading... wait a moment please.'));
            
            showDiv('status', 'panel', 500);
            
            facebook.getNewsFeed(function(fs) {
                // catch error
                if (_Util.getLength(fs) == 0) {
                    showDiv('feedlist', 'body');
                    
                    $('#status_panel').empty().append(
                        c$('div').css({'text-align':'center', 'padding-top':12})
                        .append(c$('span').text('There is some error in facebook response.'))
                        .append(b$('Retry','class:short white').css('margin-left',5).click(_Event.refresh_click))
                        .append(b$('Cancel','class:short white').css('margin-left',5).click(_Event.skip_click))
                    );
                    return;
                }
                
                feedStream = fs;
                genFeedsDom();
                
                showDiv('feedlist', 'body');
                showDiv('control', 'panel', 500);
            });
        },
        config_click: function() {
            $('#control_panel').fadeOut(500, function() {
                $('#messages_buttons').animate({height: 230}, 'normal', function() {
                    $('#config_panel').fadeIn(500);
                });
            });
        },
        save_click: function() {
            options.fromDomElements();
            options.save();
            $('#config_panel').fadeOut(500, function() {
                $('#messages_buttons').animate({height:55}, 'normal', function() {
                    $('#control_panel').fadeIn(500);
                });
            });
        },
        keyup: function() {
            var val = this.value.toLowerCase();
            
            // perform search only when user stop writing.
            if (inputSearchCalltimer) 
                clearTimeout(inputSearchCalltimer);
            
            inputSearchCalltimer = setTimeout(function() {
                $('li[id^=feed_stream_]').each(function(index, element) {
                    if ($('.body', element).text().toLowerCase().match(val)) {
                        $(this).show();
                    } else {
                        $(this).hide();
                    }
                });
            }, 500);
        },
        change: function() {
            if (this.selectedIndex == 0) {
                $('li[id^=feed_stream_]', '#feedlist_body').show();
                return;
            }
            $('li[id^=feed_stream_]', '#feedlist_body').hide();
            for (var a in _Actions) {
                if (_Actions[a].group && _Actions[a].group == this.selectedIndex)
                    $('li[name='+a+']', '#feedlist_body').show();
            }
        },
        clearall: function() {
            $('li[id^=feed_stream_]', '#feedlist_body').each(function(index, element){
                $('#clearbtn', element).click();
            });
        },
        config_change: function() {
            var selection = c$(this).attr('name');
            $('.select_tab .selected', popupElt.content).toggleClass('selected', false);
            $(this).parent().toggleClass('selected', true);
            showDiv(selection, 'config');
        }
    };
    
    function doHelp(url, action, callback) 
    {
        ajaxRequest({
            url: url,
            success: function(htmlText) 
            {
                if (!mw_updater(htmlText)) {
                    callback(ERROR_BAD_RESPONSE);
                    return;
                }
                var getElem;
                
                if (typeof(action.next) == 'function') {
                    action.next(htmlText, callback);
                    return;
                }
                if (action.filter && (getElem = action.filter(htmlText)) !== false) {
                    callback(getElem);
                    return;
                }
                if (action.bad && (getElem = e$(action.action.bad, htmlText))) {
                    callback(getElem.html()); 
                    return;
                }
                if (action.repeat && (getElem = e$(action.repeat, htmlText))) {
                    doHelp(_Util.getUrl(getElem), action, callback);
                    return;
                }
                if (action.success && action.success.exec && (getElem = action.success.exec(htmlText))) {
                    callback(getElem[1]);
                    return;
                }
                if (action.next && (getElem = e$(action.next, htmlText))) {
                    doHelp(_Util.getUrl(getElem), {}, callback);
                    return;
                }
                if (getElem = e$('.message_body:first, #mbox_generic_1 tr:eq(1)', htmlText)) {
                    callback(getElem.html());  
                }
                else {
                    callback(ERROR_BAD_RESPONSE);
                }
            }
        });
    }
    
    function doOperation(htmlText, callback) 
    {
        var qHtml = h$(htmlText);
        
        if (e$('.socialMissionSelector', qHtml) == null) {
            callback('You can\'t join. Try helping out other mafia members.');
            return;
        }
        try {
         var nFree   = options.get('maxFreeSlots');
         var sName   = $('.missionSelectHeaderTitle', qHtml).text();
         var sDiff   = $('.missionDifficulty > span', qHtml).attr('class');
         var nSpend1 = parseInt($('#feedstream_joinmission').val());
         var nSpend2 = parseInt($('#feedstream_joinmissionafter').val());
         var sQuery  = 'a:regex(onclick,action=selectPosition)';
         var nSlots  = $(sQuery, qHtml).length;
         var cSlots  = new Array();
         
         if (nSlots > nFree) {
             callback('Mission '+ sName + ' skipped: too many slots free ('+nSlots+').');
             return;
         }
         
         if (!options.get('diff_' + sDiff.toLowerCase())) {
             callback('Mission '+ sName + ' skipped: difficulty don\'t match.');
             return;
         }
         
         $('.missionSelectorBox:has('+sQuery+')', qHtml).each(function(index,elem) {
             var nSpendType = 4;
             var hasEnergy  = (e$('dd.energy', elem) !== null);
             var hasStamina = (e$('dd.stamina', elem) !== null);
             
             if (hasEnergy && !hasStamina) {
                 nSpendType = 1;
             }
             else if (!hasEnergy && hasStamina) {
                 nSpendType = 2;
             }
             else if (hasEnergy && hasStamina) {
                 nSpendType = 3;
             }
             
             if (typeof(cSlots[nSpendType]) == 'undefined') {
                 log$('Adding SpendType: '+ nSpendType);
                 cSlots[nSpendType] = $(sQuery, elem);
             }
         });
         
         var button = (cSlots[nSpend1] || cSlots[nSpend2]);
         
         if (typeof(button) == 'undefined' || button.length < 1) {
             callback('Mission '+ sName + ' skipped: spend type don\'t match.');
             return;
         }
        }
        catch(err) {
            logErr$(err);
            callback(ERROR_BAD_RESPONSE);
            return;
        }

        ajaxRequest({
            url: _Util.getUrl(button),
            success: function(htmlText) 
            {
                if (mw_updater(htmlText)) 
                    callback('You has join in ' + sName + ' mission.');
                else 
                    callback(ERROR_BAD_RESPONSE);
            }
        });
    }
    
    function showDiv(name, type, ms, fn) {
        $('div[id*=_'+type+']', popupElt.content).hide();
        $('#' + name + '_' + type, popupElt.content).show(ms, fn);
    }
    
    function autoMode() {

        var groupName = function(action) {
            return 'do'+ groups[action.group].replace(/\s*/g, '');
        };
        var messageTimer = new timerMessage('#auto_feed_helper_messages');
        var skippedActions = [];
        var completed = 0;
        var skipped = 0;
        var helpAmount = 0;
        var cancel_click = function() {
            messageTimer.clear();
            cancel_process = true;
            _Event.refresh_click();
            $('#status_panel').unbind();
            delete messageTimer;
            return false;
        };
        
        function closeAndNext(message, delay) {
            $('#completed_helps').text(completed);
            $('#skipped_helps').text(skipped);
            feedStream.splice(feedStream.length-1,1);
            $('#total_feeds', '#feed_center_header').html(--helpAmount);
            
            if (helpAmount < 1 || feedStream.length < 1) {
                messageTimer.start('All helps finished!. Refresh and continue in %N% seconds.',
                             options.get('refreshDelay')*60, refreshList);
                return;
            }           
            if (isNaN(delay) || delay < 1) {
                doNewHelp();
            } else {
                messageTimer.start(''+message, delay, doNewHelp);
            }
        } 
        // begin automatic mode
        function doNewHelp() {
            if (cancel_process) {
                return;
            }
            try {
                
            var stream  = feedStream[feedStream.length-1];
            
            if (typeof(stream) == 'undefined') {
                closeAndNext();
                return;
            }
            
            var sFilterTxt = null;
            var href       = _Util.urlFromStream(stream);
            var action     = _Actions[_Util.getActionName(href)];
            
            
            if (stream.created_time && stream.created_time > options.get('lastPostTime')) {
                options.set('lastPostTime',stream.created_time);
                options.save();
            }
            if (typeof(action) == 'undefined') {
                closeAndNext();
                return;
            }
            
            var sGroupName =  groupName(action);
            
            if (typeof(groupsFilters[sGroupName]) == 'function') {
                if ((sFilterTxt = groupsFilters[sGroupName](stream.attachment.name)) !== false) {
                    genHelpLogDom(action.name, stream, sFilterTxt);
                    skipped++;
                    closeAndNext();
                    return;
                }
            }
            if (skippedActions[sGroupName]) {
                skipped++;
            } 
            else if (options.get(sGroupName)) 
            {
                $('#auto_feed_helper_messages').html(
                    '<img style="vertical-align: middle;" src="'+global.resource.ajax_loader+'">'+
                    '<span style="margin-left: 5px;">Helping in:  "' + action.name + '"...</span>'
                );
                doHelp(
                    _Util.toIntUrl(href), action, 
                    function(data) {

                        genHelpLogDom(action.name, stream, _Util.clean(data));
                        
                        if (action.skipif && action.skipif.test(data)) {
                            skippedActions[sGroupName] = true;
                            skipped++;
                            closeAndNext(
                                'Done! but you can\'t accept more, Next help in %N%...',
                                options.get('helpDelay')
                            );
                        }
                        else {
                            completed++;
                            closeAndNext('Done!, Next help in %N%...',options.get('helpDelay'));
                        }
                    }
                );
                return;
            }
            
            closeAndNext();

            } 
            catch (err) {
                logErr$(err);
                closeAndNext();
            }
        }
        
        function refreshList() {
            if (cancel_process) {
                return;
            }
            $('#auto_feed_helper_messages').html(
                '<img style="vertical-align: middle;" src="'+global.resource.ajax_loader+'">'+
                '<span style="margin-left: 5px;">Refreshing home posts...</span>'
            );
            
            facebook.getNewsFeed(function(fs) {
                // catch error
                if (_Util.getLength(fs) == 0) {
                    messageTimer.start('There is an error, try to refresh again in %N%...',
                                       60, refreshList);
                    return;
                }
                feedStream = [];
                for (var i = 0; i < fs.length; i++) {
                    if (fs[i].created_time && fs[i].created_time > options.get('lastPostTime')) {
                        feedStream.push(fs[i]);
                    }
                }
                if (feedStream.length < 1) {
                    messageTimer.start('No new posts, refresh again in %N%...', 60, refreshList);
                    return;
                }
                helpAmount = _Util.getFixedLength(feedStream);
                $('#total_feeds', '#feed_center_header').html(helpAmount);
                doNewHelp();
            });
        }
        
        function genHelpLogDom(title, obj, html) {
            var list = $('#logList');
            
            if ($('#logList').children().length > options.get('maxLogLength')) {
                $('#logList').children().last().remove();
            }
            var atch  = obj.attachment;
            var url   = atch.media[0] ? atch.media[0].src : '#';
            var name  = '<a href="'+obj.permalink+'" target="_black">'+title+'</a>';
                
            c$('li').prependTo('#logList').append(
                c$('div').addClass('li_wrapper clearfix')
                .append(c$('img','class:feed_icon').attr('src',url))
                .append(
                    c$('div','class:body')
                    .append(c$('h4').html(name))
                    .append(c$('p').html(html))
                )
            );
        }
        
        $('#status_panel').empty();
        
        c$('div').appendTo('#status_panel').css({
            'padding':'15px 0 0 15px',
            'float': 'left'
        })
        .append(c$('span').css('color','green').text('Completed: '))
        .append(c$('span','completed_helps').text(0))
        .append(c$('span').css({'color':'green','margin-left':5}).text('Skipped: '))
        .append(c$('span','skipped_helps').text(0))     
        
        c$('div','auto_feed_helper_messages').appendTo('#status_panel')
        .html('Preparing to help...').css({
            'padding':'15px 0 0 30px',
            'float': 'left'
        });
    
        b$('CANCEL').addClass('medium red').click(cancel_click)
        .appendTo('#status_panel').css({
            'float': 'right',
            'margin-right': 40,
            'margin-top': 12
        });
        
        showDiv('automode', 'body');
        showDiv('status', 'panel', 500);
        
        options.fromDomElements();
        options.save();
        
        helpAmount = _Util.getFixedLength(feedStream);
        
        cancel_process = false;
        doNewHelp();
    }
    
    function genMainDom() {
        
        var selectOpts = {
            'feedstream_joinmission': 
                {4:'Any', 1:'Energy', 2:'Stamita', 3:'Both'},
            'feedstream_joinmissionafter': 
                {0:'None', 1:'Energy', 2:'Stamita', 3:'Both'},
            'feedstream_maxfreeslots': 
                {100:'Any slots', 1:'1 slot free', 2:'2 slots free', 3:'3 slots free', 4:'4 slots free'},
            'feedstream_helpdelay': 
                {1:'1', 2:'2', 3:'3', 5:'5'},
            'feedstream_refreshdelay': 
                {1:'1', 3:'3', 5:'5', 15:'15', 30:'30', 60:'60'}
        };
        // fix content height
        popupElt.content.height('680');
        // header of popup
        popupElt.header.append(
            c$('div', 'feed_center_header').append('<h2>').append( 
                c$('dl').addClass('total_requests')
                .append('<dt id="total_feeds">'+feedStream.length+'</dt>')
                .append('<dd>Total Posts</dd>')
            )
            .append(c$('div').append(c$('p').text('HOME FEED CENTER')))
        );
        
        var controlDiv, configDiv;
        
        // middle, config, buttons 
        c$('div', 'messages_buttons').appendTo(popupElt.content)
        .append(c$('div', 'status_panel').height(50))
        .append(controlDiv = c$('div', 'control_panel').height(50))
        .append(configDiv  = c$('div', 'config_panel'));
        
        // add configurations
        c$('div').appendTo(controlDiv).css({
            'float': 'left',
            'margin': '12px 5px 0px;',
            'width': 250,
            'text-align': 'right'
        })
        .append(c$('label', 'for:feedstream_filter').text('Search posts: '))
        .append(c$('input:text', 'id:feedstream_filter, class:black_box').width(149).keyup(_Event.keyup))
        .append('<br />')
        .append(c$('label', 'for:feedstream_grouping').text('By groups: '))
        .append(c$('select', 'id:feedstream_grouping, class:black_box').width(152).change(_Event.change));
        
        c$('div').appendTo(controlDiv).css({
            'float': 'left',
            'margin-left': '8px',
            'padding-top': 12,
            'width': 170,
            'text-align': 'left'
        })
        .append(c$('input:checkbox', 'feedstream_autoclose'))
        .append(c$('label', 'for:feedstream_autoclose').text('Autoclose'))
        .append(b$('Clear all', 'class:short white').css('float','right').click(_Event.clearall));
        
        c$('div').appendTo(controlDiv).css({
            'float': 'right',
            'margin': '12px',
            'width': 260,
            'text-align': 'center'
        })      
        .append(b$('Refresh','class:short orange').click(_Event.refresh_click))
        .append(b$('Config','class:short orange').css('margin-left',5).click(_Event.config_click))
        .append(b$('Auto-Mode','class:short orange').css('margin-left',10).click(autoMode));
        
        
        // ADD CONFIGURATION
        
        // add options checkboxes and group list
        var eConfigSelector = c$('div', 'class:select_tab').appendTo(configDiv);
        var eGroup = $('#feedstream_grouping');
        
        $.each(groups, function(index, name) {
            var tag = name.replace(/\s*/g, '').toLowerCase();
            eGroup.append(c$('option', 'value:'+index).text(name));
            var elem = c$('div').appendTo(eConfigSelector);
            if (name=='None') {
                elem.append(c$('p', 'name:'+tag).text('General').click(_Event.config_change));
            }
            else {
                elem.append(c$('input:checkbox', 'id:feedstream_do'+tag))
                .append(c$('p', 'name:'+tag).text(name).click(_Event.config_change));
            }

        });
        
        // add configuration
        c$('div', 'class:config_tab,id:none_config')
        .append(genGeneralConfig()).appendTo(configDiv);
        
        c$('div', 'class:config_tab,id:gotowar_config').appendTo(configDiv)
        .append(genConfigFilter('warfilter'));
        
        c$('div', 'class:config_tab,id:givesocialhelp_config').appendTo(configDiv)
        .append(genConfigFilter('socialhelpfilter'));
        
        c$('div', 'class:config_tab,id:socialmissions_config')
        .append(genMissionConfig()).appendTo(configDiv);
        
        c$('div', 'class:config_tab,id:claimbonusandreward_config')
        .append(genEmptyComfig()).appendTo(configDiv);
        
        c$('div', 'class:config_tab,id:collectloot_config').appendTo(configDiv)
        .append(genConfigFilter('collectlootfilter'));
        
        c$('div', 'class:config_tab,id:propertyhelp_config').appendTo(configDiv)
        .append(genConfigFilter('propertyhelpfilter'));
        
        c$('div', 'class:config_tab,id:getboost_config')
        .append(genEmptyComfig()).appendTo(configDiv);
        
        c$('div', 'class:config_tab,id:sendenergyandphones_config')
        .append(genEmptyComfig()).appendTo(configDiv);
        
        c$('div', 'class:config_tab,id:acceptgiftevent_config')
        .append(genEmptyComfig()).appendTo(configDiv);
        
        c$('div', 'class:save_config').appendTo(configDiv)
        .append(b$('Save Configuration','class:short orange').click(_Event.save_click));
        
        
        // ADD BODY ELEMENTS
        c$('div', 'feedlist_body').height(600).appendTo(popupElt.content);
        
        c$('div', 'ajaxloader_body').css('padding-top',25).height(575)
        .append(c$('img').attr('src', global.zGraphicsURL+'socialmissions/ajax-loader.gif'))
        .appendTo(popupElt.content);
        
        c$('div', 'automode_body').height(600)
        .append(c$('ul', 'id:logList,class:feed_box').height(600))
        .appendTo(popupElt.content);
        
        // apply options to select elements
        applySelectOptions(selectOpts, popupElt.content);
        
        function genEmptyComfig() {
            var elem = c$('center').css('margin-top', 10)
            .html('This category don\'t have any configuration.');
        }
        
        function genGeneralConfig() {
            var elem = c$('div')
            .append(c$('label', 'for:feedstream_helpdelay').text('Help delay (sec.): '))
            .append(c$('select', 'id:feedstream_helpdelay, class:black_box').width(100))
            .append(c$('div','class:clearfix'))
            .append(c$('label', 'for:feedstream_refreshdelay').text('Refresh delay (min.): '))
            .append(c$('select', 'id:feedstream_refreshdelay, class:black_box').width(100));
            
            return elem;
        }
        function genConfigFilter(id, value) {
            return c$('div')
            .append(c$('input:checkbox', 'id:feedstream_'+id))
            .append(c$('label','for:'+id).text('Active filter (add filters delimited by lines):'))
            .append(c$('br'))
            .append(c$('textarea', 'class:black_box,cols:45,rows:8,id:feedstream_'+id+'text'));
        }
        function genMissionConfig() {
            var elem = c$('div');
            c$('div').css('margin',5)
         .append(c$('span').text('Mission difficulty: '))
         .append(c$('input:checkbox', 'id:feedstream_diff_easy'))
         .append(c$('label', 'for:feedstream_diff_easy').text('Easy'))
         .append(c$('input:checkbox', 'id:feedstream_diff_medium'))
         .append(c$('label', 'for:feedstream_diff_medium').text('Medium'))
         .append(c$('input:checkbox', 'id:feedstream_diff_hard'))
         .append(c$('label', 'for:feedstream_diff_hard').text('Hard'))
         .append(c$('input:checkbox', 'id:feedstream_diff_event'))
         .append(c$('label', 'for:feedstream_diff_event').text('Event'))
            .appendTo(elem);
            
            c$('div').css('margin',5)
         .append(c$('label', 'for:feedstream_joinmission').text('Join only in: '))
         .append(c$('select', 'id:feedstream_joinmission, class:black_box').width(80))
         .append(c$('label', 'for:feedstream_joinmissionafter').text(' if not possible then: '))
         .append(c$('select', 'id:feedstream_joinmissionafter, class:black_box').width(80))
         .appendTo(elem);
            
            c$('div').css('margin',5)
         .append(c$('label', 'for:feedstream_maxfreeslots').text('And only if remain: '))
         .append(c$('select', 'id:feedstream_maxfreeslots, class:black_box').width(110))
         .appendTo(elem);
            
            return elem;
        }
    }
    
    function genFeedsDom() {
        var i, liElt, ulElt = c$('ul', 'class:feed_box').height(600);
        // ADD FEEDS
        function addFeed(stream, is_new) 
        {
            var actId = _Util.getActionName(_Util.urlFromStream(stream));
            if (actId == 'index_view')
                return;
                
            var atch = stream.attachment;
            var attr  = (is_new?'class:new_post, ':'')+'name:'+actId+', ';
            var url   = atch.media[0] ? atch.media[0].src : '#';
            var name  = '<a href="'+stream.permalink+'" target="_black">';
            var desp  = atch.name ? atch.description : '';
            
            name += (atch.name || atch.description) + '</a>';
                
            c$('li', attr+'id:feed_stream_'+ i).appendTo(ulElt).append(
                c$('div').addClass('li_wrapper clearfix')
                .append(c$('img', 'class:feed_icon').attr('src',url))
                .append(
                    c$('div','class:buttons')
                    .append(b$('Help', 'class:medium white,feed:'+i).click(_Event.helpFeed_click))
                    .append(c$('a', 'href:#,class:ignore,feed:'+i).text('ignore').click(_Event.deleteFeed_click))
                )
                .append(
                    c$('div','class:body').append('<h4>'+name+'</h4><p>'+desp+'</p>')
                )
            );
            
        }
        for (var i = 0; i < feedStream.length; i++) {
            addFeed(feedStream[i], feedStream[i].created_time > options.get('lastPostTime'));
        }
        options.set('lastPostTime', feedStream[0].created_time);
        options.save();
        $('#feedlist_body').empty().append(ulElt);
        $('#total_feeds', '#feed_center_header').html(_Util.getFixedLength(feedStream));
        
        if ($('#feedstream_grouping').val() !== groups[0]) {
            $('#feedstream_grouping').change();
        }
    }
    
    function Initialize(success) {
        if (success !== true) {
            showHelpPopup({
                icon: 'info',
                title: 'facebook permissions',
                message: 'Home Feed Center need to give some facebook '+
                    'permission to Mafia Wars in order to work.'
            });
            return;
        }
        
        var overlay = loadingOverlay('Loading home posts...');
        
        facebook.getNewsFeed(function(fs) {
            overlay.hide();
            // catch error
            if (_Util.getLength(fs) == 0) {
                showHelpPopup({
                    icon: 'error',
                    title: 'Error loading home posts',
                    message: 'There was an error while loading your home posts<br>' +
                        'Maybe it\'s a temporal facebook problem.<br>Try again later.'
                });
                return;
            }
            
            feedStream = fs;
            
            options.load(function() {
                genMainDom();
                options.toDomElements();
                genFeedsDom();
                
                showDiv('feedlist', 'body');
                showDiv('control', 'panel');
                showDiv('none', 'config');
                
                // show popup
                popupElt.show();
            });
        });
    }

    popupElt.addBase64Style(
        'I2hvbWVmZWVkY2VudGVyX3BvcHVwIC5ibGFja19ib3ggew0KCWZvbnQtd2VpZ2h0OiBib2xkOyANCgljb2xvcjogcmdiKDIwOCwg'+
        'MjA4LCAyMDgpOyANCglib3JkZXI6IDFweCBzb2xpZCByZ2IoMTUzLCAxNTMsIDE1Myk7IA0KCWJhY2tncm91bmQtY29sb3I6IGJs'+
        'YWNrOyANCglmb250LXNpemU6IDE0cHg7DQp9DQojaG9tZWZlZWRjZW50ZXJfcG9wdXAgdWwuZmVlZF9ib3ggew0KCWhlaWdodDog'+
        'NDAwcHg7DQoJbGlzdC1zdHlsZS10eXBlOiBub25lOw0KCW92ZXJmbG93OiBhdXRvOw0KfQ0KI2hvbWVmZWVkY2VudGVyX3BvcHVw'+
        'ICNmZWVkbGlzdF9ib2R5IHVsLmZlZWRfYm94IGxpOmZpcnN0LWNoaWxkIHsNCglib3JkZXItd2lkdGg6IDBweDsNCn0NCiNob21l'+
        'ZmVlZGNlbnRlcl9wb3B1cCAjZmVlZGxpc3RfYm9keSB1bC5mZWVkX2JveCBsaSB7DQoJYm9yZGVyLXRvcDogMnB4IHNvbGlkICMx'+
        'RjFGMUY7DQoJbWFyZ2luOiAwcHggMHB4IDZweDsNCgloZWlnaHQ6IDgwcHg7DQoJbWF4LWhlaWdodDogMTAwcHg7DQp9DQojaG9t'+
        'ZWZlZWRjZW50ZXJfcG9wdXAgI2F1dG9tb2RlX2JvZHkgdWwuZmVlZF9ib3ggbGkgew0KCWJvcmRlci1ib3R0b206IDJweCBzb2xp'+
        'ZCAjMUYxRjFGOw0KCW1hcmdpbjogMHB4IDBweCA2cHg7DQoJaGVpZ2h0OiA4MHB4Ow0KCW1heC1oZWlnaHQ6IDEwMHB4Ow0KfQ0K'+
        'I2hvbWVmZWVkY2VudGVyX3BvcHVwIHVsLmZlZWRfYm94IGxpLm5ld19wb3N0IHsNCgliYWNrZ3JvdW5kOiB1cmwoaHR0cDovL213'+
        'ZmIuc3RhdGljLnp5bmdhLmNvbS9td2ZiL2dyYXBoaWNzL3ptYy9uZXdfbWVzc2FnZV9jYWxsb3V0XzQ1eDQ1XzAxLnBuZykgbm8t'+
        'cmVwZWF0IDBweCAwcHg7DQp9DQojaG9tZWZlZWRjZW50ZXJfcG9wdXAgdWwuZmVlZF9ib3ggZGl2LmxpX3dyYXBwZXIgew0KCWJv'+
        'cmRlci10b3A6IDsNCglwYWRkaW5nOiA2cHggMTRweCAwcHggNHB4Ow0KfQ0KI2hvbWVmZWVkY2VudGVyX3BvcHVwIHVsLmZlZWRf'+
        'Ym94IGxpIGltZy5mZWVkX2ljb24gew0KCWZsb2F0OiBsZWZ0Ow0KCWRpc3BsYXk6IGJsb2NrOw0KCXdpZHRoOiA3MHB4Ow0KfQ0K'+
        'I2hvbWVmZWVkY2VudGVyX3BvcHVwIHVsLmZlZWRfYm94IGxpLm5ld19wb3N0IGltZy5mZWVkX2ljb24gew0KCW1hcmdpbjogMTVw'+
        'eCAwIDAgMTVweDsNCgl3aWR0aDogNTVweDsNCn0NCiNob21lZmVlZGNlbnRlcl9wb3B1cCB1bC5mZWVkX2JveCBsaSBkaXYuYnV0'+
        'dG9ucyB7DQoJZmxvYXQ6IHJpZ2h0Ow0KCWZvbnQtc2l6ZTogMTBweDsNCglmb250LXdlaWdodDogYm9sZDsNCgltYXJnaW46IDNw'+
        'eCAwcHggMHB4IDE0cHg7DQoJdGV4dC1hbGlnbjogcmlnaHQ7DQoJd2lkdGg6IDcwcHg7DQp9DQojaG9tZWZlZWRjZW50ZXJfcG9w'+
        'dXAgdWwuZmVlZF9ib3ggbGkgZGl2LmJvZHkgew0KCW1hcmdpbjogMHB4IDgwcHg7DQoJaGVpZ2h0OiA3MHB4Ow0KfQ0KI2hvbWVm'+
        'ZWVkY2VudGVyX3BvcHVwICNhdXRvbW9kZV9ib2R5IHVsLmZlZWRfYm94IGxpIGRpdi5ib2R5IHsNCgltYXJnaW4tbGVmdDogODBw'+
        'eDsNCgloZWlnaHQ6IDcwcHg7DQp9DQojaG9tZWZlZWRjZW50ZXJfcG9wdXAgdWwuZmVlZF9ib3ggbGkgaDQgew0KCWZvbnQtc2l6'+
        'ZTogMTRweDsNCglsaW5lLWhlaWdodDogMThweDsNCgltYXJnaW4tYm90dG9tOiA0cHg7DQoJcGFkZGluZy10b3A6IDJweDsNCn0N'+
        'CiNob21lZmVlZGNlbnRlcl9wb3B1cCB1bC5mZWVkX2JveCBsaSBwIHsNCglmb250LXNpemU6IDEycHg7DQoJbGluZS1oZWlnaHQ6'+
        'IDE1cHg7DQp9DQojaG9tZWZlZWRjZW50ZXJfcG9wdXAgdWwuZmVlZF9ib3ggbGkgZGl2LmJ1dHRvbnMgYS5zZXh5X2J1dHRvbl9u'+
        'ZXcgew0KCW1hcmdpbi1ib3R0b206IDZweDsNCn0NCiNob21lZmVlZGNlbnRlcl9wb3B1cCB1bC5mZWVkX2JveCBsaSBkaXYuYnV0'+
        'dG9ucyBhLmlnbm9yZSB7DQoJdGV4dC10cmFuc2Zvcm06IHVwcGVyY2FzZTsNCn0NCiNmZWVkX2NlbnRlcl9oZWFkZXIgcCwgI2hv'+
        'bWVmZWVkY2VudGVyX3BvcHVwIHVsLCAjaG9tZWZlZWRjZW50ZXJfcG9wdXAgbGksICNob21lZmVlZGNlbnRlcl9wb3B1cCBkbCwg'+
        'I2hvbWVmZWVkY2VudGVyX3BvcHVwIGR0LCAjaG9tZWZlZWRjZW50ZXJfcG9wdXAgZGQsICNob21lZmVlZGNlbnRlcl9wb3B1cCBo'+
        'MiwgI2hvbWVmZWVkY2VudGVyX3BvcHVwIGgzLCAjaG9tZWZlZWRjZW50ZXJfcG9wdXAgaDQsICNob21lZmVlZGNlbnRlcl9wb3B1'+
        'cCBwIHsNCgltYXJnaW46IDBweDsNCglwYWRkaW5nOiAwcHg7DQp9DQojaG9tZWZlZWRjZW50ZXJfcG9wdXAgICNjb25maWdfcGFu'+
        'ZWwgew0KCWJvcmRlcjogMXB4IHNvbGlkICMxRjFGMUY7DQoJbWFyZ2luOiA1cHg7DQp9DQojaG9tZWZlZWRjZW50ZXJfcG9wdXAg'+
        'IC5zZWxlY3RfdGFiIHsNCglib3JkZXI6IDFweCBzb2xpZCAjNEY0RjRGOw0KCWZsb2F0OiBsZWZ0Ow0KCWhlaWdodDogMTYwcHg7'+
        'DQoJbWFyZ2luOiAycHg7DQoJb3ZlcmZsb3c6IGF1dG87DQoJcGFkZGluZzogNXB4Ow0KCXRleHQtYWxpZ246IGxlZnQ7DQoJd2lk'+
        'dGg6IDI0MHB4Ow0KfQ0KI2hvbWVmZWVkY2VudGVyX3BvcHVwICAuc2VsZWN0X3RhYiBkaXYgew0KCWJvcmRlcjogMXB4IHNvbGlk'+
        'ICMyRjJGMkY7DQoJbWF4LXdpZHRoOiAyMzBweDsNCglvdmVyZmxvdzogaGlkZGVuOw0KCXBhZGRpbmc6IDJweDsJDQp9DQojaG9t'+
        'ZWZlZWRjZW50ZXJfcG9wdXAgIC5zZWxlY3RfdGFiIGRpdi5zZWxlY3RlZCB7DQoJYm9yZGVyOiAxcHggc29saWQgeWVsbG93Ow0K'+
        'fQ0KI2hvbWVmZWVkY2VudGVyX3BvcHVwICAuc2VsZWN0X3RhYiBkaXYgaW5wdXQgew0KCWZsb2F0OiBsZWZ0Ow0KfQ0KI2hvbWVm'+
        'ZWVkY2VudGVyX3BvcHVwICAuc2VsZWN0X3RhYiBkaXYgcCB7DQoJZmxvYXQ6IGxlZnQ7DQoJY3Vyc29yOiBwb2ludGVyOw0KCXdp'+
        'ZHRoOiAxOTVweDsNCgltYXgtd2lkdGg6IDE5NXB4Ow0KCW92ZXJmbG93OiBoaWRkZW47DQp9DQojaG9tZWZlZWRjZW50ZXJfcG9w'+
        'dXAgIC5jb25maWdfdGFiIHsNCglmbG9hdDogbGVmdDsNCgloZWlnaHQ6IDE1MHB4Ow0KCXBhZGRpbmc6IDEwcHg7DQoJdGV4dC1h'+
        'bGlnbjogbGVmdDsNCgl3aWR0aDogNDIwcHg7DQp9DQojaG9tZWZlZWRjZW50ZXJfcG9wdXAgIC5zYXZlX2NvbmZpZyB7DQoJYm9y'+
        'ZGVyLXRvcDogMXB4IHNvbGlkICMxRjFGMUY7DQoJY2xlYXI6IGJvdGg7DQoJbWFyZ2luLXRvcDogMTBweDsNCglwYWRkaW5nOiA1'+
        'cHg7DQp9DQojaG9tZWZlZWRjZW50ZXJfcG9wdXAgI2ZlZWRsaXN0X2JvZHksICNhdXRvbW9kZV9ib2R5ICB7DQoJdGV4dC1hbGln'+
        'bjogbGVmdDsNCn0NCiNob21lZmVlZGNlbnRlcl9wb3B1cCAjbWVzc2FnZXNfYnV0dG9ucyB7DQoJYmFja2dyb3VuZDogdXJsKGh0'+
        'dHA6Ly9td2ZiLnN0YXRpYy56eW5nYS5jb20vbXdmYi9ncmFwaGljcy96bWMvdGFic19iZ18xeDQ1XzAxLmdpZikgcmVwZWF0LXgg'+
        'MHB4IDEwMCU7DQoJaGVpZ2h0OiA1NXB4Ow0KCWxpc3Qtc3R5bGUtdHlwZTogbm9uZTsNCglvdmVyZmxvdzogdmlzaWJsZTsNCn0N'+
        'CiNmZWVkX2NlbnRlcl9oZWFkZXIgew0KCWJhY2tncm91bmQ6IGJsYWNrIHVybChodHRwOi8vbXdmYi5zdGF0aWMuenluZ2EuY29t'+
        'L213ZmIvZ3JhcGhpY3Mvem1jL2JyaWNrX2JnXzcwMHg3M18wMS5qcGcpIG5vLXJlcGVhdCAwcHggMHB4Ow0KCWhlaWdodDogNzRw'+
        'eDsNCgltYXJnaW4tdG9wOiAzcHg7DQp9DQojZmVlZF9jZW50ZXJfaGVhZGVyIGgyIHsNCgliYWNrZ3JvdW5kOiB1cmwoaHR0cDov'+
        'L213ZmIuc3RhdGljLnp5bmdhLmNvbS9td2ZiL2dyYXBoaWNzL3ptYy9td19sb2dvXzEyNngyN18wMS5wbmcpIG5vLXJlcGVhdCAw'+
        'cHggMHB4Ow0KCWRpc3BsYXk6IGlubGluZTsNCglmbG9hdDogbGVmdDsNCgloZWlnaHQ6IDI3cHg7DQoJbWFyZ2luOiAxOHB4IDMy'+
        'cHggMHB4IDE0cHg7DQoJd2lkdGg6IDEyNnB4Ow0KfQ0KI2ZlZWRfY2VudGVyX2hlYWRlciBkbC50b3RhbF9yZXF1ZXN0cyB7DQoJ'+
        'ZmxvYXQ6IGxlZnQ7DQoJZm9udC13ZWlnaHQ6IGJvbGQ7DQoJbWFyZ2luOiAxNHB4IDBweCAwcHg7DQp9DQojZmVlZF9jZW50ZXJf'+
        'aGVhZGVyIGRsLnRvdGFsX3JlcXVlc3RzIGR0IHsNCgliYWNrZ3JvdW5kOiB1cmwoaHR0cDovL213ZmIuc3RhdGljLnp5bmdhLmNv'+
        'bS9td2ZiL2dyYXBoaWNzL3ptYy90b3RhbF9yZXF1ZXN0c19idWJibGVfMzh4MzhfMDEucG5nKSBuby1yZXBlYXQgMHB4IDBweDsN'+
        'CglmbG9hdDogbGVmdDsNCglmb250LXNpemU6IDE4cHg7DQoJaGVpZ2h0OiAzOHB4Ow0KCWxpbmUtaGVpZ2h0OiAzOHB4Ow0KCW1h'+
        'cmdpbi1yaWdodDogNnB4Ow0KCXRleHQtYWxpZ246IGNlbnRlcjsNCgl3aWR0aDogMzhweDsNCn0NCiNmZWVkX2NlbnRlcl9oZWFk'+
        'ZXIgZGwudG90YWxfcmVxdWVzdHMgZGQgew0KCWJhY2tncm91bmQ6IHVybChodHRwOi8vbXdmYi5zdGF0aWMuenluZ2EuY29tL213'+
        'ZmIvZ3JhcGhpY3Mvem1jL3RvdGFsX3JlcXVlc3RzX2JnXzIwMHgyNF8wMS5wbmcpIG5vLXJlcGVhdCAxMDAlIDUwJTsNCglmb250'+
        'LXNpemU6IDEycHg7DQoJaGVpZ2h0OiAzOHB4Ow0KCWxpbmUtaGVpZ2h0OiAzOHB4Ow0KCW1hcmdpbi1sZWZ0OiA1cHg7DQoJcGFk'+
        'ZGluZzogMHB4IDIwcHggMHB4IDM5cHg7DQoJd2hpdGUtc3BhY2U6IG5vd3JhcDsNCn0NCiNmZWVkX2NlbnRlcl9oZWFkZXIgZGl2'+
        'IHsNCgliYWNrZ3JvdW5kOnVybCgiaHR0cDovL213ZmIuc3RhdGljLnp5bmdhLmNvbS9td2ZiL2dyYXBoaWNzL3ptYy9uZXdfcmVx'+
        'dWVzdHNfYmdfMjg5eDQ0XzAxLnBuZyIpIG5vLXJlcGVhdCBzY3JvbGwgMCAwIHRyYW5zcGFyZW50Ow0KCWZsb2F0OnJpZ2h0Ow0K'+
        'CWZvbnQtc2l6ZToxMnB4Ow0KCWhlaWdodDo0MnB4Ow0KCW1hcmdpbjoxMXB4IDI4cHggMCAwOw0KCXBhZGRpbmc6MXB4Ow0KCXdp'+
        'ZHRoOjI4N3B4Ow0KfQ0KI2ZlZWRfY2VudGVyX2hlYWRlciBkaXYgcCB7DQogICAgY29sb3I6ICNFMUUxRTE7DQogICAgZm9udC1z'+
        'aXplOiAxNHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGhlaWdodDogMzZweDsNCiAgICBwYWRkaW5nOiAxMnB4IDEy'+
        'cHggMCAyMHB4Ow0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg=='
    );
    
    // make sure we have permissions and Initialize
    facebook.needPermission('read_stream', Initialize);
}

/**
 * Modify secret stash for add new shorter button.
 * @param {Object} responseText
 */
function secretStash(responseText) {
    var linkRegex = /'href':'([^']+)'\+targetUrlParam}/g;
    var box_id, link, rgx;
    if (!(box_id = /pop_box_(\d+)/.exec(responseText))) {
        return;
    }
    var getShort_click = function() 
    {
        var gift_box = $('#pop_box_' + box_id[1] + ' > div:eq(0) > div:eq(1)');
        var name = $('div:eq(0) > div:eq(0)', gift_box).text();
        name += ' (' + $('div:eq(0) > div:eq(2)', gift_box).text() + ') => ';
        
        $(this).hide();
        gift_box.height(157).css('text-align', 'center').empty();
        c$('img').attr('src', global.zGraphicsURL+'socialmissions/ajax-loader.gif').appendTo(gift_box);
        
        // get short url
        getShortURL(link, function(shortURL) {
            gift_box.empty()
            if (shortURL !== 'Error') {
                $('<textarea readonly="readonly" rows="4" cols="64">')
                .appendTo(gift_box).val(name + shortURL);
            }
            else {
                c$('span').appendTo(gift_box).css('margin-bottom', 8)
                .text('Error creating short url link.');
                gift_box.append('<br>');
                c$('a').text('Open new Tab to get short URL').css('margin-left', 4)
                .appendTo(gift_box).click(function() {
                    unsafeWindow.open('http://tinyurl.com/create.php?url=' + link);
                });
            }
        });
    };
    while ((rgx = linkRegex.exec(responseText))) {
        if (/next_action=collect_loot/.test(rgx[1])) {
            link = rgx[1];
            break;
        }
    }
    if (!link) {
        log$('secretStash: has not find any link.');
        return;
    }
    b$('Get Short Link').appendTo('#pop_box_' + box_id[1] + ' > div:eq(0) > div:eq(2)')
    .addClass('short white').click(getShort_click);
}

/**
 * Collect all cities and bank cash
 */
function collectAllCities() {
    
    var message = new timerMessage('#message_log');
    var startCity = getCurrentCity();
    var abort_process = false;
    
    var options = new Config('collectall', {
        noDelay       : false,
        depositCity1  : true,
        depositCity2  : true,
        depositCity3  : true,
        depositCity4  : true,
        depositCity5  : true,
        depositCity6  : true
    }); 
    
    var collectAll_click = function() {
        if ($(this).attr('disabled')) {
            return;
        }
        $(this).attr('disabled', true);
        $(this).css('opacity', 0.5);
        $('#checkboxes_div').hide();
        options.fromDomElements();
        options.save(function() {
            travel(1);
        });
    };
    
    var popupElt = new domPopupObject('collectall_popup', {
        title: 'Collect All Cities',
        css: {
            'width': 690,
            'left': 35,
            'top': 40
        },
        onclose: function() {
            message.clear();
            abort_process = true;
            options.fromDomElements();
            options.save();
            delete message;
        },
        buttons: [{
            label: 'Collect All!',
            addClass: 'short white',
            onclick: collectAll_click
        }, {label: 'Exit'}]
    });
    
    var main_div = c$('div').appendTo(popupElt.content).addClass('clearfix');
    
    var getMsg = function(id, city) {
        switch(id) {
            case 1: return 'Traveling to ' + global.cities[city] + ' in %N%...';
            case 2: return 'Collecting all in ' + global.cities[city] + ' in %N%...';
            case 3: return 'Depositing cash in ' + global.cities[city] + ' in %N%...';
        }
    };
    
    function genCityBoobleDom(id, name) {
        
        var sqr = c$('div', 'class:booble,id:city_booble_'+id).appendTo(main_div);
        
        c$('p','class:booble_title').appendTo(sqr).text(name);
        
        c$('div','class:city'+id).appendTo(sqr)
        .append(c$('p', 'collect_from_'+id).text('Ready.'))
        .append(
            c$('p', 'cash_in_'+id)
            .append(c$('input:checkbox', 'collectall_depositcity'+id))
            .append(c$('label','for:collectall_depositcity'+id).text('Deposit cash after collect it.'))
        );
          
    }
    function setTimer(id, city, delay, callback) {
        if(options.get('noDelay')) {
            callback();
            return;
        }
        message.start(getMsg(id, city), delay, callback);
    }
    function travel(city) {
        if (abort_process || typeof global.cities[city] == 'undefined') {
            $('#message_log').text('All done!');
            travelToCity(startCity);
            return;
        }
        setTimer(1, city, 1, function()
        {
            $('#message_log').text('Traveling to ' + global.cities[city] + '...');
            travelToCity(city, function(new_city) {
                if (new_city === parseInt(city)) {
                    collectAll(city);
                }
                else {
                    $('#message_log')
                    .text('Error traveling to ' + global.cities[city] + ' try again later.');
                }
            });
        });
    }
    function depositAll(city, amount) {
        if (abort_process)
            return;

        if (isNaN(amount) || parseInt(amount) == 0) {
            $('#cash_in_' + city).html('No cash to deposit.');
            travel(++city);
            return;
        }
        if (!options.get('depositCity'+city)) {
            $('#cash_in_' + city).html('Deposit is skipped by user.');
            travel(++city);
            return;
        }
        setTimer(3, city, 2, function() 
        {
            $('#message_log').text('Depositing cash in ' + global.cities[city] + '...');
            bankDeposit(city, amount, function(result) 
            {
                $('#cash_in_' + city).html(result);
                travel(++city);
            });
        });
    }
    function collectAll(city) {
        if (abort_process)
            return;
            
        setTimer(2, city, 3, function() {
            $('#message_log').text('Collecting all in ' + global.cities[city] + '...');
            
            jsonRequest(
                'remote/' + getIntURL('propertyV2', 'collectall', city) + '&requesttype=json',
                function(jsonData) 
                {
                    var data = $.parseJSON(jsonData.data);
                    $('#collect_from_' + city).html(data.description);
                    depositAll(city, data.cash);
                }
            );
        });
    }
    
    popupElt.addBase64Style(
        'I2NvbGxlY3RhbGxfcG9wdXAgZGl2LmJvb2JsZSB7DQoJbWFyZ2luOiA1cHggMTBweDsNCgl3aWR0aDogMzIwcHg7DQp9DQojY29s'+
        'bGVjdGFsbF9wb3B1cCBkaXYuYm9vYmxlIHAuYm9vYmxlX3RpdGxlIHsNCgliYWNrZ3JvdW5kOiB0cmFuc3BhcmVudCB1cmwoaHR0'+
        'cDovL20ubWFmaWF3YXJzLmNvbS9td2ZiL2dyYXBoaWNzL21vYmlsZVdlYi8zMjAvYmctcHJvcC1oZHIucG5nKSByZXBlYXQteCBz'+
        'Y3JvbGwgMCUgMCU7DQoJYm9yZGVyOiB0aGluIHNvbGlkICM2QjZCNkI7DQoJLXdlYmtpdC1ib3JkZXItcmFkaXVzOiA4cHggOHB4'+
        'IDBweCAwcHg7DQoJLW1vei1ib3JkZXItcmFkaXVzOiA4cHggOHB4IDBweCAwcHg7DQoJYm9yZGVyLXJhZGl1czogOHB4IDhweCAw'+
        'cHggMHB4Ow0KCWNvbG9yOiAjRThFOEU4Ow0KCWZvbnQtc2l6ZTogMThweDsNCglsaW5lLWhlaWdodDogMjdweDsNCgltYXJnaW46'+
        'IDBweDsNCn0NCiNjb2xsZWN0YWxsX3BvcHVwIGRpdi5ib29ibGUgZGl2IHsNCglib3JkZXI6IHRoaW4gc29saWQgIzZCNkI2QjsN'+
        'Cgktd2Via2l0LWJvcmRlci1yYWRpdXM6IDBweCAwcHggOHB4IDhweDsNCgktbW96LWJvcmRlci1yYWRpdXM6IDBweCAwcHggOHB4'+
        'IDhweDsNCglib3JkZXItcmFkaXVzOiAwcHggMHB4IDhweCA4cHg7DQp9DQojY29sbGVjdGFsbF9wb3B1cCBkaXYuYm9vYmxlIGRp'+
        'diBwIHsNCgljb2xvcjogI0NEQ0RDRDsNCglmb250LXNpemU6IDE0cHg7DQoJaGVpZ2h0OiA0MHB4Ow0KCW1hcmdpbjogMHB4Ow0K'+
        'CXBhZGRpbmc6IDVweDsNCn0NCiNjb2xsZWN0YWxsX3BvcHVwICNjaXR5X2Jvb2JsZV8xLCAjY2l0eV9ib29ibGVfMywgI2NpdHlf'+
        'Ym9vYmxlXzUgew0KCWZsb2F0OiBsZWZ0Ow0KfQ0KI2NvbGxlY3RhbGxfcG9wdXAgI2NpdHlfYm9vYmxlXzIsICNjaXR5X2Jvb2Js'+
        'ZV80LCAjY2l0eV9ib29ibGVfNiB7DQoJZmxvYXQ6IHJpZ2h0Ow0KfQ0KI2NvbGxlY3RhbGxfcG9wdXAgZGl2LmJvb2JsZSBkaXYu'+
        'Y2l0eTEgew0KCWJhY2tncm91bmQ6IGJsYWNrIHVybChodHRwOi8vbS5tYWZpYXdhcnMuY29tL213ZmIvZ3JhcGhpY3MvbW9iaWxl'+
        'V2ViLzMyMC9iZy1wcm9wLWNpdHkxLnBuZykgbm8tcmVwZWF0IHNjcm9sbCAwJSAwJTsNCn0JDQojY29sbGVjdGFsbF9wb3B1cCBk'+
        'aXYuYm9vYmxlIGRpdi5jaXR5MiB7DQoJYmFja2dyb3VuZDogYmxhY2sgdXJsKGh0dHA6Ly9tLm1hZmlhd2Fycy5jb20vbXdmYi9n'+
        'cmFwaGljcy9tb2JpbGVXZWIvMzIwL2JnLXByb3AtY2l0eTIucG5nKSBuby1yZXBlYXQgc2Nyb2xsIDAlIDAlOw0KfQ0KI2NvbGxl'+
        'Y3RhbGxfcG9wdXAgZGl2LmJvb2JsZSBkaXYuY2l0eTMgew0KCWJhY2tncm91bmQ6IGJsYWNrIHVybChodHRwOi8vbS5tYWZpYXdh'+
        'cnMuY29tL213ZmIvZ3JhcGhpY3MvbW9iaWxlV2ViLzMyMC9iZy1wcm9wLWNpdHkzLnBuZykgbm8tcmVwZWF0IHNjcm9sbCAwJSAw'+
        'JTsNCn0NCiNjb2xsZWN0YWxsX3BvcHVwIGRpdi5ib29ibGUgZGl2LmNpdHk0IHsNCgliYWNrZ3JvdW5kOiBibGFjayB1cmwoaHR0'+
        'cDovL20ubWFmaWF3YXJzLmNvbS9td2ZiL2dyYXBoaWNzL21vYmlsZVdlYi8zMjAvYmctcHJvcC1jaXR5NC5wbmcpIG5vLXJlcGVh'+
        'dCBzY3JvbGwgMCUgMCU7DQp9DQojY29sbGVjdGFsbF9wb3B1cCBkaXYuYm9vYmxlIGRpdi5jaXR5NSB7DQoJYmFja2dyb3VuZDog'+
        'YmxhY2sgdXJsKGh0dHA6Ly9tLm1hZmlhd2Fycy5jb20vbXdmYi9ncmFwaGljcy9tb2JpbGVXZWIvMzIwL2JnLXByb3AtY2l0eTUu'+
        'cG5nKSBuby1yZXBlYXQgc2Nyb2xsIDAlIDAlOw0KfQ0KI2NvbGxlY3RhbGxfcG9wdXAgZGl2LmJvb2JsZSBkaXYuY2l0eTYgew0K'+
        'CWJhY2tncm91bmQ6IGJsYWNrIHVybChodHRwOi8vbS5tYWZpYXdhcnMuY29tL213ZmIvZ3JhcGhpY3MvbW9iaWxlV2ViLzMyMC9i'+
        'Zy1wcm9wLWNpdHk2LnBuZykgbm8tcmVwZWF0IHNjcm9sbCAwJSAwJTsNCn0NCiNjb2xsZWN0YWxsX3BvcHVwIC5zdGF0dXMgew0K'+
        'CWJhY2tncm91bmQtY29sb3I6ICMxMTE7DQoJYm9yZGVyOiAxcHggc29saWQgd2hpdGU7DQoJLXdlYmtpdC1ib3JkZXItcmFkaXVz'+
        'OiA2cHggNnB4Ow0KCS1tb3otYm9yZGVyLXJhZGl1czogNnB4IDZweDsNCglib3JkZXItcmFkaXVzOiA2cHggNnB4Ow0KCWhlaWdo'+
        'dDogMjBweDsNCgltYXJnaW46IDVweDsNCglwYWRkaW5nOiA1cHggMTBweDsNCn0='
    );  
    
    for (var c in global.cities) {
        genCityBoobleDom(c, global.cities[c]);
    }
    var bottomDiv = c$('div','class:status').appendTo(popupElt.content);
    
    c$('strong', 'message_log').appendTo(bottomDiv).css('color', 'grey');
    
    c$('div', 'checkboxes_div').appendTo(bottomDiv)
    .append(c$('input:checkbox', 'collectall_nodelay'))
    .append(c$('label','for:collectall_nodelay').text('No delay.'));
    
    options.load(function() {
        options.toDomElements();
        
        // show popup
        popupElt.show();
    });
}

/**
 * Show a popup with all user links.
 */
function userLinks() 
{
    var crimeSpreeLink;
    var options = new Config('userlinks', {
        profile: {
            'longUrl': getProfileLink()
        },
        promote: {
            'longUrl': getExtURL('group', 'view', {
                'next_params': {
                    'promote': 'yes',
                    'pid': global.USER_ID
                }
            })
        },
        slots: {
            'longUrl': getExtURL('stats', 'view', {
                'next_params': {
                    'user': global.USER_ID,
                    'vegasslots': '1',
                    'referrer': 'ad_feed'                    
                }
            })
        }
    });
    
    var popupElt = new domPopupObject('user_links', {
        title: 'My Links',
        type: 'simple',
        buttons: [{
            label: 'Reset all links',
            addClass: 'short white',
            onclick: function() {
                options = new Config('userlinks', {});
                options.save(function() {
                    popupElt.destroy();
                    userLinks();
                })
                return false;
            }
        }, {
            label: 'Close'
        }],
        onclose: function() {
            options.save();
        }
    });
    
    var isValid = function(link, button) {
        if (!/http/.test(link) || $(button).attr('disabled')) {
            return false;
        }
        $(button).attr('disabled', true).css('opacity', 0.4);
        return true;
    };
    
    var _Event = {
        promote_click: function() {
            var self = this;
            var link = options.get('promote').longUrl;
            if (!isValid(link, self)) {
                return false;
            }
            facebook.streamPublish({
                'name': 'Who doesn\'t want to be a gangster?',
                'description': 'Promote me to your top-mafia and turn you into a really gangster!!',
                'pic': global.zGraphicsURL + 'levelup_test_2.jpg',
                'url': link,
                'actionText': 'Promote me'
            }, function() {
                $(self).replaceWith(c$('b').text('Published!'));
            });
            return false;
        },
        crimeSpree_click: function() {
            var self = this;
            if (!isValid(crimeSpreeLink, self)) {
                return false;
            }
            facebook.streamPublish({
                'name': 'Who says crime doesn\'t pay?',
                'description': 'Join me on a crime spree and find out what we loot.',
                'pic': global.zGraphicsURL + 'safehouse/v2/crime_spree_feed.gif',
                'url': crimeSpreeLink,
                'actionText': 'Help or Sabotage'
            }, function() {
                $(self).replaceWith(c$('b').text('Published!'));
            });
            return false;
        },
        slots_click: function() {
            var self = this;
            var link = options.get('slots').longUrl;
            if (!isValid(link, self)) {
                return false;
            }
            facebook.streamPublish({
                'name': 'I have a Vegas Slot Machine!',
                'description': 'I\'m offering free spins to all my friends!',
                'pic': global.zGraphicsURL + 'vegas_slots_777.png',
                'url': link,
                'actionText': 'Play Slots'
            }, function() {
                $(self).replaceWith(c$('b').text('Published!'));
            });
            return false;
        },
        text_click: function() {
            $(this).select();
            return false;
        }
    };
    
    var addLink = {
        profile: function(shortUrl) {
            $('#profile_link').val('Profile => '+(options.get('profile').shortUrl = shortUrl));
        },
        promote: function(shortUrl) {
            $('#promote_link').val('Promote => '+(options.get('promote').shortUrl = shortUrl));
        },
        crimespree: function(shortUrl) {
            $('#crimespree_link').val('Crime Spree => '+shortUrl);
        },
        slots: function(shortUrl) {
            $('#slots_link').val('Slots => '+(options.get('slots').shortUrl = shortUrl));
        }
    };
    
    function genMainDom() {
        c$('dl', 'class:frame_box').appendTo(popupElt.content)
        .append(c$('dt').html('My profile link:'))
        .append(c$('dd').append(
            c$('input:text', 'id:profile_link,class:black,readonly:readonly')
            .val('Loading...').click(_Event.text_click)
        ));
        c$('dl', 'class:frame_box').appendTo(popupElt.content)
        .append(c$('dt').html('My promote link:'))
        .append(c$('dd').append(
            c$('input:text', 'id:promote_link,class:black,readonly:readonly')
            .val('Loading...').click(_Event.text_click)
        ))
        .append(c$('dd').append(
            b$('Publish', 'class:short white sexy_announce_gray').click(_Event.promote_click)
        ));
        c$('dl', 'class:frame_box').appendTo(popupElt.content)
        .append(c$('dt').html('My crime spree link:'))
        .append(c$('dd').append(
            c$('input:text', 'id:crimespree_link,class:black,readonly:readonly')
            .val('Loading...').click(_Event.text_click)
        ))
        .append(c$('dd').append(
            b$('Publish', 'class:short white sexy_announce_gray').click(_Event.crimeSpree_click)
        ));
        c$('dl', 'class:frame_box').appendTo(popupElt.content)
        .append(c$('dt').html('My slots link:'))
        .append(c$('dd').append(
            c$('input:text', 'id:slots_link,class:black,readonly:readonly')
            .val('Loading...').click(_Event.text_click)
        ))
        .append(c$('dd').append(
            b$('Publish', 'class:short white sexy_announce_gray').click(_Event.slots_click)
        ));
    }
    
    function Initialize() {
        genMainDom();
        
        ajaxRequest({
            url: 'remote/' + getIntURL('safehouse', 'safehouse_request') + '&fbml_iframe=1',
            message: 'Loading your links...',
            liteLoad: 1,
            success: function(htmlText) 
            {
                if (crimeSpreeLink = doRegex(/<fb:req-choice url='([^']+)'/, htmlText).$1) {
                    getShortURL(crimeSpreeLink, addLink.crimespree);
                }
                options.each(function(name, opt) {
                    if (opt.shortUrl) {
                        addLink[name](opt.shortUrl);
                    }
                    else {
                        getShortURL(opt.longUrl, addLink[name]);
                    }
                });
                // show
                popupElt.show();
            }
        });
    }
    
    popupElt.addBase64Style(
        'I3VzZXJfbGlua3MgLmJsYWNrIHsNCgl3aWR0aDogMzAwcHg7DQoJbWFyZ2luLWxlZnQ6IDVweDsNCglmb250LXdlaWdodDogYm9s'+
        'ZDsgDQoJY29sb3I6IHJnYigyMDgsIDIwOCwgMjA4KTsgDQoJYm9yZGVyOiAxcHggc29saWQgcmdiKDE1MywgMTUzLCAxNTMpOyAN'+
        'CgliYWNrZ3JvdW5kLWNvbG9yOiBibGFjazsgDQoJZm9udC1zaXplOiAxNHB4Ow0KfQ0KI3VzZXJfbGlua3MgZGwuZnJhbWVfYm94'+
        'IHsNCglib3JkZXI6IDFweCBzb2xpZCAjMUYxRjFGOw0KCW1pbi1oZWlnaHQ6IDI2cHg7DQoJbWFyZ2luOiA1cHg7DQoJcGFkZGlu'+
        'ZzogMTBweDsNCgl0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KI3VzZXJfbGlua3MgZGwuZnJhbWVfYm94IGR0LCBkZCB7DQoJZmxvYXQ6'+
        'IGxlZnQ7CQ0KfQ0KI3VzZXJfbGlua3MgZGwuZnJhbWVfYm94IGR0IHsNCgl3aWR0aDogMTIwcHg7DQp9'

    );
    
    options.load(Initialize);
}

/**
 * Show a popup with all craft types for build it.
 */
function craftManager() 
{
    if (getCurrentCity() !== 1) {
        travelToCity(1, 'inner_page', function(city) {
            if (city !== 1) {
                showHelpPopup({
                    icon: 'error',
                    title: 'Error traveling',
                    message: 'I can\'t travel to New York to open Craft Manager.'+
                             'Please, go there and try again.'
                });
                return;
            }
            craftManager();
        });
        return;
    }
    var arrow_url = global.zGraphicsURL+'gift_loop_arrow_green_39x50_01.png';
    var craftingUrl = getIntURL('propertyV2', 'open_chop_crafting');
    var crafts = {
        vehicles: [],
        weapons: [],
        armory: [],
        zoo: []
    };
    var popupElt = new domPopupObject('craftmanager_popup', {
        title: 'Craft Manager',
        top: 10,
        onclose: function() {
            options.fromDomElements();
            options.save(function() {
                delete options, crafts;
            });
        }
    });
    var options = new Config('showcraftable', {
        vehicles: false,
        weapons: false,
        armory: false,
        zoo: false
    });
    var gift_box_class = {
        'padding': 1,
        'width': 260,
        'height': 120,
        'float': 'left',
        'border': '1px solid rgb(153, 153, 153)',
        'overflow-x': 'hidden',
        'overflow-y': 'auto'
    };
    var gift_item_class = {
        'margin': 1, 
        'height': 45, 
        'border': '1px solid #333333', 
        'overflow': 'hidden', 
        'cursor': 'pointer'
    };
    var item_text_class = {
        'float': 'left', 
        'padding': '12px 0px',
        'height': 17, 
        'text-align': 'left',
        'overflow': 'hidden'
    }; 
    var itemList_onclick = function() {
        try {
            // mark selected item
            $('div[selected=true]', $(this).parent())
            .css('border', '1px solid #333333').attr('selected', 'false');
            
            $(this).css('border', '1px solid #FFFF00').attr('selected', 'true');
            
            // item description
            var iName = this.id;
            var cName = $(this).parent().attr('id');
            var col = crafts[cName];
            var div = $('#' + cName + '_detail_box').empty();
            
            c$('div').appendTo(div).css('float', 'left')
            .html(col[iName].attack + '<br>' + col[iName].defense + '<br>' + col[iName].special);
                     
            c$('div').appendTo(div).append(col[iName].required).css({
                'float': 'right',
                'margin-right': 10
            });
            // craft button
            div = $('#' + cName + '_button_box').empty();
            div.html(col[iName].button);
            if (e$('a', div) == null) {
                return;
            }
            if ($('a', div).text().match('Ask')) {
                return;
            }
            
            var href = $('a', div).attr('href');
            
            $('a', div).removeAttr('href').removeAttr('onclick').click(function() {
                
                $(this).hide();
                div.html(c$('img').attr('src', global.resource.ajax_loader));
                
                ajaxRequest({
                    url: href,
                    success: function(htmlText) 
                    {
                        var resultElt = $('div[class^=pop_box] > div > div', '<div>'+htmlText+'</div>').eq(2);
                        var resultText = (resultElt.length > 0 ? resultElt.html() : 'Error: can\'t get message.');
                        $('#' + cName + '_div').empty()
                        .append(c$('div').html(resultText).css({'margin': 10,'text-align': 'center'}));
                    }
                });
            });
        } 
        catch (err) {
            logErr$(err);
        }
        
    };
    // generate the current list of craftable items and a detail box.
    function genCraftListDom(elem, countDown, id, colItem) {
        var div = $('#' + id + '_div').empty().append(countDown);
        
        var craft_box = c$('div', id).css(gift_box_class).appendTo(div);

        c$('div').appendTo(div).append(c$('img').attr('src', arrow_url)).css({
            'float': 'left',
            'height': 120
        });
        c$('div', id + '_detail_box').appendTo(div).html($('#ChopShopTimer', elem).html()).css({
            'float': 'left',
            'text-align': 'left',
            'width': 300,
            'height': 80,
            'border': '1px solid #333333',
            'padding': 5
        });
        c$('div', id + '_button_box').appendTo(div).css({
            'float': 'left',
            'padding': 5,
            'width': 300
        });
        $('div[id^="rp_confirm_speedup"]', div).css({
            'left': 100,
            'top': 0
        });
        
        $('li[id^="VehicleObject"]', elem).each(function(index, domElement) {
            var itemId = id + '_list_item_' + index;
            var name = $('div[id^="RecipeName"]', domElement).html();
            var item = c$('div', itemId).appendTo(craft_box);
            
            item.css(gift_item_class).attr('selected', 'false').click(itemList_onclick);
            
            $('div[id^="VehiclePic"]', domElement).find('img').appendTo(item).css({
                'margin-right': 10,
                'float': 'left',
                'width': 40,
                'height': 40
            });
            c$('div', 'item_name').css(item_text_class).appendTo(item).html($.trim(name));

            colItem[itemId] = {
                attack: $('div[id^="ItemAttack"]', domElement).html(),
                defense: $('div[id^="ItemDefense"]', domElement).html(),
                special: $('div[id^="ItemSpecial"]', domElement).html(),
                required: $('div[id^="ItemsRequired"]/div', domElement).html(),
                button: $('div[id^="BuildButton"]', domElement).html()
            };
            if ($('#showcraftable_' + id).get(0).checked) {
                if (/<a\s*href="http/.test(colItem[itemId].button)) 
                    item.show();
                else 
                    item.hide();
            }
        });
    }
    // generate a title dom with name and checkbox option.
    function genTitleDom(name) {
        var title = c$('div').appendTo(popupElt.content).css({
            'margin-top': 10,
            'border-bottom': '1px solid rgb(85, 85, 85)',
            'text-align': 'left'
        });
        c$('span').css('margin-left', 20).text(name).appendTo(title);
        
        // name is used for id reference now, so lower case it 
        name = name.toLowerCase();
        
        // checkbox div for show craftable only 
        c$('div').appendTo(title).css({
            'float': 'right',
            'margin-right': 15
        }).append(
        $('<input type="checkbox" id="showcraftable_'+name+'">')
        // onclick checkbox fires it, if checked hide no craftable items.
        .click(function() {
            var name = this.id.match(/showcraftable_(.+)/)[1];
            if (this.checked) {
                $('div[id^=' + name + '_list_item_]').each(function(index, domElement) {
                    if (/<a\shref="http/.test(crafts[name][domElement.id].button)) 
                        $(domElement).show();
                    else 
                        $(domElement).hide();
                });
                
            }
            else
                $('div[id^='+name+'_list_item_]').show();   
        })
        ).append(c$('label').text('Show Craftable Only.').attr('for', 'showcraftable_'+name));
        
        // add ajax loader while it's first load.
        c$('div', name+'_div').height(120).appendTo(popupElt.content)
        .append(c$('img').attr('src', global.resource.ajax_loader)).css('padding', 10);
    }
    
    function buildCrafter(id, name) {
        // Get all crafting objects
        ajaxRequest({
            url: 'remote/' + craftingUrl + '&building_name=' + name,
            success: function(htmlText) 
            {
                htmlText = htmlText.replace(/"chopshopCountdown"/g, '"'+ id + 'Countdown"')
                                   .replace(/enhancedBuildablesFeedPublish/g, id+'FeedPublish');
                                      
                var script = h$(htmlText).find('script:regex(text,countdown|FeedPublish)');
                
                genCraftListDom(h$(htmlText), script, id, crafts[id]);
            }
        });
    }
    
    // Generate all 4 craft types
    genTitleDom('Vehicles');
    genTitleDom('Weapons');
    genTitleDom('Armory');
    genTitleDom('Zoo');
    
    // load options and make sure it's ready for generate the dom.
    options.load(function() {
        options.toDomElements();
        buildCrafter('vehicles', 'Chop%20Shop');
        buildCrafter('weapons', 'Weapons%20Depot');
        buildCrafter('armory', 'Armory');
        buildCrafter('zoo', 'Private%20Zoo');
    });

    // show the popup window.
    popupElt.show();
}

function mafiaWiper() 
{
    var abort_process = false;
    var users = [], groups_users;
    var options = new Config('mafiawiper', {
        ignored: []
    });
    
    var popupElt = new domPopupObject('mafiawiper_popup', {
        title: 'Mafia Wiper',
        onclose: function(){
            abort_process = true;
            delete users;
        }
    });
    
    var evalData = function(html) {
        var groups_levels;
        var startIndex = html.indexOf('var groups_levels');
        var lastIndex = html.indexOf('var friends_names', startIndex)-1;
        
        eval(html.substr(startIndex, lastIndex - startIndex));
        groups_users = groups_levels;
    };
    
    var _Event = {
        removeIgnored_click: function() {
            $('.member_list ul li').each(function(index, elem) {
                $(elem).show();
            });
            options.set('ignored', []);
            options.save();
            $(this).hide();
            return false;
        },
        ignore_click: function() {
            options.get('ignored').push($(this).attr('uid'));
            options.save();
            $(this).parent().parent().fadeOut(500, function() {
                $('#remove_ignored').css('display','inline');
            });
            
            return false;
        },
        profile_click: function() {
            var userId = $(this).attr('uid');
            $(this).removeClass('white').parent().parent().css('border-color', '#777');
            unsafeWindow.open('http://www.facebook.com/profile.php?id=' + userId, '_black');
            return false;
        },
        remove_click: function() {
            if ($('#ask_for_delete').attr('checked')) {
                if (!confirm('Are you sure to remove?')) 
                    return false;
            }
            removeUser(this.id.substring(5));
            return false;
        },
        removeAll_click: function() {
            if (confirm('Are you really sure to remove ALL?')) {
                removeAll();
            }
            return false;
        },
        createFriendList_click: function() {
            var self = this;
            if ($(self).attr('disabled')) {
                return false;
            }
            $(self).attr('disabled', true).css('opacity', 0.4);
            facebook.getPermission('manage_friendlists', function(success) {
                if (success == true) {
                    facebook.friendListCreate($('#friendlistname').val(), function(friendList) {
                        if (friendList && friendList.id) {
                            addUsersToFriendList(friendList.id);
                        }
                        else {
                            showHelpPopup({
                                icon: 'error',
                                title: 'Error creating friendlist',
                                message: 'Make sure you have updated your key and ' +
                                         'the friendlist name doesn\'t exists.',
                                buttons: [{
                                    label: 'Update key',
                                    onclick: function() {
                                        unsafeWindow.open(global.fbAuthUrl, '_top');
                                    }
                                }, {
                                    label: 'Close'
                                }]
                            });
                            $(self).css('opacity', 1).removeAttr('disabled', true);
                            log$($.toJSON(friendList));
                        }
                    });
                }
                else {
                    $(self).css('opacity', 1).removeAttr('disabled', true);
                }
            });
        }
    };
    popupElt.addBase64Style(
        'I21hZmlhd2lwZXJfcG9wdXAgLmJsYWNrIHsNCglmb250LXdlaWdodDogYm9sZDsNCgljb2xvcjogcmdiKDIwOCwgMjA4LCAyMDgp'+
        'OyANCglib3JkZXI6IDFweCBzb2xpZCByZ2IoMTUzLCAxNTMsIDE1Myk7IA0KCWJhY2tncm91bmQtY29sb3I6IGJsYWNrOyANCglm'+
        'b250LXNpemU6IDE0cHg7DQp9DQojbWFmaWF3aXBlcl9wb3B1cCAuZnJhbWVfYm94IHsNCglib3JkZXI6IDFweCBzb2xpZCAjMkYy'+
        'RjJGOw0KCWhlaWdodDogNDBweDsNCgltYXJnaW46IDVweDsNCglwYWRkaW5nOiAxMHB4IDIwcHggMHB4Ow0KCXRleHQtYWxpZ246'+
        'IGxlZnQ7DQp9DQojbWFmaWF3aXBlcl9wb3B1cCBpbnB1dCB7DQoJdmVydGljYWwtYWxpZ246IHRvcDsNCn0NCiNtYWZpYXdpcGVy'+
        'X3BvcHVwIC5mcmFtZV9ib3ggaW5wdXQgew0KCXZlcnRpY2FsLWFsaWduOiBtaWRkbGU7DQoJd2lkdGg6IDIzMHB4Ow0KCW1hcmdp'+
        'bi1yaWdodDogNXB4Ow0KCW1hcmdpbi1sZWZ0OiA1cHg7DQp9DQojbWFmaWF3aXBlcl9wb3B1cCAuZnJhbWVfYm94IGEgew0KCWZs'+
        'b2F0OiByaWdodDsNCn0NCiNtYWZpYXdpcGVyX3BvcHVwIC5pbmZvIHsNCgloZWlnaHQ6IDUwcHg7DQoJbWFyZ2luOiA1cHg7DQp9'+
        'DQojbWFmaWF3aXBlcl9wb3B1cCAubWVtYmVyX2xpc3Qgew0KCWJvcmRlcjogMXB4IHNvbGlkICM5OTk7DQoJaGVpZ2h0OiAzODBw'+
        'eDsNCgltYXJnaW46IDRweDsNCglwYWRkaW5nOiA1cHg7DQoJb3ZlcmZsb3cteDogaGlkZGVuOw0KCW92ZXJmbG93LXk6IGF1dG87'+
        'DQp9DQojbWFmaWF3aXBlcl9wb3B1cCAubWVtYmVyX2xpc3QgdWwgew0KCXBhZGRpbmc6IDBweDsNCgltYXJnaW46IDBweDsNCgls'+
        'aXN0LXN0eWxlLXR5cGU6IG5vbmU7DQp9DQojbWFmaWF3aXBlcl9wb3B1cCAubWVtYmVyX2xpc3QgdWwgbGkgew0KCWJvcmRlcjog'+
        'MXB4IHNvbGlkICMzMzM7DQoJaGVpZ2h0OiA0NXB4Ow0KCW1hcmdpbjogMXB4Ow0KCW92ZXJmbG93OiBoaWRkZW47DQp9DQojbWFm'+
        'aWF3aXBlcl9wb3B1cCAubWVtYmVyX2xpc3QgdWwgbGkgc3Bhbi51c2VyX25hbWUgew0KCWZsb2F0OiBsZWZ0Ow0KCW1heC13aWR0'+
        'aDogNDAwcHg7DQoJcGFkZGluZzogMTJweCA1cHg7DQp9DQojbWFmaWF3aXBlcl9wb3B1cCAubWVtYmVyX2xpc3QgdWwgbGkgLmJ1'+
        'dHRvbnN7DQoJZmxvYXQ6IHJpZ2h0Ow0KCXBhZGRpbmc6IDhweCA1cHg7DQp9DQojbWFmaWF3aXBlcl9wb3B1cCAubWVtYmVyX2xp'+
        'c3QgdWwgbGkgLmJ1dHRvbnMgYXsNCgltYXJnaW4tbGVmdDogNXB4Ow0KfQ0K'
    );
    
    c$('center', 'class:info').appendTo(popupElt.content)
    .append(c$('div', 'top_div').html('Loading...'))
    .append(
        c$('div', 'loading_div').css('margin-top', 5)
        .append(c$('img').attr('src', global.resource.ajax_loader).css('vertical-align', 'middle'))
        .append(
            c$('span', 'wiper_msg_log').text('Loading Mafia members...').css({
                'margin-left': 10,
                'font-weight': 'bold'
            })
        )
    );
    
    c$('div', 'id:create_friend_list').hide()
    .appendTo(c$('div', 'class:frame_box clearfix').appendTo(popupElt.content))
    .append(c$('label', 'for:friendlistname').text('You can create a new Facebook FriendList:'))
    .append(c$('input:text', 'id:friendlistname,class:black').val('No Playing Mafia Wars'))
    .append(b$('Create', 'class:short white').click(_Event.createFriendList_click));
    
    c$('div', 'class:clearfix').css('height',25).appendTo(popupElt.content)
    .append(c$('input:checkbox', 'checked:checked,id:ask_for_delete'))
    .append(c$('label', 'for:ask_for_delete').text('Ask for remove'))
    .append(
        c$('a', 'remove_ignored').text('Remove ignored members').hide()
        .css('margin-left',20).click(_Event.removeIgnored_click)
    );
    
    c$('ul').appendTo(c$('div', 'class:member_list').appendTo(popupElt.content));
    
    options.load(popupElt.show);
    
    // get all mafia members
    ajaxRequest({
        url: 'remote/' + getIntURL('gift'),
        success: function(htmlText) 
        {
            evalData(htmlText);
            
            facebook.getFriends(function(result) {
                for (i in groups_users) {
                    if (result.indexOf(parseInt(i)) == -1) {
                        users.push({
                            'id': i,
                            'name': $.trim(groups_users[i])
                        });
                    }
                }
                // show total no mafia members
                $('#top_div').html('Members that are not playing Mafia Wars: ' + users.length);
                $('#loading_div').empty().append(
                    c$('div').append(b$('Remove All','class:short red').click(_Event.removeAll_click))
                );
                
                showResults();
                delete groups_users;
            });
        }
    });
    
    function removeUser(index, callback) {
        if (abort_process) {
            return;
        }
        var parent = $('#user_' + index, '.member_list').parent();
        c$('img').attr('src', global.resource.ajax_loader).appendTo(parent.empty());
        
        ajaxRequest({
            url: 'remote/' + getIntURL('stats') + '&user=' + users[index].id,
            success: function(htmlText) 
            {
                ajaxRequest({
                    url: $('.zy_popup_box_body_dark a:regex(href,xw_action=remove)', htmlText).attr('href'),
                    success: function(htmlText) 
                    {
                        if (mw_updater(htmlText)) {
                            parent.html('<span style="color: green;">User has been removed.</span>');
                        }
                        else {
                            parent.html('<span style="color: red;">Error. but maybe removed.</span>');
                        }
                        delete users[index];
                        callback && callback();
                    }
                });
            }
        });  
    }
    
    function removeAll() {
        var last_index = 0;
        function removeNext() {
            if (last_index < users.length) {
                if (typeof(users[last_index]) !== 'undefined' && 
                    options.get('ignored').indexOf(String(users[last_index].id)) === -1) 
                {
                    $('#loading_div').html('Deleting '+users[last_index].name);
                    removeUser(last_index++, removeNext);
                }
                else 
                {
                    last_index++;
                    removeNext();
                }
            }
            else {
                $('#loading_div').html('All members has been removed.');
            }
        }
        removeNext();
    }
    
    function showResults() 
    {
        // fill the list of memebers
        var listElt = $('.member_list ul', popupElt.content); 
        var profileBtn, addedElt;
            
        for (var i = 0; i < users.length; i++) 
        {
            if (users[i].name) {
                
                addedElt = c$('li').appendTo(listElt)
                .append(c$('span', 'class:user_name').text(users[i].name))
                .append(
                    c$('div', 'class:buttons')
                    .append(b$('FB Profile', 'uid:'+users[i].id +',class:short white').click(_Event.profile_click))
                    .append(b$('Remove', 'class:short red,id:user_' + i).click(_Event.remove_click))
                    .append(b$('Ignore', 'class:short green,uid:'+users[i].id).click(_Event.ignore_click))
                );
                
                if (options.get('ignored').indexOf(users[i].id) !== -1) {
                    addedElt.hide();
                } 
            }
        }
        $('#create_friend_list').show();
        if (options.get('ignored').length > 0) {
            $('#remove_ignored').css('display','inline');
        }
    }
    function addUsersToFriendList(friendListID) {
        var len = users.length, message;
        
        $('#create_friend_list').empty()
        .append(c$('img').css('vertical-align', 'middle').attr('src', global.resource.ajax_loader))
        .append(message = c$('span').css('margin-left', 5));
        
        function addMember(index) {
            if (index >= len) {
                $('#create_friend_list').html('FriendList successfully created.');
                return;
            }
            if (users[index] && users[index].id) {
                message.text('Adding user (' + (index+1) + '/'+ len + ')...');
                facebook.friendListAddUsers(friendListID, users[index].id, function() {
                    addMember(++index);
                });
            }
            else {
                addMember(++index);
            }
        }
        addMember(0);
    }
}

/**
 * Send multiple items from inventory.
 */
function multiGifter(select_gift_cat, select_gift_id) 
{
    if (typeof(global.popups['multigifter_popup']) !== 'undefined') {
        if (select_gift_cat && select_gift_id) {
            global.popups['multigifter_popup'].selectGift(select_gift_cat, select_gift_id);
        }
        global.popups['multigifter_popup'].show();
        return;
    }
    
    var sendTimer = new timerMessage('#next_gift_timer');
    var already_working = false;
    var daily_left, gift_count_avail, gift_key;
    var Queue = [], plainTextLog = '';
    var gift_categories = {
        0: 'Collections',
        1: 'Loot',
        2: 'Boosts'
    };
    
    var options = new Config('multigift', {
        delay: 3,
        giftFav: [],
        userFav: [],
        giftPages: true,
        userPages: true,
        search: []
    });
    
    var InventoryFilter = {
        ItemTypes: {},
        Locations: {},
        Qualities: {}
    };
    
    var collectionFilter = {
        'Crew': {
            'Bring Back the Pack'       : [300022, 300023, 300024, 300025, 300026, 300027, 300028],
            'Prototype Carjacking'      : [300001, 300002, 300003, 300004, 300005, 300006, 300007],
            'Theft of a Drone'          : [300008, 300009, 300010, 300011, 300012, 300013, 300014],
            'Weapons Shipment Hijackin' : [300015, 300016, 300017, 300018, 300019, 300020, 300021]
        },
        'Special': {
            'Silence Don Romo'    : [100036, 100037, 100038, 100039, 100040, 100041, 100042],
            'Mystery Bag'         : [400008, 400009, 400010, 400011, 400012, 400013, 400014],
            'Slots'               : [100029, 100030, 100031, 100032, 100033, 100034, 100035],
            'Global Cup'          : [100022, 100023, 100024, 100025, 100026, 100027, 100028],
            'ST. Patrick\'s Day'  : [100008, 100009, 100010, 100011, 100012, 100013, 100014],
            'Chinese New Year'    : [400001, 400002, 400003, 400004, 400005, 400006, 400007],
            'Valentine Day'       : [100001, 100002, 100003, 100004, 100005, 100006, 100007],
            'Tools of the Trade'  : [500001, 500002, 500003, 500004, 500005, 500006, 500007],
            'Stolen Diamond'      : [500008, 500009, 500010, 500011, 500012, 500013, 500014],
            'Pantheon Trophies'   : [705001, 705002, 705003, 705004, 705005, 705006, 705007],
            'Continental Rings'   : [705008, 705009, 705010, 705011, 705012, 705013, 705014],
            'Championship Belts'  : [705015, 705016, 705017, 705018, 705019, 705020, 705021],
            'Easter Crime Basket' : [100015, 100016, 100017, 100018, 100019, 100020, 100021]
        },
        'Mission': {
            'Operations': [800001, 800002, 800003, 800004, 800005, 800006, 800007]
        },
        'New York': {
            'Diamond Flush'     : [1036, 1037, 1038, 1039, 1040, 1041, 1042],
            'Heart Flush'       : [1043, 1044, 1045, 1046, 1047, 1048, 1049],
            'Sculptures'        : [1022, 1023, 1024, 1025, 1026, 1027, 1028],
            'Poker Chips'       : [1029, 1030, 1031, 1032, 1033, 1034, 1035],
            'Club Flush'        : [1050, 1051, 1052, 1053, 1054, 1055, 1056],
            'Boxing'            : [1085, 1086, 1087, 1088, 1089, 1090, 1091],
            'Cigars'            : [1001, 1002, 1003, 1004, 1005, 1006, 1007],
            'Spade Flush'       : [1057, 1058, 1059, 1060, 1061, 1062, 1063],
            'Billiards'         : [1092, 1093, 1094, 1095, 1096, 1097, 1098],
            'Rings'             : [1008, 1009, 1010, 1011, 1012, 1013, 1014],
            'Ties'              : [1064, 1065, 1066, 1067, 1068, 1069, 1070],
            'Paintings'         : [1015, 1016, 1017, 1018, 1019, 1020, 1021],
            'Cufflinks'         : [1071, 1072, 1073, 1074, 1075, 1076, 1077],
            'Barber'            : [1099, 1100, 1101, 1102, 1103, 1104, 1105],
            'Great Race Horses' : [1078, 1079, 1080, 1081, 1082, 1083, 1084],
            'Daily Chance'      : [1106, 1107, 1108, 1109, 1110, 1111, 1112],
            'Money Laundering'  : [1113, 1114, 1115, 1116, 1117, 1118, 1119]
        },
        'Cuba': {
            'Rum Drinks'      : [2001, 2002, 2003, 2004, 2005, 2006, 2007],
            'Tropical Fruits' : [2008, 2009, 2010, 2011, 2012, 2013, 2014],
            'Entertainers'    : [2015, 2016, 2017, 2018, 2019, 2020, 2021],
            'Tropical Fish'   : [2022, 2023, 2024, 2025, 2026, 2027, 2028],
            'Beards'          : [2029, 2030, 2031, 2032, 2033, 2034, 2035]
        },
        'Moscow': {
            'Prison Tattoos'     : [3001, 3002, 3003, 3004, 3005, 3006, 3007],
            'Matryoshka Dolls'   : [3008, 3009, 3010, 3011, 3012, 3013, 3014],
            'Russian Leaders'    : [3015, 3016, 3017, 3018, 3019, 3020, 3021],
            'Vodka Drinks'       : [3022, 3023, 3024, 3025, 3026, 3027, 3028],
            'Soviet Memorabilia' : [3029, 3030, 3031, 3032, 3033, 3034, 3035],
            'Faberge Egg'        : [3036, 3037, 3038, 3039, 3040, 3041, 3042]
        },
        'Las Vegas': {
            'Matchbooks'      : [5057, 5058, 5059, 5060, 5061, 5062, 5063],
            'Cactus'          : [5036, 5037, 5038, 5039, 5040, 5041, 5042],
            'Mojave Animals'  : [5043, 5044, 5045, 5046, 5047, 5048, 5049],
            'Poker Hands'     : [5050, 5051, 5052, 5053, 5056, 5054, 5055]
        },
        'Bangkok': {
            'Chess Set' : [4001, 4002, 4003, 4004, 4005, 4006, 4007],
            'Masks'     : [4008, 4009, 4010, 4011, 4012, 4013, 4014],
            'Spices'    : [4015, 4016, 4017, 4018, 4019, 4020, 4021],
            'Carvings'  : [4022, 4023, 4024, 4025, 4026, 4027, 4028],
            'Orchids'   : [4029, 4030, 4031, 4032, 4033, 4034, 4035]
        },
        'Italy': {
            'Dinner Is Served'   : [6001, 6002, 6003, 6004, 6005, 6006, 6007],
            'Roman Standards'    : [6008, 6009, 6010, 6011, 6012, 6013, 6014],
            'The Great Inventor' : [6015, 6016, 6017, 6018, 6019, 6020, 6021],
            'Famous Rulers'      : [6022, 6023, 6024, 6025, 6026, 6027, 6028]
        }
    };
    
    /** @constructor
     * @param {Number} itemsPerPage
     * @return {userController}
     */
    var userController = function(itemsPerPage) {
        var userIds, friends, currPage, currCat = 0;
        
        this.setItemsPerPage = function(n) {
            itemsPerPage = n;
        };
        
        this.setCat = function(cat) {
            if (typeof(friends[cat]) !== 'undefined') {
                currCat = cat;
            }
        };
        
        this.currentPage = function(set) {
            if (set = parseInt(set)) {
                return currPage[currCat] = (set < 1) ? 1 : (set > this.pages()) ? this.pages() : set;
            }
            return currPage[currCat];
        };
        
        this.getPageItems = function(page) {
            if (!options.get('userPages')) {
                return friends[currCat];
            }
            var maxLength = friends[currCat].length;
            var startIndex = (this.currentPage(page) - 1) * itemsPerPage;
            var endIndex = startIndex + itemsPerPage;
            
            return friends[currCat].slice(startIndex, (endIndex > maxLength ? maxLength : endIndex));
        };
        
        this.getItem = function(id) {
            return userIds[id];
        };
        
        this.getName = function(id) {
            if (userIds[id]) {
                return userIds[id].name;
            }
            return 'ERROR';
        };
        
        this.pages = function() {
            if (options.get('giftPages')) {
                return Math.floor(friends[currCat].length / itemsPerPage) + 1;
            }
            return 1;
        };
        
        this.updateFavorites = function() {
            var fav = options.get('userFav');
            friends[1] = [];
            currPage[1] = 1;
            for (var i = 0; i < fav.length; i++) {
                friends[1].push(userIds[fav[i]]);
            }
        };
        
        this.search = function(text) {
            if (typeof(text) !== 'string') {
                text = '';
            }
            friends[2] = [];
            currPage[2] = 1;
            if (text.length < 1) {
                return;
            }
            for (var i = 0; i < friends[0].length; i++) {
                if (friends[0][i].name.toLowerCase().match(text.toLowerCase())) 
                    friends[2].push(friends[0][i]);
            }
        };
        
        this.update = function(data) {
            resetData();
            for (var i in data.groups_levels) {
                if (!data.groups_levels[i].match('Unknown')) {
                    friends[0].push(userIds[i] = {
                        'id'   : i,
                        'name' : data.groups_levels[i]
                    });
                }
            }
            friends[0].sort(_Util.sortByName);
            this.updateFavorites();
        }
        
        function resetData() {
            friends = {0: [],1: [],2: []};
            userIds = {};
            currPage = {0: 1,1: 1,2: 1};
            currCat = 0;
        }
        resetData();
        return this;
    };
    /**
     * @constructor
     * @param {Number} itemsPerPage
     * @return {giftController}
     */
    var giftController = function(itemsPerPage) {
        var freeGift, filterItems, giftIds, currPage, currCat = 0;
        
        this.selected = {};
        
        this.setItemsPerPage = function(n) {
            itemsPerPage = n;
        };
        
        this.setCat = function(cat) {
            if (typeof(freeGift[cat]) !== 'undefined') {
                currCat = cat;
            }
        };
        
        this.currentPage = function(set) {
            if (set = parseInt(set)) {
                return currPage[currCat] = (set < 1) ? 1 : (set > this.pages()) ? this.pages() : set;
            }
            return currPage[currCat];
        };
        
        this.getPageItems = function(page) {
            var category = getCategory();
            if (!options.get('giftPages')) {
                return category;
            }
            var maxLength = category.length;
            var startIndex = (this.currentPage(page) - 1) * itemsPerPage;
            var endIndex = startIndex + itemsPerPage;
            
            return category.slice(startIndex, (endIndex > maxLength ? maxLength : endIndex));
        };
        
        this.getItem = function(cat, id) {
            return giftIds[cat][id];
        };
        
        this.pages = function() {
            if (options.get('giftPages')) {
                return Math.floor(getCategory().length / itemsPerPage) + 1;
            }
            return 1;
        };
        
        this.lootFilter = function(nf) {
            filterItems[1] = [];
            currPage[1] = 1;
            
            var gift, bActive, bInactive, bAttack, bDefense, bType, bQuality, bLocation; 
            var nEvalAttack  = (parseInt(nf.attack.q) || 0) * nf.attack.op;
            var nEvalDefense = (parseInt(nf.defense.q) || 0) * nf.defense.op;
            
            for (var i = 0; i < freeGift[1].length; i++) {
                gift = freeGift[1][i];
                
                bActive   = (gift.active == true && nf.active) || (gift.active == false && nf.inactive);
                bAttack   = nEvalAttack == 0 || (gift.attack * nf.attack.op) > nEvalAttack;
                bDefense  = nEvalDefense == 0 || (gift.defense * nf.defense.op) > nEvalDefense;
                bType     = nf.ItemTypes.length === 0 || nf.ItemTypes[gift.type] === true;
                bQuality  = nf.Qualities.length === 0 || nf.Qualities[gift.quality] === true;
                bLocation = nf.Locations.length === 0 || nf.Locations[gift.location] === true;
                
                if (bActive && bAttack && bDefense && bType && bQuality && bLocation) {
                    filterItems[1].push(gift);
                }
            }
        };
        
        this.clearLootFilter = function() {
            filterItems[1] = null;
        };
        
        this.collectionFilter = function(group, id) {
            if (group == 'all') {
                filterItems[0] = null;
                return;
            }
            filterItems[0] = [];
            currPage[0] = 1;
            
            var filterArray = [], gift;
            
            if (id == 'all') {
                $.each(collectionFilter[group], function(name, arr) {
                    filterArray = $.merge(filterArray, arr);
                });
            }
            else {
                filterArray = collectionFilter[group][id];
            }
            for (var i = 0; i < freeGift[0].length; i++) {
                gift = freeGift[0][i];
                
                if (filterArray.indexOf(parseInt(gift.id)) !== -1) {
                    filterItems[0].push(gift);
                }
            }
        };
        
        this.clearCollectionFilter = function() {
            filterItems[0] = null;
        };
        
        this.search = function(text) {
            if (typeof(text) !== 'string') {
                text = '';
            }
            freeGift[4] = [];
            currPage[4] = 1;
            if (text.length < 1) {
                return;
            }
            for (var c in gift_categories) {
                for (var i = 0; i < freeGift[c].length; i++) {
                    if (freeGift[c][i].name.toLowerCase().match(text.toLowerCase())) 
                        freeGift[4].push(freeGift[c][i]);
                }
            }
        };
        
        this.updateFavorites = function() {
            var fav = options.get('giftFav');
            freeGift[3] = [];
            currPage[3] = 1;
            var cat = 0, id = 0;
            for (var i = 0; i < fav.length; i++) {
                cat = fav[i].charAt(0);
                id = fav[i].substring(2);
                freeGift[3].push(giftIds[cat][id]);
            }
        };
        
        this.select = function(cat, id) {
            this.selected = giftIds[cat][id];
        };
        
        this.updateAmounts = function(new_amounts) {
            var item;
            for (var c in gift_categories) {
                for (var i = 0; i < freeGift[c].length; i++) {
                    freeGift[c][i].amount = new_amounts[c][freeGift[c][i].id];
                }
            }
        };
        
        this.update = function(data, Items) {
            var item, info, cache = options.get('giftCache');
            resetData();
            for (var c in gift_categories) {
                for (var i in data.item_names[c]) {
                    freeGift[c].push(item = giftIds[c][i] = {
                        cat     : c,
                        id      : i,
                        name    : data.item_names[c][i],
                        amount  : data.item_amounts[c][i],
                        img     : data.item_imgs[c][i]
                    });
                    if (c == 1 && typeof(info = Items.data[i]) !== 'undefined') {
                        item.type     = info.type;
                        item.attack   = info.attack;
                        item.defense  = info.defense;
                        item.quality  = info.quality;
                        item.location = info.location;
                        item.active   = info.active;
                        item.eqoff    = info.equipped_offense;
                        item.eqdef    = info.equipped_defense;
                        item.image    = info.image;
                    }
                }
            }
            this.updateFavorites();
        };
        
        function getCategory() {
            return filterItems[currCat] || freeGift[currCat];
        }
        
        function resetData() {
            filterItems = {0: null, 1: null};
            freeGift = {0: [], 1: [], 2: [], 3: [], 4: [], 5: []};
            giftIds = {0: {}, 1: {}, 2: {}};
            currPage = {0: 1, 1: 1, 2: 1, 3: 1, 4: 1};
            currCat = 0;
        }
        
        resetData();
        return this;
    };
    
    var Inventory = new giftController(50);
    var Friends = new userController(50);
    var Controller = {
        user: Friends,
        gift: Inventory
    };
    
    var popupElt = new domPopupObject('multigifter_popup', {
        title: 'Multi Gifter',
        type: 'persistent',
        css: {
            'width': 732,
            'left': 11,
            'top': 40
        },
        onclose: function() {
            sendTimer.clear();
            _Event.cancel_click();
            options.fromDomElements();
            options.save();
        }
    });
    
    var _Util = {
        changeCategory: function(name, index) {
            $('#'+name+'_category')[0].selectedIndex = index;
            $('#'+name+'_category').change();
        },
        namesFromIds: function(ids) {
            var names = [];
            for (var i = 0; i < ids.length; i++) {
                names.push(Friends.getName(ids[i]));
            }
            return names;
        },
        sortByName: function(a, b) {
            var x = a.name.toLowerCase();
            var y = b.name.toLowerCase();
            return ((x < y) ? -1 : ((x > y) ? 1 : 0));
        },
        isSameArray: function(arr1, arr2) {
            var max = Math.max(arr1.length, arr2.length);
            for (var i = 0; i < max; i++) {
                if (arr1[i] != arr2[i]) {
                    return false
                }
            }
            return true;
        },
        isSameGift: function(gift1, gift2) {
            return (gift1 === gift2 || gift1.id == gift2.id && gift1.cat == gift2.cat);
        },
        getGift: function() {
            return Inventory.selected;
        },
        getUsers: function(elem) {
            var users = [];
            
            $('#selected_users').children().each(function(i, elem) {
                users.push(elem.id.substring(5));
            });
            
            return users;
        },
        deleteJob: function(id) {
            if (Queue.length > 1) {
                Queue.splice(id, 1);
                rebuildBatchProcess();
            }
            else {
                _Event.delQueue_click();
            }
            tryShowControls();
        }
    };
    
    var showDiv = function(name, ms) {
        if (already_working)
            return;
        $('*[id*=_controls]').hide();
        if (ms)
            $('#'+name+'_controls').fadeIn(ms);
        else
            $('#'+name+'_controls').show();
    };
    
    var showTab = function(name) {
        $('*[id^=tab_]', popupElt.content).hide();
        $('#tab_' + name, popupElt.content).show();
    };
    
    var cancelProcess = function() {
        Queue = [];
        already_working = false
        showDiv('finish', 'slow');
    };
    
    var tryShowControls = function(ms) {
        if (Queue.length > 0 || Inventory.selected.id && 
            $('#selected_users').children().length > 0) 
        {
            showDiv('start', ms);
        }
        else {
            $('#global_messages').css('color', 'white')
            .html('You have ' + gift_count_avail + ' gifts left to send today (10000 daily).');
            showDiv('message', ms);
        }
    };
    
    var getGiftData = function(html) {
        var groups_levels, item_amounts, item_names, item_imgs, gifts_daily_left;
        var startIndex = html.indexOf('var groups_levels');
        var lastIndex = html.indexOf('var friends_names', startIndex)-1;
        
        eval(html.substr(startIndex, lastIndex - startIndex));
        
        return {
            'gifts_daily_left' : gifts_daily_left,
            'groups_levels'    : groups_levels,
            'item_amounts'     : item_amounts,
            'item_names'       : item_names,
            'item_imgs'        : item_imgs
        };
    };
    
    var getInventoryData = function(html) {
        var Items, ItemTypes, Locations, Qualities; 
        var startIndex = html.indexOf('var Items');
        var lastIndex = html.indexOf('</script>', startIndex)-1;
        
        eval(html.substr(startIndex, lastIndex - startIndex));
        
        InventoryFilter.ItemTypes = ItemTypes.data;
        InventoryFilter.Locations = Locations.data;
        InventoryFilter.Qualities = Qualities.data;
        
        return Items;
    };
    
    // EVENTS
    var _Event = {
        selectAll_click: function() {
            $('.checkboxlist[name='+$(this).attr('name')+'] input:checkbox').attr('checked', 'checked');
            return false;
        },
        selectNone_click: function() {
            $('.checkboxlist[name='+$(this).attr('name')+'] input:checkbox').attr('checked', '');
            return false;
        },
        showTab_click: function() {
            showTab($(this).attr('name'));
            return false;
        },
        filterItems_click: function() {
            Inventory.lootFilter(buildLootFilter());
            _Util.changeCategory('gift', 1);
            return false;
        },
        clearFilter_click: function() {
            Inventory.clearLootFilter();
            _Util.changeCategory('gift', 1);
            return false;
        },
        collectionFilterType_change: function() {
            updateCollectionFilterData($(this).val());
            return false;
        },
        collectionFilter_change: function() {
            Inventory.collectionFilter($(this).attr('group'), $(this).val());
            _Util.changeCategory('gift', 0);
            return false;
        },
        saveSearch: function() {
            var name = prompt('Write the name of the new search:', 'MySearch');
            if (name) {
                options.get('search').push({name:name,text:$('#search_gift').val()});
                options.save();
                loadSavedSearch();
            } 
            return false;
        },
        removeSearch: function() {
            var index = $('#saved_search')[0].selectedIndex;
            if (index === 0) {
                return false;
            }
            if (confirm('Are you sure to delete this Search?')) {
                options.get('search').splice($('#saved_search')[0].selectedIndex-1, 1);
                loadSavedSearch();
                $('#search_gift').val('').change();
            }
            return false;
        },
        textFocus: function() {
            this.select();
            return false;
        },
        giftAddRemove_click: function() {
            var self = $(this).parent();
            addRemoveFav('gift', self.attr('gcat')+'_'+self.attr('gid'), $(this).hasClass('remove'));
            $(this).toggleClass('remove', $(this).hasClass('remove') == false);
            return false;
        },
        userAddRemove_click: function() {
            addRemoveFav('user', $(this).parent().attr('uid'), $(this).hasClass('remove'));
            $(this).toggleClass('remove', $(this).hasClass('remove') == false);
            return false;
        },
        search_change: function() {
            var index = this.selectedIndex-1;
            if (index < 0) {
                $('#search_gift').val('').change();
                return false;
            }
            $('#search_gift').val(options.get('search')[index].text).change();
            return false;
        },
        removeUser_click: function() {
            var id = $(this).parent().attr('id');
            $(this).parent().remove();
            $('li[uid=' + id.substring(5) + ']').toggleClass('selected', false);
            tryShowControls();
            return false;
        },
        user_click: function() {
            var self = $(this).parent();
            var selected = e$('#user_'+self.attr('uid'), '#selected_users');
            if (selected !== null) {
                $('a', selected).click();
                return false;
            }
            selectUser(self.attr('uid'));
            self.toggleClass('selected', true);
            tryShowControls();
            return false;
        },
        gift_click: function() {
            var self = $(this).parent();
            selectGift(self.attr('gcat'), self.attr('gid'));
            return false;
        },
        clearUsers_click: function() {
            $('li.selected', '#user_list').toggleClass('selected', false);
            $('#selected_users').empty();
            tryShowControls();
            return false;
        },
        addRem_click: function() {
            var action = $('#count_addrem').attr('action');
            var count = $(this).attr('amount');
            
            if (action == 'add') {
                addGiftToQueue(count);
            }
            else {
                addGiftToQueue('-'+ count);
            }
            return false;
        },
        finish_click: function() {
            $('#multigift_queue').empty();
            globalMessage();
            return false;
        },
        showLog_click: function() {
            $('#multigift_queue').empty()
            c$('textarea', 'readonly:readonly,rows:15,cols:80')
            .appendTo('#multigift_queue').html(plainTextLog).css({
                'margin-top': 5,
                'border': 'medium none',
                'background-color': 'transparent',
                'color': 'white'
            });
            return false;
        },
        toggleAction_click: function() {
            var action = $(this).attr('action');
            if (action == 'add') {
                $('#start_controls a[amount]').removeClass('green').addClass('red');
                $(this).attr('action', 'remove').html('REMOVE');
            }
            else {
                $('#start_controls a[amount]').removeClass('red').addClass('green');
                $(this).attr('action', 'add').html('ADD');
            }
            return false;
        },
        cancel_click: function() {
            already_working = false;
            return false;
        },
        delQueue_click: function() {
            Queue = [];
            $('#multigift_queue').empty();
            gift_count_avail = daily_left;
            return false;
        },
        start_click: function() {
            if (Queue.length > 0) {
                showDiv('status');
                already_working = true;
                startBatchProcess();
            }
            else {
                globalMessage('Please, add a job before start.', 'green');
            }
            return false;
        },
        deleteJob_click: function() {
            var n = this.id.substring(10);
            if (!isNaN(n)) {
                _Util.deleteJob(parseInt(n));
            }
            return false;
        },  
        category_change: function() {
            var index = this.selectedIndex;
            var name = $(this).attr('name');
            
            if (name == 'gift') {
                $('div[id^=filter_container]').hide();
                (e$('#filter_container_' + index) || $('#filter_container_msg')).show();
            }
            
            Controller[name].setCat(index);
            updatePageDownList(name);
            $('#'+name+'_page')[0].selectedIndex = Controller[name].currentPage() - 1;
            $('#'+name+'_page').change();
            
            //showTab('selected_gift'); 
        },
        giftPage_change: function() {
            showPage('gift', this.selectedIndex+1);
        },
        userPage_change: function() {
            showPage('user', this.selectedIndex+1);
        },
        prevPage_click: function() {
            var name = $(this).attr('name');
            
            if (Controller[name].currentPage() > 1) {
                $('#'+name+'_page')[0].selectedIndex = Controller[name].currentPage() - 2;
                $('#'+name+'_page').change();
            }
            return false;
        },
        nextPage_click: function() {
            var name = $(this).attr('name');
            
            if (Controller[name].currentPage() < Controller[name].pages()) {
                $('#'+name+'_page')[0].selectedIndex = Controller[name].currentPage();
                $('#'+name+'_page').change();
            }
            return false;
        },
        swithGiftPages_click: function() {
            options.fromDomElements();
            options.save();
            updatePageDownList('gift');
            $('#gift_page').change();
        },
        swithUserPages_click: function() {
            options.fromDomElements();
            options.save();
            updatePageDownList('user');
            $('#user_page').change();
        },
        doSearch: function() {
            $('#search_'+$(this).attr('name')).change();
        },
        input_change: function() {
            var name = this.id.substring(7);
            
            Controller[name].search(this.value.toLowerCase());
            _Util.changeCategory(name, (name == 'gift' ? 4 : 2));
        }
    };
    function genMainDom() {
        
        var selectOpts = {
            'attack_more_less': 
                {1:'More', '-1':'Less'},
            'defense_more_less': 
                {1:'More', '-1':'Less'},
            'gift_category': 
                {0:'Collections', 1:'Loot', 2:'Boosts', 3:'Favorites', 4:'Search'},
            'user_category': 
                {0:'All MW Friends', 1:'Favorites', 2:'Search'},
            'collection_filter_type': 
                {'All': 'all'}
        };
        
        // GIFT BAR
        var giftBarElt = c$('div', 'class:controlbar').appendTo(popupElt.content);
        
        c$('div', 'class:leftside').appendTo(giftBarElt)
        .append(c$('select', 'class:black,id:gift_category,name:gift').width(200).change(_Event.category_change))
        .append(c$('input:checkbox', 'multigift_giftpages').css('margin-left',5).change(_Event.swithGiftPages_click))
        .append(c$('label', 'for:multigift_giftpages').text('Use Pages.'))
        .append(
            c$('div', 'id:gift_page_box').css('float', 'right')
            .append(c$('a','name:gift,id:mgpage_prev,href:#,class:active').click(_Event.prevPage_click))
            .append(c$('select', 'class:black,id:gift_page').width(70).change(_Event.giftPage_change))
            .append(c$('a','name:gift,id:mgpage_next,href:#,class:active').click(_Event.nextPage_click))
        );
        
        c$('div', 'class:rightside').appendTo(giftBarElt)
        .append(b$('Show Filters', 'name:filter').addClass('short white').click(_Event.showTab_click))
        .append(b$('Show Search', 'name:search').addClass('short white').click(_Event.showTab_click));
        
        c$('div', 'id:gift_list,class:item_list').css('float','left').appendTo(popupElt.content);
        
        var tabContainerElt = c$('div', 'class:tab_container').appendTo(popupElt.content);
        
        // SELECTED GIFT TAB
        c$('center', 'tab_selected_gift').appendTo(tabContainerElt)
        .append(c$('div').text('Selected gift:'))
        .append(c$('div', 'id:giftcard, class:ItemCardBox').css({
            'cursor': 'default',
            'margin-top': 5,
            'width': 'auto'
        }));
        
        // COLLECTION FILTER TAB
        var filterTabElt = c$('div', 'tab_filter').hide().appendTo(tabContainerElt);
        
        c$('div', 'filter_container_0').css('padding',20).appendTo(filterTabElt)
        .append(c$('label', 'for:collection_filter_type').text('Select Collection Type:'))
        .append('<br />')
        .append(
            c$('select', 'class:black,id:collection_filter_type').width(250)
            .change(_Event.collectionFilterType_change)
        )
        .append('<br /><br />')
        .append(c$('label', 'for:collection_filter').text('Select Collection Name:'))
        .append('<br />')
        .append(
            c$('select', 'class:black,id:collection_filter').width(250)
            .change(_Event.collectionFilter_change)
        );
        
        // LOOT FILTER TAB
        var tab = new domTabObject(
            c$('div', 'filter_container_1').hide().appendTo(filterTabElt),
            'filter_list',['GENERAL','TYPE','QUALITY','ORIGIN'], 110
        );
        
        // General
        tab.getLayout(0).css('padding', '0px 5px')
        .append(c$('input:checkbox', 'id:active_filter,checked:checked'))
        .append(c$('label', 'for:active_filter').text('Active items.'))
        .append(c$('input:checkbox', 'id:inactive_filter,checked:checked'))
        .append(c$('label', 'for:inactive_filter').text('Inactive items.'))
        .append('<br /><br />')
        .append(c$('span').text('Attack is: '))
        .append(c$('select', 'class:black,id:attack_more_less'))
        .append(c$('span').text(' than '))
        .append(c$('input:text', 'class:black,id:attack_amount').width(60))
        .append('<br />')
        .append(c$('span').text('Defense is: '))
        .append(c$('select', 'class:black,id:defense_more_less'))
        .append(c$('span').text(' than '))
        .append(c$('input:text', 'class:black,id:defense_amount').width(60));
        
        // Type
        tab.getLayout(1).append(c$('ul', 'class:checkboxlist, name:ItemTypes'))
        .append(
            c$('center').css('margin', 10)
            .append(b$('Select All', 'name:ItemTypes').click(_Event.selectAll_click))
            .append('<br /><br />')
            .append(b$('Select None', 'name:ItemTypes').click(_Event.selectNone_click))
        );
        
        // Quality
        tab.getLayout(2).append(c$('ul', 'class:checkboxlist, name:Qualities'))
        .append(
            c$('center').css('margin', 10)
            .append(b$('Select All', 'name:Qualities').click(_Event.selectAll_click))
            .append('<br /><br />')
            .append(b$('Select None', 'name:Qualities').click(_Event.selectNone_click))
        );
        
        // Location
        tab.getLayout(3).append(c$('ul', 'class:checkboxlist, name:Locations'))
        .append(
            c$('center').css('margin', 10)
            .append(b$('Select All', 'name:Locations').click(_Event.selectAll_click))
            .append('<br /><br />')
            .append(b$('Select None', 'name:Locations').click(_Event.selectNone_click))
        );  
        
        $('#filter_container_1').append(
            c$('center').css('margin-top', 2)
            .append(b$('Filter Items', 'class:short white').click(_Event.filterItems_click))
            .append(b$('Clear Filter', 'class:short white').css('margin-left',5).click(_Event.clearFilter_click))
        );
        
        // FILTER MESSAGE
        c$('div', 'filter_container_msg').hide().appendTo(filterTabElt)
        .append(c$('center').css('margin', 10).text('Filter work only with "Collection" and "Loot" categories.'));

        // ADD FILTER OPTIONS
        $.each(InventoryFilter, function(filterName, obj) {
            var chkList = $('ul[name='+filterName+']');
            
            $.each(obj, function(name, value) {
                var sText = typeof(value) == 'string' ? value : value.name;
                
                c$('li').appendTo(chkList)
                .append(c$('input:checkbox', 'id:'+filterName+'_'+name+',checked:checked').val(name))
                .append(c$('label', 'for:'+filterName+'_'+name).text(sText));
            }); 
        });
        
        // SEARCH TAB
        c$('div', 'tab_search').css('padding-top',20).hide().appendTo(tabContainerElt)
        .append(c$('div').append(c$('label','for:search_gift').text('Type the text to search:')))
        .append(c$('input:text','class:black,id:search_gift').width(200).focus(_Event.textFocus).change(_Event.input_change))
        .append(b$('Go', 'class:short white,name:gift').css('margin-left',5).click(_Event.doSearch))
        .append(b$('Save', 'class:short white').css('margin-left',5).click(_Event.saveSearch))
        .append('<br /><br />')
        .append(c$('div').append(c$('label', 'for:saved_search').text('Select a saved search:')))
        .append(c$('select', 'class:black,id:saved_search').width(220).change(_Event.search_change))
        .append(b$('Remove', 'class:short white').css('margin-left',5).click(_Event.removeSearch))
        
        // USER
        giftBarElt = c$('div', 'class:controlbar').css('margin-top', 10).appendTo(popupElt.content);
        
        c$('div', 'class:leftside').appendTo(giftBarElt)
        .append(c$('select', 'class:black,id:user_category,name:user').width(200).change(_Event.category_change))
        .append(c$('input:checkbox', 'multigift_userpages').css('margin-left',5).change(_Event.swithUserPages_click))
        .append(c$('label', 'for:multigift_userpages').text('Use Pages.'))
        .append(
            c$('div', 'id:user_page_box').css('float','right')
            .append(c$('a','name:user,id:mgpage_prev,href:#,class:active').click(_Event.prevPage_click))
            .append(c$('select', 'class:black,id:user_page').width(70).change(_Event.userPage_change))
            .append(c$('a','name:user,id:mgpage_next,href:#,class:active').click(_Event.nextPage_click))
        );

        c$('div', 'class:rightside').appendTo(giftBarElt)
        .append(c$('label','for:search_user').text('Search:'))
        .append(
            c$('input:text', 'class:black,id:search_user').width(150)
            .focus(_Event.textFocus).change(_Event.input_change)
        )
        .append(b$('Go', 'class:short white,name:user').css('margin-left',5).click(_Event.doSearch))
        .append(
            c$('div').css('float', 'right')
            .append(
                c$('a', 'href:#,title:Clear all selected friends.')
                .html('(Clear)').click(_Event.clearUsers_click)
            )   
        );
        
        c$('div', 'id:user_list,class:item_list').appendTo(popupElt.content);
        c$('div', 'id:selected_users').appendTo(popupElt.content);
        
        var controls = c$('div', 'class:controls').appendTo(popupElt.content);
        
        // global_messages
        c$('div', 'message_controls').appendTo(controls).append('<span id="global_messages">');
        
        // CONTROL
        c$('div', 'start_controls').appendTo(controls)
        .append(
            c$('div', 'class:gift_delay')
            .append(c$('label', 'for:multigift_delay').html('Delay:&nbsp;'))
            .append(c$('input:text', 'class:black,id:multigift_delay').width(30).focus(_Event.textFocus))
        )       
        .append(
            c$('span').width(50).append(
                c$('a','id:count_addrem,action:add').html('ADD').click(_Event.toggleAction_click)
            )
        ) 
        .append(b$('1', 'amount:1').addClass('medium green').click(_Event.addRem_click))
        .append(b$('5', 'amount:5').addClass('medium green').click(_Event.addRem_click))
        .append(b$('10', 'amount:10').addClass('medium green').click(_Event.addRem_click))
        .append(b$('25', 'amount:25').addClass('medium green').click(_Event.addRem_click))
        .append(b$('50', 'amount:50').addClass('medium green').click(_Event.addRem_click))
        .append(b$('ALL', 'amount:all').addClass('medium green').click(_Event.addRem_click)) 
        .append(b$('START').addClass('short orange').click(_Event.start_click))
        .append(b$('DELETE QUEUE').addClass('short orange').click(_Event.delQueue_click));
        
        // FINISH
        c$('div', 'finish_controls').appendTo(controls)
        .append(b$('FINISH').addClass('short orange').click(_Event.finish_click))
        .append(b$('SHOW LOG').addClass('short orange').click(_Event.showLog_click));
            
        // STATUS 
        var status_control = c$('div', 'status_controls').appendTo(controls);
        
        b$('CANCEL', 'cancel_button').appendTo(status_control)
        .addClass('short orange').click(_Event.cancel_click);
        
        c$('img').attr('src', global.resource.ajax_loader).appendTo(status_control);
        
        c$('div', 'class:job_status').appendTo(status_control)
        .append(c$('span', 'class:current_job').text('Current Job:'))
        .append(c$('div', 'status_current_job_text'))
        .append(c$('span', 'next_gift_timer'))
        .append(c$('br'))
        .append(c$('div', 'status_send_message'));
            
        // QUEUE
        c$('div', 'multigift_queue').appendTo(popupElt.content);
        updatePageDownList('user');
        updatePageDownList('gift');
        loadSavedSearch();
        
        applySelectOptions(selectOpts, popupElt.content);
        
        var collectionFilterTypeElt = $('#collection_filter_type');
        for (var i in collectionFilter) {
            collectionFilterTypeElt.append(c$('option', 'value:'+i).text(i));
        }
        
        updateCollectionFilterData('all');
    }
    
    function updateCollectionFilterData(id) {
        var collectionFilterElt = $('#collection_filter').attr('group', id).empty()
        .append(c$('option', 'value:all').text('All'));
        
        if (typeof(collectionFilter[id]) !== 'undefined') {
            for (var i in collectionFilter[id]) {
                collectionFilterElt.append(c$('option', 'value:'+i).text(i));
            }
        }
        collectionFilterElt.change();
    }
    
    function loadSavedSearch() {
        var elem = $('#saved_search').empty()
                   .append(c$('option', 'value:-1').text('None'));
        var searchList = options.get('search');
        
        for (var i = 0; i < searchList.length; i++) {
            elem.append(c$('option', 'value:'+i).text(searchList[i].name));
        }
    }
    
    function updatePageDownList(name) {
        var elem = $('#'+name+'_page').empty();
         
        for (var i = 0, len = Controller[name].pages(); i < len; i++) {
            elem.append(c$('option', 'value:'+i).text((i + 1) + '/' + len));
        }
        
        $('#'+name+'_page_box')[options.get(name+'Pages') ? 'show' : 'hide']();
    }
    
    var selectGift = function(cat, id) {
        Inventory.select(cat, id);
        $('li.selected', '#gift_list').toggleClass('selected', false);
        $('li[gcat='+cat+'][gid='+id+']', '#gift_list').toggleClass('selected', true);
        $('#giftcard').empty().append( buildCard(Inventory.selected) );
        showTab('selected_gift');
        tryShowControls();
    }
    
    function selectUser(id) {
        if (e$('#user_' + id) !== null) {
            return;
        }
        c$('div', 'user_' + id).appendTo('#selected_users').text(Friends.getName(id))
        .append(c$('a').text('X').click(_Event.removeUser_click));
    }
    
    function showPage(listName, page) {
        var i, shtml = '';
        var elem = {
            'user': function(item) {
                var r = '<li uid="' + item.id + '"><div class="checkbox">' + item.name + '</div>';
                r += '<a title="Add/Remove from favorites" ';
                
                if (options.get('userFav').indexOf(item.id) === -1) {
                    r += 'class="favorite"></a></li>';
                }
                else {
                    r += 'class="favorite remove"></a></li>';
                }
                return r;
            },
            'gift': function(item) {
                var r = '<li gcat="' + item.cat + '" gid="' + item.id + '">';
                r += '<img src="' + item.img + '">';
                r += '<div class="item_name">' + item.name;
                r += ' (<span class="more_in">' + item.amount + '</span>)';
                if ((item.attack && item.attack > 0) || (item.defense && item.defense > 0)) {
                    r += ' (<span class="more_in">';
                    r += item.attack + '|' + item.defense + '</span>)';
                }
                r += '</div><a title="Add/Remove from favorites" ';
                if (options.get('giftFav').indexOf(item.cat + '_' + item.id) === -1) {
                    r += 'class="favorite"></a></li>';
                }
                else {
                    r += 'class="favorite remove"></a></li>';
                }
                return r;
            }
        };
        
        var pageArray = Controller[listName].getPageItems(page);
        
        for (i = 0; i < pageArray.length; i++) {
            shtml += elem[listName](pageArray[i]);
        }
        
        $('#'+listName+'_list').html('<ul>'+shtml+'</ul>');
        delete shtml;
        
        $('div', '#'+listName+'_list').click(_Event[listName+'_click']);
        
        if (listName == 'user') {
            $('#selected_users').children().each(function(index,elem) {
                $('#user_list li[uid='+elem.id.substring(5)+']').addClass('selected');
            });
        }
        else if (Inventory.selected.id) {
            i = Inventory.selected;
            $('#gift_list li[gid='+i.id+'][gcat='+i.cat+']').addClass('selected');
        }
        
        $('a', '#'+listName+'_list').click(_Event[listName+'AddRemove_click']);
        
    }
    
    function addRemoveFav(lstName, value, remove) {
        var list = options.get(lstName+'Fav');
        if (remove === true) {
            list.splice(list.indexOf(value), 1);
        }
        else {
            list.push(value);
        }
        options.save();
        Controller[lstName].updateFavorites();
    }
    
    function buildLootFilter() {
        var new_filter = {
            active   : $('#active_filter')[0].checked,
            inactive : $('#inactive_filter')[0].checked,
            attack   : { 
                op : parseInt( $('#attack_more_less').val()) || 0,
                q  : parseInt( $('#attack_amount').val() ) || 0
             },
            defense  : { 
                op : parseInt( $('#defense_more_less').val() ) || 0,
                q  : parseInt( $('#defense_amount').val() ) || 0 
            }
        };
        
        $('.checkboxlist').each(function(list_index, list_elem) {
            var current_list = new_filter[$(list_elem).attr('name')] = {};
            
            $('input:checkbox', list_elem).each(function(i, elem) {
                if (elem.checked) {
                    current_list[elem.value] = true;
                }
            });
        });
        
        return new_filter;
    }
    
    function buildCard(gift) {
        var ItemQuantity
        var iconSrc = 'http://mwfb.static.zgncdn.com/mwfb/graphics/inventory/ItemCard/icons/';
        
        var card = c$('div', 'class:defenseCard equipped visible').css({
            'float': 'none',
            'text-align': 'left'
        })
        .append(c$('div', 'class:itemCardName').text(gift.name))
        .append(
            c$('div', 'class:itemCardQuantity').html('x'+gift.amount)
            .append(ItemQuantity = c$('span').css('margin-left', 5))
        )
        .append(c$('div', 'class:itemCardImage').html(gift.image || '<img src="'+gift.img+'">'));
        
        if (parseInt(gift.cat) == 1) {
            
            c$('div', 'class:attack_defense').appendTo(card)
            .append(
                c$('span', 'class:attack').text(gift.attack).css({
                    'margin-left': 17,
                    'padding-right': 6
                })
            )
            .append(c$('span', 'class:defense').text(gift.defense));
            
            var imgTitle = (gift.active ? 'Active item - Your Mafia is using this item in fights/robs.' : 
                                          'Inactive item - Your Mafia is not using this item in fights/robs.');
                                          
            c$('div', 'class:icon equippedIcon').appendTo(card)
            .append(
                c$('img', 'title:'+imgTitle)
                .attr('src', iconSrc+'Inventory-'+(gift.active?'':'in')+'active-icon.png')
            );
            
            c$('div', 'class:icon').appendTo(card).html(InventoryFilter.Qualities[gift.quality].image);
            
            if ((gift.eqoff && gift.eqoff > 0) || (gift.eqdef && gift.eqdef > 0)) {
                ItemQuantity
                .append('(')
                .append(c$('span', 'title:Number active on attack.').css('color', '#FF9121').text(gift.eqoff))
                .append('/')
                .append(c$('span', 'title:Number active on defense.').css('color', '#609AD1').text(gift.eqdef))
                .append(')');
            }
        }
        
        return card;
    }
    
    function globalMessage(msg, color) {
        var text = msg || 'You have ' + gift_count_avail + ' gifts left to send today (10000 daily).';
        if (daily_left) {
            $('#global_messages').css('color', color || 'white').html('<strong>'+text+'</strong>');
        }
        showDiv('message');
        setTimeout(tryShowControls, 4000);
    }
    
    function addGiftToQueue(quantity) {
        var qID = -1;
        var recipients = _Util.getUsers();
        var giftToSend = _Util.getGift();
        var maxAmounts = giftToSend.amount || 0;
        var giftCount = 0;
        // handle total gift count and gift count.
        for (var i = 0; i < Queue.length; i++) {
            if (Queue[i].quantity) {
                // total count
                giftCount += (Queue[i].quantity * Queue[i].recip.length);
                if (_Util.isSameGift(Queue[i].gift, giftToSend)) {
                    // gift count
                    maxAmounts -= (Queue[i].quantity * Queue[i].recip.length); 
                    if (_Util.isSameArray(Queue[i].recip, recipients))
                        qID = i; // job exist
                }
            }
        }
        
        // Fix amount per user
        maxAmounts = Math.floor(maxAmounts / recipients.length);
        var maxQuantity = Math.min(maxAmounts, daily_left - giftCount);
        switch(quantity) {
            case 'all':  quantity = maxQuantity;            break;
            case '-all': quantity = giftToSend.amount * -1; break;
            default:     quantity = parseInt(quantity);     break;
        }
        // check all is ok
        if (giftToSend.cat < 0 || giftToSend.id < 1) {
            globalMessage('Please, select a gift to send.', 'red');
            return false;
        }
        if (recipients.length < 1) {
            globalMessage('Please, select the user to send gift.', 'red');
            return false;
        }
        if (typeof(quantity) == 'undefined') {
            globalMessage('You need to set the gift amount.', 'red');
            return false;
        }
        if (maxQuantity < 1 && quantity > 0) {
            globalMessage('You dont have gifts left to send.', 'red');
            return false;
        }
        // fix quantity
        quantity = Math.min(quantity, maxQuantity)
        // all ok, add job to queue
        if (qID > -1) {
            Queue[qID].quantity += quantity;
        }
        else {
            qID = Queue.length;
            Queue[qID] = {
                thisID:   qID,
                gift:     giftToSend,
                recip:    recipients,
                quantity: quantity,
                giftSend: 0
            };
        }
        gift_count_avail = daily_left - giftCount;
        gift_count_avail -=  (Math.max(0, quantity) * recipients.length);

        if (Queue[qID].quantity > 0)
            addBatchProcess(qID);
        else
            _Util.deleteJob(qID);
        
        return true;
    }
    function rebuildBatchProcess() {
        var giftCount = 0;
        $('#multigift_queue').empty();
        for (var i = 0; i < Queue.length; i++) {
            Queue[i].thisID = i;
            giftCount += (Queue[i].quantity * Queue[i].recip.length);
            addBatchProcess(i);
        }
        gift_count_avail = daily_left - giftCount;
    }
    function addBatchProcess(id) {
        var item = Queue[id];
        var jobID = 'queue_item_' + id;
        var message = 'Send ' + item.quantity + ' ' + item.gift.name + '(s) To ';
        if (item.recip.length == 1) {
            message += '<span style="color: yellow;">' ;
            message += Friends.getName(item.recip[0]) + '.</span>';
        }
        else {
            message += '<span title="'+ _Util.namesFromIds(item.recip).join(', ');
            message += '" style="color: yellow; cursor: pointer;">'
            message += item.recip.length+ ' users.</span>';
        }
        var updateItem = e$('#'+jobID) || 
        c$('div', 'class:queue_item,id:'+jobID).prependTo('#multigift_queue');
        
        updateItem.empty();
        c$('div','class:update_timestamp').appendTo(updateItem).html(new Date().toUTCString());
        c$('div','class:status').append(c$('div')).appendTo(updateItem);
        c$('div','class:icon').appendTo(updateItem).append(c$('img').attr({
            'width': 40,
            'height': 40,
            'src': item.gift.img
        }));
        var table = new domTableObject(updateItem, 2, 2);
        c$('span').css('float', 'right').text('Job:').appendTo(table.cell(0,0));
        c$('span').css('float', 'right').text('Status:').appendTo(table.cell(1,0));
        c$('span', 'class:job_txt,id:queue_item_status_'+id).text('Waiting.').appendTo(table.cell(1,1));
        c$('span', 'class:job_txt,id:queue_job_name').appendTo(table.cell(0,1)).html(message);
        
        b$('delete', 'delete_id_'+id).click(_Event.deleteJob_click)
        .appendTo(updateItem).css('float','right');
    }
    function getFixedGiftCount(q) {
        q = parseInt(q);
        return (q>49)?50 : (q>24)?25 : (q>9)?10 : (q>4)?5 : 1;
    }
    function startBatchProcess() {
        if (Queue.length < 1)             
            return;
        
        var params, job, message_header = '';
        var timerInterval = function(delay, fn) {
            sendTimer.start('Next in %N% sec.', delay, fn);
        }
        
        // Hide all delete buttons of batch process to prevent errors
        $('*[id^="delete_id_"]', '#multigift_queue').hide();
        // empty plain text log
        plainTextLog = '';
        // start a new job
        function startNewJob() 
        {
            // set current job
            job = Queue[0];
            // set link parameters
            params = {
                'gift_category':job.gift.cat,
                'gift_count':   1,
                'gift_id':      job.gift.id,
                'gift_key':     gift_key,
                'sendkey':      ''
            };
            for (var i = 0; i < job.recip.length; i++) {
                params['recipients['+i+']'] = job.recip[i];
            }
            $('#status_current_job_text')
            .text('Sending ' + (job.quantity * job.recip.length) + ' ' + job.gift.name + '(s)');
            $('#queue_item_status_' + job.thisID).text('Working...');
            sendGift();
        }
        // end the current job
        function endCurrentJob()
        {
            plainTextLog += '# Sent '+ job.giftSend + ' ' + job.gift.name;
            plainTextLog += '(s) to ' + _Util.namesFromIds(job.recip).join(', ') + '\n';
            // delete finished job or abort all
            if (!already_working)
                Queue = [];
            else
                Queue.splice(0, 1);
                
            $('.status > div', '#queue_item_' + job.thisID).addClass('complete');
            
            if (Queue.length > 0) 
                startNewJob();
            else 
                cancelProcess();
        }
        // send a gift
        function sendGift() {
            if (!already_working) {
                endCurrentJob();
                return;
            }
            // Fix quantity to send 
            params['gift_count'] = getFixedGiftCount(job.quantity);
            // update status
            $('#next_gift_timer').html('Sending now.');
            $('#status_send_message')
            .html('Sending ' + params['gift_count'] + ' ' + job.gift.name + '.');
            // send gift
            ajaxRequest({
                url: 'remote/' + getIntURL('gift', 'send'),
                liteLoad: 0,
                data: params,
                success: function(htmlText) 
                {
                    if (mw_updater(htmlText) !== true) {
                        timerInterval(10, sendGift);
                        return;
                    }
                    Inventory.updateAmounts(getGiftData(htmlText).item_amounts);
                        
                    var amount = job.gift.amount || 0;
                    $('.more_in',
                      '#gift_list li[gid=' + job.gift.id + '][gcat=' + job.gift.cat + ']'
                    ).text(amount);
                    
                    message_header = h$(htmlText).find('.message_body').text();
                    
                    $('#status_send_message').html(message_header);
                    $('#next_gift_timer').html('Next in ' + $('#multigift_delay').val() + ' sec.');
                    
                    if (/You\s*gave|Has\s*dado|Du\s*hast|Vous\s*avez\s*donn|Hai\s*dato/i.test(message_header)) 
                    {
                        job.quantity = Math.min(job.quantity - params['gift_count'], amount);
                        job.giftSend += params['gift_count'];
                        if (job.quantity > 0) {
                            timerInterval($('#multigift_delay').val(), sendGift);
                        }
                        else {
                            timerInterval($('#multigift_delay').val(), endCurrentJob);
                        }
                    }
                    else if (amount > 0) 
                    {
                        timerInterval(10, sendGift);
                    }
                    else 
                    {
                        timerInterval($('#multigift_delay').val(), endCurrentJob);
                    }
                    $('#queue_item_status_' + job.thisID).html(
                        'You have sent ' + (job.giftSend * job.recip.length) + ' ' + job.gift.name + '(s).'
                    );
                }
            });
        }
        // Start all batch process.
        startNewJob();
    }

    function Initialize() {
        ajaxRequest({
            url: 'remote/' + getIntURL('gift'),
            message: 'Loading friend list...',
            success: function(htmlText) 
            {
                if (mw_updater(htmlText) !== true) {
                    popupElt.destroy();
                    badServerResponse();
                    return;
                }
                var data = getGiftData(htmlText);
                
                Friends.update(data);
                
                daily_left        = data.gifts_daily_left;
                gift_count_avail  = data.gifts_daily_left;
                gift_key          = doRegex(/gift_key['"]\s*value=['"]([^'"]+)/, htmlText).$1;
                
                log$(gift_key);
                log$('daily_left: ' + data.gifts_daily_left);
                
                ajaxRequest({
                    url: 'remote/' + getIntURL('inventory'),
                    message: 'Loading inventory data...',
                    success: function(htmlText) 
                    {
                        if (mw_updater(htmlText) !== true) {
                            popupElt.destroy();
                            badServerResponse();
                            return;
                        }
                        log$('Loading inventory...');
                        Inventory.update(data, getInventoryData(htmlText));
                        log$('Inventory loaded...');
                        
                        genMainDom();
                        popupElt.selectGift = selectGift;
                        
                        if (select_gift_cat && select_gift_id) {
                            selectGift(select_gift_cat, select_gift_id);
                        }
                        
                        _Util.changeCategory('gift', (options.get('giftFav').length > 0) ? 3 : 0);
                        _Util.changeCategory('user', (options.get('userFav').length > 0) ? 1 : 0);
                        
                        globalMessage();
                        
                        options.toDomElements();
                        showDiv('none');
                        // show popup
                        popupElt.show();
                    }
                });
            }
        });
    }
    
    popupElt.addBase64Style(
        'I211bHRpZ2lmdGVyX3BvcHVwIC5ibGFjayB7DQoJZm9udC13ZWlnaHQ6IGJvbGQ7DQoJY29sb3I6IHJnYigyMDgsIDIwOCwgMjA4'+
        'KTsgDQoJYm9yZGVyOiAxcHggc29saWQgcmdiKDE1MywgMTUzLCAxNTMpOyANCgliYWNrZ3JvdW5kLWNvbG9yOiBibGFjazsgDQoJ'+
        'Zm9udC1zaXplOiAxNHB4Ow0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwIGEgew0KCXRleHQtZGVjb3JhdGlvbjogbm9uZTsNCn0NCiNt'+
        'dWx0aWdpZnRlcl9wb3B1cCBkaXYuY29udHJvbGJhciB7DQoJYmFja2dyb3VuZC1pbWFnZTogdXJsKGh0dHA6Ly9td2ZiLnN0YXRp'+
        'Yy56Z25jZG4uY29tL213ZmIvZ3JhcGhpY3MvbWFwX2Jhc2VkX2pvYnMvZXhwZXJ0X3ZpZXcvZXhwZXJ0dmlld19uYXZfbWlkLmdp'+
        'Zik7DQoJYm9yZGVyLWNvbG9yOiBibGFjazsNCgljbGVhcjogYm90aDsNCgloZWlnaHQ6IDM1cHg7DQoJdGV4dC1hbGlnbjogbGVm'+
        'dDsNCgl3aWR0aDogYXV0bzsNCn0NCiNtdWx0aWdpZnRlcl9wb3B1cCBkaXYuY29udHJvbGJhciAqIHsNCgl2ZXJ0aWNhbC1hbGln'+
        'bjogbWlkZGxlOw0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwIGRpdi5jb250cm9sYmFyIGRpdi5sZWZ0c2lkZSB7DQoJZmxvYXQ6IGxl'+
        'ZnQ7DQoJcGFkZGluZzogNXB4IDBweCA1cHggNXB4Ow0KCXdpZHRoOiA0MDBweDsNCn0NCiNtdWx0aWdpZnRlcl9wb3B1cCBkaXYu'+
        'Y29udHJvbGJhciBkaXYucmlnaHRzaWRlIHsNCglmbG9hdDogbGVmdDsNCgltYXJnaW4tbGVmdDogMTVweDsNCglwYWRkaW5nOiA1'+
        'cHg7DQp9DQojbXVsdGlnaWZ0ZXJfcG9wdXAgZGl2LmNvbnRyb2xiYXIgZGl2LnJpZ2h0c2lkZSBhIHsNCgltYXJnaW4tcmlnaHQ6'+
        'IDZweDsNCn0NCiNtdWx0aWdpZnRlcl9wb3B1cCBkaXYudGFiX2NvbnRhaW5lciB7DQoJdGV4dC1hbGlnbjogbGVmdDsNCglmbG9h'+
        'dDogbGVmdDsNCgloZWlnaHQ6IDE1MHB4Ow0KCW1hcmdpbjogNXB4Ow0KCXdpZHRoOiAzMTVweDsNCn0NCiNtdWx0aWdpZnRlcl9w'+
        'b3B1cCBkaXYuY29udHJvbHMgew0KCWJhY2tncm91bmQtaW1hZ2U6IHVybChodHRwOi8vbXdmYi5zdGF0aWMuemduY2RuLmNvbS9t'+
        'd2ZiL2dyYXBoaWNzL21hcF9iYXNlZF9qb2JzL2V4cGVydF92aWV3L2V4cGVydHZpZXdfbmF2X21pZC5naWYpOw0KCWhlaWdodDog'+
        'MzhweDsNCgl0ZXh0LWFsaWduOiBjZW50ZXI7DQoJd2lkdGg6IGF1dG87DQoJYm9yZGVyLWNvbG9yOiBibGFjazsNCgljbGVhcjog'+
        'Ym90aDsJDQp9DQojbXVsdGlnaWZ0ZXJfcG9wdXAgZGl2LmNvbnRyb2xzICNzdGFydF9jb250cm9scyBhLm1lZGl1bSB7DQoJbWFy'+
        'Z2luLWxlZnQ6IDVweDsNCgltYXJnaW4tdG9wOiAycHg7DQp9DQojbXVsdGlnaWZ0ZXJfcG9wdXAgZGl2LmNvbnRyb2xzICNzdGFy'+
        'dF9jb250cm9scyBhLnNob3J0IHsNCgltYXJnaW4tbGVmdDogNXB4Ow0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwIGRpdi5jb250cm9s'+
        'cyAjZmluaXNoX2NvbnRyb2xzIGEuc2hvcnQgew0KCW1hcmdpbjogNHB4Ow0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwIGRpdi5jb250'+
        'cm9scyAjbWVzc2FnZV9jb250cm9scyB7DQoJd2lkdGg6IGF1dG87DQoJcGFkZGluZy10b3A6IDEwcHg7DQp9DQojbXVsdGlnaWZ0'+
        'ZXJfcG9wdXAgZGl2LmNvbnRyb2xzICNzdGF0dXNfY29udHJvbHMgew0KCWhlaWdodDogMzVweDsNCn0NCiNtdWx0aWdpZnRlcl9w'+
        'b3B1cCBkaXYuY29udHJvbHMgI3N0YXR1c19jb250cm9scyAjY2FuY2VsX2J1dHRvbiB7DQoJbWFyZ2luLXJpZ2h0OiAzMHB4Ow0K'+
        'CW1hcmdpbi10b3A6IDRweDsJDQoJZmxvYXQ6IHJpZ2h0Ow0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwIGRpdi5jb250cm9scyAjc3Rh'+
        'dHVzX2NvbnRyb2xzIGltZ3sNCglmbG9hdDogbGVmdDsNCgltYXJnaW46IDEwcHggMHB4IDEwcHggMTVweDsNCn0NCiNtdWx0aWdp'+
        'ZnRlcl9wb3B1cCBkaXYuY29udHJvbHMgI3N0YXR1c19jb250cm9scyAuam9iX3N0YXR1cyB7DQoJZmxvYXQ6IGxlZnQ7DQoJbWFy'+
        'Z2luLWxlZnQ6IDQwcHg7DQoJdGV4dC1hbGlnbjogbGVmdDsNCn0NCiNtdWx0aWdpZnRlcl9wb3B1cCBkaXYuY29udHJvbHMgI3N0'+
        'YXR1c19jb250cm9scyAuam9iX3N0YXR1cyAuY3VycmVudF9qb2Igew0KCWZsb2F0OiBsZWZ0Ow0KCW1hcmdpbi1yaWdodDogNXB4'+
        'Ow0KCWNvbG9yOiBncmVlbjsNCn0NCiNtdWx0aWdpZnRlcl9wb3B1cCBkaXYuY29udHJvbHMgI3N0YXR1c19jb250cm9scyAuam9i'+
        'X3N0YXR1cyAjbmV4dF9naWZ0X3RpbWVyIHsNCglmbG9hdDogbGVmdDsNCgltYXJnaW4tbGVmdDogNXB4Ow0KfQ0KI211bHRpZ2lm'+
        'dGVyX3BvcHVwIGRpdi5jb250cm9scyAjc3RhdHVzX2NvbnRyb2xzIC5qb2Jfc3RhdHVzICNzdGF0dXNfY3VycmVudF9qb2JfdGV4'+
        'dCB7DQoJd2lkdGg6IDMwMHB4Ow0KCWZsb2F0OiBsZWZ0Ow0KCWNvbG9yOiBncmV5Ow0KCW92ZXJmbG93OiBhdXRvOw0KCW1heC13'+
        'aWR0aDogMzAwcHg7DQoJbWF4LWhlaWdodDogMTlweDsNCn0NCiNtdWx0aWdpZnRlcl9wb3B1cCBkaXYuY29udHJvbHMgI3N0YXR1'+
        'c19jb250cm9scyAuam9iX3N0YXR1cyAjc3RhdHVzX3NlbmRfbWVzc2FnZSB7DQoJd2lkdGg6IDUwMHB4Ow0KCW92ZXJmbG93OiBo'+
        'aWRkZW47DQoJbWF4LXdpZHRoOiA1MDBweDsNCgltYXgtaGVpZ2h0OiAxOXB4Ow0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwICBkaXYu'+
        'Z2lmdF9kZWxheSB7DQoJZmxvYXQ6IGxlZnQ7DQoJbWFyZ2luOiA1cHg7DQoJdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KI211bHRp'+
        'Z2lmdGVyX3BvcHVwICNtZ3BhZ2VfcHJldiB7DQoJYmFja2dyb3VuZDogdHJhbnNwYXJlbnQgdXJsKGh0dHA6Ly9td2ZiLnN0YXRp'+
        'Yy56Z25jZG4uY29tL213ZmIvZ3JhcGhpY3MvaW52ZW50b3J5L0ZpbHRlckRyb3BEb3duL2ludmVudG9yeV9hcnJvd19pbmFjdGl2'+
        'ZV9sZWZ0LnBuZykgbm8tcmVwZWF0Ow0KCWN1cnNvcjogZGVmYXVsdDsNCglsaW5lLWhlaWdodDogMTZweDsNCglwYWRkaW5nLWxl'+
        'ZnQ6IDE2cHg7DQoJd2lkdGg6IDE2cHg7DQp9DQojbXVsdGlnaWZ0ZXJfcG9wdXAgI21ncGFnZV9wcmV2LmFjdGl2ZSB7DQoJYmFj'+
        'a2dyb3VuZDogdHJhbnNwYXJlbnQgdXJsKGh0dHA6Ly9td2ZiLnN0YXRpYy56Z25jZG4uY29tL213ZmIvZ3JhcGhpY3MvaW52ZW50'+
        'b3J5L0ZpbHRlckRyb3BEb3duL2ludmVudG9yeV9hcnJvd19hY3RpdmVfbGVmdC5wbmcpIG5vLXJlcGVhdDsNCgljdXJzb3I6IHBv'+
        'aW50ZXI7DQp9DQojbXVsdGlnaWZ0ZXJfcG9wdXAgI21ncGFnZV9uZXh0ew0KCWJhY2tncm91bmQ6IHRyYW5zcGFyZW50IHVybCho'+
        'dHRwOi8vbXdmYi5zdGF0aWMuemduY2RuLmNvbS9td2ZiL2dyYXBoaWNzL2ludmVudG9yeS9GaWx0ZXJEcm9wRG93bi9pbnZlbnRv'+
        'cnlfYXJyb3dfaW5hY3RpdmVfcmlnaHQucG5nKSBuby1yZXBlYXQ7DQoJY3Vyc29yOiBkZWZhdWx0Ow0KCWxpbmUtaGVpZ2h0OiAx'+
        'NnB4Ow0KCXBhZGRpbmctbGVmdDogMTZweDsNCgl3aWR0aDogMTZweDsNCn0NCiNtdWx0aWdpZnRlcl9wb3B1cCAjbWdwYWdlX25l'+
        'eHQuYWN0aXZlIHsNCgliYWNrZ3JvdW5kOiB0cmFuc3BhcmVudCB1cmwoaHR0cDovL213ZmIuc3RhdGljLnpnbmNkbi5jb20vbXdm'+
        'Yi9ncmFwaGljcy9pbnZlbnRvcnkvRmlsdGVyRHJvcERvd24vaW52ZW50b3J5X2Fycm93X2FjdGl2ZV9yaWdodC5wbmcpIG5vLXJl'+
        'cGVhdDsNCgljdXJzb3I6IHBvaW50ZXI7DQp9DQojbXVsdGlnaWZ0ZXJfcG9wdXAgICNzZWxlY3RlZF91c2VycyB7DQoJZmxvYXQ6'+
        'IHJpZ2h0Ow0KCW1hcmdpbi1yaWdodDogNXB4Ow0KCXdpZHRoOiAzMDBweDsNCglib3JkZXI6IDFweCBzb2xpZCByZ2IoMTUzLCAx'+
        'NTMsIDE1Myk7DQoJaGVpZ2h0OiAxNjBweDsNCglvdmVyZmxvdzogYXV0bzsNCglmb250LXNpemU6IDEycHg7DQp9DQojbXVsdGln'+
        'aWZ0ZXJfcG9wdXAgICNzZWxlY3RlZF91c2VycyBkaXYgew0KCWJhY2tncm91bmQtY29sb3I6ICMzMzM7DQoJbWFyZ2luOiAycHg7'+
        'DQoJcGFkZGluZzogMnB4Ow0KCXRleHQtYWxpZ246IGxlZnQ7DQp9DQojbXVsdGlnaWZ0ZXJfcG9wdXAgICNzZWxlY3RlZF91c2Vy'+
        'cyBkaXYgYSB7DQoJZmxvYXQ6IHJpZ2h0Ow0KCW1hcmdpbi1sZWZ0OiA1cHg7DQp9DQojbXVsdGlnaWZ0ZXJfcG9wdXAgI211bHRp'+
        'Z2lmdF9xdWV1ZSB7DQoJd2lkdGg6IGF1dG87DQoJaGVpZ2h0OiAzMjBweDsNCgl0ZXh0LWFsaWduOiBsZWZ0Ow0KCXBhZGRpbmc6'+
        'IDBweCA2cHg7DQoJYm9yZGVyOiAxcHggc29saWQgcmdiKDE1MywgMTUzLCAxNTMpOw0KCWNsZWFyOiBib3RoOw0KCW92ZXJmbG93'+
        'LXg6IGhpZGRlbjsNCglvdmVyZmxvdy15OiBhdXRvOw0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwICNtdWx0aWdpZnRfcXVldWUgZGl2'+
        'LnF1ZXVlX2l0ZW0gew0KCWJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjMzMzOw0KCWNsZWFyOiBib3RoOw0KCWZsb2F0OiBsZWZ0'+
        'Ow0KCW1hcmdpbi10b3A6IDVweDsNCglwYWRkaW5nLWJvdHRvbTogNXB4Ow0KCXdpZHRoOiBhdXRvOw0KfQ0KI211bHRpZ2lmdGVy'+
        'X3BvcHVwICNtdWx0aWdpZnRfcXVldWUgZGl2LnF1ZXVlX2l0ZW0gZGl2LnN0YXR1cyB7DQoJbWFyZ2luLXJpZ2h0OiAxMHB4Ow0K'+
        'CWJvcmRlcjogMHB4Ow0KCWZsb2F0OiBsZWZ0Ow0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwICNtdWx0aWdpZnRfcXVldWUgZGl2LnF1'+
        'ZXVlX2l0ZW0gZGl2LnN0YXR1cyBkaXYgew0KCWJhY2tncm91bmQ6IHVybCgiaHR0cDovL213ZmIuc3RhdGljLnp5bmdhLmNvbS9t'+
        'd2ZiL2dyYXBoaWNzL2ZsYWdzL213X21lc3NhZ2Vib3hfY2hlY2tib3gyX25vcm1hbGl6ZWQuZ2lmIikgbm8tcmVwZWF0IHNjcm9s'+
        'bCAwJSAwJSB0cmFuc3BhcmVudDsNCgltYXJnaW46IDEwcHg7DQoJbWluLWhlaWdodDogMjBweDsNCgltaW4td2lkdGg6IDIwcHg7'+
        'DQp9DQojbXVsdGlnaWZ0ZXJfcG9wdXAgI211bHRpZ2lmdF9xdWV1ZSBkaXYucXVldWVfaXRlbSBkaXYuc3RhdHVzIGRpdi5jb21w'+
        'bGV0ZSB7DQoJYmFja2dyb3VuZDogdXJsKCJodHRwOi8vbXdmYi5zdGF0aWMuenluZ2EuY29tL213ZmIvZ3JhcGhpY3MvZmxhZ3Mv'+
        'bXdfbWVzc2FnZWJveF9jaGVja2JveDFfbm9ybWFsaXplZC5naWYiKSBuby1yZXBlYXQgc2Nyb2xsIDAlIDAlIHRyYW5zcGFyZW50'+
        'Ow0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwICNtdWx0aWdpZnRfcXVldWUgZGl2LnF1ZXVlX2l0ZW0gZGl2Lmljb24gew0KCWJvcmRl'+
        'cjogMHB4Ow0KCWZsb2F0OiBsZWZ0Ow0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwICNtdWx0aWdpZnRfcXVldWUgZGl2LnF1ZXVlX2l0'+
        'ZW0gdGFibGUgew0KCWZsb2F0OiBsZWZ0Ow0KCW1hcmdpbi1sZWZ0OiAxMHB4Ow0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwICNtdWx0'+
        'aWdpZnRfcXVldWUgZGl2LnF1ZXVlX2l0ZW0gdGFibGUgI3F1ZXVlX2pvYl9uYW1lLmpvYl90eHQgew0KCWZvbnQtd2VpZ2h0OiBi'+
        'b2xkOw0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwICNtdWx0aWdpZnRfcXVldWUgZGl2LnF1ZXVlX2l0ZW0gdGFibGUgLmpvYl90eHQg'+
        'ew0KCWZsb2F0OiBsZWZ0Ow0KCWZvbnQtc2l6ZTogMTJweDsNCgltYXJnaW4tbGVmdDogMTVweDsNCgl2ZXJ0aWNhbC1hbGlnbjog'+
        'dG9wOw0KCWNvbG9yOiB3aGl0ZTsNCgl3aWR0aDogNDUwcHg7DQp9DQojbXVsdGlnaWZ0ZXJfcG9wdXAgLmNoZWNrYm94bGlzdCB7'+
        'DQoJZmxvYXQ6IGxlZnQ7DQoJYm9yZGVyOiAxcHggc29saWQgIzk5OTsNCgloZWlnaHQ6IDEwNHB4Ow0KCW1hcmdpbjogMXB4Ow0K'+
        'CXBhZGRpbmc6IDFweDsNCgl3aWR0aDogMTYwcHg7CQ0KCW92ZXJmbG93LXg6IGhpZGRlbjsNCglvdmVyZmxvdy15OiBhdXRvOw0K'+
        'fQ0KI211bHRpZ2lmdGVyX3BvcHVwIC50YWJfYm94X2NvbnRlbnQgY2VudGVyIHsNCglmbG9hdDogbGVmdDsNCgltYXJnaW46IDVw'+
        'eA0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwIC5pdGVtX2xpc3Qgew0KCWZsb2F0OiBsZWZ0Ow0KCXBhZGRpbmc6IDFweDsNCgl3aWR0'+
        'aDogNDAwcHg7DQoJYm9yZGVyOiAxcHggc29saWQgcmdiKDE1MywgMTUzLCAxNTMpOw0KCW92ZXJmbG93LXg6IGhpZGRlbjsNCglv'+
        'dmVyZmxvdy15OiBhdXRvOw0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwIC5pdGVtX2xpc3QgdWwgew0KCW1hcmdpbjogMHB4OyANCglw'+
        'YWRkaW5nOiAwcHg7DQoJbGlzdC1zdHlsZS10eXBlOiBub25lOw0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwIC5pdGVtX2xpc3QgdWwg'+
        'bGkgew0KCXdpZHRoOiBhdXRvOw0KCW1hcmdpbjogMXB4OyANCgloZWlnaHQ6IDMwcHg7IA0KCWJvcmRlcjogMXB4IHNvbGlkICMz'+
        'MzMzMzM7IA0KCW92ZXJmbG93OiBoaWRkZW47IA0KCWN1cnNvcjogcG9pbnRlcjsNCn0NCiNtdWx0aWdpZnRlcl9wb3B1cCAuaXRl'+
        'bV9saXN0IHVsIGxpIC5mYXZvcml0ZSB7DQoJYmFja2dyb3VuZDogdXJsKCJodHRwOi8vbXdmYi5zdGF0aWMuemduY2RuLmNvbS9t'+
        'd2ZiL2dyYXBoaWNzL3YzL2ljb25fd2lzaGxpc3RfYWRkXzE5eDE0XzAxLmdpZiIpIG5vLXJlcGVhdCBzY3JvbGwgMCUgMCUgdHJh'+
        'bnNwYXJlbnQ7DQoJY3Vyc29yOiBwb2ludGVyOw0KCWZsb2F0OiByaWdodDsNCgloZWlnaHQ6IDE0cHg7DQoJbWFyZ2luOiA4cHg7'+
        'DQoJd2lkdGg6IDE5cHg7DQp9DQojbXVsdGlnaWZ0ZXJfcG9wdXAgLml0ZW1fbGlzdCB1bCBsaSAuZmF2b3JpdGUucmVtb3ZlIHsN'+
        'CgliYWNrZ3JvdW5kOiB1cmwoImh0dHA6Ly9td2ZiLnN0YXRpYy56Z25jZG4uY29tL213ZmIvZ3JhcGhpY3MvdjMvaWNvbl93aXNo'+
        'bGlzdF9yZW1vdmVfMTl4MTRfMDEuZ2lmIikgbm8tcmVwZWF0IHNjcm9sbCAwJSAwJSB0cmFuc3BhcmVudDsNCn0NCiNtdWx0aWdp'+
        'ZnRlcl9wb3B1cCBkaXYjZ2lmdF9saXN0IHsNCgloZWlnaHQ6IDE4MHB4Ow0KfQ0KI211bHRpZ2lmdGVyX3BvcHVwIGRpdiN1c2Vy'+
        'X2xpc3Qgew0KCWhlaWdodDogMTYwcHg7DQp9CQ0KI211bHRpZ2lmdGVyX3BvcHVwIGRpdiNnaWZ0X2xpc3QgdWwgbGkgZGl2Lml0'+
        'ZW1fbmFtZSB7DQoJZmxvYXQ6IGxlZnQ7DQoJd2lkdGg6IDI5MHB4Ow0KCWhlaWdodDogMTdweDsNCglvdmVyZmxvdzogaGlkZGVu'+
        'Ow0KCXBhZGRpbmc6IDZweCAwcHg7DQoJdGV4dC1hbGlnbjogbGVmdDsNCn0NCiNtdWx0aWdpZnRlcl9wb3B1cCBkaXYjZ2lmdF9s'+
        'aXN0IHVsIGxpIGltZyB7DQoJZmxvYXQ6IGxlZnQ7DQoJaGVpZ2h0OiAyNXB4Ow0KCW1hcmdpbjogMnB4IDEwcHg7DQoJd2lkdGg6'+
        'IDI1cHg7DQp9DQojbXVsdGlnaWZ0ZXJfcG9wdXAgZGl2I3VzZXJfbGlzdCB1bCBsaSBkaXYuY2hlY2tib3ggew0KCWJhY2tncm91'+
        'bmQ6IHVybCgiaHR0cDovL213ZmIuc3RhdGljLnp5bmdhLmNvbS9td2ZiL2dyYXBoaWNzL2ZsYWdzL213X21lc3NhZ2Vib3hfY2hl'+
        'Y2tib3gyX25vcm1hbGl6ZWQuZ2lmIikgbm8tcmVwZWF0IHNjcm9sbCAwJSAwJSB0cmFuc3BhcmVudDsNCgl0ZXh0LWFsaWduOiBs'+
        'ZWZ0Ow0KCW1hcmdpbjogNXB4IDBweCAwcHggMTBweDsNCgltaW4taGVpZ2h0OiAyMHB4Ow0KCXdpZHRoOiAzMDBweDsgDQoJcGFk'+
        'ZGluZy1sZWZ0OiAzMHB4OyANCgloZWlnaHQ6IDIwcHg7DQoJY3Vyc29yOiBwb2ludGVyOw0KCWZsb2F0OiBsZWZ0Ow0KfQ0KI211'+
        'bHRpZ2lmdGVyX3BvcHVwIGRpdiN1c2VyX2xpc3QgdWwgbGkuc2VsZWN0ZWQgZGl2LmNoZWNrYm94IHsNCgliYWNrZ3JvdW5kOiB1'+
        'cmwoImh0dHA6Ly9td2ZiLnN0YXRpYy56eW5nYS5jb20vbXdmYi9ncmFwaGljcy9mbGFncy9td19tZXNzYWdlYm94X2NoZWNrYm94'+
        'MV9ub3JtYWxpemVkLmdpZiIpIG5vLXJlcGVhdCBzY3JvbGwgMCUgMCUgdHJhbnNwYXJlbnQ7DQp9DQojbXVsdGlnaWZ0ZXJfcG9w'+
        'dXAgZGl2I2dpZnRfbGlzdCB1bCBsaS5zZWxlY3RlZCB7IA0KCWJvcmRlcjogMXB4IHNvbGlkICNGRkZGMDA7DQp9DQo='
    );
    
    // load options and Initialize.
    options.load(Initialize);
}

/**
 * Show a new popup which start a massive multi-attack mode.
 * @param {String} _sHtmlText
 * @param {String} _sList
 * @param {Function} _callback
 */
function battlefield(_sHtmlText, _sList, _callback) 
{
    const ERROR_SUCCESS = 0;
    const ERROR_BAD_RESPONSE = 1;
    const ERROR_NO_FIGHT_RESULT = 2;
                          
    var statusTimer = new timerMessage('#status_log'); 
    var StartCity = getCurrentCity();
    var CurrentCity = 0;
    var abort_process = false;
    var bfirstRun = true;
    var bAttackWhiteList = false;
    var publishFunctions = [];
    
    var cities = {
        1: ['New York', 'new_york', 65000],
        2: ['Cuba','cuba', 10000],
        3: ['Moscow','moscow', 65000],
        4: ['Bangkok','bangkok', 10000],
        5: ['Las Vegas','vegas', 65000],
        6: ['Italy', 'italy', 65000]
    };
    var logIcon = {
        'asn'      : global.zGraphicsURL + 'AsnFight/victory-coin-55x55.png',
        'loot'     : global.zGraphicsURL + 'achievements/mwach_collector_75x75_01.gif',
        'fight'    : global.zGraphicsURL + 'home/icon_fight_75x75_01.gif',
        'iced'     : global.zGraphicsURL + 'home/icon_hitlist_75x75_01.gif',
        'kill'     : global.zGraphicsURL + 'home/icon_hitlist_75x75_01.gif',
        'stash'    : global.zGraphicsURL + 'achievements/mwach_collector_75x75_01.gif',
        'help'     : global.zGraphicsURL + 'home/icon_call_for_help_75x75_01.gif',
        'heal'     : global.zGraphicsURL + 'red_cross_small.gif',
        'bank'     : global.zGraphicsURL + 'home/icon_loot_75x75_01.gif',
        'whitelist': global.zGraphicsURL + 'DW_feed_grn_01.png',
        'blacklist': global.zGraphicsURL + 'DW_feed_red_01.png'
    };
    var options = new Config('bfopt', {
        maxLogLength    : 40,
        useHeal         : true,
        healIn          : 1,
        healWhen        : 40,
        useBank         : true,
        useBankWhen     : 5000,
        useAttackDelay  : true,
        attackDelay     : 2,
        skipLevel       : false,
        skipLevelWay    : 1,
        skipLevelOf     : 1000,
        skipMafia       : false,
        skipMafiaWay    : 1,
        skipMafiaOf     : 501,
        addUserToWList  : false,
        cashPercent     : 100,
        useAttackCount  : false,
        attackCounter   : 11,
        skipIced        : true,
        skipNoCash      : false,
        usePowerAttack  : true,
        attackEvenLost  : false,
        useNameFilter   : true,
        nameFilter      : '[{(*~|',
        showloot        : true,
        showstash       : true,
        showcoins       : true,
        showhelp        : true,
        showBlackListed : true,
        showWhiteListed : true,
        useBlacklist    : true,
        blackList       : {},
        whiteList       : {},
        stopBeforeLvlUp : true,
        expLeftToStop   : 50,
        stopWhenStamina : false,
        staminaToKeep   : 500
    });
    var fightStats = {
        health         : 0,
        maxHealth      : 0,
        stamina        : 0,
        maxStamina     : 0,
        userCash       : 0,
        totalFight     : 0,
        wonFights      : 0,
        lostFights     : 0,
        experience     : 0,
        victorycoins   : 0,
        blacklisted    : 0,
        whitelisted    : 0,
        iced           : 0,
        kill           : 0,
        money          : 0,
        stash          : 0,
        coins          : 0,
        startGroupAtk  : 0,
        startGroupDef  : 0,
        atkGained      : 0,
        defGained      : 0,
        expToNextLevel : 0,
        
        exp_per_sta: function() 
        {
            if (isNaN(this.experience) || isNaN(this.totalFight) || (this.experience+this.totalFight < 1)) {
                return 0;
            }
            var fixedInt = function(n) {
                return n.toFixed(Math.abs(n) < 10 ? 2 : 0);
            }
            return fixedInt(this.experience / this.totalFight);
        },
        healthpercent: function() 
        {
            if (isNaN(unsafeWindow.User.max_health) || isNaN(this.health) ) {
                return 0;
            }
            return parseFloat((this.health * 100) / unsafeWindow.User.max_health);
        },
        cash: function() 
        {
            var m = this.money, s = '';
            if (m > 1000) {
                m = parseInt(m/1000);
                s = 'k';
            }   
            return '' + m + s;
        }
    };
    var _Util = {
        htmlDecode: function(text) {
            return $.trim(c$('textarea').html(text).val());
        },
        /**
         * Return a Hex color string.
         * @param {String} color
         */
        rgbToHex: function(color) {
            if (typeof(color) !== 'string' || color.length < 1) 
                return color;
            
            if (color.charAt(0) !== '#') {
                var rgx, rgb;
                if ((rgx = /rgba?\((\d+)[,\s]*(\d+)[,\s]*(\d+)\)/.exec(color))) {
                
                    rgb = 1 << 24 | parseInt(rgx[1]) << 16 | parseInt(rgx[2]) << 8 | parseInt(rgx[3]);
                    return '#' + rgb.toString(16).substr(1);
                }
            }
            while (color.length < 7) {
                color += '0';
            }
            return String(color).toLowerCase();
        },
        getUrlAndId: function(text) {
            var rgx;
            if ((rgx = /\d+[,\s'"]*([^"']+)[,\s'"]*([^'"]+)['"]/.exec(text+''))) {
                return {url: rgx[1], id: this.getNumber(rgx[2])};
            }
            return {url: '', id: 0};
        },
        getNumber: function(text) {
            var new_text = String(text).replace(/\D*/g, '');
            return (new_text.length > 0) ? parseInt(new_text) : 0;
        },
        toArray: function(obj) {
            var new_array = [], opp;
            $.each(obj, function(id, name) {
                if (parseInt(id) && typeof(name) === 'string');
                    new_array.push({'id':id , 'name':name});
            });
            return new_array;
        },
        opponentListed: function(name, id) {
            return typeof(options.get(name)[id]) !== 'undefined';
        },
        applyColor: function(text, color) {
            return '<span style="color: ' + color + ';">' + text + '</span>';
        },
        getLevel: function(elem) {
            return this.getNumber(
                $(elem).contents().filter(function() {
                    return this.nodeType === 3;
                }).text()
            );
        },
        addStashCount: function(html, count) {
            return html.replace(/popFightLootFeed_\d+/g, 'popFightLootFeed_'+count)
                       .replace(/fight_loot_feed_btn_\d+/g, 'fight_loot_feed_btn_'+count);
        },
        addIcedCount: function(html, count) {
            return html.replace(/postFeedAndSendFightBrag/g,'postFeedAndSendFightBrag_'+count)
                       .replace(/#pop_bg_\d+/gi, '#feed_send_fight_btn'+count); 
        },
        addCoinsCount: function(html, count) {
            return html.replace(/postW2Wback/g, 'postW2Wback_'+count)
                       .replace(/share_asn_feed/g, 'share_asn_feed_'+count)
                       .replace(/ASNFightW2Wcallback/g, 'ASNFightW2Wcallback_'+count);
                       
        }
    };
    /**
     * Create a new fight result query
     * @constructor
     * @param {Object} str
     * @return {queryResult}
     */
    var queryResult = function(data) {
        var obj  = h$(data).find('.fight_results');
        var plr  = $('.fightres_player', obj);
        var opp  = $('.fightres_opponent', obj);
        
        this.hint         = $('.fightres_hint > span', obj);
        this.title        = $('.fightres_title', obj);
        this.health       = $('.fightres_stats > .fightres_health', obj);
        this.damage       = $('.fightres_stats > .fightres_damage', obj);
        this.experience   = $('.fightres_stats > .fightres_experience', obj);
        this.attackAgain  = $('.sexy_button_new:regex(onclick,action=attack)', obj).attr('onclick');
        this.pwrAttack    = $('.sexy_button_new:regex(onclick,action=power_attack)', obj).attr('onclick');
        this.cash         = $('.fightres_stats > div[class^=sexy_]', obj);
        this.vCoin        = $('img:regex(src,victory_icon)', obj).parent();
        this.share_asn    = $('#asn_fight_module > div:eq(1), #share_asn_feed', obj);
        this.bonuses      = $('.fightres_bonuses', obj);
        this.won          = this.title.hasClass('good');
        
        this.player = {
            name:         $('.fightres_name > a', plr).text(),
            image:        $('.fightres_image > img', plr),
            groupSize:    $('.fightres_fightstats > .fightres_group_size', plr).text(),
            groupAttack:  $('.fightres_fightstats > .fightres_group_attack', plr).text(),
            groupDefense: h$(data).find('.fightbar_group_stat > div:eq(1)').text(),
            skillAttack:  $('.fightres_fightstats > .fightres_skill_attack', plr).text()
        };
        this.opponent = {
            name:         $('.fightres_name > a', opp).text(),
            image:        $('.fightres_image > img', opp),
            groupSize:    $('.fightres_fightstats > .fightres_group_size', opp).text(),
            groupDefense: $('.fightres_fightstats > .fightres_group_defense', opp).text(),
            skillDefense: $('.fightres_fightstats > .fightres_skill_defense', opp).text()
        };
        
        delete obj, plr, opp;
        return this;
    };
    /**
     * Player opponent
     * @constructor
     * @param {Number} id
     * @param {String} title
     * @param {String} name
     * @param {Number} level
     * @param {Number} mafia
     * @param {String} url
     * @return {fightOpponent}
     */
    var fightOpponent = function(id, title, name, level, mafia, profile, url) {
        
        this.id      = _Util.getNumber(id);
        this.title   = title;
        this.name    = name;
        this.level   = parseInt(level);
        this.mafia   = parseInt(mafia);
        this.profile = '<a href="'+profile+'" target="_black">'+name+'</a>';
        this.url     = url;
        this.pw_url  = null;
        this.fights  = 0;
        this.alive   = false;
        this.win     = false;
        
        return this;
    };

    var _List = {
        players: [],
        /**
         * @type {fightOpponent}
         */
        current: undefined,
        
        sortBy: {
            'name': function(a, b) {
                var x = a.name.toLowerCase();
                var y = b.name.toLowerCase();
                return ((x < y) ? -1 : ((x > y) ? 1 : 0));
            },
            'level': function(a, b) {
                return b.level - a.level;
            },
            'mafia': function(a, b) {
                return b.mafia - a.mafia;
            }
        },
        /**
         * Add opponent to list
         * @param {String} list
         * @param {fightOpponent} opp
         */
        addToList: function(list, opp) {
            try {
                if (!_Util.opponentListed(list, opp.id)) {
                    log$('adding to ' + list + ': ' + opp.id);
                }
                var mafia = (opp.mafia > 0 ? ' mafia ' + opp.mafia : '');
                // add to list
                options.get(list)[opp.id] = opp.name + '  level ' + opp.level + mafia;
                return true; 
            }
            catch(err) {
                logErr$(err);
                return false;
            }
        },
        addCurrentToBlackList: function() {
            return this.addToList('blackList', this.current);
        },
        addCurrentToWhiteList: function() {
            return this.addToList('whiteList', this.current);
        },
        setRandomCurrent: function() {
            return this.setCurrent(Math.floor(Math.random() * this.players.length));
        },
        /**
         * Set the current opponent
         * @param {Number} id
         * @return {fightOpponent}
         */
        setCurrent: function(id) {
            if (this.players.length < 1) {
                return this.current = undefined;
            }
            if (typeof id == 'undefined') {
                return this.current;
            }
            id = parseInt(id);
            this.current = this.players[id];
            if (this.players.length > 1)
                this.players.splice(id, 1);
            else
                this.players = new Array();
            
            return this.current;
        },
        /**
         * Add a new opponent to list
         * @param {fightOpponent} opponent
         */
        add: function(opponent) {
            if (this.players.length > 30) {
                this.players = [];
                if (this.current) 
                    this.players.push(this.current);
            }
            this.players.push(opponent);
        },
        length: function() {
            return this.players.length;
        },
        clear: function() {
            this.players = [];
            this.current = undefined;
        },
        sort: function(by) {
            this.players.sort(this.sortBy[by]);
        },
        each: function(fn) {
            if (typeof fn !== 'function')
                return;
            for (var i = this.players.length - 1; i >= 0; i--) {
                fn.apply(this.players[i], [i, this.players[i]]);
            }   
        }
    };
    var getSelectedListKey = function(listName) {
        return $('#bfopt_'+listName).find('option[selected]');
    };
    // EVENTS
    var _Event = {
        addNewToList_click: function() {
            var listName = $(this).attr('name');
            
            var profileUrl = showPromptPopup(
                'Paste here all MW profiles by line delimited:', '',
                function(text) { addMWProfiles(listName, text); }
            );
            return false;
        },
        deleteSelected_click: function() {
            var name = $(this).attr('name').toLowerCase();
            $('option[selected]', '#bfopt_'+name).remove();
            options.fromDomElements();
            options.save();
            return false;
        },
        clearList_click: function() {
            var name = $(this).attr('name');
            $('#bfopt_'+name.toLowerCase()).empty();
            options.set(name, {});
            options.save();
            return false;
        },
        mwProfile_click: function() {
            var name = $(this).attr('name').toLowerCase();
            var url = 'http://facebook.mafiawars.com/mwfb/remote/'+getIntURL('stats');
            var selectedElts = $('#bfopt_'+name).find('option[selected]');
            if (selectedElts.length === 0) {
                showHelpPopup({
                    icon: 'info',
                    title: 'No opponents selected.',
                    message: 'You need to select at least one opponent for go to his profile page.'
                });
                return;
            }
            if (selectedElts.length < 2 || confirm('Are you sure to open ALL selected users?')) {
                selectedElts.each(function(index, elem) {
                    unsafeWindow.open(url + '&user=p|' + elem.value);
                });
            }
            return false;
        },
        addFromList_click: function() {
            var name = $(this).attr('name');
            var list = options.get(name);
            
            showPromptPopup(
                'Paste here the encoded list to add:', '', 
                function(resp) 
                {
                    if (typeof(resp) !== 'string' || resp.length < 2) {
                        return;
                    }
                    var index = resp.indexOf('base64,');
                    if (index > 0) {
                        resp = global.Base64.decode(resp.substr(index + 7));
                    }
                    $.each($.parseJSON(resp), function(name, value) {
                        if (parseInt(name)) 
                            list[name] = value;
                    });
                    options.toDomElements();
                    options.save();
                }
            );
            return false;
        },
        getList_click: function() {
            var name = $(this).attr('name');
            var sOutput = String($.toJSON(options.get(name)));
            if (sOutput.length < 5) {
                return false;
            }
            showTextPopup(
                'Copy this encoded text to save or share your list:', 
                'data:application/json;base64,' + global.Base64.encode(sOutput)
            );
            return false;
        },
        sort_click: function() {
            _List.sort(this.id.match(/sort_by_(\w+)/)[1]);
            genEnemyListDom();
            return false;
        },
        refresh_click: function() {
            showDiv('status', '_panel');
            $('#manual_fight').empty();
            autoModeMessage('Refreshing target list...', true, true);
            options.fromDomElements();
            setTimeout(function() {
                _List.clear();
                refreshPlayerList(function() {
                    if (_List.length() > 0) {
                        genEnemyListDom();
                    }
                    else {
                        $('#manual_fight').append(
                            c$('center').css({'padding':40, 'font-weight':'bold', 'font-size':14})
                            .text('No players found. Try change filters and click "Refresh".')
                        );
                    }
                    showDiv('start', '_panel', 500);
                });
            }, 500);
            return false;
        },
        attack_click: function() {
            abort_process = false;
            options.fromDomElements();
            var id = this.id.match(/attack_id_(\d+)/)[1];
            var url = _List.setCurrent(id).url;
            updateNewOpponent();
            showDiv('ajaxloader', '_panel');
            showDiv('fightlog', '_list');
            showDiv('fight', '_div');
            $('#manual_fight').empty();
            manualAttack(url);
            return false;
        },
        powerAttack_click: function() {
            updateStats();
            showDiv('ajaxloader', '_panel');
            manualAttack(_List.current.pw_url);
            return false;
        },
        attackAgain_click: function() {
            updateStats();
            showDiv('ajaxloader', '_panel');
            manualAttack(_List.current.url);
            return false;
        },
        runAway_click: function() {
            bAttackWhiteList = false;
            options.setToElement('blackList');
            options.setToElement('whiteList');
            options.save();
            showDiv('', '_panel');
            if (_List.length() > 0) {
                genEnemyListDom();
            }
            $('#massacre_health_sign').hide();
            $('.leaders_rewards', '#fight_div')
            .children().stop().css('opacity', 1).hide();
            showDiv('start', '_panel', 500);
            showDiv('fightplayer', '_list');
            showDiv('options', '_div');
            return false;
        },
        autoMode_click: function() {
            abort_process = false;
            $('#attack_again_button, #power_attack_button').hide();
            options.fromDomElements();
            _List.setRandomCurrent();
            updateNewOpponent();
            showDiv('status', '_panel', 500);
            showDiv('fightlog', '_list');
            showDiv('fight', '_div');
            $('#manual_fight').empty();
            autoAttackNew();
            return false;
        },
        attackWhiteList_click: function() {
            bAttackWhiteList = true;
            _Event.autoMode_click();
            return false;
        },
        stop_click: function() {
            abort_process = true;
            statusTimer.clear();
            showDiv('buttons', '_panel', 500);
            return false;
        },
        showLog_click: function() {
            if (!$('#temp_dialog_popup').dialog('isOpen'))
                $('#temp_dialog_popup').dialog('open');
            return false;
        }
    };
    // ACTIONS
    var showDiv = function(name, type, ms, fn) {
        $('div[id*='+type+']', popupElt.content).stop().hide();
        $('#' + name + type, popupElt.content).show(ms, fn);
    };
    var showDialog = function(id, win) {
        var speech1 = c$('span').css('color', win ? 'green' : 'red');
        var speech2 = c$('span').css('color', win ? 'red' : 'green');
        var leaderElt = $('.leaders_rewards', '#fight_div');
        var dlg = (fightDialog[id] || fightDialog[win?'WON':'LOST']);
        
        leaderElt.children().stop().css('opacity', 1).hide();
        
        if (dlg.length == 1) {
            speech1.html(dlg[0].me);
            speech2.html(dlg[0].he);
        }
        else if (dlg.length > 1) {
            var index = Math.floor(Math.random() * dlg.length);
            speech1.html(dlg[index].me);
            speech2.html(dlg[index].he);
        }
        
        setTimeout(function() {
            $('.left', leaderElt).show();
            $('#left_side_text', leaderElt).empty().append(speech1).fadeIn(400);
        }, 500);
        
        setTimeout(function() {
            $('.right', leaderElt).show();
            $('#right_side_text', leaderElt).empty().append(speech2).fadeIn(400);
        }, 1000);
    };
    var setAttackTimer = function(fn) {
        if (options.get('useAttackDelay') !== true) {
            fn.apply(document);
            return;
        }
        var min = 1, max = 3, delay = 5;
        switch(options.get('attackDelay')) {
            case 2: min = 2; max = 4; break;
            case 3: min = 3; max = 5; break;
            case 4: max = 5; break;
        }
        delay = Math.floor(Math.random() * (max-min+1)) + min;
        
        statusTimer.start('Attack to '+_List.current.profile+' in %N% seconds...', delay, fn);
    };  
    var updateNewOpponent = function() {
        if (typeof(_List.current) == 'undefined') {
            _List.current = {name:'???', level:'???', mafia:'???'};
        }
        
        $('.leaders_rewards', '#fight_div').children().stop().css('opacity', 1).hide();
        
        $('#fight_side_left, #fight_side_right', '#fight_div')
        .toggleClass('losing winning', false);
        
        $('h3', '#fight_div').empty();
        $('.war_x', '#fight_div').hide();
        
        var rightSide = $('#fight_div #fight_side_right');
        $('.leader_name', rightSide).text(_List.current.name);
        $('li:eq(2)', rightSide).html('<strong>Level: </strong>'+_List.current.level);
        $('.mafia_size', rightSide).html(_List.current.mafia);
        $('.mafia_defense', rightSide).html('???');
        $('li > img', rightSide).attr('src', global.zGraphicsURL+'character_silhouette.jpg');
    };
    // POPUP
    var popupElt = new domPopupObject('battlefield_popup', {
        title: 'Mafia Wars: Battlefield!',
        css: {
            'width': 732,
            'left': 11,
            'top': 40
        },
        onclose: function() {
            statusTimer.clear();
            abort_process = true;
            options.fromDomElements();
            options.save();
            _List.clear();
            
            delete _List, _Event, _Regex, options, queryResult, statusTimer;

            $('#temp_dialog_popup').dialog('destroy');
            $('#temp_dialog_popup').remove();
        }
    });
    // Regex Expresions
    var _Regex = {
        user_health: function(text) {
            return parseInt(doRegex(/user_health..\s?=\s?parseInt..(\d+)/, text).$1 || 0);
        },
        exp_to_next_level: function(text) {
            return parseInt(doRegex(/exp_to_next_level..\s?=\s?parseInt..(\d+)/, text).$1 || 0);
        },
        user_stamina: function(text) {
            return parseInt(doRegex(/user_stamina..\s?=\s?parseInt..(\d+)/, text).$1 || 0);
        },
        fight_results: function(text) {
            var a = /class=.fight_results./;
            return a.test(text);
        },
        fight_controller: function(text) {
            return /<!--[^:]*:\s*fight_controller/.test(text);
        },
        icedCount: function(text) {
            return doRegex(/description.:.\D+([\d,]+)/, text).$1 || 0;
        },
        fightUrl: function(text) {
            return doRegex(/['"](remote[^"']*)/, String(text)).$1;
        },
        stashCount: function(text) {
            return doRegex(/popFightLootFeed_\d/, text).$0;
        }, 
        cashAmount: {
            1: function (text) {
                return _Util.getNumber(doRegex(/user_cash_nyc..\s*=\s*.([^"]*)/, text).$1);
            },
            2: function (text) {
                return _Util.getNumber(doRegex(/user_cash_cuba..\s*=\s*.([^"]*)/, text).$1);
            },
            3: function (text) {
                return _Util.getNumber(doRegex(/user_cash_moscow..\s*=\s*.([^"]*)/, text).$1);
            },
            4: function (text) {
                return _Util.getNumber(doRegex(/user_cash_bangkok..\s*=\s*.([^"]*)/, text).$1);
            },
            5: function (text) {
                return _Util.getNumber(doRegex(/user_cash_vegas..\s*=\s*.([^"]*)/, text).$1);
            },
            6: function (text) {
                return _Util.getNumber(doRegex(/user_cash_italy..\s*=\s*.([^"]*)/, text).$1);
            }
        }
    };
        
    var fightDialog = {
        'WON' : [
            {'me':'I\'m Max-Pain<br>slow... killer!'     ,'he':'No more pain<br>please!.'}
        ],
        'LOST': [
            {'me':'I\'m sorry man but, i need to go.'    ,'he':'I\'ll see my log...<br>you\'re dead man.'}
        ],
        'POWERATTACK': [
            {'me':'Today you\'ll know<br>all my power!'  ,'he':'What the hell i do<br>for deserve it?'},
            {'me':'More, more...<br>more blood!!!'       ,'he':'More, more...<br>more blaaah!'},
            {'me':'I\'ll kill you<br>very FAST!!'        ,'he':'No if i\'m healing myself!'},
            {'me':'Hey man! it\'s<br>a power attack!'    ,'he':'Hey man! it\'s<br>my fucking ass.'},
            {'me':'Sure ya\'re a<br>slacker, kill ya!'   ,'he':'Sure ya\'re a<br>slucker, fuck ya.'}
        ],
        'ICED': [
            {'me':'Great battle!<br>but you\'re iced!'   ,'he':'You\'re very strong...'},
            {'me':'Just a l"ice"!<br>Next, please ^^'    ,'he':'And hope you<br>get lace!'},
            {'me':'And... iced.<br>good day :)'          ,'he':'Someone will catch you!'},
            {'me':'Iced so soon?,<br>what gay!'          ,'he':'Soon?? of a bitch<br>you are.'}
        ],
        '#ffffff_WON': [
            {'me':'It\'s my job.<br>Nothing personal.'   ,'he':'**CRUSH**'},
            {'me':'Killed.. well<br>i\'ll pray for you'  ,'he':'.........'}
        ],
        '#ffff00_WON': [
            {'me':'It was close,<br>but i\'m better!'    ,'he':'You\'re just<br>a lucky man!'}
        ],
        '#00ff00_WON': [
            {'me':'You\'re very weak,<br>anyway...'      ,'he':'I\'ll tell my mafia<br>to attack you!'},
            {'me':'Easy...<br>very easy...'              ,'he':'Let me change<br>my account...'},
            {'me':'I can win<br>even closed eyes.'       ,'he':'Close your eyes then... Away.'},
            {'me':'Bored, bored,<br>bored...'            ,'he':'Find out any<br>strong player.'},
            {'me':'Farm is best<br>place for you...'     ,'he':'I\'m not married<br>with PC as you.'}
        ],    
        '#ff9900_WON' : [
            {'me':'Yeah, closed but i win!!!'            ,'he':'Next time man<br>next time...'},
            {'me':'You\'re strong man, but i more!'      ,'he':'Now... but we\'ll<br>see next time!'}
        ],
        '#ff0000_LOST': [
            {'me':'Oh!, i\'ll forgot u, see ya...'       ,'he':'lol stupid girl,<br>run, run Forest!'}
        ],
        '#ff9900_LOST': [
            {'me':'Shit!, i need more power...'          ,'he':'Try tomorrow<br>maybe? hahaha!'}
        ]
    };
    
    // GENERATE ALL MAIN DOM ELEMENTS
    function genMainDom() {
        
        var selectOpts = {
            'bfopt_healin': 
                {1:'New York', 2:'Cuba', 3:'Moscow', 4:'Bangkok', 5:'Las Vegas', 6:'Italy'},
            'bfopt_attackdelay': 
                {1:'1-3', 2:'2-4', 3:'3-5', 4:'1-5'},
            'bfopt_skiplevelway': 
                {1:'greater', '-1':'lower'},
            'bfopt_skipmafiaway': 
                {1:'greater', '-1':'lower'},
            'bfopt_cashpercent': 
                {25:'25%', 50:'50%', 75:'75%', 100:'100%'},
            'bfopt_maxloglength': 
                {10:'10', 50:'50', 100:'100', 250:'250', 500:'500', 1000:'1000'}
        };
        
        var battle_div = c$('div', 'class:battleground').appendTo(popupElt.content);
        var fightStatus = c$('div', 'class:war_status clearfix')
        .appendTo(
            c$('div', 'declare_war')
            .appendTo(c$('div', 'fight_div').appendTo(battle_div))
        );
        
        c$('div', 'id:fight_side_left,class:side left').appendTo(fightStatus)
        .append(c$('h3'))
        .append(
             c$('ul', 'class:leader_info')
            .append(c$('li','class:leader_name').text('???'))
            .append(
                c$('li').append(
                    c$('img','width:50,height:50')
                    .attr('src',global.zGraphicsURL+'character_silhouette.jpg')
                )
                .append(c$('div','class:war_x').hide())
            )
            .append(c$('li').append('<strong>Level: </strong>???'))
            .append(c$('li').append(c$('span','class:mafia_size').text('???')))
            .append(c$('li').append(c$('span','class:mafia_attack').text('???')))
        )
        .clone().attr('id', 'fight_side_right').appendTo(fightStatus)
        .removeClass('left').addClass('right')
        .find('.mafia_attack').removeClass('mafia_attack').addClass('mafia_defense');
        
        c$('div', 'class:war_rewards').appendTo(fightStatus)
        .append(c$('h3'))
        .append(
            c$('div', 'class:leaders_rewards')
            .append(c$('dl', 'id:left_side_text'))
            .append(c$('div', 'class:left'))
            .append(c$('dl', 'id:right_side_text'))
            .append(c$('div', 'class:right'))
        );
        
        var tabs = new domTabObject(
            c$('div', 'options_div').appendTo(battle_div), 'fightOpt', 
            ['General','BlackList','WhiteList'], 190, 'auto', 'transparent'
        );
        // ---------------
        // GENERAL OPTIONS
        // ---------------
        
        var divListElt = c$('ul').appendTo(tabs.getLayout(0));
        // HEAL
        c$('li').appendTo(divListElt)
        .append(c$('input:checkbox', 'bfopt_useheal'))
        .append(c$('label','for:bfopt_useheal').text('Heal in '))
        .append(c$('select','bfopt_healin').width(100))
        .append(c$('label','for:bfopt_healwhen').text(' when less than:'))
        .append(c$('input:text', 'id:bfopt_healwhen,size:5,class:right'));
        // NAME FILTER
        c$('li').appendTo(divListElt)
        .append(c$('input:checkbox','bfopt_usenamefilter'))
        .append(c$('label','for:bfopt_usenamefilter').text('Name filter:'))
        .append(c$('input:text', 'id:bfopt_namefilter,size:24,class:right'));
        // BANK MONEY
        c$('li').appendTo(divListElt)
        .append(c$('input:checkbox', 'bfopt_usebank'))
        .append(c$('label','for:bfopt_usebank').text('Bank when money is more than:'))
        .append(c$('input:text', 'id:bfopt_usebankwhen,size:5,class:right'));
        // STOP ON LEVELUP
        c$('li').appendTo(divListElt)
        .append(c$('input:checkbox','bfopt_stopbeforelvlup'))
        .append(c$('label','for:bfopt_stopbeforelvlup').text('Stop if i have:'))
        .append(c$('input:text', 'id:bfopt_explefttostop, size:5'))
        .append(c$('label','for:bfopt_explefttostop').text(' EXP left to Level-Up.'));
        // ATTACK DELAY
        c$('li').appendTo(divListElt)
        .append(c$('input:checkbox', 'bfopt_useattackdelay'))
        .append(c$('label','for:bfopt_useattackdelay').text('Attack delay (Automatic Mode):'))
        .append(c$('select', 'id:bfopt_attackdelay,class:right').width(68));
        // SPEND STAMINA
        c$('li').appendTo(divListElt)
        .append(c$('input:checkbox','bfopt_stopwhenstamina'))
        .append(c$('label','for:bfopt_stopwhenstamina').text('keep: '))
        .append(c$('input:text', 'id:bfopt_staminatokeep, size:5'))
        .append(c$('label','for:bfopt_skiplevel').text(' amount of stamina.'))
        
        // LEVEL CAP
        c$('li').appendTo(divListElt)
        .append(c$('input:checkbox','bfopt_skiplevel'))
        .append(c$('label','for:bfopt_skiplevel').text('Skip users level '))
        .append(c$('select', 'bfopt_skiplevelway').width(80))
        .append(c$('label','for:bfopt_skiplevel').text(' than:'))                           
        .append(c$('input:text', 'id:bfopt_skiplevelof,size:5,class:right'));
        // SKIP ICED
        c$('li').appendTo(divListElt)
        .append(c$('input:checkbox','bfopt_skipiced'))
        .append(c$('label','for:bfopt_skipiced').text('Skip iced.'))
        // SKIP NO MONEY                                
        .append(c$('input:checkbox','bfopt_skipnocash').css('margin-left', 5))
        .append(c$('label','for:bfopt_skipnocash').text('Skip when no cash.'))
        // USE POWER ATTACK 
        .append(c$('input:checkbox','bfopt_usepowerattack').css('margin-left', 5))
        .append(c$('label','for:bfopt_usepowerattack').text('Power attack.'));
        // MAFIA CAP
        c$('li').appendTo(divListElt)
        .append(c$('input:checkbox','bfopt_skipmafia'))
        .append(c$('label','for:bfopt_skipmafia').text('Skip users mafia '))
        .append(c$('select', 'bfopt_skipmafiaway').width(80))
        .append(c$('label','for:bfopt_skipmafia').text(' than:'))                           
        .append(c$('input:text', 'id:bfopt_skipmafiaof,size:5,class:right'));
        // LOG LENGTH
        c$('li').appendTo(divListElt)
        .append(c$('label','for:bfopt_maxloglength').text('-- Log Length: '))
        .append(c$('select', 'bfopt_maxloglength').width(70));
        // ADD TO WHITELIST
        c$('li').appendTo(divListElt)
        .append(c$('input:checkbox','bfopt_addusertowlist'))
        .append(c$('label','for:bfopt_addusertowlist').text('Add to WhiteList when gain:'))
        .append(c$('select', 'id:bfopt_cashpercent,class:right').width(68));
         c$('li').appendTo(divListElt)
        .append(c$('input:checkbox','bfopt_showloot'))
        .append(c$('label','for:bfopt_showloot').text('Show Loot.'))
        .append(c$('input:checkbox','bfopt_showcoins').css('margin-left', 5))
        .append(c$('label','for:bfopt_showcoins').text('Show Coins.'))
        .append(c$('input:checkbox','bfopt_showstash').css('margin-left', 5))
        .append(c$('label','for:bfopt_showstash').text('Show Stash.'));       
        // ATTACK COUNT
        c$('li').appendTo(divListElt)
        .append(c$('input:checkbox','bfopt_useattackcount'))
        .append(c$('label','for:bfopt_useattackcount').text('Maximum attacks per figther:'))
        .append(c$('input:text', 'id:bfopt_attackcounter,size:5,class:right'));
        c$('li').appendTo(divListElt)
        .append(c$('input:checkbox','bfopt_showhelp'))
        .append(c$('label','for:bfopt_showhelp').text('Show Troops.'))
        .append(c$('input:checkbox','bfopt_showblacklisted'))
        .append(c$('label','for:bfopt_showblacklisted').text('Blacklisted.'))
        .append(c$('input:checkbox','bfopt_showwhitelisted'))
        .append(c$('label','for:bfopt_showwhitelisted').text('Whitelisted.'));
        
        // ---------------
        // LIST OPTIONS
        // ---------------
        
        // blacklist
        c$('div').css({'float':'left','text-align':'left','margin':5}).appendTo(tabs.getLayout(1))
        .append(c$('input:checkbox','bfopt_useblacklist'))
        .append(c$('label','for:bfopt_useblacklist').text('Add players who defeat me to BlackList:'))
        .append(c$('br'))
        .append(c$('select', 'id:bfopt_blacklist,multiple:multiple').width(400).height(160));
        
        var tb = new domTableObject(c$('div','blackList_table').appendTo(tabs.getLayout(1)), 6, 1, {
            'width': 300, 
            'float': 'left'
        });
        
        tb.cell(0,0).append(c$('span').html('To add, delete or clear the list:'));
        tb.cell(1,0).append(b$('Add New', 'id:add_new_list,name:blackList,class:short white'));
        tb.cell(1,0).append(b$('Delete', 'id:delete_item_list,name:blackList,class:short white'));
        tb.cell(1,0).append(b$('Clear List', 'id:clear_list,name:blackList,class:short white'));
        tb.cell(2,0).append(c$('span').html('To see selected user\'s MW profiles:'));
        tb.cell(3,0).append(b$('MW Profile', 'id:go_profile,name:blackList,class:short white'));
        tb.cell(4,0).append(c$('span').html('To save/load a list in txt format:'));
        tb.cell(5,0).append(b$('Load List', 'id:add_from_list,name:blackList,class:short white'));
        tb.cell(5,0).append(b$('Save List', 'id:get_current_list,name:blackList,class:short white'));
        
        $('a', tabs.getLayout(1)).css('margin-left',5);
        
        // whitelist    
        c$('div').css({'float':'left','text-align':'left','margin':5}).appendTo(tabs.getLayout(2))
        .append(c$('select', 'id:bfopt_whitelist,multiple:multiple').width(400).height(180));
        $('table', tabs.getLayout(1)).clone().appendTo(c$('div','whiteList_table').appendTo(tabs.getLayout(2)))
        .find('a').each(function(index, elem) {
            $(elem).attr('name', 'whiteList');
        });
        
        // Assign click events
        $('#add_new_list', '#options_div').click(_Event.addNewToList_click);
        $('#delete_item_list', '#options_div').click(_Event.deleteSelected_click)
        $('#clear_list', '#options_div').click(_Event.clearList_click)
        $('#go_profile', '#options_div').click(_Event.mwProfile_click)
        $('#add_from_list', '#options_div').click(_Event.addFromList_click)
        $('#get_current_list', '#options_div').click(_Event.getList_click)
        
        // fix class
        $('input:text, select', battle_div).addClass('black_box');
        
        // ---------------          
        // USER PANELS
        // ---------------          
        var panels = c$('div', 'class:panels').appendTo(popupElt.content);
        
        // AJAX LOADER
        c$('div', 'ajaxloader_panel').appendTo(panels).hide()
        .append(c$('img').attr('src', global.resource.ajax_loader))
        .css({
            'width': 'auto',
            'text-align': 'center'
        });
        // START PANEL
        c$('div', 'start_panel').appendTo(panels).css({
            'width': 'auto',
            'text-align': 'center'
        });
        c$('span').appendTo('#start_panel').css('margin-right', '10pt')
        .append(b$('Random Attacks!', 'class:short red').click(_Event.autoMode_click))
        .append(
            b$('Attack WhiteList!', 'class:short red')
            .css('margin-left', 5).click(_Event.attackWhiteList_click)
        );
        // ATTACK BUTTONS
        c$('div', 'buttons_panel').appendTo(panels).hide().css({
            'width': 'auto',
            'text-align': 'center'
        })
        .append(
            b$('Attack again', 'attack_again_button')
              .addClass('short red').click(_Event.attackAgain_click)
        )
        .append(
            b$('Power Attack', 'power_attack_button').css('margin-left', '10pt')
              .addClass('short red').click(_Event.powerAttack_click)
        )
        .append(
            b$('Run Away', 'run_away_button')
              .css('margin-left', '10pt').click(_Event.runAway_click)
        );
        
        // ACTIVE STATUS
        c$('div', 'status_log')
        .appendTo(c$('div', 'status_panel').appendTo(panels).hide()).css({
            'margin-left': 30,
            'float': 'left',
            'width': 'auto'
        });
        
        c$('span').attr('style', 'margin-right: 15pt; float: right;').appendTo('#status_panel')
        .append(b$('Stop').attr('id', 'stop_button').click(_Event.stop_click));
        
        // BOTTOM PART
        var bottomElt = c$('div', 'id:bottom_fixed,class:bottom').appendTo(popupElt.content);
        
        // STATS
        var statsPanel = c$('div', 'class:stats').appendTo(bottomElt);

        c$('div').height(30).appendTo(statsPanel)
        .append(
            c$('div', 'class:bossfight_health_bar').width(140)
            .append(
                c$('div', 'class:bossfight_current_health_med')
                .css('width', global.userStats.healthpercent() + '%')
            )
        )
        .append(
            c$('span', 'id:massacre_health_sign,class:health_sign').text('HEALING').hide()
        );
        
        var statsArray = [
            {id:'mass_stat_maxhealth',tl:'health:',cl:'health'},
            {id:'mass_stat_maxstamina',tl:'Stamina:',cl:'stamina'},
            {id:'mass_stat_totalfight',tl:'Total Fights:',cl:'stamina'},
            {id:'mass_stat_wonfights',tl:'Won Fights:',cl:'attack'},
            {id:'mass_stat_lostfights',tl:'Lost Fights:',cl:'defense'},
            {id:'mass_stat_atkgained',tl:'Attack gained:',cl:'mafia_attack'},
            {id:'mass_stat_defgained',tl:'Defense gained:',cl:'mafia_defense'},
            {id:'mass_stat_experience',tl:'Exp. gained:',cl:'experience'},
            {id:'mass_stat_exp_per_sta',tl:'Exp. per stamina:',cl:'experience'},
            {id:'mass_stat_victorycoins',tl:'Victory Coins:',cl:'stat_victory'},
            {id:'mass_stat_iced',tl:'Fighters ICED:',cl:'stat_iced'},
            {id:'mass_stat_kill',tl:'Fighters KILL:',cl:'stat_kill'},
            {id:'mass_stat_cash',tl:cities[StartCity][0]+' cash:',cl:'cash'},
            {id:'mass_stat_blacklisted',tl:'Blacklisted:',cl:'listed'},
            {id:'mass_stat_whitelisted',tl:'Whitelisted:',cl:'listed'}
        ];
        
        for (var i = 0, s; i < statsArray.length; i++) {
            s = statsArray[i];
            c$('dl').appendTo(statsPanel)
            .append(c$('dt', 'class:'+s.cl).css('float','left').html(s.tl))
            .append(c$('dt', 'id:'+s.id).css('float','right').text('0'));
        }
        
        $('#mass_stat_maxhealth').parent()
        .append(c$('dt').text('/').css('float','right'))
        .append(c$('dt', 'id:mass_stat_health').css('float','right'));
        
        $('#mass_stat_maxstamina').parent()
        .append(c$('dt').text('/').css('float','right'))
        .append(c$('dt', 'id:mass_stat_stamina').css('float','right'));
        
        c$('div').appendTo(statsPanel).append(
            c$('a', 'href:#').text('Show Loot log')
            .css('text-decoration', 'none').click(_Event.showLog_click)
        );
        
        // PANELS
        var listPanel = c$('div', 'class:list').appendTo(bottomElt);
        
        // AUTOMATIC LOG
        c$('div', 'fightlog_list').appendTo(listPanel).hide()
        .append(
            c$('div','class:player_updates').height(100)
            .append(c$('div', 'id:fightlogs,class:update_item'))
        )
        .append(c$('div', 'id:itemslogs,class:player_updates').height(290));
        
        // FIGHT LIST
        c$('div', 'fightplayer_list').appendTo(listPanel)
        .append(
            c$('div', 'fightplayer_header').height(20)
            .append(c$('a', 'sort_by_name').text('Name').click(_Event.sort_click))
            .append(c$('a', 'sort_by_level').text('Level').click(_Event.sort_click))
            .append(c$('a', 'sort_by_mafia').text('Mafia').click(_Event.sort_click))
            .append(c$('a').text('Refresh').click(_Event.refresh_click))
        )
        // MANUAL LIST OF FIGHTERS
        .append(c$('div', 'id:manual_fight,class:player_updates').height(370));
        
        // Loot Log Dialog
        c$('div', 'temp_dialog_popup').hide().appendTo(popupElt.content).append('<ul>')
        .dialog({
            width: 500,
            height: 350,
            position: 'top',
            title: 'Loot Log',
            autoOpen: false,
            resizable: true,
            zIndex: 9999
        });
        
        $('#fight_div').hide();
        
        applySelectOptions(selectOpts, popupElt.content);
    }
    // -------
    // Methods
    function addMWProfiles(listName, profilesText) {
        var profileRegex = /profile.php\?id=([^\n]+)/g;
        var rgx, data = [];
        var eDiv = $('#'+listName+'_table');
        var eCenter = c$('center').css('margin-top', 10);
        var eLoadInfo =  c$('div').css({'margin':10,'font-weight':'bold'}).text('Loading...');

        while ((rgx = profileRegex.exec(profilesText))) {
            data.push(unescape(rgx[1]));
        }
        if (data.length < 1) {
            return;
        }
        $('table', eDiv).hide();
        eCenter.append(eLoadInfo)
        .append(c$('img').attr('src', global.zGraphicsURL+'socialmissions/ajax-loader.gif'))
        .appendTo(eDiv);
        
        function addProfile() {
            if (data.length < 1) {
                eCenter.remove();
                $('table', eDiv).show();
                options.toDomElements();
                options.save();
                return;
            }
            try {
                var id = global.Base64.decode($.parseJSON(data[0]).user);
                if (_Util.opponentListed(listName, _Util.getNumber(id))) {
                    return;
                }
                eLoadInfo.text('Loading user id: '+id);
                ajaxRequest({
                    url: 'remote/' + getIntURL('stats') + '&user=' + id,
                    success: function(htmlText) 
                    {
                        data.splice(0, 1); 
                        addPlayerToWhiteList(htmlText, listName);
                        addProfile();
                    }
                });
            }
            catch(err) {
                logErr$(err);
                data.splice(0, 1);
                addProfile();
            }
        }
        addProfile();
    }
    
    function addPlayerToWhiteList(page, listName) {
        var player = getOpponentFromProfile(page);
        if (player.error_msg) {
            showHelpPopup({
                icon: 'error',
                title: 'Error adding player to list',
                message: player.error_msg
            });
            return false;
        }
        else {
            return _List.addToList(listName, player);
        }
    }
    
    function getOpponentFromProfile(data) {
        var eQry = h$(data), id, attack, url, sText, startIndex, endIndex, name, level;
        try {
            attack     = String($('a:regex(onclick,xw_action=attack)', eQry).attr('onclick'));
            url        = doRegex(/['"](remote[^"']*)/, attack).$1;
            id         = splitUrl(url).opponent_id;
            sText      = _Util.htmlDecode(eQry.find('.stats_title_text:first').text());
            startIndex = sText.indexOf('"') + 1;
            endIndex   = sText.lastIndexOf('"');
            name       = sText.substr(startIndex, endIndex - startIndex);
            level      = _Util.getNumber(sText.substr(endIndex + 1));
        }
        catch(err) {
            logErr$(err);
            return {error_msg:e}; 
        }
        return new fightOpponent(id, '', name, level, 0, getProfileLink(id),  url);
    }
    function fromRandomWhiteList() {
        var p, lst = _Util.toArray(options.get('whiteList'));
          
        if (lst.length == 0) {
            autoModeMessage('No enemy in WhiteList.\nPlease add some enemy to begin.');
            abort_process = true;
            return;
        }
        if (lst.length == 1) {
            p = lst[0];
        }
        else {
            p = lst[Math.floor(Math.random() * lst.length)];
        }
        if (_Util.opponentListed('blackList', p.id)) {
            log$('skiping blacklisted id: ' + p.id);
            delete options.get('whiteList')[p.id];
            fromRandomWhiteList();
            return;
        }
        autoModeMessage('Loading profile page of enemy: (' + p.name + ')...', true);    
        ajaxRequest({
            url: 'remote/' + getIntURL('stats') + '&user=p|' + p.id,
            success: function(htmlText) 
            {
                _List.current = getOpponentFromProfile(htmlText);
                updateNewOpponent();
                autoAttack();
            }
        });
    } 
    function filter(plr, iced) {
        var i = 0, c = '', op = options.get;
        
        if (op('skipIced') && iced) {
            return false;
        }
        if (op('skipMafia')) {
            if ( (plr.mafia*op('skipMafiaWay')) > (op('skipMafiaOf')*op('skipMafiaWay')) ) {
                log$('skiping "'+plr.name+'" mafia: '+plr.mafia);
                return false;
            }
        }
        if (op('skipLevel')) {
            if ( (plr.level*op('skipLevelWay')) > (op('skipLevelOf')*op('skipLevelWay')) ) {
                log$('skiping "'+plr.name+'" level: '+plr.level);
                return false;
            }
        }
        if (op('useNameFilter')) {
            var v = op('nameFilter');
            while (i < v.length) {
                c = v.charAt(i++);
                if ((c !== ' ') && (plr.name.indexOf(c) !== -1)) {
                    log$('skiping name: ' + plr.name);
                    return false;
                }
            }
        }
        if (_Util.opponentListed('blackList', plr.id)) {
            log$('skiping blacklisted id: ' + plr.id);
            return false;
        }
        return true;
    }
    function parseOpponentTable(htmlText) {
        var ftb = h$(htmlText).find('.fight_table');
        // fighters table
        $('tr:has(a:regex(onclick,action=attack))', ftb).each(function(index, element) 
        {
            try {
                var user    = _Util.getUrlAndId($('a:regex(onclick,action=attack)', element).attr('onclick')),
                    b_iced  = $('img:regex(src,iced)', element).length > 0,
                    s_prfl  = $('td:eq(0) a', element).attr('href'),
                    s_name  = $.trim($('td:eq(0) a', element).text()),
                    s_title = $.trim($('td:eq(0) span', element).text()),
                    n_mafia = _Util.getNumber($('td:eq(1)', element).text()),
                    n_level = _Util.getLevel($('td:eq(0)', element));
                
                if (n_level == 0 || user.id < 1) {
                    return;
                }
                
                var opp = new fightOpponent(user.id, s_title, s_name, n_level, n_mafia, s_prfl, user.url);
                if (filter(opp, b_iced))
                    _List.add(opp);
                
                }
            catch(err) {
                logErr$(err);
            }
        });
        log$('UserList parsed: new fighters total: ' + _List.length());
    }
    function refreshPlayerList(callback) {
        $('#manual_fight').empty();
        
        ajaxRequest({
            url: 'remote/' + getIntURL('fight'),
            success: function(htmlText) 
            {
                if (_Regex.fight_controller(htmlText)) {
                    parseOpponentTable(htmlText);
                }
                if (typeof(callback) == 'function') {
                    callback.apply(document, [htmlText]);
                }
            }
        });
    }
    function genEnemyListDom() {
        if (_List.length() < 1) {
            return; 
        }
        
        var listDiv = $('#manual_fight').empty();
        
        _List.each(function(index, pl) {
            c$('div', 'class:update_item,id:enemy_player_' + index)
            .appendTo(listDiv).css('width', 490)
            .append(c$('div', 'class:update_timestamp'))
            .append(
                c$('div', 'class:update_icon').append(
                    c$('img', {
                        'width': 40,
                        'height': 40,
                        'src': global.zGraphicsURL + 'home/icon_hitlist_75x75_01.gif'
                    })
                )
            ).append(    
                c$('span', 'id:player_name,class:update_txt').width(260)
                .html(pl.title + '<br>' + pl.name + '<br>Level: ' + pl.level)
            ).append(
                c$('span', 'id:player_mafia,class:update_txt')
                .width(50).css('padding',5).text(pl.mafia)
            ).append(
                b$('Attack', 'class:short red,id:attack_id_'+ index)
                .click(_Event.attack_click).css({
                    'float': 'right',
                    'margin-right': 15
                })
            );
        });
    }
    function genLogDom(message, icon, pic) {
        if (typeof icon !== 'string') 
            icon = 'fight';
        
        // check items amount and kill last if more than max.
        if ($('#itemslogs').children().length > options.get('maxLogLength')) {
            $('#itemslogs').children().last().remove();
        }
        var updateItem, lootPic;
        var updateIcon = c$('img').attr({
            'width': 40,
            'height': 40,
            'src': logIcon[icon]
        });
        if (icon == 'fight') {
            updateItem = $('#fightlogs', '#fightlog_list').empty();
        }
        else {
            updateItem = c$('div', icon+'_item').addClass('update_item').prependTo('#itemslogs');
        }
        c$('div').addClass('update_timestamp').appendTo(updateItem).html(new Date().toUTCString());
        c$('div').addClass('update_icon').appendTo(updateItem).append(updateIcon);
        if (pic) {
            c$('div').addClass('update_pic').appendTo(updateItem).append(
                lootPic = c$('img').attr({
                    'width': 40,
                    'height': 40,
                    'src': pic
                })
            );
        }
        c$('div', 'class:update_txt').appendTo(updateItem).html(message);
        
        if (icon == 'loot' || icon == 'stash') {
            updateItem.addClass(icon);
        }
        $('a.sexy_button_new', updateItem).css('color', 'black');   
        if (icon == 'loot' && lootPic && lootPic.length == 1) {
            addLootToLog(message, lootPic.clone());
        }
    }
    
    function addLootToLog(message, pic) {
        var obj = $('<div>'+message+'</div>');
        
        $('a', obj).remove();
        message = obj.text();
        
        var rgx = message.match(/\s(\d)\s([^!]*)!/);
        
        if (rgx) {  
            var title = rgx[2].replace(/\s*/g, '');
            var count = parseInt(rgx[1]); 
            var elt = e$('#loot_item_'+title, '#temp_dialog_popup');
            if (elt !== null) {
                count += parseInt($('#item_count', elt).text());
                $('#item_count', elt).text(count);
            }
            else {
                var stats = rgx[2];
                if ((rgx = message.match(/\((\d+)\s*(\d+)\)/))) {
                    stats += ' (A:'+rgx[1]+' D:'+rgx[2]+')';
                }
                c$('li', 'loot_item_'+title).prependTo('#temp_dialog_popup > ul')
                  .append(pic.css('vertical-align', 'middle'))
                  .append(c$('span').css('margin-left',10).text('Found '))
                  .append(c$('span','item_count').css('color','green').text(count))
                  .append(c$('span').text(' '+stats+'.'));
            }
        }
    }
    
    function updateStats() {
        $('#mass_stat_exp_per_sta').text(fightStats.exp_per_sta());
        $('.bossfight_current_health_med').attr('style', 'width: ' + fightStats.healthpercent() + '%;');
        $('#mass_stat_cash').html(fightStats.cash());
        
        for (f in fightStats) {
            var stat = fightStats[f];
            var elem = e$('#mass_stat_' + f.toLowerCase());
            if (elem !== null && typeof(stat) == 'number') {
                elem.text(stat);
            }
        }
    }
    function autoModeMessage(message, hasAjax, hideStopButton) {
        if (hasAjax === true) {
            $('#status_log')
            .html('<img style="vertical-align: middle;" src="' + global.resource.ajax_loader + '">')
            .append('<span style="margin-left: 5px;">' + message + '</span>');
        }
        else {
            $('#status_log').html(message);
        }
        if (hideStopButton === true)
            $('#stop_button', '#status_panel').hide();
        else
            $('#stop_button', '#status_panel').show();
    }
    function tavelTo(toCity, callback) {
        if (abort_process) return;
        autoModeMessage('Traveling to ' + cities[toCity][0] + '...', true);
        travelToCity(toCity, function(city) {
            if ((CurrentCity = city) == parseInt(toCity)) {
                callback && callback();
            }
            else {
                statusTimer.start(
                    'Unexpected city, taveling to '+ cities[toCity][0] + ' in %N% seconds.', 
                    15, tavelTo, [toCity, callback]
                );
            }
        });
    }
    function healPlayer(city, callback) {
        if (abort_process) return;
        tavelTo(city, function() {
            autoModeMessage('Healing at ' + cities[city][0] + '...', true);
            jsonRequest(
                'remote/' + getIntURL('hospital', 'heal', city), 
                function(jsonData) 
                {
                    if (!jsonData.hospital_success || typeof(jsonData.user_fields) == 'undefined') {
                        statusTimer.start(
                            'Error healing. Try again in %N% seconds.', 
                            30, healPlayer, [city, callback]
                        );
                        return;
                    }   
                    fightStats.health = parseInt(jsonData.user_fields["user_health"]);
                    if (fightStats.health < options.get('healWhen')) {
                        statusTimer.start(
                            jsonData.hospital_message+' try again in %N% seconds.', 
                            15, healPlayer, [city, callback]
                        );
                    }
                    else {
                        $('#heal_item', '#itemslogs').remove();
                        genLogDom(jsonData.hospital_message, 'heal');
                        updateStats();
                        $('#massacre_health_sign').hide();
                        callback();
                    }
                }
            );
        });
    }
    function manualAttack(url) {
        
        if (global.userStats.stamina() < 1) {
            showHelpPopup({
                icon: 'info',
                title: 'No stamina left',
                message: 'You need to have some stamina to attack.'
            });
            _Event.runAway_click();
            return;
        }
        ajaxRequest({
            url: url,
            liteLoad: 1,
            success: function(htmlText)
            {
                if (_List.length() < 6) {
                    parseOpponentTable(htmlText);
                }
                switch( parseAttackResponse(htmlText) ) {
                    case ERROR_BAD_RESPONSE:
                        badServerResponse();
                        showDiv('buttons', '_panel', 800);
                        break;
                        
                    case ERROR_NO_FIGHT_RESULT:
                        checkHealth(function() {
                            showDiv('buttons', '_panel', 800);
                        });
                        break;
                        
                    case ERROR_SUCCESS:
                        checkBankMoney(function() {
                            showDiv('buttons', '_panel', 800);
                        });
                        break;
                }
            }
        });
    }
    // AUTOMATIC MODE
    var autoAttackNew = function() {
        if (bAttackWhiteList) {
            fromRandomWhiteList();
            return;
        }
        // next opponent
        _List.setRandomCurrent();
        if (typeof(_List.current) == 'undefined') {
            autoRefreshList();
            return;
        }
        if (_Util.opponentListed('blackList', _List.current.id)) {
            autoAttackNew();
            return;
        }
        setAttackTimer(function() {
            updateNewOpponent();
            autoAttack();
        });
    }
    function autoRefreshList() {
        if (abort_process) 
            return;
        
        autoModeMessage('Can\'t find fighters, try to change filters, or wait...', true);
        _List.clear();
        
        refreshPlayerList(function() {
            if (_List.length() > 0) {
                autoAttackNew();
            }
            else {
                setTimeout(autoRefreshList, 5000);
            }
        });
    }
    function autoAttack() {
        var op = options.get, fs = fightStats;
        
        if (abort_process) {
            return;
        }
        
        if (CurrentCity !== StartCity) {
            tavelTo(StartCity, autoAttack);
            return;
        }
        if (op('stopBeforeLvlUp') && fs.expToNextLevel < op('expLeftToStop')) {
            checkBankMoney();
            autoModeMessage('Auto-Attack deactivated, experience is less than specified.');
            abort_process = true;
            return;
        }
        if (fs.stamina < 1 || (op('stopWhenStamina') && fs.stamina < op('staminaToKeep'))) {
            checkBankMoney();
            statusTimer.start('No stamina left, continue in %N% seconds.', 600, reqSurvey);
            return;
        }
        if (fs.health < op('healWhen')) {
            if (!op('useHeal')) {
                checkBankMoney();
                statusTimer.start('Healing is set off, continue in %N% seconds.', 600, reqSurvey);
            }
            else {
                checkHealth(autoAttack);
            }
            return;
        }
        var url = _List.current.url, 
            counter = op('attackCounter') - _List.current.fights;
        
        if (op('useAttackCount') && counter < 1) {
            log$('skiping '+_List.current.name+' - due max. attacks, count: '+_List.current.fights);
            checkBankMoney(autoAttackNew);
            return;
        }
        if (op('usePowerAttack') && _List.current.pw_url) {
            if (counter > 4 || !op('useAttackCount'))
                url = _List.current.pw_url;
        }
        
        autoModeMessage('Attacking to ' + _List.current.profile + '...', true);
        
        ajaxRequest({
            url: url,
            liteLoad: 1,
            success: function(htmlText) 
            {
                if (abort_process) {
                    return;
                }
                if (_List.length() < 6 && !bAttackWhiteList) {
                    parseOpponentTable(htmlText);
                }
                switch( parseAttackResponse(htmlText, true) ) {
                    case ERROR_BAD_RESPONSE:
                        statusTimer.start(
                            'Some error in server response, try again in %N% seconds.', 
                            30, autoAttack
                        );
                        break;
                        
                    case ERROR_NO_FIGHT_RESULT:
                        if (fightStats.health < op('healWhen')) {
                            autoAttack();
                        }
                        else if (!bAttackWhiteList) {
                            autoRefreshList();
                        }
                        break;
                        
                    case ERROR_SUCCESS:
                        if (_List.current.alive && _List.current.win) {
                            setAttackTimer(autoAttack);
                        }
                        else {
                            checkBankMoney(autoAttackNew);
                        }
                        break;
                }
            }
        });
    }

    function checkBankMoney(callback) {
        if (options.get('useBank') && fightStats.userCash > options.get('useBankWhen')) {
            bankDeposit(StartCity, fightStats.userCash, function(result) {
                $('#bank_item', '#itemslogs').remove();
                genLogDom(result, 'bank');
                callback && callback();
            });
        }
        else {
            callback && callback();
        }
    }
    
    function checkHealth(callback) {
        $('#massacre_health_sign').show();
        setTimeout(function() 
        {
            if (fightStats.health < options.get('healWhen')) {
                healPlayer(options.get('healIn'), function() {
                    tavelTo(StartCity, callback);
                });
            }
            else {
                $('#massacre_health_sign').hide();
                callback.apply(document);
            }
        }, 500);
    }
    
    function updateUserFields(data) {
        var user_fields;
        if (typeof(data.user_fields) == 'object') {
            user_fields = data.user_fields;
        }
        else {
            data = String(data);
            var startIndex = data.indexOf('var user_fields');
            var endIndex = data.indexOf('user_fields_update', startIndex);
            eval(data.substr(startIndex, endIndex - startIndex));
        }
        fightStats.health          = user_fields['user_health'];
        fightStats.maxHealth       = user_fields['user_max_health'];
        fightStats.stamina         = user_fields['user_stamina'];
        fightStats.maxStamina      = user_fields['user_max_stamina'];
        fightStats.expToNextLevel  = user_fields['exp_to_next_level'];
        fightStats.userCash        = user_fields['user_cash'];
        
        
        CurrentCity = user_fields['current_city_id'];
    }
    
    function reqSurvey() {
         jsonRequest(
            'remote/' + getIntURL('survey', 'show_nps_survey'),
            function(jsonData) 
            {
                updateUserFields(jsonData);
                updateStats();
                autoAttack();
            }
        );
    } 

    /**
     * Evaluate a fight result. 
     * @param {String} html HTML Response Text
     * @param {Boolean} autoMode True for automatic mode
     */
    function parseAttackResponse(htmlText, autoMode) {
        var oScript = {
            user_fields: h$(htmlText).find('script:regex(text,local_xw_sig =|var user_fields)'),
            postW2Wback: h$(htmlText).find('script:regex(text,postW2Wback|share_asn_feed)'),
            postFightBrag: h$(htmlText).find('script:regex(text,_postFeedAndSendFightBrag)')
        };
        
        // update stats and signature
        if (oScript.user_fields.length < 1) {
            return ERROR_BAD_RESPONSE;
        }
        
        $('#sf_updater').append(oScript.user_fields);
        updateUserFields(oScript.user_fields.text());
        
        // check it has a fight results
        if (!_Regex.fight_results(htmlText)) {
            return ERROR_NO_FIGHT_RESULT;
        }
        
        var obj = new queryResult(htmlText);
        var rgx, s_dialog, s_outText = '';
        var opponent = _List.current;
        var n_cash = _Util.getNumber(obj.cash.text().replace(',',''));
        var n_done = _Util.getNumber(obj.damage.text());
        var n_take = _Util.getNumber(obj.health.text());
        var n_expe = _Util.getNumber(obj.experience.text());
        var n_won = 0, n_lost = 0;
        var s_cashfrom = String(obj.cash.attr('class')).replace(/sexy_|_cash|good|bad|\s*/g, '');
        var b_goodCash = (s_cashfrom  == cities[StartCity][1]);
        
        
        /**
         * Return a new HTML text of a Iced bonus.
         * @param {Number, String} count Iced count.
         * @return {String}
         */
        function addIcedToLog(script) {
            var sHtml = '', bHtml = '';
            var n_count = _Regex.icedCount(script);
            
            bHtml += '<a id="feed_send_fight_btn'+fightStats.iced;
            bHtml += '" onclick="postFeedAndSendFightBrag_'+fightStats.iced+'(); return false;" ';
            bHtml += 'class="sexy_button_new medium white"><span><span style="color: black;">';
            bHtml += 'Share with Friends</span></span></a>';
            
            sHtml += 'You ICED ' + opponent.profile + ', bringing your body count to ' + n_count;
            sHtml += '.<div id="iced_bonus">'; 
            sHtml += _Util.addIcedCount(script, fightStats.iced);
            sHtml += bHtml + '</div>';
            
            genLogDom(sHtml, 'iced');
            fightStats.iced++;
        }
        function addCoinsToLog() {
            try {
                var asn         = c$('div').append(obj.share_asn);
                var icon        = String($('img', asn).attr('src'));
                var sHtml       = '<script>'+oScript.postW2Wback.text()+'</script>';
                var startIndex  = icon.lastIndexOf('/')+1;
                var endIndex    = icon.lastIndexOf('.');
                var id          = $.trim(icon.substr(startIndex, endIndex-startIndex));
                
                log$('addCoinsToLog:'+ id);
        
                if (id.length > 2 && e$('#' + id) == null) 
                {
                    asn.attr('id', id);
                    $('img', asn).remove();
                    $('div', asn).removeAttr('style');
                    
                    sHtml += c$('div').append(asn).html();
                    
                    genLogDom(_Util.addCoinsCount(sHtml, fightStats.coins), 'asn', icon);
                    fightStats.coins++;
                }
                else {
                    $('#' + id).append(_Util.addCoinsCount(sHtml, fightStats.coins));
                }
            } catch (err) {
                logErr$(err);
            }
        }
        
        // update opponent image and mafia
        $('#fight_side_right li > img', '#fight_div').attr('src', obj.opponent.image.attr('src'));
        $('#fight_side_right .mafia_size', '#fight_div').text(obj.opponent.groupSize);
        $('#fight_side_right .mafia_defense', '#fight_div').text(obj.opponent.groupDefense);
        
        // set opponent attack buttons
        opponent.url    = _Regex.fightUrl(obj.attackAgain);
        opponent.pw_url = _Regex.fightUrl(obj.pwrAttack  );
        
        
        // first run get my name and image
        if (bfirstRun) {
            bfirstRun = false;
            $('#fight_side_left li > img', '#fight_div').attr('src', obj.player.image.attr('src'));  
            $('#fight_side_left .leader_name', '#fight_div').text(obj.player.name);
        }
        $('#fight_side_left .mafia_attack', '#fight_div').text(obj.player.groupAttack);

        if (obj.hint.length > 1)
        {
            s_dialog = 'POWERATTACK';
            
            n_won  = _Util.getNumber(obj.hint.eq(0).text());
            n_lost = _Util.getNumber(obj.hint.eq(1).text());
            
            s_outText = 'You fought '+ (n_lost + n_won) +' times. '
                      + '<span class="good">You won ' + n_won + ' fights</span> and '
                      + '<span class="bad">lost ' + n_lost + ' fights</span>, ';
        }
        else 
        {
            s_dialog = _Util.rgbToHex(obj.hint.css('color'));
            
            if (s_dialog == '#ffffff') {
                fightStats.kill++;
                genLogDom('You killed to ' + opponent.profile + 
                    ', bringing your total body count to ' +
                    _Util.getNumber(obj.hint.text()) + '!', 'kill');              
            }
            if (obj.won) {
                s_dialog += '_WON';
                n_won++; 
                s_outText = 'You fought 1 time. <span class="good">You won the fight</span>, ';
            }
            else {
                s_dialog += '_LOST';
                n_lost++;
                s_outText = 'You fought 1 time. <span class="bad">You lost the fight</span>, ';
            }
        }
        // apply stats
        fightStats.atkGained   = _Util.getNumber(obj.player.groupAttack) - fightStats.startGroupAtk;
        fightStats.defGained   = _Util.getNumber(obj.player.groupDefense) - fightStats.startGroupDef;
        fightStats.wonFights   += n_won;
        fightStats.lostFights  += n_lost;
        opponent.fights        += (n_lost + n_won);
        fightStats.totalFight  += (n_lost + n_won); 
        fightStats.experience  += n_expe;
        if (b_goodCash)
            fightStats.money   += (obj.cash.hasClass('good') ? n_cash : n_cash * -1);
        
        // Set player to dead by default
        opponent.alive = false;
        
        // Hide buttons by default
        $('#attack_again_button, #power_attack_button').hide();
        
        if (opponent.pw_url) 
        {
            opponent.alive = true;
            if (options.get('usePowerAttack') && obj.won) 
                $('#power_attack_button').show();
        }
        if (opponent.url) 
        {
            opponent.alive = true;
            $('#attack_again_button').show();
        }

        if (obj.won) 
        {
            opponent.win = true;
            $('#fight_side_left', '#fight_div').addClass('winning');
            $('#fight_side_left h3', '#fight_div').text('WON');
            $('#fight_side_right', '#fight_div').addClass('losing');
            $('#fight_side_right h3', '#fight_div').text('LOST');
            
            // add enemy to cash list
            if (obj.cash.hasClass('good') && b_goodCash) 
            {
                if (options.get('addUserToWList') && n_cash >= 
                   (options.get('cashPercent') * cities[StartCity][2]) / 100) 
                {
                    if (_List.addCurrentToWhiteList()) {
                        fightStats.whitelisted++;
                        if (options.get('showWhiteListed'))
                            genLogDom( 
                                '"The bank" ' + _List.current.profile + 
                                ' has nice cash, added to WhiteList.',
                                'whitelist', 
                                obj.opponent.image.attr('src')
                            );
                    }
                }
            }
            // opponent dead
            if (!opponent.alive) {
                $('#fight_side_right .war_x', '#fight_div').show();
            }
            else {
                // skip if no cash
                if (options.get('skipNoCash') && (n_cash < 1 || !b_goodCash)) {
                    log$('skiping ' + opponent.name + ' drop cash: ' + n_cash);
                    opponent.alive = false;
                }
            }
        }
        else 
        {
            opponent.win = false;
            $('#fight_side_left', '#fight_div').addClass('losing');
            $('#fight_side_left h3', '#fight_div').text('LOST');
            $('#fight_side_right', '#fight_div').addClass('winning');
            $('#fight_side_right h3', '#fight_div').text('WON');
            
            // add enemy to blacklist
            if (options.get('useBlacklist')) {
                if (_List.addCurrentToBlackList()) {
                    fightStats.blacklisted++;
                    if (options.get('showBlackListed'))
                        genLogDom(
                            '"The beast" ' + _List.current.profile + 
                            ' is too strong!, added to BlackList.',
                            'blacklist',
                            obj.opponent.image.attr('src')
                        );
                }
            }
        }
        
        s_outText += 'taking <span class="bad">' + n_take + '</span> damage ';
        s_outText += 'and dealing <span class="good">' + n_done + '</span> damage to your enemy. ';
        s_outText += 'You ' + (obj.won ? 'gained' : 'losed');
        s_outText += ' <span class="' + obj.experience.attr('class') + '">' + n_expe; 
        s_outText += '</span> experience points ';
        s_outText += 'and <span class="' + obj.cash.attr('class') + '">';
        s_outText += obj.cash.text().replace(/[\t\s+]*/g,'') + '</span>. ';
        
        
        // VICTORY POINTS
        if (obj.vCoin.length) {
            fightStats.victorycoins += _Util.getNumber(obj.vCoin.text());
        }
        
        if (options.get('showcoins') && obj.share_asn.length > 0) {
            addCoinsToLog();
        }
        
        // BONUSES
        $('.fightres_bonus', obj.bonuses).each(function(index, element)
        {
            var imgUrl   = $('.fightres_bonus_image > img', element).attr('src');
            var imgLoot  = e$('img:regex(src,bonusloot)', element);
            var imgStash = e$('img:regex(src,secretstash)', element);
            var elt      = $('.fightres_bonus_message', element);
            var s_bonus  = imgLoot ? 'loot' : (imgStash ? 'stash' : 'help');
            
            if (!options.get('show'+s_bonus)) {
                return;
            }
            
            if (s_bonus == 'loot') {
                imgUrl = $('.fightres_bonus_message img', element).attr('src');
                $('div:has(img)', elt).remove();
            }

            if (s_bonus == 'stash') {
                genLogDom(_Util.addStashCount(elt.html(), fightStats.stash), s_bonus,  imgUrl);
                fightStats.stash++;
            }
            else {
                genLogDom(elt.html(), s_bonus,  imgUrl);
            }
        });

        // Add data to log
        genLogDom(s_outText);
        
        // ICED bonus
        if (oScript.postFightBrag.length > 0) {
            addIcedToLog('<script>'+oScript.postFightBrag.text()+'</script>');
            s_dialog = 'ICED';
        }
        
        // UPDATE ALL FIELDS STATS
        updateStats();
        
        if (!autoMode || (options.get('useAttackDelay') && options.get('attackDelay') >= 1)) {
            showDialog(s_dialog, obj.won);
        }
        
        _List.current = opponent;
        
        delete obj;
        
        return ERROR_SUCCESS;
    }
    
    function Initialize() {
        
        // Generate DOM
        genMainDom();
        
        $('.leaders_rewards', '#fight_div').children().hide();
        showDiv('status', '_panel');
        autoModeMessage('', false, true);
        
        // Get stats.
        jsonRequest(
            'remote/' + getIntURL('survey', 'show_nps_survey'),
            function(jsonData) 
            {
                updateUserFields(jsonData);
                
                fightStats.startGroupAtk = _Util.getNumber(jsonData.fightbar.group_atk);
                fightStats.startGroupDef = _Util.getNumber(jsonData.fightbar.group_def);
                
                $('#fight_side_left li:eq(2)', '#fight_div')
                .html('<strong>Level: </strong>' + parseInt(jsonData.user_fields.user_level));
                    
                $('#fight_side_left .mafia_size', '#fight_div')
                .text(jsonData.user_fields.user_group_size);
                    
                $('#fight_side_left .mafia_attack', '#fight_div')
                .text(jsonData.fightbar.group_atk);
                
                updateStats();
            }
        );
        
        // get players and show them
        if ($('#inner_page').attr('class') == 'fight_controller') {
            setTimeout(function(){
                parseOpponentTable($('#inner_page').html());
                if (_List.length() > 0) {
                    genEnemyListDom();
                }
                showDiv('start', '_panel', 500);
            }, 100);
        }
        else {
            setTimeout(_Event.refresh_click, 500);
        }
        
        options.toDomElements();
        // show popup
        popupElt.show();
    }
    
    popupElt.addBase64Style(
        'I2JhdHRsZWZpZWxkX3BvcHVwIC5ibGFja19ib3ggew0KCWZvbnQtd2VpZ2h0OiBib2xkOyANCgljb2xvcjogcmdiKDIwOCwgMjA4'+
        'LCAyMDgpOyANCglib3JkZXI6IDFweCBzb2xpZCByZ2IoMTUzLCAxNTMsIDE1Myk7IA0KCWJhY2tncm91bmQtY29sb3I6IGJsYWNr'+
        'OyANCglmb250LXNpemU6IDE0cHg7DQp9DQojYmF0dGxlZmllbGRfcG9wdXAgLm1hZmlhX2F0dGFjayAgew0KCWJhY2tncm91bmQ6'+
        'IHVybChodHRwOi8vbXdmYi5zdGF0aWMuemduY2RuLmNvbS9td2ZiL2dyYXBoaWNzL2ljb25fbWFmaWFfYXR0YWNrXzIyeDE2XzAx'+
        'LmdpZikgbm8tcmVwZWF0IDBweCA1MCU7DQoJcGFkZGluZy1sZWZ0OiAyM3B4Ow0KfQ0KI2JhdHRsZWZpZWxkX3BvcHVwIC5tYWZp'+
        'YV9kZWZlbnNlIHsNCgliYWNrZ3JvdW5kOiB1cmwoaHR0cDovL213ZmIuc3RhdGljLnpnbmNkbi5jb20vbXdmYi9ncmFwaGljcy9p'+
        'Y29uX21hZmlhX2RlZmVuc2VfMjJ4MTZfMDEuZ2lmKSBuby1yZXBlYXQgMHB4IDUwJTsNCglwYWRkaW5nLWxlZnQ6IDIzcHg7DQp9'+
        'DQojYmF0dGxlZmllbGRfcG9wdXAgLmJhdHRsZWdyb3VuZCB7DQoJYmFja2dyb3VuZDogYmxhY2sgdXJsKGh0dHA6Ly9td2ZiLnN0'+
        'YXRpYy56eW5nYS5jb20vbXdmYi9ncmFwaGljcy9zb2NpYWxtaXNzaW9ucy9iZ190ZXh0dXJlX21vZHVsZS5qcGcpIG5vLXJlcGVh'+
        'dCBzY3JvbGwgNTAlIDAlOw0KCWJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjM0MzQzNDOw0KCWhlaWdodDogMjMwcHg7DQoJd2lk'+
        'dGg6IGF1dG87DQp9DQojYmF0dGxlZmllbGRfcG9wdXAgLmJvc3NmaWdodF9oZWFsdGhfYmFyIHsNCglmbG9hdDogbGVmdDsNCn0N'+
        'CiNiYXR0bGVmaWVsZF9wb3B1cCAucmlnaHQgew0KCWZsb2F0OiByaWdodDsNCn0NCiNiYXR0bGVmaWVsZF9wb3B1cCAuaGVhbHRo'+
        'X3NpZ24gew0KCWZsb2F0OiByaWdodDsNCglmb250LXdlaWdodDogYm9sZDsNCgljb2xvcjogZ3JlZW47DQoJdGV4dC1kZWNvcmF0'+
        'aW9uOiBibGluazsNCn0NCiNiYXR0bGVmaWVsZF9wb3B1cCAuc3RhdF92aWN0b3J5IHsNCgliYWNrZ3JvdW5kOiB1cmwoaHR0cDov'+
        'L213ZmIuc3RhdGljLnp5bmdhLmNvbS9td2ZiL2dyYXBoaWNzL3ZpY3RvcnlfaWNvbi5naWYpIG5vLXJlcGVhdCAtMnB4IDUwJTsN'+
        'CglwYWRkaW5nLWxlZnQ6IDE5cHg7DQp9DQojYmF0dGxlZmllbGRfcG9wdXAgLnN0YXRfaWNlZCB7DQoJYmFja2dyb3VuZDogdXJs'+
        'KGh0dHA6Ly9td2ZiLnN0YXRpYy56Z25jZG4uY29tL213ZmIvZ3JhcGhpY3MvbWFwX2Jhc2VkX2pvYnMvbWFzdGVyeV9zdGFyc19t'+
        'ZWRfODF4MzBfMDIucG5nKSBuby1yZXBlYXQgLTY0cHggLTEzcHg7DQoJcGFkZGluZy1sZWZ0OiAxOXB4Ow0KfQ0KI2JhdHRsZWZp'+
        'ZWxkX3BvcHVwIC5zdGF0X2tpbGwgew0KCWJhY2tncm91bmQ6IHVybChodHRwOi8vbXdmYi5zdGF0aWMuemduY2RuLmNvbS9td2Zi'+
        'L2dyYXBoaWNzL21hcF9iYXNlZF9qb2JzL21hc3Rlcnlfc3RhcnNfbWVkXzgxeDMwXzAyLnBuZykgbm8tcmVwZWF0IC00N3B4IDJw'+
        'eDsNCglwYWRkaW5nLWxlZnQ6IDE5cHg7DQp9DQojYmF0dGxlZmllbGRfcG9wdXAgLmxpc3RlZCB7DQoJYmFja2dyb3VuZDogdHJh'+
        'bnNwYXJlbnQgdXJsKGh0dHA6Ly9td2ZiLnN0YXRpYy56Z25jZG4uY29tL213ZmIvZ3JhcGhpY3MvdjMvaWNvbl93aXNobGlzdF9h'+
        'ZGRfMTl4MTRfMDEuZ2lmKSBuby1yZXBlYXQgLTFweCA1MCU7DQoJcGFkZGluZy1sZWZ0OiAxOXB4Ow0KfQ0KI2JhdHRsZWZpZWxk'+
        'X3BvcHVwICNkZWNsYXJlX3dhciB7DQoJYmFja2dyb3VuZDogbm9uZTsNCgltYXJnaW46IDBweCA0NHB4Ow0KfQ0KI2JhdHRsZWZp'+
        'ZWxkX3BvcHVwICNkZWNsYXJlX3dhciAud2FyX3Jld2FyZHMgew0KCXRvcDogMjBweDsNCn0NCiNiYXR0bGVmaWVsZF9wb3B1cCAj'+
        'ZGVjbGFyZV93YXIgLndhcl9yZXdhcmRzICNsZWZ0X3NpZGVfdGV4dCB7DQoJaGVpZ2h0OiAzNXB4Ow0KCXBhZGRpbmc6IDBweCAx'+
        'NHB4Ow0KfQ0KI2JhdHRsZWZpZWxkX3BvcHVwICNkZWNsYXJlX3dhciAud2FyX3Jld2FyZHMgI3JpZ2h0X3NpZGVfdGV4dCB7DQoJ'+
        'cGFkZGluZzogMHB4IDE0cHg7DQp9DQojYmF0dGxlZmllbGRfcG9wdXAgI2RlY2xhcmVfd2FyIC53YXJfcmV3YXJkcyAubGVmdCB7'+
        'DQoJdG9wOiAyMHB4Ow0KfQ0KI2JhdHRsZWZpZWxkX3BvcHVwICNkZWNsYXJlX3dhciAud2FyX3Jld2FyZHMgLnJpZ2h0IHsNCgl0'+
        'b3A6IDcwcHg7DQp9DQojYmF0dGxlZmllbGRfcG9wdXAgI2RlY2xhcmVfd2FyIC53YXJfc3RhdHVzIHsNCgloZWlnaHQ6IDIzMHB4'+
        'Ow0KfQ0KI2JhdHRsZWZpZWxkX3BvcHVwICNkZWNsYXJlX3dhciAud2FyX3N0YXR1cyAuc2lkZSB7DQoJYmFja2dyb3VuZC1wb3Np'+
        'dGlvbjogMHB4IDU1cHg7DQoJbWluLWhlaWdodDogMjMwcHg7DQp9DQojYmF0dGxlZmllbGRfcG9wdXAgI2ZpZ2h0T3B0IHsNCglt'+
        'YXJnaW46IDBweDsNCgl3aWR0aDogYXV0bzsNCn0NCiNiYXR0bGVmaWVsZF9wb3B1cCAjZmlnaHRPcHQgdWwgew0KCWhlaWdodDog'+
        'MTAwJTsNCgl3aWR0aDogMTAwJTsNCgltYXJnaW46IDBweDsNCglwYWRkaW5nOiAwcHg7DQoJdGV4dC1hbGlnbjogbGVmdDsNCglv'+
        'dmVyZmxvdzogYXV0bzsNCn0NCiNiYXR0bGVmaWVsZF9wb3B1cCAjZmlnaHRPcHQgdWwgbGkgew0KCWRpc3BsYXk6IGJsb2NrOw0K'+
        'CWZsb2F0OiBsZWZ0Ow0KCW1hcmdpbjogMHB4IDBweCAwcHggNXB4Ow0KCXBhZGRpbmc6IDBweDsNCgloZWlnaHQ6IDI1cHg7DQoJ'+
        'bWF4LWhlaWdodDogMjVweDsNCgl3aWR0aDogNDglOw0KCW92ZXJmbG93OiBoaWRkZW47DQp9DQojYmF0dGxlZmllbGRfcG9wdXAg'+
        'LnBhbmVscyB7DQoJYmFja2dyb3VuZC1jb2xvcjogIzExMTsNCglib3JkZXI6IDFweCBzb2xpZCAjM0MzQzNDOw0KCWhlaWdodDog'+
        'MzBweDsNCglwYWRkaW5nOiAxNXB4Ow0KCXdpZHRoOiBhdXRvOw0KfQ0KI2JhdHRsZWZpZWxkX3BvcHVwIC5ib3R0b20gew0KCWJh'+
        'Y2tncm91bmQtY29sb3I6ICMxMTE7DQoJYmFja2dyb3VuZC1pbWFnZTogdXJsKGh0dHA6Ly9td2ZiLnN0YXRpYy56eW5nYS5jb20v'+
        'bXdmYi9ncmFwaGljcy9pdGFseV9kNC5qcGcpOw0KCWJhY2tncm91bmQtcG9zaXRpb246IDUwJSAwJTsNCgliYWNrZ3JvdW5kLXJl'+
        'cGVhdDogbm8tcmVwZWF0Ow0KfQ0KI2JhdHRsZWZpZWxkX3BvcHVwIC5ib3R0b20gZGwgew0KCWhlaWdodDogMjBweDsNCgltYXJn'+
        'aW46IDBweDsNCn0NCiNiYXR0bGVmaWVsZF9wb3B1cCAuYm90dG9tIC5zdGF0cyB7DQoJYm9yZGVyLWxlZnQ6IDFweCBzb2xpZCAj'+
        'M0MzQzNDOw0KCWZsb2F0OiByaWdodDsNCgloZWlnaHQ6IDM4MHB4Ow0KCW1hcmdpbi1sZWZ0OiAycHg7DQoJcGFkZGluZzogNXB4'+
        'Ow0KCXRleHQtYWxpZ246IGxlZnQ7DQoJd2lkdGg6IDIxMHB4Ow0KfQ0KI2JhdHRsZWZpZWxkX3BvcHVwIC5ib3R0b20gLnN0YXRz'+
        'IC5udW1iZXJzIHsNCglmbG9hdDogcmlnaHQ7DQoJZm9udC13ZWlnaHQ6IGJvbGQ7DQoJbWFyZ2luOiAwcHg7DQoJb3ZlcmZsb3c6'+
        'IGhpZGRlbjsNCglwYWRkaW5nOiAwcHg7DQp9DQojYmF0dGxlZmllbGRfcG9wdXAgLmJvdHRvbSAubGlzdCB7DQoJYm9yZGVyOiAx'+
        'cHggc29saWQgIzNDM0MzQzsNCn0NCiNiYXR0bGVmaWVsZF9wb3B1cCAuYm90dG9tIC5saXN0ICNmaWdodGxvZ19saXN0IHsNCglo'+
        'ZWlnaHQ6IGF1dG87DQoJb3ZlcmZsb3c6IGhpZGRlbjsNCgl0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KI2JhdHRsZWZpZWxkX3BvcHVw'+
        'IC5ib3R0b20gLmxpc3QgI2ZpZ2h0cGxheWVyX2xpc3Qgew0KCWhlaWdodDogYXV0bzsNCgl3aWR0aDogYXV0bzsNCn0NCiNiYXR0'+
        'bGVmaWVsZF9wb3B1cCAuYm90dG9tIC5saXN0ICNmaWdodHBsYXllcl9saXN0ICNmaWdodHBsYXllcl9oZWFkZXIgYSB7DQoJZmxv'+
        'YXQ6IGxlZnQ7DQoJbWFyZ2luLWxlZnQ6IDIwcHg7DQp9DQojYmF0dGxlZmllbGRfcG9wdXAgLmJvdHRvbSAubGlzdCAucGxheWVy'+
        'X3VwZGF0ZXMgew0KICAgIG92ZXJmbG93LXg6IGhpZGRlbjsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KI2JhdHRsZWZpZWxk'+
        'X3BvcHVwIC5ib3R0b20gLmxpc3QgLnVwZGF0ZV90eHQgew0KCXdpZHRoOiAzNjBweDsNCglmb250LWZhbWlseTogdHJlYnVjaGV0'+
        'IE1TOw0KCWZvbnQtd2VpZ2h0OiBib2xkOw0KCWNvbG9yOiB3aGl0ZTsNCgljbGVhcjogbm9uZTsNCn0NCiNiYXR0bGVmaWVsZF9w'+
        'b3B1cCAuYm90dG9tIC5saXN0ICNpdGVtc2xvZ3MgLmxvb3Qgew0KCWJhY2tncm91bmQ6IGJsYWNrIHVybChodHRwOi8vbXdmYi5z'+
        'dGF0aWMuenluZ2EuY29tL213ZmIvZ3JhcGhpY3MvZmlnaHRfYm9udXNlcy9zaWRlX2JvbnVzbG9vdC5wbmcpIG5vLXJlcGVhdCBz'+
        'Y3JvbGwgMTAwJSA1MCU7DQp9DQojYmF0dGxlZmllbGRfcG9wdXAgLmJvdHRvbSAubGlzdCAjaXRlbXNsb2dzIC5zdGFzaCB7DQoJ'+
        'YmFja2dyb3VuZDogYmxhY2sgdXJsKGh0dHA6Ly9td2ZiLnN0YXRpYy56eW5nYS5jb20vbXdmYi9ncmFwaGljcy9maWdodF9ib251'+
        'c2VzL3NpZGVfc2VjcmV0c3Rhc2gucG5nKSBuby1yZXBlYXQgc2Nyb2xsIDEwMCUgNTAlOw0KfQ0KI2JhdHRsZWZpZWxkX3BvcHVw'+
        'IC5ib3R0b20gLmxpc3QgI2l0ZW1zbG9ncyAuc3Rhc2ggLnVwZGF0ZV90eHQgew0KCWJhY2tncm91bmQtY29sb3I6IGJsYWNrOw0K'+
        'CW9wYWNpdHk6IDAuOTsNCn0NCiNiYXR0bGVmaWVsZF9wb3B1cCAuYm90dG9tIC5saXN0ICNpdGVtc2xvZ3MgLmxvb3QgLnVwZGF0'+
        'ZV90eHQgew0KCWJhY2tncm91bmQtY29sb3I6IGJsYWNrOw0KCW9wYWNpdHk6IDAuOTsNCn0='
    );
    
    // load options and Initialize
    options.load(function() {
        if (_sList && _sHtmlText && addPlayerToWhiteList(_sHtmlText, _sList)) {
            if (typeof(_callback) == 'function') {
                _callback('The user has been added to ' + _sList + '.');
                popupElt.destroy();
                return false;
            }
            showHelpPopup({
                icon: 'info',
                title: 'Player added!',
                message: 'The user has been added to ' + _sList + '.',
                buttons: [{
                    label: 'Open Battlefield!',
                    addClass: 'short white',
                    onclick: Initialize
                }, {
                    label: 'Close',
                    onclick: popupElt.destroy
                }] 
            });
            return false;
        }
        Initialize();
    });
}

// =========================================================
// serverfbml gift request.
// =========================================================
/**
 * Add some buttons to facebook serverfbml gift requests for save/load friends 
 * and get the gift url.
 */
function giftFormControls() 
{
    if (x$('//form[contains(@id, "req_form_")]') == null) 
        return false;
        
    var contentText = x$('//form[contains(@id, "req_form_")]').getAttribute('content');
    if (!/next_action=accept_gift/.test(contentText))         
        return false;
        
    var parentElt = document.getElementById('app_content_10979261223');
    var getTiny_click = function() {
        var time = Math.round(new Date().getTime() / 1000);
        var url = /<fb:req-choice url='([^']+)'/.exec(contentText)[1];
        var name = /ztrack_subcategory=([^&]+)/.exec(url)[1];
        window.open('http://tinyurl.com/create.php?alias=' + time + '-' + unescape(name) + '&url=' + escape(url));
        
    };
    try {
        var divElt = document.createElement('div');
        parentElt.insertBefore(divElt, parentElt.firstChild);
        divElt.setAttribute('style', 'text-align: center; padding-bottom: 10px; background-color: rgb(0, 0, 0);');
        divElt.innerHTML = '<input style="width: 180px; height: 30px; margin-left: 5px;" id="tiny_button" type="button" value="Get Tiny URL">';
        document.getElementById('tiny_button').addEventListener('click', getTiny_click, false);
    } 
    catch (err) {
        logErr$(err);
    }
    return false;
}


(function(){
    
    var getWindow = function() {
        var elt = document.createElement("div");
        elt.setAttribute("onclick", "return window;");
        return elt.onclick();
    };
    var getDocumentUrl = function() {
        var elt = document.createElement("div");
        elt.setAttribute("onclick", "return document.location.href;");
        return elt.onclick();
    };
    // =========================================================
    // Make sure we are in a correct url 
    // =========================================================
    
    try {
        global.href = document.location.href;
    }
    catch(e) {
        global.href = getDocumentUrl();
    }
    var _accessToken, _tokenRgx;
    
    if (/serverfbml/.test(global.href)) {
        setTimeout(giftFormControls, 5000);
    }
    else if (/html_server/.test(global.href)) {
        // catch a new access_token key
        if ((_tokenRgx = /&access_token=([^&]+)/.exec(global.href))) {
            log$('detected access_token: '+_tokenRgx[1]);
            _accessToken = _tokenRgx[1];
        }
        // make sure it's the real game
        if (document.getElementById('final_wrapper')) {
            // catch chrome 
            if (typeof(chrome) !== 'undefined' && chrome.extension) {
                log$('Chromium browser detected.');
                unsafeWindow = getWindow();
            }
            log$('Mafia Wars Game detected.');
            initStorage();
            initjQuery(_accessToken);
        }
    }
    else if (/apps.facebook.com\/inthemafia/.test(global.href)) {
        modNoCanvasFrame();
        if ((_tokenRgx = /#(access_token.+)$/.exec(global.href))) {
            unsafeWindow.location.replace(
                'http://apps.facebook.com/inthemafia/track.php?'+
                'next_controller=index&next_action=view&next_params='+ 
                JSON.stringify( splitUrl(_tokenRgx[1]) )
            );
        }
    }
    else if (global.href.match(scriptAppInfo.appMeta)) {
        updateCheck(document.getElementsByTagName('body')[0].innerHTML);
    }
    // died...
    return false;
})(); 

// =========================================================
// END OF ALL CODE.
//
// RESOURCES:
// =========================================================

global.resource = {

    info_icon: 'data:image/png;base64,' +
    'iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAABKZJREFUSImdll1oHFUUx3/3zp2Z3Wyaj23SbNI2S02rrU1t+oUUjBYRqgj6UKHgx4NWCpZqEVTEBxV8UhFUKGJb0CIVK1ifKj4pioKVftivB61JWzHZZNPsJruT3dmZnbk+'+
    'zG6yaVJBDxzuzNxz/v9zz7nn3hH8i2itASSgAKs2CsBv0FAIcUuMRWdqwAaQKJS87h8ujWwplPyNQoplIvLJtsTNC/fc2X26NWFnAAcIFiNa8KUGbp8fnkh/+dOVfU0x+7GVnS09cdMSShlR+EFAqeLpv28URl3PP7Fr+20fDfQtuwq4N5OIm8HDMIy9dOTHBwtu8MGm'+
    'vp6VhmGK6RmfiLfBUUBrwiQMq/rCcGak2ZYvvrNn8KSUstxIMo+g7HrqkTe+eqqro/3gwOreeLFcvUVm50tLk+LS1RF3NJt//uvXHz3aFLf9+pxsjH5g7+FBLdTBvp7ueHaqQrkSzCpas3NTip2bukHreXPj+Qrprq6YocwPt+77ZIfvz+Kj6g/x+15LtKdSh+5anY7n'+
    'HW9+XdDs6E+xfW0nAIUZl5NnMoiGBLhelQ19K+OXh0c/bt/51gBQaFjBLlxt7N+4Jt3nuAGuX52nFa9KwXFnwaYdF9erLrDLOz7b1q1a5QTsp2tXwwrWp6yW5viero6louwtnvdvzmYoewFCwHcXx9HCWNQu2dZKsqXp2Vxn53uMU4kIEnZ/qjPZV6osBNdas3Z5K6AZ'+
    'Gp8BoMlSTDr+ol3ketDb3ZHOZSc2AKcjAqE3x2Jx6S4SfRCEvPnEAIac3Q8c+/5Pvvj5LwSaBfsXWJJISARb5gi07hbSYH56BEhJGApeOXqW+/uX8fC2XgC8QOMGtfBDDWEARESGlEhDgQ57oF4DraXrBcyuQEiQBmgB0uDUNYfVqSWz1NVQUw4FQgsMIGZKPK9Cvlhm'+
    'LD/DWHYSdCjnCCA7li9S1iaWaWLZNsqSGEqgTIkUBlWtCYIArTWuHzDtS3y/ilNymcg7eK4L1QrosKaMzxGE+sK0UwqnfVNiWKA8UDYoC2FaIBWDfQ6FQgGATL7EpTEPwioEAWgFhhkBVz3QoSbU56HeB2X/PG5xBGWDUTNWJigLbVhow47SNlseAaYdqbIiW8OMfE0b'+
    'KoUMvv/bHMHkiEPFOUZQ0UgjMpQNTlLeRFB7lwoMqzaqaAw8cIufMz5ahOjMh5nfoWPrZfAfp23FEqRRi8yCMOTE0ysYvL2VtiYTgBXtNg/dEef42XwEXM+7NCD7xzgl5xmGPis2FhkuT40xYBwgN3yMVL81F6VAKcVoIWC0GDUaWqNMhTAUmpqdsiFz0ac0dYCh6ZGG'+
    'zd4ga/ZK2ppeYGn6bZYPWPU6YFi1nMei/PsV8F0I/KioVQ9GzvncuPYqufL7DB0K65DzD5TcGU1i/a8EpSuUJu4l1pIgkZwrvFG/ksPZxqKQgeunJsiPPsdU+QhDh8NGyMVv6/QDkFzXi6VeprljN8l0By1dAqs58qg4UMxqctcmKU4eF57/rp66cp2r3y6AuvXvAED6'+
    'SSGTbUls826N2KylSAEIrceE1ueoVH8Jc8Uc1z9deCD9L0nthu7d/8nlH/ZrI5qfAOMrAAAAAElFTkSuQmCC'
    ,
    ajax_loader: 'data:image/gif;base64,' +
    'R0lGODlhEAAQAPYAAAAAAP///yoqKmpqap6enr6+vrq6upCQkFxcXCIiIlpaWtra2tbW1s7OzsjIyMDAwJSUlEREROLi4oyMjBISEhAQEDw8PHR0dK6urqCgoEBAQC4uLsTExOjo6HJyclRUVKKiooKCghwcHHh4ePDw8JaWlmJiYpiYmEhISLi4uPT09E5OTmhoaObm' +
    '5vj4+BYWFgoKCoaGhnp6eggICHx8fFZWVgQEBAICAj4+PjQ0NAYGBigoKFBQUA4ODiwsLBoaGiAgIDAwMDg4OEJCQh4eHiYmJgwMDCQkJISEhEpKSkxMTLKysqysrKSkpJycnLy8vMLCwjo6OoiIiMzMzBQUFNTU1HBwcKamptLS0uDg4F5eXrCwsOzs7HZ2dpqamsrK' +
    'yjY2NjIyMhgYGEZGRoCAgGxsbGBgYKioqG5ubrS0tLa2ttzc3FhYWO7u7vLy8lJSUvr6+mRkZNjY2Orq6sbGxoqKitDQ0Pb29o6Ojt7e3qqqqpKSkn5+fgAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJ' +
    'CgAAACwAAAAAEAAQAAAHjYAAgoOEhYUbIykthoUIHCQqLoI2OjeFCgsdJSsvgjcwPTaDAgYSHoY2FBSWAAMLE4wAPT89ggQMEbEzQD+CBQ0UsQA7RYIGDhWxN0E+ggcPFrEUQjuCCAYXsT5DRIIJEBgfhjsrFkaDERkgJhswMwk4CDzdhBohJwcxNB4sPAmMIlCwkOGh' +
    'Ro5gwhIGAgAh+QQJCgAAACwAAAAAEAAQAAAHjIAAgoOEhYU7A1dYDFtdG4YAPBhVC1ktXCRfJoVKT1NIERRUSl4qXIRHBFCbhTKFCgYjkII3g0hLUbMAOjaCBEw9ukZGgidNxLMUFYIXTkGzOmLLAEkQCLNUQMEAPxdSGoYvAkS9gjkyNEkJOjovRWAb04NBJlYsWh9K' +
    'Q2FUkFQ5SWqsEJIAhq6DAAIBACH5BAkKAAAALAAAAAAQABAAAAeJgACCg4SFhQkKE2kGXiwChgBDB0sGDw4NDGpshTheZ2hRFRVDUmsMCIMiZE48hmgtUBuCYxBmkAAQbV2CLBM+t0puaoIySDC3VC4tgh40M7eFNRdH0IRgZUO3NjqDFB9mv4U6Pc+DRzUfQVQ3NzAU' +
    'LxU2hUBDKENCQTtAL9yGRgkbcvggEq9atUAAIfkECQoAAAAsAAAAABAAEAAAB4+AAIKDhIWFPygeEE4hbEeGADkXBycZZ1tqTkqFQSNIbBtGPUJdD088g1QmMjiGZl9MO4I5ViiQAEgMA4JKLAm3EWtXgmxmOrcUElWCb2zHkFQdcoIWPGK3Sm1LgkcoPrdOKiOCRmA4' +
    'IpBwDUGDL2A5IjCCN/QAcYUURQIJIlQ9MzZu6aAgRgwFGAFvKRwUCAAh+QQJCgAAACwAAAAAEAAQAAAHjIAAgoOEhYUUYW9lHiYRP4YACStxZRc0SBMyFoVEPAoWQDMzAgolEBqDRjg8O4ZKIBNAgkBjG5AAZVtsgj44VLdCanWCYUI3txUPS7xBx5AVDgazAjC3Q3Ze' +
    'ghUJv5B1cgOCNmI/1YUeWSkCgzNUFDODKydzCwqFNkYwOoIubnQIt244MzDC1q2DggIBACH5BAkKAAAALAAAAAAQABAAAAeJgACCg4SFhTBAOSgrEUEUhgBUQThjSh8IcQo+hRUbYEdUNjoiGlZWQYM2QD4vhkI0ZWKCPQmtkG9SEYJURDOQAD4HaLuyv0ZeB4IVj8ZN' +
    'J4IwRje/QkxkgjYz05BdamyDN9uFJg9OR4YEK1RUYzFTT0qGdnduXC1Zchg8kEEjaQsMzpTZ8avgoEAAIfkECQoAAAAsAAAAABAAEAAAB4iAAIKDhIWFNz0/Oz47IjCGADpURAkCQUI4USKFNhUvFTMANxU7KElAhDA9OoZHH0oVgjczrJBRZkGyNpCCRCw8vIUzHmXB' +
    'hDM0HoIGLsCQAjEmgjIqXrxaBxGCGw5cF4Y8TnybglprLXhjFBUWVnpeOIUIT3lydg4PantDz2UZDwYOIEhgzFggACH5BAkKAAAALAAAAAAQABAAAAeLgACCg4SFhjc6RhUVRjaGgzYzRhRiREQ9hSaGOhRFOxSDQQ0uj1RBPjOCIypOjwAJFkSCSyQrrhRDOYILXFSu' +
    'Nkpjggwtvo86H7YAZ1korkRaEYJlC3WuESxBggJLWHGGFhcIxgBvUHQyUT1GQWwhFxuFKyBPakxNXgceYY9HCDEZTlxA8cOVwUGBAAA7AAAAAAAAAAAA'
    ,
    ajax_error: 'data:image/png;base64,' +
    'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAACYQAAAmEBwTBV+gAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAQHSURBVDiNtZVtbxRVFMd/596ZnS1L210otMB2t62gmKA2gVLtC5Ug' +
    'aGi0Eg2JfgY+AdAWWq0fgKJGE33ZqCQF5EFqCIoJ0RoTXpRATHjY0hYa2i6d7XZ2u7tzfbHttlgKiYn/5M5N7j33N+fMOfeMGGP4P2Q9yyCxSloUxBAioCKIyviW1R9/5N152jlZyeORkOwz6A5VVdWsa2uxamOAonB/hPzoCH4yOahE922acHsxJv9M8L2QbETbp/Sm' +
    'aNOqtv1Yz20BgeJD5ichf+c23oWzFMbHB4IZ82HVw4epFcET66R8Nu9cKdv9diNbnsefm6Ns46YSbCk4OzmF0gpz+xaZ3369ZgK6tfbm8NgCSy2+QixPVp8MNr/WmF+zlqnECNlwFVODg/gpF991i3PKJTV0HXdiisnbCfIVYZztOxoV1qmlHpfAo9Xhg1a8fm+hJorr' +
    'ptnyzbfE2ttRL71C8q9r+KkUJpVi5ubfeNqm4Xgvm7/6GncySWFdNToWbxp5+YV9y8DGtj+26hvw3WnKtr6ICgYBiB1pR2/fwaOh68zcukUmVM7mE58jWqMch+DWrRSmXaxYHB1wOh4DJ+pq6iUcaUIUAccmd+ki944dLYUV6zyKtfNVsmvWsfmLL0HrYqK7jpH/7Rec' +
    'UBkoBRWVzWMtO1tgvo4tJ7BftMafngbbYnWkEvfsGRKFAvGu7iK8qxt8vwgAhjs7mLv0MxWxKH46Db6PaI2xVAy4WrwglhM0+Rz5sVEktAoVClERqcQ908/dQoG6T3vm4ytC7x4+TG7gAhXRDZjZWUw2g8lmAUE5gUjJYyydFKVAFORy+G6qCMnlyD94AIVCKfxiQgwm' +
    'mynaLZSiZYEojKhFsAScZNFAFY2UYnY6hX5zNw3He0ueLqiup4eEVqR+PEV5TTUoQUQWwJnFqrDVMHYAbBuxbdKpNNa+d2noPbEY/qFD3D18qASPd39CsO0DZianEMsGuziU2P2w5Obdf6Pld5Q0Z9Oz8NY71PV8VoIk2o+QPXcGEJzW94h3dy/udXTA1Ss4kTCIDNZ8' +
    '39/8WB2LY3dh20gwSObGDXzPm89+J9mfzlFRG6UiFiU7cJ7ho50A+J6Hd30IFQwiWiNK9ZV4S3vFg9Y9g4hqyqZm8Naup2zbNuYuXqA8uuGx7z8zeh979x68oSHK0i7BcCVgBqrHk61cvpxfBp5o27uxoALnjEjjnOdh8gWcSBj5V/IAMo+mUZZFYHUIkGvay71edfp0' +
    'qcMta5sTbW3lBUefRMneZbQn608t+fer+k6PLV18cqPftcsar15zEOEjDDtXAP5hjHTVfHfy/JM2V/yDLGj8wIF6Uf5+IyYoRpIGPymih9f3/XD1aeeeCf6v+gfLYZXwkd5f2QAAAABJRU5ErkJggg=='
    ,
    menu_arrow: 'data:image/png;base64,' +
    'iVBORw0KGgoAAAANSUhEUgAAACcAAAAyCAYAAADfuMIdAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABdRJREFUeNrsmWtoHFUUx+feOzu7yWZNmoeNu6liC9ZqNFAfKEitSbGPTyp+1E8KQkUpgoJSFaz6oT4+iFYFQW1FUFuaNgVtMWkiWGNN'+
    'LFWhJGKa127SPDabTbLPeXjvcm84ezuTTTITUfDCYSbZmZ3f/s8995xzR1H+xQOt8Bq76y2H8zWHQ5Ip0rkFgCzJ1hROQGBuSDpCIIMfTenoaqglPmcQBByhKRzC5HDQFC8A1WUoR/h1PnD08c8EjE4tD455yd1rAicUYzB+agFqGj/H/MEMJMctK00Vww0gKfGZj8Mw'+
    'qDJqFQ1blQ17DmpvJ2PGX7PRwkMD/DoC5qRpEzCeKIfAfFO5SgwsxEwLonCwFt9z95MaGfst90E+rWTo/9PUFqjNcUgZaFUKEgc3Eq5YQS1q11CrolatVSj1m3f5dgYqcaS+EYcHuoyoaRR+gMbvQyBQXClIJDAMAoCBBTnYOgZGrc4XQNc1PqRtQwgpofUkUrsJXTt8'+
    '3ogb+cI9qhSprgCJTVSKCV8OwGoZGLV61Y/CTY9qWxkcs6oGUl8VVupGeowEBYTrn2tAFcwvLAVABXdljQBjpmeVeoRx0Zds3B64ybSwv+NgptPIFb6j1FjWHCRANR+YZ0EOxhRbz8HC1CLUKu96LHCDUE5YzY1qVVUDrrv8oz5jmYtquVJQBfNNuLScR+Y6oBgDa2DQ'+
    'VDlTlZQT4+bmQISiNp9+PdVumcvy3JIKqtJ8E3Otkrnzia8rX80tKCSXsjQjbyFTt0xVQwRj55S8ZUcgrFiouf2tVFc+Y7kCVEFACDgRodVVYd/1q1k8b91ZFqGuvr/jnQUlu7B6QFVK8EXBgB3ct5zRuKucAW779sCcCVxsrQRQdcihTL0QwUhxM27fXd6gqbj51IFk'+
    'h56zYK0HAwYGjWGnnBwUTL1yTIjrgvGWXUEaTOiB1pcTulTFwKMdaFFuJZJ6ZcSFW+G4bU9FhIZRy8lX4t8ZeqF6yQATFQ2Wi19VKsNh+tLcuhWOpt3BDSpGLW1vzLRl5swkLxJYsZDiz8s5ZQhkl2O9cGuxgqGNaoA82Pba9Mx83JjmHtI4B7FTzrHL8sqtRVG8o2JL'+
    'qFp9+Itnxt9PzZoymHCtpYBGxT59YLImtunOYFPL3uo7pAIVrajBoZN4TZrlwd70xfZDM702keoId1VzrK6BW//4fv7SN/tjx1OzxjwPAt2mtSyCs6Q6rNDuEY+Vu3BqduCr/WNn0kljikdp1gawSDl55RaLYw5j76K192Ri5Mhz0XZDt67QPxN8KUkBuCXdKlbvPP9F'+
    'aa+itad1JvrZs8Pt9DRKbYJaXIIz7JpwVXKnzi9mK3eKeLDO9ZyIx448P3KWno5QGwNwSd61Zbkght2cg+4UqhXaPIzcKdd9bHr0032DnaZhDXLVxqmx+TZLbZ7DQTBbtwo4oRq7MeHGrT8dnYp++dLQDxxslINNUpvhqgmX5kEwOAaEDlRjN8fjsfxwZs4gmXlDy+cs'+
    'RKth0+dHZPO9lTVLg01GD79wuSubMgcA2MRKwGAu9YEthxCvhOtAUxMRPQS76fDUfdsdXXl8MvbhU32shxhyAybPOREMKVC2+6SEHNbKcKWTu7tbJ6Mf7+0/6wWYHK26VFNhkJQXE7K/jCC78v3csYmhj57u66SuH/UCTA4IxG8UsAiALXbyVLmrstrPJyb7P9nX15HP'+
    'mOMcyjUYdKsiJWADwMGdTMsfJBoCS8yvp6cvUsXOpOcKKSnOI9I1mN0ijCQl4bZr4f+hai0o3HrpXOL8u4//fjSXNuf4ip/gUK7B7KoSeDPiSwsMCKM24q/GCCmxP1O/vPnIhUMUTN6fS3oB5lTPQTeLtW9RuVRSjyWu5Lo/f7H/PerKCX6NAExzKNdgpbb64ZaYtoI9'+
    '4YwXYKUqYTnnKiDFZZexm+4KbDlw8gsQ8fBS7yFML97klHpJYtqo+I+9wfnPvvty7GcdoltRPH5r+P9Y7fhbgAEAMJrdIgjV5tQAAAAASUVORK5CYII='
    
};  

0 comments:

Post a Comment