Chewbaka69 / OGame : Imperio

// ==UserScript==
// @version     2.7.8
// @name        OGame: Imperio
// @autor       SGM
// @colaborator Chewbaka69
// @date        2020-07-15
// @description Ogame Empire, show resources, buildings, defences, ships, average and total require TamperMonkey (/!\ NOT GREASE MONKEY /!\)
// @include     *.ogame.gameforge.*/game/*
// @icon        https://i.imgur.com/UVCIYlt.png
// @icon2       https://i.gyazo.com/e0824021d422e08da5ffd0ee3b821136.png
// @grant       none
// @updateURL   https://openuserjs.org/meta/Chewbaka69/OGame_Imperio.meta.js
// @downloadURL https://openuserjs.org/install/Chewbaka69/OGame_Imperio.user.js
// @copyright   2019, Chewbaka69 (https://openuserjs.org/users/Chewbaka69)
// @license     MIT
// ==/UserScript==
// ==OpenUserJS==
// @autor Chewbaka69
// ==//OpenUserJS==
var VERSION = '2.7.8';
var UPDATE = '2020-07-15';

if(!String.prototype.format){String.prototype.format=function(){var c=arguments;if(c.length==1&&Array.isArray(c[0]))c=c[0];return this.replace(/{(\d+)}/g,function(a,b){return(typeof c[b]!='undefined')?c[b]:a;});};}
if(!String.format){String.format=function(c){var d=Array.prototype.slice.call(arguments,1);if(c.length==1&&Array.isArray(c[0]))c=c[0];var e=function(a,b){return(b in d)?d[b]:a;};var f=/\{(\d+)\}/g;return c.replace(f,e);};}
if(!Number.prototype.trunc) {Number.prototype.trunc = function(digits) {var re = RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"),m = this.toString().match(re);return m ? parseFloat(m[1]) : this.valueOf();};}
var win = (typeof unsafeWindow) == 'undefined' ? window : unsafeWindow;

function OG_parseNum(v){var n=v+'';if(n.indexOf(win.LocalizationStrings.unitMilliard)!=-1){n=n.replace(win.LocalizationStrings.unitMilliard,'').replace(/\,/g,'.');n=parseFloat(n);n*=1000000000}else if(n.indexOf(win.LocalizationStrings.unitMega)!=-1){n=n.replace(win.LocalizationStrings.unitMega,'').replace(/\,/g,'.');n=parseFloat(n);n*=1000000}else n=n.replace(/\./g,'').replace(/\,/g,'');return parseInt(n)}
function getNum(s){return jQuery.trim( s.replace(/\D/g,'') );}
function formatDateFuture(date){
	var _ceros = function(n){return (n === 0) ? '00' : ((n < 10) ? '0'+n : n ); };
	var _now = new Date(),
	M = _ceros(date.getMonth()+1),
	d = _ceros(date.getDate()),
	h = _ceros(date.getHours()),
	m = _ceros(date.getMinutes()),
	s = _ceros(date.getSeconds());
	var w = "";
		if ( _now.getTime() > (date.getTime()-86400000) ){
			// solo faltan horas
			w += "{0}:{1}:{2}".format(h,m,s);
		} else {
			w += "{0}.{1} {2}:{3}:{4}".format(d,M,h,m,s);
		}
		return w;
}
function stellarSort(stellars) {
    var sortable = [];
    for(var s in stellars) sortable.push(stellars[s]);
    sortable.sort(function(a, b){
        // Primera implementación unicamente basado en coordenadas
        //if(__GLOBALS__.stellarOrder == 0) { // ordenado por coordenadas

        var c = a.coords[0] - b.coords[0]; // galaxia ?
        if(c === 0) c = a.coords[1] - b.coords[1]; // misma galaxia, sistema
        if(c === 0) c = a.coords[2] - b.coords[2]; // mismo sistema, radio
        return c;

        //} else { // alfabeto
        //    var an = a.name.toLocaleLowerCase(),
        //        bn = b.name.toLocaleLowerCase();
        //    return an.localeCompare(bn);
        //}
    });
    return sortable;
}

// http://s110-mx.ogame.gameforge.com/nocdn/5.8.5/img/small/small_408.jpg
if ('function' != typeof(Object.assign)) { Object.assign = jQuery.extend; }
/**
 * Define propiedades en la raiz del objeto _fnOGame (root)
 * @param key Nombre de la propiedad a definir
 * @param value valor asignado a la propiedad
 * @param e indica si es enumerable (def : true)
 * @param w indica si se puede escribir (def : false)
 * @param c indica si puede ser reconfigurable (def : false)
 * @returns Propiedad creada
 */
function _define(o, key, value, e, w, c) {
	var config = {};
	config.enumerable = ('undefined' === typeof(e)) ? true : e;
	config.writable = ('undefined' === typeof(w)) ? false : w;
	config.configurable = ('undefined' === typeof(c)) ? false : c;
	if('undefined' !== typeof(value) || null !== value) config.value = value;
	return Object.defineProperty(o, key, config);
}

function _fnImperium() {
	var root = this;

	/* ====================================================================== */
	/* ============== Objeto para el almacenamiento de datos ================ */
	/* ====================================================================== */

	function _storage() {
		var skey = document.querySelector('meta[name="ogame-universe"]').content.split('.')[0];
		var uid  = document.querySelector('meta[name="ogame-player-id"]').content;
		Object.defineProperty(this, 'mask', {
			value : 'OG.' + skey + '@' + uid + ':',
			enumerable : true,
			configurable : false,
			writable : false
		});
	}

	_storage.prototype.item = function(key, value) {
		if ('undefined' === typeof(value) ) {
			var raw = localStorage.getItem(this.mask + key) || 0;
			return JSON.parse( raw );
		} else {
			value = JSON.stringify( value );
			return localStorage.setItem(this.mask + key, value);
		}
	};

	_storage.prototype.objectUpdate = function(key, name, value){
		var d = this.item( key );
		d[name] = value;
		return this.item(key, d);
	};

	_storage.prototype.remove = function (key) {
		localStorage.removeItem(this.mask + key);
	};

	_storage.prototype.has = function (key) {
		return (this.option(key) !== 0);
	};

	_storage.prototype.construction = function(planet, val) {
		return this.item(planet + '_construction', val);
	};

	_storage.prototype.production = function(planet, val) {
		return this.item(planet + '_production', val);
	};

	_define(root, 'Storage', new _storage(), false);

    function _getTranslation() {

        if(root.Storage.item('i18n')[1] !== undefined && root.Storage.item('i18n')[1] !== [])
            return;

        let i18n = [];

        let xmlHTTP = new XMLHttpRequest();
        xmlHTTP.open('GET', 'https://' + document.querySelector('meta[name="ogame-universe"]').content + '/api/localization.xml', false);
        xmlHTTP.send(null);

        if (xmlHTTP.readyState === 4) {
            if (xmlHTTP.status === 200) {
                let parser = new DOMParser();
                let xmlDoc = parser.parseFromString(xmlHTTP.responseText,"text/xml");
                let techs = xmlDoc.documentElement.getElementsByTagName('techs')[0].getElementsByTagName('name');
                let missions = xmlDoc.documentElement.getElementsByTagName('missions')[0].getElementsByTagName('name');

                let i18n = [];

                if(techs !== undefined) {
                    for (let i = 0; i < techs.length; i++) {
                        i18n[techs[i].id] = techs[i].innerHTML;
                    }
                }

                if(missions !== undefined) {
                    for (let i = 0; i < missions.length; i++) {
                        i18n[missions[i].id] = missions[i].innerHTML;
                    }
                }

                root.Storage.item('i18n', i18n);

                parser = xmlDoc = techs = missions = null;
            }
        }
        xmlHTTP = null;
    }

    _getTranslation();

    function _I18N(tech_id) {

        let techs = root.Storage.item('i18n');

        return techs[tech_id];
    }


    _define(root, 'I18N', _I18N, false);


	/* ###################################################################### */

	function oMoon( data ) {
		var rootMoon = this;
		Object.assign(this, data);

		var r = root.resources[rootMoon.id];
		if ( 'undefined' == typeof(r) ) return null;
		this.resources = r.input;
		this.imageName = r.imageFileName + '_1.gif';
		this.isMoon = true;

		var tech = root.Storage.item(rootMoon.id);
		this.techs = tech;
	}

	oMoon.prototype.toJSON = function() {
		return JSON.stringify({
			id : this.id,
			name : this.name,
			coords : this.coords,
			diametre : this.diametre,
			space : this.space,
			temp : this.temp,
			moon : this.moon
		});
	};
	oMoon.prototype.toString = function() {
		return this.toJSON();
	};
	oMoon.prototype.update = function() {
		return root.updates[this.id];
	};

	function oPlanet( data ) {
		oMoon.call(this, data);

		var r = root.resources[ this.id ];
		this.imageName = r.imageFileName + '_1.png';
		this.isMoon = false;
	}
	oPlanet.prototype = Object.create(oMoon.prototype);
	oPlanet.prototype.constructor = oPlanet;
	oPlanet.prototype.getStorage = function() {
		return {
			metal : resourcesBar.resources.metal.storage,
			crystal : resourcesBar.resources.crystal.storage,
			deuterium : resourcesBar.resources.deuterium.storage
		};
	};
	oPlanet.prototype.getProduction = function() {
		return root.Storage.production( this.id );
	};
	oPlanet.prototype.getMoon = function() {
		if (!this.moon) return null;
		return root.moons[this.moon];
	};


	/**
	 * root.planets   (enumerable)
	 * root.moons     (enumerable)
	 * root.resources (enumerable)
	 */
	function _loader() {
		var rootLoader = this;

		/**
		 * root.planets (enumerable)
		 * root.moons   (enumerable)
		 */
		function readPlanets() {
			var aPlanetas = {}, aMoons = {};

			jQuery("#planetList a.planetlink").each(function() {
				var $this = jQuery(this),
				planet = new Object(),
				titledata = $this.attr('title').match(/([\d-:\.]+)/ig),
				coords = titledata[0].split(':');

				coords.forEach( function(d,i){
					coords[i] = parseInt(d);
				});

				planet.id = parseInt($this.parent()[0].id.split('-')[1]);
				planet.name = $this.find('span.planet-name').text();
				planet.coords = coords;
				planet.diametre = parseInt(titledata[1].replace('.',''));
				planet.space = [parseInt(titledata[2]), parseInt(titledata[3])];
				planet.temp =  [parseInt(titledata[4]), parseInt(titledata[5])];

				var moon = $this.parent().find('a.moonlink');
				if (moon.length > 0) {
					moon = _readMoon(moon[0]);
					planet.moon = moon.id;
					aMoons[moon.id] = new oMoon(moon);
				} else {
					planet.moon = null;
				}

				aPlanetas[planet.id] = new oPlanet(planet);
			});

			function fnTotal(){
				var result = {
					metal : 0,
					crystal : 0,
					deuterium : 0
				};
				for (var z in this )
					root.fnSumResources(result, this[z].resources);

				return result;
			}
			_define(aPlanetas, 'fnResourcesTotal', fnTotal, false);
			_define(aMoons, 'fnResourcesTotal', fnTotal, false);

			function fnLength(){
				var i = 0;
				for(var z in this ) i++;
				return i;
			}
			_define(aPlanetas, 'length', fnLength, false);
			_define(aMoons, 'length', fnLength, false);

			_define(root, 'planets', aPlanetas);
			_define(root, 'moons', aMoons);
		}

		function _readMoon(thiz) {
			var $this = jQuery(thiz),
			m = new Object(),
			titledata = $this.attr('title').match(/([\d-:\.]+)/ig),
			coords = titledata[0].split(':');

			coords.forEach( function(d,i){
				coords[i] = parseInt(d);
			});

			m.id = parseInt(thiz.href.match(/cp=(\d+)/ig)[0].slice(3));
			m.name = thiz.title.match(/([\w]+) \[/ig)[0].slice(0,-2);
			m.coords = coords;
			m.diametre = parseInt(titledata[1].replace('.',''));
			m.space = [ parseInt(titledata[2]), parseInt(titledata[3]) ];
			return m;
		}

		/**
		 * root.resources (enumerabe)
		 */
		function loadResourcesAjax() {
			return jQuery.post('/game/index.php?page=traderOverview', {
				ajax : 1,
				show : 'importexport'
			}, function(data, textStatus, jqXHR) {
				var script_re = /<script\b[^>]*>([\s\S]*?)<\/script>/gm,
				planet_re = /planetResources=({[\s\S]*?});/gm,
				script = script_re.exec(data)[1],
				impResources = planet_re.exec(script)[1];
				impResources = JSON.parse(impResources);

				_define(impResources, 'fnTotal', function(){
					var result = {
						metal : 0,
						crystal : 0,
						deuterium : 0
					};

					for (var z in this )
						root.fnSumResources(result, this[z].input);

					return result;
				}, false);

				_define(root, 'resources', impResources);
			});
		}

		/**
		 * Lee las tecnologias del planeta actual
		 *
		 * Storage.researchs
		 * Storage.*currentPlanetId*
		 *
		 */
		function loadTechsAjax() {
			var ajax = null;
			if ( root.Storage.item(document.querySelector('meta[name="ogame-planet-id"]').content) === 0
				|| win.location.href.indexOf('OGImperium=lTechs' != -1)
				|| currentPage == 'resourceSettings') {
				// lectura de recursos por primera carga
				ajax = jQuery.ajax({
					url : "/game/index.php?page=fetchTechs&ajax=1",
					dataType : 'json'
				}).done( function(data) {
					// se eliminan las investigaciones y se actualizan
					var idResearch = [113, 120, 121, 114, 122, 115, 117, 118,
						106, 108, 124, 123, 199, 109, 110, 111],
					aResearch = {};
					for(var z in idResearch){
						aResearch[ idResearch[z] ] = data[ idResearch[z] ];
						delete data[ idResearch[z] ];
					}

					root.Storage.item('researchs', aResearch);
					root.Storage.item(document.querySelector('meta[name="ogame-planet-id"]').content, data);
				});

			} else {
				var d = jQuery.Deferred();
				d.resolve('planetTechs');
				ajax = d.promise();
			}
			return ajax;
		}

		/**
		 * Lee la produccion de recursos del planeta actual
		 *
		 * Storage.*currentPlanetId* _production
		 *
		 */
		function loadConstructionFleetDefense() {
			var ajax = null;
			if ( root.Storage.production(document.querySelector('meta[name="ogame-planet-id"]').content) === 0
				|| win.location.href.indexOf('OGImperium=lProduction') != -1
				|| currentPage == 'resourceSettings') {
				// lectura de produccion cuando no existen los datos
				// o se solicita una recarga mediante url
				// o se visita la pagina "resourceSettings"

				ajax = jQuery.ajax({
					url : '/game/index.php?page=fetchResources&ajax=1',
					dataType : 'json'
				}).done( function(data) {
                    let resources = new ResourceTicker();
                    resources.reload(data);

					var result = {
						metal : resources.getProduction(ResourceTicker.Metal),
						crystal : resources.getProduction(ResourceTicker.Crystal),
						deuterium : resources.getProduction(ResourceTicker.Deuterium),
						energy : data.resources.energy.amount
					};
					root.Storage.production(document.querySelector('meta[name="ogame-planet-id"]').content, result);
				});

			} else {
				var d = jQuery.Deferred();
				d.resolve('planetProduction');
				ajax = d.promise();
			}
			return ajax;
		}

		function loadPlayer() {
			// code ...
		}

		var _defered = jQuery.when(
			loadResourcesAjax(),
			loadTechsAjax(),
			loadConstructionFleetDefense(),
		).done(function(){
			readPlanets();
		});

		_define(this, 'defered', function() {
			return _defered;
		});
	}
	var oLoader = new _loader();

	/* ###################################################################### */


	/**
	 * Objeto encargado de detectar actualizaciones de edificios,
	 * investigaciones y del hangar.
	 *
	 * this.init()
	 * this.tokenCancel (no-enumerable)
	 *
	 * root.updates        (enumerable) (this)
	 * root.hasTokenCancel (enumerable) (boolean)
	 */
	function _updates() {
		var rootUpdates = this;

		function oUpdate(data) {
			for (var n in data) {
				_define( this, n, data[n] );
			}
		}
		oUpdate.prototype.fnEndDate = function() {
			var time = this.timeDown,
			read = this.timeRead,
			now = Date.now(),
			addTime = (time * 1000) - (now - read);
			now = new Date(now + addTime);
			return now;
		};
		oUpdate.prototype.fnTimeLeft = function() {
			var time = this.timeDown,
			read = this.timeRead,
			now = Date.now(),
			left = ((time * 1000) - (now - read)) / 1000;
			return time;
		};
		oUpdate.prototype.getName = function() {
			return root.I18N(this.build);
		};

		var scriptResearch = jQuery("script:not([src]):contains('refreshLinkresearch')").eq(0).text(),
		scriptBuild = jQuery("script:not([src]):contains('refreshLinkbuilding')").eq(0).text(),
		// Exprecion para buscar la funcion que cancela
		// la construccion de edificios
		rexProductionFn = /cancelLinkbuilding = '.+\&token=(.+)\&.+'/i,
		// Exprecion para encontrar la funcion que cancela la investigación
		rexResearchFn = /cancelLinkresearch = '.+\&token=(.+)\&.+'/i;

		var tokenCancel = scriptBuild.match(rexProductionFn);
		if (null !== tokenCancel) {
			tokenCancel = tokenCancel[1];
		} else {
			tokenCancel = scriptResearch.match(rexResearchFn);
			if (null !== tokenCancel) {
				tokenCancel = tokenCancel[1];
			}
		}
		_define(this, 'tokenCancel', tokenCancel);
		_define(this, 'urlCancel', '/game/index.php?page=ingame&component={0}&modus=2&token=ed807bd7911af0e49ab3dc28280cb13c&action=cancel /game/index.php?page={0}&modus=2&token='
			+ tokenCancel + '&type={1}&listid={2}');
		_define(root, 'hasTokenCancel', (tokenCancel !== null));

		function readCurrentBuild() {

			var rexCountdown = /var restTimebuilding = (\d+) \- Math.floor\(\(Date.now\(\) \+ window.timeDiff \+ window.timeZoneDiffSeconds \* 1000\) \/ 1000\);/i,
			rexResearch = /var restTimeresearch = (\d+) \- Math.floor\(\(Date.now\(\) \+ window.timeDiff \+ window.timeZoneDiffSeconds \* 1000\) \/ 1000\);/i;
			var countdown = scriptBuild.match(rexCountdown),
			research = scriptResearch.match(rexResearch);

			function _build(table) {
				var data = false;
				if (!table.find('.idle').length) {
					var level = jQuery.trim( table.find('.level').text() ),
					title = $(table.find('a.abortNow')[0]).attr('title'),
					click = table.find('a.abortNow')[0].onclick;
					if ('function' === typeof(click))
						click = click.toString();
					click = click.match(/cancel[\w]+\((\d+)[ ,]*(\d+)/i);
					// [build, nivel, lista, planeta]
					data = {
						build    : parseInt( click[1] ),
						level    : parseInt( level.replace(/\D+/i, '') ),
						list     : parseInt( click[2] ),
						planet   : document.querySelector('meta[name="ogame-planet-id"]').content,
						timeRead : localTime,
						title    : title
					};
				}
				return data;
			}

			var c = jQuery('table.construction'), data = false;
			if (null !== countdown) {
				var t = c.eq(0);
				data = _build(t);
				data.timeDown = parseInt(countdown[1] - Math.floor(Date.now() / 1000));
				root.updates[ data.planet ] = new oUpdate( data );
			}
			root.Storage.construction(document.querySelector('meta[name="ogame-planet-id"]').content, data);

			data = false;
			if (null !== research) {
				t = currentPage === 'overview' ? c.eq(1) : c.eq(0);
				data = _build(t);
				data.timeDown = parseInt(research[1] - Math.floor(Date.now() / 1000));
				root.Storage.construction('researchs', data);
				root.updates.researchs = new oUpdate( data );
			}
		}


		/**
		 * Lee las construcciones actuales y guardadas anteriormente
		 *
		 * root.updates (enumerable)
		 *
		 * Storage.*planet* _production "dinamica según termina la construcción"
		 *                              "o se detecta una construccion nueva   "
		 */
		function chargeBuilds() {
			var aUpdates = {}, update = false;

			function auxUpdateStorage(planet, build, level){
				// elementos que afectan a la produccion
				var elmsProduction = [1, 2, 3, 4, 12 ,212];
				if (elmsProduction.indexOf(build) != -1) {
					root.Storage.production(planet, 0);
				}
				root.Storage.objectUpdate(planet, build, level );
			}

			// buscando construcciones en planetas
			for(var z in root.planets) {
				update = root.Storage.construction(z);
				if (!update) continue;

				update = new oUpdate(update);
				if ( update.fnTimeLeft() >= 0 ) {
					auxUpdateStorage(z, update.build, update.level );
					root.Storage.construction(z, false);
					continue;
				}

				aUpdates[ z ] = update;
			}

			// buscando construcciones en lunas
			for (var y in root.moons) {
				update = root.Storage.construction(y);
				if (!update) continue;

				update = new oUpdate(update);
				if ( update.fnTimeLeft() <= 0 ) {
					auxUpdateStorage(y, update.build, update.level );
					root.Storage.construction(y, false);
					continue;
				}

				aUpdates[ y ] = update;
			}

			// buscando actualización de investigación
			update = root.Storage.construction('researchs');
			if ( update ) {
				update = new oUpdate(update);
				if (update.fnTimeLeft() <= 0) {
					root.Storage.objectUpdate('researchs', update.build, update.level);
					root.Storage.construction('researchs', false);
				} else {
					aUpdates.researchs = update;
				}
			}

			_define(aUpdates, 'length', function(){
				var keys = Object.keys(this),
					n = keys.length;
				if (keys.indexOf('researchs') >= 0) n--;
				return n;
			}, false);

			_define(root, 'updates', aUpdates);
		}


		/* ATENCION!!
		 *
		 * La siguientes funciones re-escriben los procesos para cancelar una
		 * construcion en progreso en el planeta actual.
		 *
		 * Tambien se sobre escribe la funcion para cancelar una investigacion
		 * que se encuentra en progreso.
		 */

		function __cancelProductionStart() {
			root.Storage.construction(document.querySelector('meta[name="ogame-planet-id"]').content, false);
			var url = rootUpdates.urlCancel.format(currentPage,
				win.cancelProduction_id, win.production_listid );
			win.location.replace(url);
		}
		if (typeof(win.cancelProductionStart) === 'function') {
			win.cancelProductionStart = __cancelProductionStart;
		}

		function __cancelResearch(id, listId, question) {
			win.errorBoxDecision(LocalizationStrings.attention, question,
				LocalizationStrings.yes, LocalizationStrings.no, function() {
					root.Storage.construction('researchs', false);
					var url = rootUpdates.urlCancel.format(currentPage, id, listId );
					win.location.replace(url);
				});
		}
		if (typeof(win.cancelResearch) === 'function') {
			win.cancelResearch = __cancelResearch;
		}

		_define(this, 'init', function() {
			chargeBuilds();
			readCurrentBuild();
		});
	}
	var oUpdates = new _updates();


	/* ###################################################################### */

	function oFlyPack() {
		this.directs = [];
		this.returns = [];
		this.hasReturn = false;
		this.hasDirect = false;
	}
	oFlyPack.prototype.addFly = function(data, isReturn) {

		var ships = {};
		for(var z in data.ships ) {
			var n = data.ships[ z ];
			var k = root.flying.configuration.ShipsNameKey[ z ];
			ships[ k ] = n;
		}
		data.ships = ships;

		if (isReturn) {
			this.hasReturn = true;
			this.returns.push( new oFly(data) );
		} else {
			this.hasDirect = true;
			this.directs.push( new oFly(data) );
		}
	};
	oFlyPack.prototype.fnTotalResources = function() {
		var result =  {
			metal : 0,
			crystal : 0,
			deuterium : 0
		};

		for(var z in this.directs)
			root.fnSumResources(result, this.directs[ z ].resources);

		for( z in this.returns)
			root.fnSumResources(result, this.returns[ z ].resources);

		return result;
	}
	// obtiene el total de los vuelos en direccion
	oFlyPack.prototype.fnTotalDirects = function() {
		if (!this.hasDirect) return null;
		var data = {
			resources: {metal:0, crystal:0, deuterium:0},
			ships : {},
			id : NaN,
			timeArrival : NaN
		}, array = this.directs;

		for(var z in array) {
			root.fnSumResources(data.resources, array[ z ].resources);

			for(var a in array[ z ].ships ){
				if ( !data.ships[ a ] ) data.ships[ a ] = 0;
				data.ships[ a ] += array[ z ].ships[ a ];
			}
		}
		return new oFly( data );
	}
	// obtiene el total de los vuelos en retorno
	oFlyPack.prototype.fnTotalReturns = function() {
		if (!this.hasReturn) return null;
		var data = {
			resources: {metal:0, crystal:0, deuterium:0},
			ships : {},
			id : NaN,
			timeArrival : NaN
		}, array = this.returns;

		for(var z in array) {
			root.fnSumResources(data.resources, array[ z ].resources);

			for(var a in array[ z ].ships ){
				if ( !data.ships[ a ] ) data.ships[ a ] = 0;
				data.ships[ a ] += array[ z ].ships[ a ];
			}
		}
		return new oFly( data );
	};

	function oFly(data) {
		// id, resources, ships
		Object.assign(this, data);
	}
	oFly.prototype.countShips = function () {
		var n = 0;
		for (var z in this.ships) n++;
		return n;
	};

	/**
	 * Lectura de los vuleos en progreso
	 */
	function _flys() {
		var config = {};


		_define(config, 'ShipsTypes', {
			/* Cazador ligero  */ 204 : 1,
			/* Cazador pesado  */ 205 : 1,
			/* Crucero         */ 206 : 1,
			/* Nave de batalla */ 207 : 1,
			/* Acorazado       */ 215 : 1,
			/* Bombardero      */ 211 : 1,
			/* Destructor      */ 213 : 1,
			/* EDL Muerte      */ 214 : 1,
			/* NP de carga     */ 202 : 2,
			/* NG de carga     */ 203 : 2,
			/* Nave de colonia */ 208 : 2,
			/* Reciclador      */ 209 : 2,
			/* Sonda espionaje */ 210 : 2,
			/* Satelite solar  */ 212 : 1
		});
		Object.freeze( config.ShipsTypes );

		_define(config, 'ShipsNameKey', {});

		for(var s in config.ShipsTypes ) {
			config.ShipsNameKey[ root.I18N(s) ] = parseInt(s);
		}
		Object.freeze( config.ShipsNameKey );

		_define(config, 'TYPE_MILITAR', 2);
		_define(config, 'TYPE_CIVIL', 1);



		function flyData(data) {
			var pre = data.replace(/\n/g, '').split("<th"),
			result = {
				ships : {},
				resources : {metal : 0, crystal : 0, deuterium : 0}
			};
			if (!pre[1] && !pre[2]) return;
			// naves
			var part = pre[1].split("<td");
			for (var i = 1; i < part.length - 2; i += 2) {
				var n = jQuery.trim(part[i]).slice(1, -6),
				c = part[i + 1].match(/>([\d.]+)</)[1].replace(/\./g, "");
				result.ships[n] = parseInt(c);
			}
			// recursos
			if ('undefined' != typeof(pre[2]) ) {
				part = pre[2].split("<td");
				var flyMetal = part[2].match(/>([\d.]+)</)[1].replace(/\./g, ""),
				flyCrystal = part[4].match(/>([\d.]+)</)[1].replace(/\./g, ""),
				flyDeuterium = part[6].match(/>([\d.]+)</)[1].replace(/\./g, "");

				result.resources = {
					metal : parseInt(flyMetal),
					crystal : parseInt(flyCrystal),
					deuterium : parseInt(flyDeuterium)
				};
			}
			return result;
		}


		var planetsCoords = {};
		var _aFly = {};
		_define(root, 'flying', _aFly);

		_define( _aFly, 'configuration', config, false);
		// funcion para obtener el total de recursos en vuelo
		_define( _aFly, 'fnResourcesTotal', function() {
			var result = { metal:0, crystal:0, deuterium:0 };
			for (var z in this) {
				var pack = this[z].fnTotalResources();
				root.fnSumResources(result, pack);
			}
			return result;
		}, false);

		for (var x in root.planets)
			planetsCoords [ root.planets[x].coords.join(':') ] = x;

		function _planetid(coords, isMoon) {
			var planet =  planetsCoords[coords];
			if('undefined' === typeof(planet)) return 0;
			planet = root.planets[planet];
			if (isMoon) {
				planet = planet.moon;
			}
			return planet.id;
		}

		var ignore_flight = [];

		// mision type 3 : transporte
		// mision type 4 : despliege

		jQuery("#eventContent .eventFleet").each(function () {
			var $this = jQuery(this),
			isDeploy = $this.data('missionType') == 4,
			timeArrival = $this.data('arrivalTime'),
			isReserve = $this.find('td.icon_movement_reserve').length > 0,
			flightId = parseInt(this.id.replace(/[\D]+-/g, ''));
			var id = null,
			title = null,
			name = '';

			if (ignore_flight.indexOf(flightId) > -1) return;

			if (isReserve) {
				var coords = jQuery.trim($this.find('.coordsOrigin').text()).slice(1, -1),
				isMoon = $this.find('.originFleet .moon').length > 0;
				id = _planetid(coords, isMoon);
				title = $( $this.find('td.icon_movement_reserve span')[0] ).attr('title');
			} else if (isDeploy || !isReserve) {
				var coords = jQuery.trim($this.find('.destCoords').text()).slice(1, -1),
				isMoon = $this.find('.destFleet .moon').length > 0;
				id = _planetid(coords, isMoon);
				title = $( $this.find('td.icon_movement span')[0] ).attr('title');
				ignore_flight.push(flightId + 1);
			}
            if(id === 0) return;
			var fData = flyData(title);
			fData.id = flightId;
			fData.timeArrival = timeArrival;
			if ('undefined' === typeof(_aFly[id])) {
				_aFly[id] = new oFlyPack();
			}
			_aFly[id].addFly(fData, isReserve);
		});
	}

	var rootDefered = jQuery.when(
		oLoader.defered()
	).done( function() {
		oUpdates.init();
		_flys();
	});
	/** en este se encapsulan todos los ajax del sistema */
	_define(root, 'defered', function(){
		return rootDefered;
	});
	// procesos init...

}
_fnImperium.prototype.fnCancelUpdate = function(idUpdate) {
	var update = this.updates[idUpdate];
	if (!update) return;
	var url = this.oUpdates.urlCancel,
	storage = this.Storage;
	win.errorBoxDecision( LocalizationStrings.attention, // Titulo del mensaje
	 update.title, // mensaje que muestra el cuadro
	 LocalizationStrings.yes, LocalizationStrings.no, function() {
	 	storage.construction(idUpdate, false);
	 	url = url.format(currentPage, update.build, update.list);
	 	win.location.replace( url );
	 });
};
_fnImperium.prototype.fnSumResources = function(to, data ) {
	if ('undefined' == typeof(to.metal)) to.metal = 0;
	if ('undefined' == typeof(to.crystal)) to.crystal = 0;
	if ('undefined' == typeof(to.deuterium)) to.deuterium = 0;
	to.metal += data.metal;
	to.crystal += data.crystal;
	to.deuterium += data.deuterium;
};



function _fnImperiumUI(imperium, c) {
	var root = this;

	function __language() {

		var lang_es = {
			menu_link : 'Empire',
			investigacion : "Researchs",
			recursos : "Resources",

			metal : "Metal",
			cristal : "Crystal",
			deuterio : "Deuterium",
			total : "Total:",

			production_hour : "Production per hour:",
			production_day : "Daily production:",
			production_week : "Weekly production:",
			production_month : "Monthly production:",

			researchs_noData : "No research data!",
			production : "Production",
			produccion_no : "No production data!",

			construction : 'Construction',

			title_produccion : "Production of the whole empire",
			title_recursos : "Resources per Planet",
			title_currentcostruction : "Constructions in progress",
			title_builds : 'Buildings per planets',

			fly_resources : "Flying resources",
			moon_resources : "Moon resources",
			planet_resources : "Planet resources",

			tooltip_fleet : "Fleet details:",
			tooltip_fleet_ships : "Ships:",
			tooltip_fleet_resources : "Resources:",
			sent : "Sent:",
			returning : "Returning:",

			research_basic : 'Basic research',
			research_drives : 'Drive research',
			research_advanced : 'Advanced researchs',
			research_combat : 'Combat researchs',
			research_noprogress : 'No research in progress',

			resource_buildings : 'Resource buildings',
			station_buildings : 'Station buildings',
            defences_number: 'Number Defences',
            ships_number: 'Number Ships',

			nivel : 'Level',
			cancel : 'cancel',

			nbsp:' '
		};
		var lang_en = {
			menu_link : 'Empire',
			investigacion : "Researchs",
			recursos : "Resources",

			metal : "Metal",
			cristal : "Crystal",
			deuterio : "Deuterium",
			total : "Total:",

			production_hour : "Production per hour:",
			production_day : "Daily production:",
			production_week : "Weekly production:",
			production_month : "Monthly production:",

			researchs_noData : "No research data!",
			production : "Production",
			produccion_no : "No production data!",

			construction : 'Construction',

			title_produccion : "Production of the whole empire",
			title_recursos : "Resources per Planet",
			title_currentcostruction : "Constructions in progress",
			title_builds : 'Buildings per planets',

			fly_resources : "Flying resources",
			moon_resources : "Moon resources",
			planet_resources : "Planet resources",

			tooltip_fleet : "Fleet details:",
			tooltip_fleet_ships : "Ships:",
			tooltip_fleet_resources : "Resources:",
			sent : "Sent:",
			returning : "Returning:",

			research_basic : 'Basic research',
			research_drives : 'Drive research',
			research_advanced : 'Advanced researchs',
			research_combat : 'Combat researchs',
			research_noprogress : 'No research in progress',

			resource_buildings : 'Resource buildings',
			station_buildings : 'Station buildings',
            defences_number: 'Number Defences',
            ships_number: 'Number Ships',

			nivel : 'Level',
			cancel : 'cancel',

			nbsp:' '
		};
		var lang_de = {
            menu_link : 'Empire',
            investigacion : "Forschungsdaten",
            recursos : "Rohstoffe",

            metal : "Metal",
            cristal : "Kristall",
            deuterio : "Deuterium",
            total : "Gesamt:",

            production_hour : "Stündlich:",
            production_day : "Täglich:",
            production_week : "Wöchentlich:",
            production_month : "Monatlich:",

            researchs_noData : "Keine Forschungsdaten!",
            production : "Produktion",
            produccion_no : "Keine Produktionsdaten!",

            construction : 'Konstruktion',

            title_produccion : "Produktion deines Imperiums",
            title_recursos : "Rohstoffübersicht",
            title_currentcostruction : "Bauarbeiten in Gange",
            title_builds : 'Gebäudeübersicht',

            fly_resources : "Rohstoffe auf Transportwegen",
            moon_resources : "Rohstoffe auf dem Mond",
            planet_resources : "Rohstoffe auf dem Planet",

            tooltip_fleet : "Flottendetails:",
            tooltip_fleet_ships : "Schiffe:",
            tooltip_fleet_resources : "Rohstoffe:",
            sent : "Gesendet:",
            returning : "Ankunft:",

            research_basic : 'Grundlagenforschung',
            research_drives : 'Antriebsforschung',
            research_advanced : 'Erweiterte Forschung',
            research_combat : 'Kampfforschung',
            research_noprogress : 'Keine Forschung im Gange',

            resource_buildings : 'Versorgungsgebäude',
            station_buildings : 'Anlagen',
            defences_number: 'Verteidigungsanlagen',
            ships_number: 'Flottenstärke',

            nivel : 'Stufe',
            cancel : 'Abbruch',

            nbsp:' '
        };
        var lang_fr = {
			menu_link : 'Empire',
			investigacion : "Recherche",
			recursos : "Ressources",

			metal : "Métal",
			cristal : "Cristal",
			deuterio : "Deutérium",
			total : "Total:",

			production_hour : "Production par heure:",
			production_day : "Production journalière:",
			production_week : "Production hebdomadaire:",
			production_month : "Production Mensuel:",

			researchs_noData : "No research data!",
			production : "Production",
			produccion_no : "No production data!",

			construction : 'Construction',

			title_produccion : "Production entière de l'Empire",
			title_recursos : "Ressources par Planète",
			title_currentcostruction : "Construction en cours",
			title_builds : 'Bâtiment par planète',

			fly_resources : "Ressources en vole",
			moon_resources : "Ressources Lunes",
			planet_resources : "Ressources planète",

			tooltip_fleet : "Flottes détails:",
			tooltip_fleet_ships : "Vaisseaux:",
			tooltip_fleet_resources : "Ressources:",
			sent : "Envoyé:",
			returning : "Retourné:",

			research_basic : 'Recherche de base',
			research_drives : 'Recherche de déplacement',
			research_advanced : 'Recherche avancée',
			research_combat : 'Recherche de combat',
			research_noprogress : 'Aucune recherche en cours',

			resource_buildings : 'Batiments Ressources',
			station_buildings : 'Batiments Militaire',
            defences_number: 'Nombre Défences',
            ships_number: 'Nombre vaisseaux',

			nivel : 'Niveau',
			cancel : 'annuler',

			nbsp:' '
		};

		var current = lang_en;
		if (location.href.indexOf('-es.ogame.gameforge.com') != -1)
			Object.assign(current, lang_es);
		else if (location.href.indexOf('-fr.ogame.gameforge.com') != -1)
			Object.assign(current, lang_fr);
	     else if (location.href.indexOf('-de.ogame.gameforge.com') != -1)
            Object.assign(current, lang_de);
		else if (location.href.indexOf('-mx.ogame.gameforge.com') != -1)
			Object.assign(current, lang_es);

		_define(this, 'current', current);
	}

	__language.prototype.get = function(key) {
		if ( 'undefined' == typeof this.current[key] ) return key;
		return this.current[key];
	}
	__language.prototype.format = function(text) {
		jQuery.each(this.current, function(k, v) {
			var reg = new RegExp("\{" + k + "\}", 'ig');
			text = text.replace(reg, v);
		});
		return text;
	};

	_define(root, 'Language', new __language() );

    // Colocando el boton del imperio en el menu de navegación y agregando
	// el contenedor principal para la información.
	var ui_menu = jQuery('<li class="btnImperium">').append(
			'<span class="menu_icon"><div class="menuImage empire"></div></span>',
			'<a class="menubutton" href="javascript:void(0);">'
				+ '<span class="textLabel">' + root.Language.get('menu_link') + '</span></a>' );
	jQuery("#links #menuTable").append( ui_menu );

	var ui_fastmenu = jQuery('<ul>',{
		id: 'OGI_fastmenu',
		class : 'OGI-horizontal'
	}).append(
		jQuery('<li>').append(
			jQuery('<a>', {class:'dark_highlight',
				href : '#OGICurrentProduction',
				html:"<span class='img-main menu-icon32' ref='production'></span>"} )
		),
		jQuery('<li>').append(
			jQuery('<a>', {class:'dark_highlight',
				href : '#OGICurrentConstruction',
				html:"<span class='img-main menu-icon32' ref='construction'></span>"} )
		)
	);
	jQuery('#rechts').append( ui_fastmenu );

	/* ###################################################################### */
	/* ############## Objeto contenedor de los estilos CSS ################## */
	/* ###################################################################### */

	function __style() {

		_define(this, 'links', [

		]);
		Object.freeze(this.links);

		_define(this, 'directives', [

			".OGI-boxz {background: none repeat scroll 0px center transparent;margin: 0px auto 25px;width: 670px;}",
			".OGI-boxz .header{background: transparent url('//gf3.geo.gfsrv.net/cdnef/bfb16d45a8ab1ca15ca3029feb8b44.gif') 0 0 no-repeat;height: 28px;}",
			".OGI-boxz .content{background: url('//gf1.geo.gfsrv.net/cdn03/db530b4ddcbe680361a6f837ce0dd7.gif') repeat-y;padding: 5px 20px;position: relative;}",
			".OGI-boxz .footer{background: transparent url('//gf3.geo.gfsrv.net/cdnbe/04a7b39dc27c29c4c2cadd3fd44ec0.gif') no-repeat 0 -13px;/*bottom: -13px*/;height: 50px;left: 0px;position: absolute;width: 667px;z-index: -1;}",
			".OGI-boxz .OG-layer{margin-top:0;}",
			".OGI-boxz .header h2{cursor:default;text-align:center;color: #6F9FC8;font: 700 12px/28px Verdana,Arial,Helvetica,sans-serif;}",
			".OGI-boxz .header>.tabOpenClose { float:right; position:relative; top:7px; right:35px; }",

			".OGI-layer {margin: 5px 0 0 5px;position:relative;float:left;}",
			".OGI-layer > .overlayer{background-color:rgb(20, 30, 38);}",
			".OGI-layer > .information h2{cursor:default;text-align: center; background-color: rgb(35, 40, 45); box-shadow: 0px 0px 3px 1px rgb(0, 5, 10) inset; padding: 0.1em; border:1px solid black; margin-bottom: 1px;}",
			".OGI-layer > .information td, .OG-layer > .information th{padding:3px 0 0 0;}",
			".OGI-layer .rigth{text-align:right}",
			".OGI-layer .bar_container{width:auto !important;}",

			".research-icon { width:50px; height:50px; }",
			".resources00-icon, .resources01-icon, .resources02-icon, .defence-icon, .station-icon,"
				+ ".shipyard-icon { width:30px !important; height:30px !important;}",
			/* (icons) metal, crystal, deuterium, energy, dark */
			".resources00-icon { background-repeat:no-repeat; background-image: url('https://i.imgur.com/2Klisqo.png'); }",
			/* fusion, metal, solar, deuterium, crystal, satellite */
			".resources01-icon { background-repeat:no-repeat; background-image: url('//gf3.geo.gfsrv.net/cdn53/7a9861be0c38bf7de05a57c56d73cf.jpg'); background-size: 600px 900px;}", // update 30
			/* metal storage, crystal storage, deuterium storage
			   metal hiden, crystal hiden, deuterium hiden */
			".resources02-icon { background-repeat:no-repeat; background-image: url('//gf3.geo.gfsrv.net/cdn53/7a9861be0c38bf7de05a57c56d73cf.jpg');  background-size: 600px 900px;}", // update 30
			".station-icon  { background-repeat:no-repeat; background-image: url('//gf3.geo.gfsrv.net/cdn53/7a9861be0c38bf7de05a57c56d73cf.jpg');  background-size: 600px 900px;}",  // update 50
			".research-icon { background-repeat:no-repeat; background-image: url('//gf3.geo.gfsrv.net/cdn53/7a9861be0c38bf7de05a57c56d73cf.jpg'); background-size: 1000px 1600px; }",  // update 50
			".shipyard-icon { background-repeat:no-repeat; background-image: url('https://i.imgur.com/IXpDJ4g.png'); background-size: 420px 90px;}",
			".defence-icon  { background-repeat:no-repeat; background-image: url('https://i.imgur.com/Y4YSU1X.png'); background-size: 330px 90px; }",
			".menu-icon32 { background: url('https://i.imgur.com/WuayUF0.png') no-repeat; width:24px; height:24px; display:inline-block;}",

			".menu-icon32[ref='construction'] { background-position: 0 0; }",
			".menu-icon32[ref='production'] { background-position: -24px 0; }",

			".research-icon[ref='106'] { background-position: 42.1% 68.96%; }",
			".research-icon[ref='108'] { background-position: 47.36% 68.96%; }",
			".research-icon[ref='109'] { background-position: 73.68% 68.96%; }",
			".research-icon[ref='110'] { background-position: 78.94% 68.96%; }",
			".research-icon[ref='111'] { background-position: 68.42% 68.96%; }",
			".research-icon[ref='113'] { background-position: 0 68.96%; }",
			".research-icon[ref='114'] { background-position: 15.78% 68.96%; }",
			".research-icon[ref='115'] { background-position: 26.31% 68.96%; }",
			".research-icon[ref='117'] { background-position: 31.57% 68.96%; }",
			".research-icon[ref='118'] { background-position: 36.84% 68.96%; }",
			".research-icon[ref='120'] { background-position: 5.25% 68.96%; }",
			".research-icon[ref='121'] { background-position: 10.52% 68.96%; }",
			".research-icon[ref='122'] { background-position: 21.05% 68.96%; }",
			".research-icon[ref='123'] { background-position: 57.88% 68.96%; }",
			".research-icon[ref='199'] { background-position: 63.15% 68.96%; }",
			".research-icon[ref='124'] { background-position: 52.62% 68.96%; }",

			".resources01-icon[ref='12']{ background-position: 0px 0 }",
			".resources01-icon[ref='1']{ background-position: 0 0 }",
            ".resources01-icon[ref='2']{ background-position: -30px 0 }",
            ".resources01-icon[ref='3']{ background-position: -60px 0 }",
			".resources01-icon[ref='4']{ background-position: -90px 0 }",
			".resources01-icon[ref='212']{ background-position: -150px 0 }",


			".resources02-icon[ref='22']{ background-position: 0 0 }",
			".resources02-icon[ref='23']{ background-position: -30px 0 }",
			".resources02-icon[ref='24']{ background-position: -60px 0 }",
			".resources02-icon[ref='25']{ background-position: -90px 0 }",
			".resources02-icon[ref='26']{ background-position: -120px 0 }",
			".resources02-icon[ref='27']{ background-position: -150px 0 }",

			".station-icon[ref='14'] { background-position: 0 0 }",
			".station-icon[ref='31'] { background-position: -30px 0 }",
			".station-icon[ref='34'] { background-position: -60px 0 }",
			".station-icon[ref='21'] { background-position: -90px 0 }",
			".station-icon[ref='15'] { background-position: -120px 0 }",
			".station-icon[ref='33'] { background-position: -150px 0 }",
			".station-icon[ref='44'] { background-position: -180px 0 }",
			".station-icon[ref='41'] { background-position: -210px 0 }",
			".station-icon[ref='42'] { background-position: -240px 0 }",
			".station-icon[ref='43'] { background-position: -270px 0 }",

			".defence-icon[ref='401'] { background-position: 0px 0 }",
			".defence-icon[ref='402'] { background-position: -30px 0 }",
			".defence-icon[ref='403'] { background-position: -60px 0 }",
			".defence-icon[ref='404'] { background-position: -90px 0 }",
			".defence-icon[ref='405'] { background-position: -120px 0 }",
			".defence-icon[ref='406'] { background-position: -150px 0 }",
			".defence-icon[ref='407'] { background-position: -180px 0 }",
			".defence-icon[ref='408'] { background-position: -210px 0 }",
			".defence-icon[ref='502'] { background-position: -240px 0 }",
			".defence-icon[ref='503'] { background-position: -270px 0 }",

            ".shipyard-icon[ref='202'] { background-position: 0px 0 }",
			".shipyard-icon[ref='203'] { background-position: -30px 0 }",
			".shipyard-icon[ref='204'] { background-position: -60px 0 }",
			".shipyard-icon[ref='205'] { background-position: -90px 0 }",
			".shipyard-icon[ref='206'] { background-position: -120px 0 }",
			".shipyard-icon[ref='207'] { background-position: -150px 0 }",
			".shipyard-icon[ref='208'] { background-position: -180px 0 }",
			".shipyard-icon[ref='209'] { background-position: -210px 0 }",
			".shipyard-icon[ref='210'] { background-position: -240px 0 }",
			".shipyard-icon[ref='211'] { background-position: -270px 0 }",
			".shipyard-icon[ref='212'] { background-position: -300px 0 }",
			".shipyard-icon[ref='213'] { background-position: -330px 0 }",
			".shipyard-icon[ref='214'] { background-position: -360px 0 }",
			".shipyard-icon[ref='215'] { background-position: -390px 0 }"
		]);

		this.add('.icon30', {
			height: '30px !important',
			width: '30px !important'
		});

		this.add('.iconH24', {
			height: '24px !important',
			width: '40px !important'
		});

		this.addArray([
			['#OGImperium', {
				width: '670px',
				overflow: 'visible',
				position: 'relative',
				padding: '0px',
				float: 'left',
				margin: '10px 0',
				"font-size" :'11px' }],
			["#OGImperium .bar_container, .fixbar_container", {
				width : 'auto !important' }]
		]);

		this.addArray([
			["ul.OGI-horizontal, #OGImperium ul.horizontal", {
				'text-align':'center' }],
			["ul.OGI-horizontal li, #OGImperium ul.horizontal li", {
				display:'inline-block',
				margin:'1px 0px',
				position:'relative',
				top:'auto'}],

			[".tabOpenClose", {
				cursor:'pointer',
				background:"url('https://i.imgur.com/yCUsTvZ.gif') no-repeat",
				width:'18px',
				height:'16px',
				'background-position': '0 0',
				display:'block'}],
			[".tabOpenClose.tabClose", {
				'background-position': '0 -16px' }],

			[".overlayer", {
				'z-index':1,
				opacity:0.5,
				width:'100%',
				height:'100%',
				position:'absolute',
				background:'none repeat scroll 0% 0%',
				'border-radius':'7px',
				'-webkit-border-radius':'7px',
				'-moz-border-radius':'7px' }],
			[".OGI-layer .information", {
				'z-index':2,
				position:'relative',
				padding:'2px 0px'}]
		]);

		this.addArray([
			["table.OGItable-fix tr td:last-child, table.OGItable-fix tr th:last-child", {
				'padding-right':'10px'
			}],
			["table.OGItable-fix td, table.OGItable-fix th", {
				'text-align' : 'right', height : '25px'
			}],
			["table.OGItable-fix th", {
				'font-weight' : 700, 'padding-bottom' : 0, 'vertical-align' : 'middle'
			}],
			["table.OGItable-fix td.label" ,{
				color : '#808080', 'text-align':'left', 'padding-left':'5px'
			}],
			["table.OGItable-fix tr.summary td", {
				'border-top':'1px dotted #848484'
			}]
		]);

		this.addArray([
			["#menuTableImperium .btnShorts", {
				height : '35px !important'	}],
			["#OGI_fastmenu a", {
				display:'inline-block', padding:'3px',
				width:'24px', height:'24px',
				'margin-right':'3px'
			}]
		]);
	}

	__style.prototype.add = function(selector, data) {
		tx = '';
		for(var keyName in data )
			tx += "\t" + keyName + ":" + data[keyName] + "; \n";
		tx = selector + ' {\n' + tx + '}';
		this.directives.push(tx);
	};
	__style.prototype.addArray = function ( group ) {
		for(var z in group ) {
			this.add( group[z][0], group[z][1] );
		}
	};
	__style.prototype.toString = function() {
		return this.directives.join("\n");
	};
	__style.prototype.links = function() {
	};

	_define(root, 'style', new __style());


	/* ###################################################################### */
	/* ################ Objeto de renderisado para imagenes ################# */
	/* ###################################################################### */


	root.style.addArray([
		['div.img-tech', { cursor:'default',
			border : '2px double black',
			margin : '0.35em', position : 'relative' }],

		['div.img-tech.update', {
			'border-color' : 'rgb(231, 166, 26)' }],

		['div.layer',{
			position:'absolute', "text-align" : 'center',
			top : '-0.45em', left : '-0.45em' }],

		['div.layer .overlayer', {
			"background-color" : 'black', opacity:'0.8', border : "1px solid gray" }],

		['div.layer .information', {
			margin : 0, padding : '1px 5px' }],

		['div.layer.update',{
			top : 'inherit', left : 'inherit', right : '-0.35em', bottom : '-0.35em'}],

		['div.layer.update .overlayer', {
			"background-color" : '#55AA1A',
			border : '1px solid #75890c',  opacity : 1}]
	]);

	function __image( group, id, options) {
		if ('undefined' === typeof(options)) options = {};
		Object.assign({level:null, update:null}, options);
		_define(this, 'options', options, false);


		var main = jQuery('<div>', {
			class : 'img-tech ' + group,
			ref : id
		});
		_define(this, 'main', main, false);


		if ('undefined' != typeof(options.title)) {
			if ('undefined' === typeof(options.tooltip)) options.tooltip = 'tooltip';
			main.attr('title', options.title).addClass(options.tooltip);
		}

		var level = jQuery('<div>' , {
			class : 'layer level'
		}).append(
			"<div class='overlayer'></div>",
			jQuery("<div> <b>").addClass('information')
		);
		_define(this, 'level', level.find('b'), false);
		this.setLevel(options.level);


		var update = jQuery('<div>', {
			class : 'layer update',
			style : 'display:none'
		}).append (
			"<div class='overlayer'></div>",
			jQuery("<div> <b>").addClass('information')
		);
		_define(this, 'update', update.find('b'), false);
		this.setUpdate(options.update);

		main.append(level, update);
	}
	__image.prototype.setLevel = function(l) {
		var layer = this.level.closest('.layer'),
		options = this.options;
		this.level.text( win.gfNumberGetHumanReadable(l) );

		if ( 'undefined' == typeof(l) || null === l ) {
			layer.hide();

		} else {
			layer.show();

			if(l >= 1000000 && options.title) {
				var title = options.title + " (" + win.number_format(l) + ")";
				win.changeTooltip(this.main, title);
			}
		}
	};
	__image.prototype.setUpdate = function(l) {
		var layer = this.update.closest('.layer');
		this.update.text(l);

		if ( 'undefined' == typeof(l) || null === l || '' === l ) {
			if ( layer.is(':visible') ) layer.hide();
			layer.parent().removeClass('update');
		} else {
			if ( !layer.is(':visible') ) layer.show();
			layer.parent().addClass('update');
		}
	};
	__image.prototype.objectHTML = function() {
		return this.main[0];
	};

	/* ###################################################################### */

	_define(root, 'container', c);
	_define(root, 'imperium', imperium, false);

	root.style.addArray([
		["#main_navigation",{
			'margin-bottom' : '5px' }],
		["#main_navigation > li",{
			margin:'0 3px !important' }],
		["#main_navigation a",{
			position : 'relative', padding:'3px 3px' }],
		["#main_navigation a > .menu-icon32",{
			'vertical-align':'middle', margin:'3px' }]
	]);
	function _renderTopbar() {
		var ul = jQuery('<ul>', {
			id : 'main_navigation',
			class : 'horizontal'
		});

		jQuery('<li>').append( jQuery('<a>', {
			class : 'dark_highlight',
			href : '#OGICurrentProduction',
			ref : 'dialog'
		}).append(
			"<span class='img-main menu-icon32' ref='production'></span>",
			"<p>" + root.Language.get('production') + "</p>"
		)).appendTo(ul);

		jQuery('<li>').append( jQuery('<a>', {
			class : 'dark_highlight',
			href : '#OGICurrentConstruction',
			ref : 'dialog'
		}).append(
			"<span class='img-main menu-icon32' ref='construction'></span>",
			"<p>" + root.Language.get('construction') + "</p>"
		)).appendTo(ul);

		return ul;
	}

	root.style.addArray([
		['#OGImperium .boxCurrentUpdate',{
			width : '120px',  float : 'right', 'padding-bottom':'1em'}],
		["#OGImperium .boxCurrentUpdate .information h2",{
			color: "#E7AE46" }],

		["#OGIResearchs .boxCurrentUpdate div.image",{
			width:'78px', height:'78px', display:'inline-block' }],
		["#OGIResearchs .boxCurrentUpdate div.image > a:first-child",{
			width:'76px', height:'76px', display:'inline-block',
			border:'1px solid rgb(1, 81, 0)', 'border-radius':"5px" }],
		["#OGIResearchs div.techWrapper a.abortNow", {
			bottom:'3px', right:0}],
		["#OGIResearchs .basics, #OGIResearchs .advanced", {}]
	]);
	function _renderResearchs() {
		var box = root.makeBoxZ(root.Language.get('investigacion'));
		box.root.attr('id','OGIResearchs');
		var info = root.imperium.Storage.item('researchs');
		var update = root.imperium.updates.researchs;

		function ulTech(index, data) {
			var ul = jQuery('<ul>',{
				width : '100%',
				class : 'horizontal'
			});
			for(var z in index ) {

				var idResearch = index[ z ],
				img = new __image('research-icon', idResearch, {
					title : $Imperium.I18N( idResearch ),
					level : data[ idResearch ],
				});
				if ( update && (idResearch == update.build) ) {
					img.setUpdate(update.level);
				}
				ul.append( jQuery('<li>').append(img.objectHTML()) );
			}
			return ul;
		}

		function boxCurrentUpdate(data) {
			var table = jQuery('<div>', {
				width : '100%',
				style : 'text-align:center'
			}),
			ulImg = "<div class='techWrapper' style='display:inline-block;position:relative;' >\n";
			if (null !== root.imperium.hasTokenCancel) {
				ulImg += "\t<a class='tooltip abortNow' href='javascript:void(0);' title='" + data.title
					+ "' onclick=\"cancelResearch(" +data.build+", " +data.list+ ", '" +data.title+ "');return false;\"></a> \n";
			}
			ulImg += "\t<div class='techImage research tech"+data.build+" image' ><a></a></div>\n</div>";

			table.append( ulImg );

			var timedown = jQuery('<p>').append( LocalizationStrings.loading );

			table.append(
				jQuery('<p>', {style:'margin-bottom:10px'}).append(
					"<b style='color:#9C0'>" + root.Language.get('Level') + ' ' + data.level + "</b>"
				),

				timedown,

				jQuery('<p>', { style:'color:green;font-size:80%' }).append(
					formatDateFuture( update.fnEndDate() )
				)
			);

			new win.baulisteCountdown( timedown[0], update.fnTimeLeft(), null );

			return table;
		}

		var basic = [113, 120, 121, 114, 122],
		drives = [115, 117, 118],
		advanced = [106, 108, 124, 123, 199],
		combat = [109, 110, 111];

		box.appendLayer( ulTech(basic, info), {
			class:'basics',
			title: root.Language.get('research_basic'),
		});
		box.appendLayer( ulTech(drives, info), {
			class:'drives',
			title: root.Language.get('research_drives')
		});

		// box update
		if ( update ) {
			box.appendLayer( boxCurrentUpdate(update) ,{
				class : 'boxCurrentUpdate',
				title : $Imperium.I18N(update.build),
				overlayer : true
			} );
		} else {
			box.appendLayer( '<p style="text-align:center">'
				+ root.Language.get('research_noprogress') + '</p>' ,{
				class : 'boxCurrentUpdate'
			} );
		}

		box.appendLayer( ulTech(advanced, info),{
			class:'advanced',
			title: root.Language.get('research_advanced')
		});
		box.appendLayer( ulTech(combat, info), {
			class:'combat',
			title: root.Language.get('research_combat')
		});
		return box.root;
	}

	root.style.addArray([
		["#OGIResources table img.planet", {'vertical-align':'middle', 'margin-right':'5px' }],
		["#OGIResources table tr.moon td", {color:'#9F4A4A'}],
		["#OGIResources table tr.moon img.planet", {'margin-left':'20px'}],
		["#OGIResources table tr.fly td", {color:'#75BAB0'}],
		["#OGIResources table tr td:not(:first-child)", { padding:'2px 4px' }],
		["#OGIResources table .bar_container", {height:'3px'}],
		["#OGIResources table .em-storage", {'font-size':'8px'}],
		["#OGIResources tr.planet-details",{ 'display':'none'}],
		["#OGIResources tr.planet-details .resources",{ width:'200px' }]
	]);
	function _renderResources() {
		var box = root.makeBoxZ( root.Language.get('title_recursos') );
		box.root.attr('id','OGIResources');

		var planet_img = "/cdn/img/planets/{0}",
		table = jQuery('<table>', {
			width : '100%',
			cellspacing : 0,
			class : 'OGItable-fix'
		}),
		thead = jQuery('<thead>'),
		tbody = jQuery('<tbody>'),
		tfoot = jQuery('<tfoot>');
		table.append(thead, tbody, tfoot);

		var HEAD = [
			'', // planeta
			[root.Language.get('metal'), { width : 120 }],
			[root.Language.get('crystal'), { width : 120 }],
			[root.Language.get('deuterium'), { width : 120 }]
		];

		var tr_head = jQuery('<tr>');
		thead.append(tr_head);
		for (var z in HEAD) {
			var elm = HEAD[ z ], th;
			if ('object' === typeof(elm)) {
				th = jQuery('<th>', elm[1]);
				elm = elm[0];
			} else {
				th = jQuery('<th>');
			}
			th.append(elm).appendTo(tr_head);
		}


		function __row(data , trConfig) {
			var ROW = [

				[_planet,{ class : 'label' }],
				_resourceMetal,
				_resourceCryst,
				_resourceDeute

			], tr = jQuery('<tr>', trConfig);

			for (var z in ROW) {
				var elm = ROW[ z ], td;

				if ('object' === typeof(elm)) {
					td = jQuery('<td>', elm[1]);
					elm = elm[0];
				} else {
					td = jQuery('<td>');
				}

				if('string' === typeof(elm)) {
					var str = elm;
					elm = function(p){ return str; };
				}

				td.append( elm(planet) ).appendTo(tr);
			}

			/* celda del nombre del planeta */
			function _planet(data) {
				return [
					jQuery('<img>', {
						height : '16px',
						width  : '16px',
						class : 'planet',
						src : planet_img.format(data.imageName)
					}),
					" " + data.name
				];
			}

			/* celda de recursos en planeta */
			function __resources(data, keyResource) {
				var resources = data.resources;
				function color(current, storage) {
					var c = '';
					if (current >= storage)
						c = 'overmark';
					else if (current >= storage * 0.9)
						c = 'middlemark';
					return c;
				}

				var div = jQuery('<div>').append(
					win.number_format( resources[keyResource] )
				);

				if (data.isMoon) {
					return div;
				}

				var storage = data.getStorage(), emStorage;
				if ( isNaN(storage[keyResource]) ) {
					storage[keyResource] = undefined;
					emStorage = " <em class='em-storage'>/#</em>";
				} else {
					emStorage = " <em class='em-storage'>/" + win.gfNumberGetHumanReadable(storage[keyResource], 3) + "</em>";
				}


				div.append(
					emStorage,
					root.progressbar(null, resources[keyResource], storage[keyResource])
				).addClass( color(resources[keyResource], storage[keyResource]) );

				return div;
			}
			function _resourceMetal(data){ return __resources(data, 'metal'); }
			function _resourceCryst(data){ return __resources(data, 'crystal'); }
			function _resourceDeute(data){ return __resources(data, 'deuterium'); }

			function _aDetails(data) {
				var a = jQuery('<a>',{
					class : 'tabOpenClose tabClose showDetails',
					href  : "javascript:void("+ data.id +");",
					'data-planet' : data.id
				})
				return a;
			}
			return tr;
		}

		var fill = 1;
		var planets = stellarSort(root.imperium.planets);
		for (var pid in planets) {
			var planet = planets[pid];

			__row(planet, {
				class: (fill ? 'alt' : '')
			}).appendTo(tbody);

			fill = !fill;

			if (planet.moon) {
				planet = planet.getMoon();

				__row(planet, {
					class : 'moon' + (fill ? ' alt' : '')
				}).appendTo(tbody);

				fill = !fill;
			}
		}

		var totalPlayer = {metal:0, crystal:0, deuterium:0};
		var totalEnd = root.imperium.planets.fnResourcesTotal();
		root.imperium.fnSumResources(totalPlayer, totalEnd);
		jQuery('<tr>', { class : 'summary '+ (fill ? 'alt' : '') })
		.append(

			jQuery('<td>', {class:'label'}).append(root.Language.get('planet_resources')+":"),
			jQuery('<td>').append( win.number_format(totalEnd.metal, 0) ),
			jQuery('<td>').append( win.number_format(totalEnd.crystal, 0) ),
			jQuery('<td>').append( win.number_format(totalEnd.deuterium, 0) ),

			'<td></td>'
		).appendTo(tfoot);
		fill = !fill;

		totalEnd = root.imperium.moons.fnResourcesTotal();
		root.imperium.fnSumResources(totalPlayer, totalEnd);
		jQuery('<tr>', { class : 'moon ' + (fill ? 'alt' : '') })
		.append(

			jQuery('<td>', {class:'label'}).append(root.Language.get('moon_resources')+":"),
			jQuery('<td>').append( win.number_format(totalEnd.metal, 0) ),
			jQuery('<td>').append( win.number_format(totalEnd.crystal, 0) ),
			jQuery('<td>').append( win.number_format(totalEnd.deuterium, 0) ),

			'<td></td>'
		).appendTo(tfoot);
		fill = !fill;

		totalEnd = root.imperium.flying.fnResourcesTotal();
		root.imperium.fnSumResources(totalPlayer, totalEnd);
		jQuery('<tr>', { class : 'fly ' + (fill ? 'alt' : '') })
		.append(

			jQuery('<td>', {class:'label'}).append(root.Language.get('fly_resources')+":"),
			jQuery('<td>').append( win.number_format(totalEnd.metal, 0) ),
			jQuery('<td>').append( win.number_format(totalEnd.crystal, 0) ),
			jQuery('<td>').append( win.number_format(totalEnd.deuterium, 0) ),

			'<td></td>'
		).appendTo(tfoot);
		fill = !fill;

		jQuery('<tr>', { class : 'summary ' + (fill ? 'alt' : '') })
		.append(

			jQuery('<td>', {class:'label'}).append("<b>"+root.Language.get('total')+"</b>"),
			jQuery('<td>').append( "<b>"+win.number_format(totalPlayer.metal, 0) + "</b>"),
			jQuery('<td>').append( "<b>"+win.number_format(totalPlayer.crystal, 0) + "</b>"),
			jQuery('<td>').append( "<b>"+win.number_format(totalPlayer.deuterium, 0) +"</b>" ),

			'<td></td>'
		).appendTo(tfoot);
		fill = !fill;

		box.append(table);
		return box.root;
	}

	root.style.addArray([


		["#OGIGlobalView .table-responsive", {
			"margin-bottom" : '15px', "overflow-x": 'auto',
			"overflow-y": "hidden", width: '610px'
		}],
		["#OGIGlobalView .table-responsive table", { "margin-bottom" : '15px'}],
		["#OGIGlobalView .table-responsive table .lock-col", {
			position:'absolute', left:0, top:'auto',
			//"border-right" : '1px dotted #848484',
			"border-top-width":'0px', /*only relevant for first row*/
        	"margin-top":'0px' /*compensate for top border*/ }],

		["#OGIGlobalView table div.img-tech", {
			margin : '-2px 0px 0px 0px', border:'0px'
		}],

		["#OGIGlobalView table td", {
			"vertical-align" : 'middle', "text-align" : 'center', 'height':'30px'
		}],
		["#OGIGlobalView table td:nth-child(2)",{
			'padding-left' : '32px'
		}],

		["#OGIGlobalView .planet-name", {
			'vertical-align':'super'
		}],

		["#OGIGlobalView .planet-name :first-child", {
			display:'block', "word-wrap":'break-word',
			"text-align":'center', "min-width":'70px'
		}],

		['#OGIGlobalView table tr.head', {
			"text-align":'center', "background-color":'rgb(35, 40, 45)', "box-shadow": '0px 0px 3px 1px rgb(0, 5, 10) inset',
			"padding": '0.1em', border:'1px solid black', "margin-bottom": '1px'
		}],
		['#OGIGlobalView table tr.head td', {
			"height" : '19px', "vertical-align":'top'
		}],

		['#OGIGlobalView table tr.head :first-child', {
			"border-right":'0px'
		}],

		['#OGIGlobalView table tr.head .head-closer', {
			"display": 'inline-block', "padding-top" : '1px'
		}]
	]);
	function _renderGlobalView() {
		var box = root.makeBoxZ(root.Language.get('title_builds'));
		box.root.attr('id','OGIGlobalView');

		var responsive = jQuery('<div>', {class:'table-responsive'} ),
		oT = root.tableFix();
		responsive.append( oT.table );
		box.appendLayer( responsive );

		function cell(lv) {
			props = {};
			if ( 'undefined' === typeof(lv) || parseInt(lv) === 0 ) {
				lv = 0;
				props.style = "color:#292929";
			}
			return [ win.gfNumberGetHumanReadable( lv ) , props	];
		}
		function head(title, section) {
			var trhead = oT.appendRowBody([
				[ "<div class='head-closer'><a class='tabOpenClose'></a></div>", {class:'lock-col', width:'30px'} ],
				[ "<b>"+ root.Language.get( title ) +"<b>", {colspan: root.imperium.planets.length() + 1}]
			]);
			trhead.addClass('head');
			trhead.attr('data-section', section);
		}


		// var techs = planet.techs;
		var resources = [ // ((Edificios de recursos))
			[1,   'resources01-icon'],
			[2,   'resources01-icon'],
			[3,   'resources01-icon'],
			[4,   'resources01-icon'],
			[12,  'resources01-icon'],
			[212, 'resources01-icon'],
			[22,  'resources02-icon'],
			[23,  'resources02-icon'],
			[24,  'resources02-icon']
		];
		var stations = [ // ((Estacion))
			[14,  'station-icon'],
			[21,  'station-icon'],
			[31,  'station-icon'],
			[34,  'station-icon'],
			[44,  'station-icon'],
			[15,  'station-icon'],
			[33,  'station-icon']
		];
        var defences = [
			[401,  'defence-icon'],
			[402,  'defence-icon'],
			[403,  'defence-icon'],
			[404,  'defence-icon'],
			[405,  'defence-icon'],
			[406,  'defence-icon'],
			[407,  'defence-icon'],
			[408,  'defence-icon'],
			[502,  'defence-icon'],
			[503,  'defence-icon']
		];
        var ships = [
			[202,  'shipyard-icon'],
			[203,  'shipyard-icon'],
			[204,  'shipyard-icon'],
			[205,  'shipyard-icon'],
			[206,  'shipyard-icon'],
			[207,  'shipyard-icon'],
			[208,  'shipyard-icon'],
			[209,  'shipyard-icon'],
			[210,  'shipyard-icon'],
			[211,  'shipyard-icon'],
			[212,  'shipyard-icon'],
			[213,  'shipyard-icon'],
			[214,  'shipyard-icon'],
			[215,  'shipyard-icon']
		];


		var row = [ '&nbsp;' ], // Columna inical donde va la imagen del edificio
		tr, pid;

		for(var pid in root.imperium.planets) {
			var planet = root.imperium.planets[ pid ];
			row.push(
				["<b>"+planet.name+"</b><i class='planet-coords'>["+ planet.coords.join(':') +"]</i>", { class:'planet-name' }]
			);
		}
        row.push(
            ["<b>Total</b>", { class:'planet-name' }]
        );
		oT.appendRowBody( row );

		// ===== Encabezados para los edificios de recursos
		// =================================================
		head('resource_buildings', "resources-details");

        let total = [];

		var fill = 1;
		for(let r in resources) {
			let resource = resources[ r ],
			img = new __image(resource[1], resource[0], {
				title : $Imperium.I18N( resource[0] ),
				tooltip : 'tooltipLeft'
			});
            total[resource[0]] = (total[resource[0]] !== undefined ? total[resource[0]] : 0);

			row = [ [img.objectHTML(), {class:'lock-col', height:'30px'}] ];
			for(pid in root.imperium.planets ){
				let planet = root.imperium.planets[ pid ];
				let lv = planet.techs[ resource[0] ];
                total[resource[0]] += (planet.techs[ resource[0] ] === undefined ? 0 : planet.techs[ resource[0] ]);
				row.push( cell(lv) );
			}
            row.push( cell(total[resource[0]] / root.imperium.planets.length()) );

			tr = oT.appendRowBody( row );
			tr.addClass( (fill ? 'alt' : '')+ ' resources-details' );
			fill = !fill;
		}


		// ===== Encabezados para los edificios de la estación
		// ===================================================
		head('station_buildings', 'stations-details');

        total = [];

		for(let s in stations ) {
			let station = stations[ s ],
			img = new __image(station[1], station[0], {
				title : $Imperium.I18N( station[0] ),
				tooltip : 'tooltipLeft'
			});
            total[station[0]] = (total[station[0]] !== undefined ? total[station[0]] : 0);

			row = [ [img.objectHTML(), {class:'lock-col', height:'30px'}] ];
			for(pid in root.imperium.planets ){
				let planet = root.imperium.planets[ pid ];
				let lv = planet.techs[ station[0] ];
                total[station[0]] += (planet.techs[ station[0] ] === undefined ? 0 : planet.techs[ station[0] ]);
				row.push( cell(lv) );
			}
            row.push( cell(total[station[0]] / root.imperium.planets.length()) );

			tr = oT.appendRowBody( row );
			tr.addClass( (fill ? 'alt' : '')+ ' stations-details' );
			fill = !fill;
		}

        head('defences_number', 'defences-number');

        total = [];

		for(let d in defences ) {
			let defence = defences[ d ],
			img = new __image(defence[1], defence[0], {
				title : $Imperium.I18N( defence[0] ),
				tooltip : 'tooltipLeft'
			});
            total[defence[0]] = (total[defence[0]] !== undefined ? total[defence[0]] : 0);

			row = [ [img.objectHTML(), {class:'lock-col', height:'30px'}] ];
			for(pid in root.imperium.planets ){
				let planet = root.imperium.planets[ pid ];
				let lv = planet.techs[ defence[0] ];
                total[defence[0]] += (planet.techs[ defence[0] ] === undefined ? 0 : planet.techs[ defence[0] ]);
				row.push( cell(lv) );
			}
            row.push( cell(total[defence[0]]) );

			tr = oT.appendRowBody( row );
			tr.addClass( (fill ? 'alt' : '')+ ' defences-number' );
			fill = !fill;
		}

        head('ships_number', 'ships-number');

        total = [];
        total.total = 0;

		for(let s in ships ) {
			let ship = ships[ s ],
			img = new __image(ship[1], ship[0], {
				title : $Imperium.I18N( ship[0] ),
				tooltip : 'tooltipLeft'
			});
            total[ship[0]] = (total[ship[0]] !== undefined ? total[ship[0]] : 0);

			row = [ [img.objectHTML(), {class:'lock-col', height:'30px'}] ];
			for(pid in root.imperium.planets ){
				let planet = root.imperium.planets[ pid ];
				let lv = planet.techs[ ship[0] ];
                total[ ship[0] ] += (planet.techs[ ship[0] ] === undefined ? 0 : planet.techs[ ship[0] ]);
                if(total[ pid ] === undefined)
                    total[ pid ] = 0;
                total[ pid ] += (planet.techs[ ship[0] ] === undefined ? 0 : planet.techs[ ship[0] ]);
				row.push( cell(lv) );
			}
            row.push( cell(total[ ship[0] ]) );
            total.total += (total[ ship[0] ] === undefined ? 0 : total[ ship[0] ]);

			tr = oT.appendRowBody( row );
			tr.addClass( (fill ? 'alt' : '')+ ' ships-number' );
			fill = !fill;
		}

        row = [ ['<img src="https://i.imgur.com/JyLvTkJ.jpg" class="tooltipLeft" style="height: 30px" title="Total" />', {class:'lock-col', height:'30px'}] ];
        for(pid in root.imperium.planets ){
            let planet = root.imperium.planets[ pid ];
            row.push( cell(total[ pid ] ) );
        }
        row.push( cell(total.total) );

        tr = oT.appendRowBody( row );
        tr.addClass( (fill ? 'alt' : '')+ ' ships-number' );
        fill = !fill;

		jQuery(box.root).on('click', '.head a.tabOpenClose', function(e) {
			var section = jQuery(this).closest('tr').data('section');
			var obj = jQuery(box.root).find('tr.'+section);
			var open = jQuery(this).hasClass('tabClose');
			if ( open ) {
				obj.show('slow');
				jQuery(this).removeClass('tabClose');
			} else {
				obj.hide('slow');
				jQuery(this).addClass('tabClose');
			}
		});

		return box.root;
	}

	c.append(
		_renderResearchs(),
		_renderResources(),
		_renderGlobalView()
	);

	// dialogos

	// #OGICurrentConstruction
	root.style.addArray([
		['#OGICurrentConstruction', {
			display:'none' }],
		['#OGICurrentConstruction .OGI-layer',{
			width : '32.5%', 'margin-bottom':'5px'}],
		['#OGICurrentConstruction .OGI-layer .img-tech ',{
			float: 'left', margin:'2px 10px 5px 0.35em', color:'#f1f1f1'}],
		['#OGICurrentConstruction .OGI-layer .information .text-information ', {
			display: 'table'}],
		['#OGICurrentConstruction .OGI-layer .information .planet-name ', {
			color : '#6F9FC8', 'font-size': '9px'}],
		['#OGICurrentConstruction .OGI-layer .information .timedown ', {
			'margin-top': '2px'}],
		['#OGICurrentConstruction .OGI-layer .information .timeend ', {
			color : 'green' , 'font-size' : '80%'}]
	]);
	function _dialogCurrentBuild() {

		var box = root.makeBoxZ( '' );

		function layer(planet) {
			var ul = jQuery('<div>');
			var update = planet.update();
			// buscamos la calse para la imagen de la costruccion

			var classIconGroup = '';
			if ([1,2,3,4,12].indexOf(update.build) != -1) {
				// fusion, metal, solar, deuterium, crystal
				classIconGroup = 'resources01-icon';
			} else if ([22,23,24,25,26,27].indexOf(update.build) != -1) {
				// metal storage, crystal storage, deuterium storage,
				// metal hiden, crystal hiden, deuterium hiden
				classIconGroup = 'resources02-icon';
			} else if ([14,21,31,34,44,15,33,41,42,43].indexOf(update.build) != -1) {
				// station
				classIconGroup = 'station-icon';
			}

			var img = new __image(classIconGroup, update.build, {
				update : update.level
			});

			var iconMoon = planet.isMoon ? "<figure class='planetIcon moon'></figure> " : '',
			namePlanet = "[" + planet.coords.join(':') + "] " + iconMoon + planet.name,
			nameUpdate = $Imperium.I18N( update.build ),
			timedown = jQuery('<p>',{
				class : 'timedown'
			}).append( LocalizationStrings.loading );

			new win.baulisteCountdown( timedown[0], update.fnTimeLeft(), null );

			return [
				img.objectHTML(),
				jQuery('<div>',{ class:'text-information'}).append(
					'<span class="planet-name">'+namePlanet+'</span>',
					'<p>' + nameUpdate + '</p>',
					timedown,
					'<p class="timeend">' + formatDateFuture(update.fnEndDate()) + "</p>"
				)
			];
		}

		var i = 0;
		for(var z in root.imperium.updates ) {
			if (z === 'researchs') continue;

			var planet = root.imperium.planets[ z ];
			if ('undefined' === typeof(planet) )
				planet = root.imperium.moons[ z ];

			var items = layer(planet);

			if (i%3 === 0)
				box.append('<div class="clearfloat"></div>');

			box.appendLayer( items , {
				overlayer : true
			});

			i++;
		}

		box.container.parent()
		.attr('id', 'OGICurrentConstruction')
		.dialog({
			autoOpen : false,
			title :root.Language.get('title_currentcostruction')
				+ " ({0})".format(root.imperium.updates.length()),
			width : '670px',
			resizable : false
		});
	}

	// #OGICurrentProduction
	root.style.addArray([
		["#OGICurrentProduction", {
			display : 'none'
		}],
		["#OGICurrentProduction .planet-coords", {
			'text-align': 'center', color : 'rgb(111, 159, 200)'
		}],
		["#OGICurrentProduction .no-production", {
			'text-align': 'center', color : '#d43635 !important'
		}],
		["#OGICurrentProduction .no-production a", {
			color : '#d43635 !important'
		}],
		["#OGICurrentProduction .em-level", {
			color : 'lightyellow', 'font-size' : '9px', 'font-style' : 'normal',
			display : 'block', width : '30px'
		}]
	]);
	function _dialogProduction() {
		var box = root.makeBoxZ( '' );
		var oT = root.tableFix();
		box.appendLayer( oT.table );

		var productionTotal = {};

		function row( planet ) {
			var columns = [];

			// coordenadas y nombre
			var current = (document.querySelector('meta[name="ogame-planet-id"]').content == planet.id) ? 'overmark' : '';
			columns.push([ "[" + planet.coords.join(':') + "]", {
				class : 'label planet-coords ' + current, width: 90
			}]);

			columns.push([ "<b>"+ planet.name +"</b>", { class : 'label' }]);

			// produccion
			var production = planet.getProduction();
			if (!production) {

				columns.push([
					root.Language.get("produccion_no")
					+ " - <a href='/game/index.php?cp=" + planet.id + "&OGIDialog=production' >"
					+ root.Language.get('update') + "...</a>" , {
						colspan : 7, class : 'no-production'
				}]);

			} else {
				root.imperium.fnSumResources(productionTotal, production);
				// la produccion esta guardada en segundos por lo que se
				// multiplica por 3600 para obtener la produccion por hora.
				var metal = Math.round( production.metal * 3600 );
				var crystal = Math.round( production.crystal * 3600 );
				var deuterium = Math.round( production.deuterium * 3600 );

				columns.push(
					[ win.number_format(metal) ,{
						class : 'undermark', width:110
					}],
					"<em class='em-level'>["+ planet.techs[1] + "]<em>"
				);

				columns.push(
					[ win.number_format(crystal) ,{
						class : 'undermark', width:110
					}],
					"<em class='em-level'>["+ planet.techs[2] + "]<em>"
				);

				columns.push(
					[ win.number_format(deuterium) ,{
						class : 'undermark', width:110
					}],
					"<em class='em-level'>["+ planet.techs[3] + "]<em>"
				);

				columns.push([ win.number_format(production.energy) ,{
					class : 'undermark', width:110
				}]);
			}


			return columns;
		}

		oT.appendRowHead([
			[root.Language.get('planet') , { colspan : 2 }],
			[root.Language.get('metal'), { colspan : 2 }],
			[root.Language.get('crystal'), { colspan : 2 }],
			[root.Language.get('deuterium'), { colspan : 2 }],
			root.Language.get('energy')
		]);
		var fill = true;
		var planets = stellarSort(root.imperium.planets);
		for (var p in planets) {
			var planet = planets[ p ];
			var items = row ( planet );
			var tr = oT.appendRowBody( items );
			if (fill) tr.addClass('alt');
			fill = !fill;
		}

		// la produccion esta guardada en segundos por lo que se
		// multiplica por 3600 para obtener la produccion por hora.
		var tMetal = productionTotal.metal * 3600;
		var tCrystal = productionTotal.crystal * 3600;
		var tDeuterium = productionTotal.deuterium * 3600;
		var times = [
			{label : 'production_hour', time : 1},
			{label : 'production_day', time : 24},
			{label : 'production_week', time : 168},
			{label : 'production_month', time : 720}
		];

		for (var o in times) {
			var footTime = times[ o ];
			var tr = oT.appendRowFoot([
				[root.Language.get(footTime.label),
					{ class : 'label', colspan:2}],
				[win.number_format( Math.round(tMetal * footTime.time) ),
					{ class : 'undermark'}], '',
				[win.number_format( Math.round(tCrystal * footTime.time) ),
					{ class : 'undermark'}], '',
				[win.number_format( Math.round(tDeuterium* footTime.time) ),
					{ class : 'undermark'}], '',
				''
			]);
			if ( o === 0) tr.addClass('summary');
			if (fill) tr.addClass('alt');
			fill = !fill;
		}


		box.container.parent()
		.attr('id', 'OGICurrentProduction')
		.dialog({
			autoOpen : false,
			title : root.Language.get('title_produccion'),
			width : '670px',
			resizable : false
		});
	}

	// #OGIFleet
	function _seendFleed(){
		var box = root.makeBoxZ( '' );
		box = box.container.parent();

		var fleet1 = "/game/index.php?page=fleet1&cp=";

		function proccessFleet(rootPlanet){
			// primero se obtiene el fomulario principal de la naves,
			// mediante un GET.
			box.load( fleet1+rootPlanet + " #" );



		}


		box.attr('id', 'OGISendfleet')
		.dialog({
			autoOpen : false,
			width : '670px',
			resizable : false
		});
	}

	_dialogCurrentBuild();
	_dialogProduction();


}

_fnImperiumUI.prototype.makeBoxZ = function( title , ops ) {
	function __BoxZ(t) {
		var _box = this;
		var root = jQuery('<div>',{
			class : 'OGI-boxz'
		}),
		name = jQuery('<div> <h2>').addClass('header'),
		body = jQuery('<div>',{class:'body'}),
		container = jQuery('<div>',{
			class : 'content'
		});

		container.append(
			body.append('<div class="clearfloat"></div>'), '<div class="footer"></div>'
		);
		root.append(name, container);

		if('undefined' != typeof(t))
			name.children().append(t);

		_define(this, 'name', name, false);
		_define(this, 'container', body, false);
		_define(this, 'root', root, false);

		if ('undefined' === typeof(ops)) ops = {};
		var _options = {
			isClosable : false,
			isContentOpen : true
		};
		Object.assign(_options, ops);

		if (_options.isClosable) {
			var action = jQuery('<a>', { class : 'tabOpenClose'});
			name.prepend( action ).on('click', 'h2, a.tabOpenClose', function() {
				_box.toggleShow();
			});
			if (!_options.isContentOpen) {
				_box.toggleShow();
			}
		}
	}
	__BoxZ.prototype.setTitle = function(t) {
		this.name.children().empty().append(t).end();
	};
	__BoxZ.prototype.appendLayer = function(content, layerConfig) {
		var titleLayer = '', overlayer = '';
		if ('undefined' === typeof(layerConfig))
			layerConfig = {};

		if ( 'undefined' != typeof(layerConfig.title) ) {
			titleLayer = jQuery('<h2>').text(layerConfig.title);
			delete layerConfig.title;
		}


		if ( 'undefined' != layerConfig.overlayer && layerConfig.overlayer) {
			overlayer = '<div class="overlayer"></div>';
			delete layerConfig.overlayer;
		}


		var layer = jQuery('<div>', layerConfig).addClass('OGI-layer');
		layer.append( overlayer, jQuery('<div>',{
				class : 'information'
			}).append(titleLayer, content)
		);

		this.append(layer);
		//this.container.append(layer);
		return this;
	};
	__BoxZ.prototype.append = function(content) {
		this.container.find('>:last-child').before(content);
		return this;
	};
	__BoxZ.prototype.getRoot = function() {
		return this.root;
	};
	__BoxZ.prototype.toString = function() {
		return this.root.outerHTML;
	};
	__BoxZ.prototype.toggleShow = function( ) {
		var isClose = this.name.find('.tabOpenClose').is('.tabClose');
		// var efect = {duration:400, easing : 'blind'};
		if ( !isClose ) {
			this.name.find('.tabOpenClose').addClass('tabClose');
			this.container.hide('blind');
		} else {
			this.name.find('.tabOpenClose').removeClass('tabClose');
			this.container.show('blind');
		}
		return !isClose;
	};
	return new __BoxZ( title );
};

_fnImperiumUI.prototype.progressbar = function(id, current, capacity) {
	if (!capacity) {
		capacity = 10;
		current = 0;
	} else if (!current) {
		current = 0;
	}

	var progress = current / capacity * 100;
	color = 'filllevel_undermark'; // progreso menor al 90%
	if (progress >= 90 && progress < 100) {
		color = 'filllevel_middlemark';
	} else if (progress >= 100) {
		color = 'filllevel_overmark';
		progress = 100;
	}

	var HTMLProgress = jQuery('<div>', {
		id : id,
		class : 'filllevel_bar ' + color,
		css : { width : progress + "%" }
	});

	return jQuery('<div>', {class:'bar_container'})
		.attr('data-current-amount', current)
		.attr('data-capacity', capacity)
		.append(HTMLProgress, "<div class='premium_bar tooltipPremium'></div>");
};

_fnImperiumUI.prototype.tableFix = function(options) {
	function __UITableFix( options ) {
		var opts = {
			width : '100%',
			cellspacing : 0,
			class : ''
		};
		Object.assign(opts, options);
		opts.class += 'OGItable-fix';

		var table = jQuery('<table>', opts),
			thead = jQuery('<thead>'),
			tbody = jQuery('<tbody>'),
			tfoot = jQuery('<tfoot>');
		table.append(thead, tbody, tfoot);

		_define(this, 'table', table);
		_define(this, 'tbody', tbody);
		_define(this, 'thead', thead);
		_define(this, 'tfoot', tfoot);
	}
	__UITableFix.prototype._fixArguments = function(args) {
		var colums = [], i = 0;
		for ( ; i < args.length; i++ ){
			if (args[i] instanceof Array) colums = colums.concat(args[i]);
			else colums.push ( args[i] );
		}
		return colums;
	};
	__UITableFix.prototype._appendTo = function(typeColumn, columns) {
		var tr = jQuery('<tr>'), e = 0;
		for ( ; e < columns.length; e++) {
			var data = columns[e], props = {};
			if ( columns[e] instanceof Array){
				data = columns[e][0];
				props = columns[e][1];
			}

			jQuery(typeColumn, props).append( data ).appendTo( tr );
		}
		return tr;
	};
	__UITableFix.prototype.appendRowBody = function() {
		var columns = this._fixArguments(arguments), e = 0;
		var tr = this._appendTo('<td>', columns);
		this.tbody.append(tr);
		return tr;
	};
	__UITableFix.prototype.appendRowHead = function() {
		var columns = this._fixArguments(arguments), e = 0;
		var tr = this._appendTo('<th>', columns);
		this.thead.append(tr);
		return tr;
	};
	__UITableFix.prototype.appendRowFoot = function() {
		var columns = this._fixArguments(arguments), e = 0;
		var tr = this._appendTo('<td>', columns);
		this.tfoot.append(tr);
		return tr;
	};
	return new __UITableFix( options );
};

try{


var $Imperium = new _fnImperium();
				win.$OGImperium = $Imperium;


jQuery.when(
	//$OGame.defered(),
	$Imperium.defered()
).then(function() {
	//console.info( $Imperium );

	var container = jQuery('<div>', {
		id : 'OGImperium' , style:'display:none'
	});
	jQuery("#pageContent #middle").prepend( container );

	var $UI = new _fnImperiumUI($Imperium, container );

	jQuery('<style>',{ type:'text/css', name:'OGI-UI' })
	.append( $UI.style.toString() ).appendTo('head');


	// evento de click para ver el imperio
	jQuery('body').on('click', "#menuTable .btnImperium a", function(e) {
		var inhalt = jQuery("#pageContent #middle > div:not(#OGImperium)");
		if (container.is(':visible')) {
			container.hide();
			inhalt.show();
		} else {
			container.show();
			inhalt.hide();
		}
	});

	// evento de click para el menu de opciones rapidos (dialogos)
	jQuery('body').on('click', "#OGI_fastmenu a, #main_navigation a[ref='dialog']", function(e) {
		e.preventDefault();
		var href = this.getAttribute('href');
		jQuery(href).dialog('open');
		return false;
	});

	if (win.location.href.indexOf('OGIView') !== -1) {
		jQuery("#menuTableImperium .btnImperium a").trigger('click');
	}

	if (win.location.href.indexOf('OGIDialog') !== -1) {
		var dialog = win.location.href.match(/OGIDialog=(\w+);*/ig)[0];
		dialog = dialog.split('=')[1];
		var o;
		if (dialog == 'production') {
			o = "#OGICurrentProduction";
		}

		o = jQuery("#OGI_fastmenu a[href='" + o + "'], #main_navigation a[href='" + o + "']");
		o.trigger('click');
	}


});

} catch(err) {
    console.error("OGame5:Imperium "+VERSION, err);
}