Draym / OG-GalaxySpy

// ==UserScript==
// @name        OG-GalaxySpy
// @description Tools to help spy more efficiently. Add coords in spy list, launch autoSpy in galaxy view.
// @include     *.ogame*gameforge.com/game/index.php*
// @author      Draym
// @copyright   2019, Draym (draymlab.fr)
// @license     MIT
// @version     2.0.0.1
// @updateURL https://openuserjs.org/meta/Draym/OG-GalaxySpy.meta.js
// @downloadURL https://openuserjs.org/install/Draym/OG-GalaxySpy.user.js
// @grant          GM_getValue
// @grant          GM_setValue
// @grant          GM_addStyle
// ==/UserScript==

// ==OpenUserJS==
// @author Draym
// ==/OpenUserJS==

(function () {
  'use strict';

  /* **************************************************************/
  /* ******************** PARAMETERS ******************************/
  /* **************************************************************/
  let gs_minutes = 15;
  let gs_secondes = 2;
  let gs_currentSpyGroup = undefined;
  let gs_status = {
    "R": "status_abbr_strong",
    "Y": "status_abbr_honorableTarget",
    "W": "status_abbr_active",
    "I": "status_abbr_inactive"
  };

  let gs_itSpyMsg;

  /* **************************************************************/
  /* ******************** WAIT HANDLER ****************************/
  /* **************************************************************/

  let gs_itWaitGalaxyReady;
  let gs_itWaitSlotAndProbes;

  function gs_waitAvailableSlotOrProbe(callback) {
    gs_itWaitSlotAndProbes = setInterval(() => {
      unsafeWindow.initGalaxy();
      gs_waitGalaxyReady(() => {
        if (GM_getValue("gs_toggleOn") != true) {
          clearInterval(gs_itWaitSlotAndProbes);
          return;
        }
        let probes = Number($("#probeValue").text());
        let slotUsed = Number($("#slotUsed").text());
        let slotMax = Number($("#slotValue").text().split("/")[1]);
        if (probes <= 0 || slotUsed >= slotMax) {
          console.log("WAIT probes & slots");
          return;
        }
        console.log("Probe & Slot is OK");
        clearInterval(gs_itWaitSlotAndProbes);
        if (callback) {
          callback();
        }
      });
    }, 30000);
  }

  function gs_waitGalaxyReady(callback) {
    gs_itWaitGalaxyReady = setInterval(() => {
      if (GM_getValue("gs_toggleOn") != true) {
        clearInterval(gs_itWaitGalaxyReady);
        return;
      }
      if ($("#galaxyLoading").is(":visible") || !$("tr.row").get(0)) {
        console.log("WAIT galaxy");
        return;
      }

      clearInterval(gs_itWaitGalaxyReady);
      if (callback) {
        callback();
      }
    }, 800);
  }

  /* **************************************************************/
  /* ********************** TOOLS *********************************/
  /* **************************************************************/

  function gs_isEmpty(value) {
    return value === "" || !value;
  }

  function gs_arrayToString(array, delim) {
    let result = "";
    let first = true;

    for (let i in array) {
      if (!first) {
        result += delim;
      }
      result += array[i];
      first = false;
    }
    return result;
  }

  function gs_setCurrentSpyGroup(group) {
    gs_currentSpyGroup = group;
    if (!group) {
      $("#gs_galaxySpySwitchBtn").hide();
    }
    else {
      $("#gs_galaxySpySwitchBtn").show();
    }
  }

  // working
  function gs_spyPosition(planet, callback) {
    let row = $("tr:nth-child(" + planet + ")");
    row.find("td.action a.espionage").click();

    if (callback) {
      callback();
    }
  }

  function gs_goToGalaxyPosition(galaxy, system) {
    $("#galaxy_input").val(galaxy);
    $("#system_input").val(system);
    unsafeWindow.submitForm();
  }

  function gs_spyGalaxyPosition(galaxy, system, planet, callback) {
    gs_goToGalaxyPosition(galaxy, system);
    gs_waitGalaxyReady(() => gs_spyPosition(planet, callback));
  }

  function gs_spyGalaxyEachPosTarget(targets, index, finalCallback) {
    if (GM_getValue("gs_toggleOn") != true) {
      return;
    }
    if (index >= targets.length) {
      if (finalCallback) {
        finalCallback();
      }
      return;
    }
    let probes = Number($("#probeValue").text());
    let slotUsed = Number($("#slotUsed").text());
    let slotMax = Number($("#slotValue").text().split("/")[1]);
    console.log("launch espio:", index, targets[index], probes, slotUsed, slotMax);
    if (probes > 0 && slotUsed < slotMax) {
      console.log("ESPIO LAUNCHED");
      $(targets[index]).find("td.action a.espionage").click();
      setTimeout(() => gs_spyGalaxyEachPosTarget(targets, index + 1, finalCallback), 3000);
    }
    else {
      gs_waitAvailableSlotOrProbe(() => gs_spyGalaxyEachPosTarget(targets, index, finalCallback));
    }
  }

  function gs_spyGalaxyEachPosition(galaxy, system, filters, callback) {
    console.log("go to " + galaxy + ":" + system);
    gs_goToGalaxyPosition(galaxy, system);
    console.log(">done");
    gs_waitGalaxyReady(() => {
      let targets = [];

      console.log("filters:", filters);
      for (let i = 0; i < filters.length; ++i) {
        let rows = $("#galaxytable").find("tr:has(td.playername:has(a span." + gs_status[filters[i]] + "))");

        console.log("check for ", gs_status[filters[i]], rows.length, rows.toArray(), targets);
        targets = targets.concat(rows.toArray());
      }

      gs_spyGalaxyEachPosTarget(targets, 0, callback);
    });
  }

  function gs_spyGalaxyRangePosition(position, index, callback) {

    console.log(position, index, GM_getValue("gs_toggleOn"));
    if ((position.system + index <= 0) || (position.system + index > 499) || (position.range >= 0 && index > position.range) || (position.range < 0 && index < position.range) || GM_getValue("gs_toggleOn") != true) {
      console.log("finished range");
      callback();
      return;
    }

    gs_spyGalaxyEachPosition(position.galaxy, position.system + index, position.filters, () => {
      if (position.range >= 0) {
        ++index;
      }
      else {
        --index;
      }
      setTimeout(function () {
        gs_spyGalaxyRangePosition(position, index, callback);
      }, gs_secondes * 1000);
    });
  }

  /* **************************************************************/
  /* ********************** ICONS *********************************/
  /* **************************************************************/
  let trashIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAA81BMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9YqtblAAAAUHRSTlMAAQIDBAUGBwgJCwwNDxARFBYYHCAiJSYoLTA1Nzg5Ozw/QUtPWFxhZG11e3x+f4iLkZKUlZieqKuvtb7DxcrO09nc4ubo6evt8fP19/n7/baRV4cAAAFLSURBVDjL3ZTJVsJAEEUrARURQXFGcZ4QnBIUFUURQhAR7v9/jQuSkA6dA2tqVzm3K/VeVbfI3MZqVhMZc4I7QxuDmwi6R1zUFTI/iAW5CnErXWgvaxo3StAZpwtN6K9pJS4BCT8x68CO3oskkPSTZ+BUpoNl4FqmgxfAvf/9oF0xRioqzqEKFoEXwwcdsEVEjCo4Crg5hEYgS8qAJSI2UAmDuR60UiHfqoBlWoBthMBUC35zisM24Hp1AzDRALYiOi0Ycx5YAu6ihpgu4JoKmPgAtrUVH1UfF7+hvz69R5FMF9x0hLNMO6paJP8HzUXFR9vjFR9FdoH3YIkdr9LkZEROgJo/w6ITzLpzFN2eS+Bhhu0ZNVaaBZQn4HwW0HgD9rVgGgjd1+QnDAualyJfg6/wwVQr/l4fK7/I/sRxt5FmNrRvRe+1IHMW/wzugelBDRgVAAAAAElFTkSuQmCC";
  let plusIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAvVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+Ke75sAAAAPnRSTlMAAQMEBQcICQoZGiEoKi0uLzM2NzxPUVJWWFldX2dpbG1zd4CCiIuSlLe5ury+wMHMztfZ3ODi5u3v8/X7/QehlGwAAADUSURBVDjL7ZRXD4IwGEWvC9wiat1bcW/FSf//zxKpMVJSqSa+cd56c5q0Tb8L2KSH2xsVcJrXVTBiE/oZq+x4ikl96T7EBZUgD2RlPHoARlIiTWDPRwYhpLbh0yIsLuk4N4xcubgEfqvG3mzJxcQj5pi4CMR3saXlGAoTU89lYe4WBxARdYsVoYh/i33ZM9Km4Nb6NPgUP4nCKeTnuu144Ytnrj1NMbSborr2NsVYrnuS0KQ8MwSsZETdPrd69Pd6rJtnfh3++tYZY2eJrPOyEcc33AEfCR2wsoznKgAAAABJRU5ErkJggg==";

  /* **************************************************************/
  /* ********************** SCRIPT ********************************/
  /* **************************************************************/
  var $ = unsafeWindow.$;

  function gs_getPositions(group) {
    let groups = JSON.parse(GM_getValue('gs_SpyList'));

    console.log("GET", group, groups);
    return groups[group].positions;
  }

  function gs_checkEachPositionJob(group, i, callback) {
    console.log("do:", gs_getPositions(group), i);
    let gs_positions = gs_getPositions(group);

    if (gs_positions.length == 0 || i >= gs_positions.length || GM_getValue("gs_toggleOn") != true) {
      console.log("END");
      callback();
      return;
    }
    if (gs_isEmpty(gs_positions[i].range)) {
      gs_spyGalaxyPosition(gs_positions[i].galaxy, gs_positions[i].system, gs_positions[i].planet, () => {
        setTimeout(function () {
          console.log("single: ", i + 1);
          gs_checkEachPositionJob(group, i + 1, callback);
        }, gs_secondes * 1000);
      });
    }
    else {
      gs_spyGalaxyRangePosition(gs_positions[i], 0, () => {
        setTimeout(function () {
          console.log("range: ", i + 1);
          gs_checkEachPositionJob(group, i + 1, callback);
        }, gs_secondes * 1000);
      });
    }
  }

  function gs_spyPositionInGalaxy(callback) {
    if (!gs_currentSpyGroup) {
      return;
    }
    gs_checkEachPositionJob(gs_currentSpyGroup, 0, callback);
  }

  /* **************************************************************/
  /* ********************* STARTUP ********************************/
  /* **************************************************************/

  function gs_launch() {
    if (GM_getValue("gs_toggleOn") == true) {
      gs_spyPositionInGalaxy(() => {
        GM_setValue("gs_toggleOn", false);
        $("#cbActiveGS").prop('checked', false);
      });
    }
  }

  /* **************************************************************/
  /* ******************** GUI - PANEL 1 - GROUP *******************/
  /* **************************************************************/

  /** SCREEN 1 - LIST OF SPY GROUP **/
  $("body").append(`
<div id="gsPanelSpyGroup" style="display: none;">
<form>
<h3 id="gsPanelTitle">OG-GalaxySpy Panel</h3>
<p class="mt-2">Create a group: </p>
<div class="form-group">
<input id="gs_panelSpyGroupValue" class="form-control" type="text" placeholder="group name"/>
<a id="gs_panelSpyGroupSubmit" class="form-control">
<img class="clickable" src="` + plusIcon + `" rel="` + plusIcon + `" height="15" width="15">
</a>
</div>
<p class="mt-2 mb-1">Spy groups: </p>
<ul id="gsSpyGroup">
</ul>
<button id="gs_CloseSpyGroupBtn" class="mt-3" type="button">Close</button>
</form>
</div>
`);

  $("#gs_panelSpyGroupSubmit").click(function () {
    gs_saveSpyGroupFromPanel($("#gs_panelSpyGroupValue").val());
  });
  $("#gs_CloseSpyGroupBtn").click(function () {
    gs_drawPanel(1, false);
  });

  unsafeWindow.gs_clickDeleteSpyGroup = function (group) {
    gs_deleteSpyGroupFromPanel(group);
  }
  unsafeWindow.gs_clickSpyGroup = function (group) {
    gs_setCurrentSpyGroup(group);
    $("#gsPanelTitleValue").text(gs_currentSpyGroup);
    gs_drawPanel(2, true);
  }

  function gs_addSpyGroupInPanelListView(i, group) {
    $('#gsSpyGroup').append(
      $("<li>").attr('id', group.name).append(
        $('<span>').attr('class', 'tab clickable').attr('onclick', "gs_clickSpyGroup('" + group.name + "')").append(group.name)
      ).append(
        $('<a>').attr('class', 'tab clickable').attr("style", "margin-left:20px").attr('onclick', "gs_clickDeleteSpyGroup('" + group.name + "')").append(
          `<img src="` + trashIcon + `" rel="` + trashIcon + `" height="15" width="15">`
        )
      )
    );
  }

  function gs_saveSpyGroupFromPanel(name) {
    let groups = {};

    if (gs_isEmpty(name)) {
      return;
    }
    if (GM_getValue('gs_SpyList')) {
      groups = JSON.parse(GM_getValue('gs_SpyList'));
    }
    groups[name] = {
      name: name,
      positions: []
    };
    GM_setValue('gs_SpyList', JSON.stringify(groups));
    gs_updatePanelListView(1);
  }

  function gs_deleteSpyGroupFromPanel(id) {
    if (GM_getValue('gs_SpyList')) {
      let groups = JSON.parse(GM_getValue('gs_SpyList'));
      if (groups[id]) {
        delete groups[id];
      }
      GM_setValue('gs_SpyList', JSON.stringify(groups));
      gs_updatePanelListView(1);
    }
  }

  /* **************************************************************/
  /* ******************** GUI - PANEL 2 - LIST ********************/
  /* **************************************************************/
  unsafeWindow.gs_handlePosHasRangeClick = function (cb) {
    if (cb.checked) {
      $("#gs_panelRangePosition").show();
    }
    else {
      $("#gs_panelRangeValue").val(0);
      $("#gs_targetInactive").prop('checked', false);
      $("#gs_targetYellow").prop('checked', false);
      $("#gs_targetRed").prop('checked', false);
      $("#gs_targetWhite").prop('checked', false);
      $("#gs_panelRangePosition").hide();
    }
  }
  unsafeWindow.gs_clickDeleteSpyPos = function (row) {
    let id = $(row).attr('id')
    console.log("delete row:", id);
    gs_deleteSpyPositionFromPanel(gs_currentSpyGroup, id);
  }

  /** SCREEN 2 - LIST OF POS **/
  $("body").append(`
<div id="gsPanelPosList" style="display: none;">
<form>
<h3 id="gsPanelTitle"> Spy group: <span id='gsPanelTitleValue'>` + gs_currentSpyGroup + `</span>
</h3>
<p class="mt-2">Add a position: </p>
<div class="form-group">
<input id="gs_panelGalaxyValue" class="form-control" type="number" min="1" max="9" placeholder="galaxy"/>
<input id="gs_panelSystemValue" class="form-control" type="number" min="1" max="499" placeholder="system"/>
<input id="gs_panelPlanetValue" class="form-control" type="number" min="1" max="15" placeholder="planet"/>
<a id="gs_panelSpyPosSubmit" class="form-control">
<img class="clickable" src="` + plusIcon + `" rel="` + plusIcon + `" height="15" width="15">
</a>
</br>
<input id="gs_isRangePos" class="form-control" type="checkbox" name="isRangePos" onclick="gs_handlePosHasRangeClick(this);"/>
<label for="isRangePos">Include Range</label><br>
<div id="gs_panelRangePosition">
<p class="mt-2">Select a range (+ or -): </p>
<input id="gs_panelRangeValue" class="form-control" type="number" placeholder="range"/>
<p class="mt-2">Select target type: </p>
<input id="gs_targetInactive" class="form-control" type="checkbox" name="targetInactive"/>
<label for="targetInactive" class="c_grey">Inactive</label><br>
<input id="gs_targetWhite" class="form-control" type="checkbox" name="targetWhite"/>
<label for="targetWhite" class="c_white">White</label><br>
<input id="gs_targetYellow" class="form-control" type="checkbox" name="targetYellow"/>
<label for="targetYellow" class="c_yellow">Yellow</label><br>
<input id="gs_targetRed" class="form-control" type="checkbox" name="targetRed"/>
<label for="targetRed" class="c_red">Red</label><br>
</div>
</div>
<p class="mt-3 mb-1">Position to spy: </p>
<ul id="gsPosList">
</ul>
<div class="mt-2">
<button id="gs_panelView2Back" type="button">Back</button>
<button id="gs_CloseSpyListBtn" type="button">Close</button>
</div>
</form>
</div>
`);

  $("#gs_panelSpyPosSubmit").click(function () {
    let spyPos = {
      galaxy: Number($("#gs_panelGalaxyValue").val()),
      system: Number($("#gs_panelSystemValue").val()),
      planet: Number($("#gs_panelPlanetValue").val())
    }
    if ($("#gs_isRangePos").is(":checked")) {
      spyPos.isRange = true;
      spyPos.range = Number($("#gs_panelRangeValue").val());
      spyPos.filters = [];
      if ($("#gs_targetInactive").is(":checked")) {
        spyPos.filters.push("I");
      }
      if ($("#gs_targetWhite").is(":checked")) {
        spyPos.filters.push("W");
      }
      if ($("#gs_targetYellow").is(":checked")) {
        spyPos.filters.push("Y");
      }
      if ($("#gs_targetRed").is(":checked")) {
        spyPos.filters.push("R");
      }
    }
    console.log("ADD SPy: ", spyPos);
    gs_saveSpyPositionFromPanel(gs_currentSpyGroup, spyPos);
  });
  $("#gs_CloseSpyListBtn").click(function () {
    gs_drawPanel(2, false);
  });
  $("#gs_panelView2Back").click(function () {
    gs_setCurrentSpyGroup(undefined);
    gs_drawPanel(1, true);
  });

  function gs_addPositionInPanelListView(i, position) {
    $('#gsPosList').append(
      $("<li>").attr('class', 'clickable').attr('onclick', 'gs_clickDeleteSpyPos(this)').attr('id', i).append(
        $('<span>').attr('class', 'tab').append(position.galaxy + " : " + position.system + (position.isRange ? "  -> " + position.range + "  ~ " + gs_arrayToString(position.filters, ".") : " : " + position.planet))
      ).append(
        $('<a>').attr('class', 'tab').attr("style", "margin-left:20px").append(
          `<img src="` + trashIcon + `" rel="` + trashIcon + `" height="15" width="15">`
        )
      )
    );
  }

  function gs_saveSpyPositionFromPanel(group, spyPos) {
    let groups = {};

    if (gs_isEmpty(spyPos.galaxy) || gs_isEmpty(spyPos.system) || (!spyPos.isRange && gs_isEmpty(spyPos.planet))) {
      return;
    }
    if (spyPos.isRange && gs_isEmpty(spyPos.range)) {
      spyPos.range = 0;
    }
    if (GM_getValue('gs_SpyList')) {
      groups = JSON.parse(GM_getValue('gs_SpyList'));
    }
    if (!groups[group]) {
      return;
    }
    if (!groups[group].positions) {
      groups[group].positions = [];
    }
    for (let i in groups[group].positions) {
      if (groups[group].positions[i].galaxy == spyPos.galaxy && groups[group].positions[i].system == spyPos.system && groups[group].positions[i].planet == spyPos.planet && groups[group].positions[i].isRange == spyPos.isRange) {
        return;
      }
    }
    groups[group].positions.push(spyPos);
    GM_setValue('gs_SpyList', JSON.stringify(groups));
    console.log(GM_getValue('gs_SpyList'));
    gs_updatePanelListView();
  }

  function gs_deleteSpyPositionFromPanel(group, id) {
    if (GM_getValue('gs_SpyList')) {
      let groups = JSON.parse(GM_getValue('gs_SpyList'));
      if (groups[group]) {
        console.log("delete row: ", group, id);
        groups[group].positions.splice(id, 1);
      }
      GM_setValue('gs_SpyList', JSON.stringify(groups));
      gs_updatePanelListView(2);
    }
  }

  /* **************************************************************/
  /* ******************** GUI - PANEL - GENERIC *******************/
  /* **************************************************************/

  function gs_updatePanelListView(view) {
    if (GM_getValue('gs_SpyList')) {

      let data = JSON.parse(GM_getValue('gs_SpyList'));
      if (view == 1) {
        $('#gsSpyGroup').empty();
        for (let id in data) {
          gs_addSpyGroupInPanelListView(id, data[id]);
        }
      }
      else {
        $('#gsPosList').empty();
        if (!gs_currentSpyGroup) {
          return;
        }
        for (let pos in data[gs_currentSpyGroup].positions) {
          gs_addPositionInPanelListView(pos, data[gs_currentSpyGroup].positions[pos]);
        }
      }

    }
  }

  function gs_drawPanel(view, visible) {
    let main = "#gsPanelSpyGroup";
    let prev = "#gsPanelPosList";
    if (view == 2) {
      let tmp = prev;
      prev = main;
      main = tmp;
    }
    if (!visible) {
      $(main).hide();
    }
    else {
      gs_updatePanelListView(view);
      $(prev).hide();
      gs_updatePanelListView(view);
      $(main).show();
    }
  }

  /* **************************************************************/
  /* ******************** GUI - MESSAGE - SPY *********************/
  /* **************************************************************/

  function gs_addSpyManagementBtnToMsg() {
    $("ul.tab_inner").find("li.msg.TRreSpy").each(function () {
      console.log("this: ", this);
      clearInterval(gs_itSpyMsg);
      let head = $(this).find(".msg_head");
      let target = head.find(".msg_title .txt_link").text();
      let coords = target.slice(target.indexOf("[") + 1, target.indexOf("]")).split(":");
      let positions = {
        galaxy: Number(coords[0]),
        system: Number(coords[1]),
        planet: Number(coords[2])
      };
      console.log(positions);
      let actions = $(this).find(".msg_actions");

      if (!actions.find("button.gs_AddtoSpyGroupBtn").get(0)) {
        let btn = $("<button class='gs_AddtoSpyGroupBtn' type='button' title='OG-GalaxySpy'></button>");
        btn.click(function () {
          //gs_addToSpyGroup(true, postions);
        });
        actions.append(btn);
      }
    });
  }

  /* **************************************************************/
  /* ******************** GUI - MENU ******************************/
  /* **************************************************************/

  unsafeWindow.gs_handleClick = function (cb) {
    GM_setValue('gs_toggleOn', cb.checked);
    if (cb.checked == true && gs_currentSpyGroup) {
      gs_launch(gs_currentSpyGroup);
    }
  }

  if (/component=galaxy/.test(location.href)) {
    var aff_option = `
<span class="menu_icon" id="gs_galaxySpySwitchBtn">
<label class="tooltipRight js_hideTipOnMobile sa-switch">
<input id="cbActiveGS" type="checkbox" onclick="gs_handleClick(this);">
<span class="sa-slider round"></span>
</label>
</span>
<a id="drawOptionGS" class="menubutton" href="#" accesskey="" target="_self">
<span class="textlabel">OG-GalaxySpy</span></a>`;
    var tableau = document.createElement("li");
    tableau.innerHTML = aff_option;
    tableau.className += "custom-option";
    tableau.id = 'option-GalaxySpy';
    document.getElementById('menuTable').appendChild(tableau);

    let isToggle = GM_getValue("gs_roggleOn");
    $("#cbActiveGS").prop('checked', isToggle ? isToggle : false);
    document.getElementById('drawOptionGS').addEventListener("click", function (event) {
      if (gs_currentSpyGroup) {
        gs_drawPanel(2, $("#gsPanelPosList").is(":hidden"));
      }
      else {
        gs_drawPanel(1, $("#gsPanelSpyGroup").is(":hidden"));
      }
    }, true);

    if (isToggle && gs_currentSpyGroup) {
      gs_launch(gs_currentSpyGroup);
    }
  }

  if (/page=messages/.test(location.href)) {
    gs_itSpyMsg = setInterval(gs_addSpyManagementBtnToMsg, 800);
  }
  /* **************************************************************/
  /* ************************ CSS *********************************/
  /* **************************************************************/

  GM_addStyle(`
/*** CUSTOM ***/
#gsPanelPosList, #gsPanelSpyGroup {
position:               fixed;
top:                    18%;
left:                   2%;
width:                  300px;
padding:                10px;
background:             rgba(51, 102, 153, 0.9);
border:                 2px black;
border-radius:          1ex;
z-index:                777;
}

#gsPosList{
overflow-y: scroll;
height: 150px;
margin-bottom: 10px;
}

.gs_AddtoSpyGroupBtn {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAbCAYAAABvCO8sAAAD+0lEQVRIS61WS08UQRCumZ19yEtYY6ImkIjxJBEEfIKsJhqPGv+nJnjSqFFQjAZDlLtw4GYEAoKwzMv6qrt6etdBL9Zmtqurquvdj2Dw7PmcGCqVkOq1BlWrNYoqFcqFaiAICrwMg6wvo/M0S+mo3aZ23KY0TVkmoCgMjbbeRg8NDJ2mnv5BCqOI8iwTAUDOGoDrWGZUab5MmiZ0uLdLO9vfaX9/nzLKORirtO9kkxq9/RQfHVLezv6mkz2wbPgDXPziPy8tOU9D1g2dCRs+OPhFWcYGNcJGTx/F7QMOPTHa/JxavVat4WvEZlbYVSF2JGWZjDN1gnVXwpASxqPAuEfId5LERrV4bT3uGnOdQzE75ebWAVnHkZgxoyQ+ElzLE7k6sfU857rxD6NLm6bPjksv521MZpi591CQWlSlo5gd9uWtczkHg9oCIrcaBHjsVhhOrWoULb54yp2M7s25k6vCRLo+vH7GmUlo7sFjp6pDJybqBKMhcDNnU6ygG+D10qt5MYavXq+LIXwRdzOMh1wfyHQDnDNf0fGhdBZ/UOA54tYuPH8iOJRi8fr6Ol0YHZUPOACGASorEwZnUAk8hg4Xu39GCGWIDLXe2NigO60WbW5tyQdcjUJGDatO6JPa2UhB561iOkiqB2YJqAwM/NjcdJ4DB0353Us1nb5e1zTCLKlhtxI9cUDXDu+W0Tn0SY+wbpX1UloeoasDL3q7sECnmk0XEXDQfBnfeJHOolShCkvTlEQ4e/+RHLyQGx4edkbV2MjIiNiADGR9cDpRRstwGx8kP9cdK3mCxWgMGPi2tibsWq0mexBfGfARImS/GV1KYSwr6VIswGmScASIAp9Cm68eMcg0PXF8w6ndr1JDy3AplXSWdCkOXUDLO0l042tGlKeyahQ6Ja26PZjREWFZSuGlQlkUPs2XNWukR4sC8qw4S6WGGf3c2RbZlY9vaPLGXWdMkctX52h1eVGmwMsAfJ8nlwIOcobgzMhFqWzfwBC1D/aLtwKnd+XTAk1ebx17VeHakTJ44+ryOzZ2u4OOu3Zvd5sO+VwuThpeKFvE5j1jfOLanBiVmqGp/jHC2NjUTKmclityfQJjbrdwyIibA5hgb7+wouMADy6Fsalbbp2uNyqtMhbkGpq9YrrJtG/hhFE1Pj0ryNfP70vtXrpys5NuVLpmyVIccYYYaWfhLYOyauhBgOsIxS7G8ekZmWvEOofmMnldn/GNjwcUIGieM+/SOl+kFX4mZPYYU5fhme0vSzLpkc0sDMM1cuKyyOEfd2gYVPiwiKVhAJFGD0LExvzNK60stdVG1FOfKcaOzYI+xUzj6RaA83EWy2tNwduHJAyf6aT+I/IbIRLUWL6ADeIAAAAASUVORK5CYII=');
background-repeat: no-repeat;
height: 26px;
width: 26px;
}
.gs_AddtoSpyGroupBtn:hover {
cursor: pointer;
}

/*** THEME ***/
#menuTable > .custom-option {
margin-top: 10px !important;
margin-bottom: 10px !important;
}
#menuTable > .custom-option ~ .custom-option {
margin-top: -10px !important;
margin-bottom: 10px !important;
}
.custom-option a span {
color: #68a2ff !important;
}
.clickable {
cursor: pointer;
}
#gs_panelGalaxyValue {
width: 60px;
}
#gs_panelPlanetValue {
width: 60px;
}
#gs_galaxySpySwitchBtn {
display: none;
}
#gsPanelTitleValue {
display: initial;
}

#gs_panelRangePosition {
display: none;
}

/*** TOGGLE SWITCH ***/
.sa-switch {
position: relative;
display: inline-block;
width: 30px;
height: 17px;
margin-top: 5px;
}
.sa-switch input {
opacity: 0;
width: 0;
height: 0;
}
.sa-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ff4949;
-webkit-transition: .4s;
transition: .4s;
}
.sa-slider:before {
position: absolute;
content: "";
height: 13px;
width: 13px;
left: 2px;
bottom: 2px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
input:checked + .sa-slider {
background-color: #0664b0;
}
input:focus + .sa-slider {
box-shadow: 0 0 1px #0664b0;
}
input:checked + .sa-slider:before {
-webkit-transform: translateX(13px);
-ms-transform: translateX(13px);
transform: translateX(13px);
}
.sa-slider.round {
border-radius: 17px;
}
.sa-slider.round:before {
border-radius: 50%;
}

/*** MARGIN ***/
.mb-1 {
margin-bottom: 5px;
}
.mt-2 {
margin-top: 10px;
}
.mt-3 {
margin-top: 20px;
}

/*** COLOR ***/
.c_red {
color: red;
}
.c_grey {
color: grey;
}
.c_yellow {
color: yellow;
}
.c_white {
color: white;
}
`);
})();