context: 
  #region using directives
  
  using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.IO;
  using System.Linq;
  using System.Net;
  using System.Reflection;
  using System.Security.Cryptography;
  using System.Threading;
  using Newtonsoft.Json;
  using Newtonsoft.Json.Converters;
  using PoGo.NecroBot.Logic.Common;
  using PoGo.NecroBot.Logic.Logging;
  using PoGo.NecroBot.Logic.State;
  using PoGo.NecroBot.Logic.Utils;
  using PokemonGo.RocketAPI;
  using PokemonGo.RocketAPI.Enums;
  using POGOProtos.Enums;
  using POGOProtos.Inventory.Item;
  using Newtonsoft.Json.Linq;
  using System.Text.RegularExpressions;
  
  #endregion
  
  namespace PoGo.NecroBot.Logic
  {
      public class AuthSettings
      {
          [JsonIgnore]
          private string _filePath;
  
          public AuthType AuthType;
          public string GoogleUsername;
          public string GooglePassword;
          public string PtcUsername;
          public string PtcPassword;
          public bool UseProxy;
          public string UseProxyHost;
          public string UseProxyPort;
          public bool UseProxyAuthentication;
          public string UseProxyUsername;
          public string UseProxyPassword;
          // device data
          [DefaultValue("random")]
          public string DevicePackageName;
          [DefaultValue("8525f5d8201f78b5")]
          public string DeviceId;
          [DefaultValue("msm8996")]
          public string AndroidBoardName;
          [DefaultValue("1.0.0.0000")]
          public string AndroidBootloader;
          [DefaultValue("HTC")]
          public string DeviceBrand;
          [DefaultValue("HTC 10")]
          public string DeviceModel;
          [DefaultValue("pmewl_00531")]
          public string DeviceModelIdentifier;
          [DefaultValue("qcom")]
          public string DeviceModelBoot;
          [DefaultValue("HTC")]
          public string HardwareManufacturer;
          [DefaultValue("HTC 10")]
          public string HardwareModel;
          [DefaultValue("pmewl_00531")]
          public string FirmwareBrand;
          [DefaultValue("release-keys")]
          public string FirmwareTags;
          [DefaultValue("user")]
          public string FirmwareType;
          [DefaultValue("htc/pmewl_00531/htc_pmewl:6.0.1/MMB29M/770927.1:user/release-keys")]
          public string FirmwareFingerprint;
  
          public AuthSettings()
          {
              InitializePropertyDefaultValues(this);
          }
  
          public void InitializePropertyDefaultValues(object obj)
          {
              FieldInfo[] fields = obj.GetType().GetFields();
  
              foreach (FieldInfo field in fields)
              {
                  var d = field.GetCustomAttribute<DefaultValueAttribute>();
  
                  if (d != null)
                      field.SetValue(obj, d.Value);
              }
          }
  
          public void Load(string path)
          {
              try
              {
                  _filePath = path;
  
                  if (File.Exists(_filePath))
                  {
                      // if the file exists, load the settings
                      var input = File.ReadAllText(_filePath);
  
                      var settings = new JsonSerializerSettings();
                      settings.Converters.Add(new StringEnumConverter { CamelCaseText = true });
                      JsonConvert.PopulateObject(input, this, settings);
                  }
                  // Do some post-load logic to determine what device info to be using - if 'custom' is set we just take what's in the file without question
                  if (!this.DevicePackageName.Equals("random", StringComparison.InvariantCultureIgnoreCase) && !this.DevicePackageName.Equals("custom", StringComparison.InvariantCultureIgnoreCase))
                  {
                      // User requested a specific device package, check to see if it exists and if so, set it up - otherwise fall-back to random package
                      string keepDevId = this.DeviceId;
                      SetDevInfoByKey(this.DevicePackageName);
                      this.DeviceId = keepDevId;
                  }
                  if (this.DevicePackageName.Equals("random", StringComparison.InvariantCultureIgnoreCase))
                  {
                      // Random is set, so pick a random device package and set it up - it will get saved to disk below and re-used in subsequent sessions
                      Random rnd = new Random();
                      int rndIdx = rnd.Next(0, DeviceInfoHelper.DeviceInfoSets.Keys.Count - 1);
                      this.DevicePackageName = DeviceInfoHelper.DeviceInfoSets.Keys.ToArray()[rndIdx];
                      SetDevInfoByKey(this.DevicePackageName);
                  }
                  if (string.IsNullOrEmpty(this.DeviceId) || this.DeviceId == "8525f5d8201f78b5")
                      this.DeviceId = this.RandomString(16, "0123456789abcdef"); // changed to random hex as full alphabet letters could have been flagged
  
                  // Jurann: Note that some device IDs I saw when adding devices had smaller numbers, only 12 or 14 chars instead of 16 - probably not important but noted here anyway
  
                  Save(_filePath);
              }
              catch (JsonReaderException exception)
              {
                  if (exception.Message.Contains("Unexpected character") && exception.Message.Contains("PtcUsername"))
                      Logger.Write("JSON Exception: You need to properly configure your PtcUsername using quotations.",
                          LogLevel.Error);
                  else if (exception.Message.Contains("Unexpected character") && exception.Message.Contains("PtcPassword"))
                      Logger.Write(
                          "JSON Exception: You need to properly configure your PtcPassword using quotations.",
                          LogLevel.Error);
                  else if (exception.Message.Contains("Unexpected character") &&
                           exception.Message.Contains("GoogleUsername"))
                      Logger.Write(
                          "JSON Exception: You need to properly configure your GoogleUsername using quotations.",
                          LogLevel.Error);
                  else if (exception.Message.Contains("Unexpected character") &&
                           exception.Message.Contains("GooglePassword"))
                      Logger.Write(
                          "JSON Exception: You need to properly configure your GooglePassword using quotations.",
                          LogLevel.Error);
                  else
                      Logger.Write("JSON Exception: " + exception.Message, LogLevel.Error);
              }
          }
  
          public void Save(string fullPath)
          {
              var jsonSerializeSettings = new JsonSerializerSettings
              {
                  DefaultValueHandling = DefaultValueHandling.Include,
                  Formatting = Formatting.Indented,
                  Converters = new JsonConverter[] { new StringEnumConverter { CamelCaseText = true } }
              };
  
              var output = JsonConvert.SerializeObject(this, jsonSerializeSettings);
  
              var folder = Path.GetDirectoryName(fullPath);
              if (folder != null && !Directory.Exists(folder))
              {
                  Directory.CreateDirectory(folder);
              }
  
              File.WriteAllText(fullPath, output);
          }
  
          public void Save()
          {
              if (!string.IsNullOrEmpty(_filePath))
              {
                  Save(_filePath);
              }
          }
  
          public void checkProxy(ITranslation translator)
          {
              using (var tempWebClient = new NecroWebClient())
              {
                  string unproxiedIP = WebClientExtensions.DownloadString(tempWebClient, new Uri("https://api.ipify.org/?format=text"));
                  if (UseProxy)
                  {
                      tempWebClient.Proxy = this.InitProxy();
                      string proxiedIPres = WebClientExtensions.DownloadString(tempWebClient, new Uri("https://api.ipify.org/?format=text"));
                      string proxiedIP = proxiedIPres == null?"INVALID PROXY": proxiedIPres;
                      Logger.Write(translator.GetTranslation(TranslationString.Proxied, unproxiedIP, proxiedIP), LogLevel.Info, (unproxiedIP == proxiedIP) ? ConsoleColor.Red : ConsoleColor.Green);
  
                      if (unproxiedIP == proxiedIP || proxiedIPres == null)
                      {
                          Logger.Write(translator.GetTranslation(TranslationString.FixProxySettings), LogLevel.Info, ConsoleColor.Red);
                          Console.ReadKey();
                          Environment.Exit(0);
                      }
                  }
                  else
                  {
                      Logger.Write(translator.GetTranslation(TranslationString.Unproxied, unproxiedIP), LogLevel.Info, ConsoleColor.Red);
                  }
              }
          }
  
          private string RandomString(int length, string alphabet = "abcdefghijklmnopqrstuvwxyz0123456789")
          {
              var outOfRange = Byte.MaxValue + 1 - (Byte.MaxValue + 1) % alphabet.Length;
  
              return string.Concat(
                  Enumerable
                      .Repeat(0, Int32.MaxValue)
                      .Select(e => this.RandomByte())
                      .Where(randomByte => randomByte < outOfRange)
                      .Take(length)
                      .Select(randomByte => alphabet[randomByte % alphabet.Length])
              );
          }
  
          private byte RandomByte()
          {
              using (var randomizationProvider = new RNGCryptoServiceProvider())
              {
                  var randomBytes = new byte[1];
                  randomizationProvider.GetBytes(randomBytes);
                  return randomBytes.Single();
              }
          }
  
          private void SetDevInfoByKey(string devKey)
          {
              if (DeviceInfoHelper.DeviceInfoSets.ContainsKey(this.DevicePackageName))
              {
                  this.AndroidBoardName = DeviceInfoHelper.DeviceInfoSets[this.DevicePackageName]["AndroidBoardName"];
                  this.AndroidBootloader = DeviceInfoHelper.DeviceInfoSets[this.DevicePackageName]["AndroidBootloader"];
                  this.DeviceBrand = DeviceInfoHelper.DeviceInfoSets[this.DevicePackageName]["DeviceBrand"];
                  this.DeviceId = DeviceInfoHelper.DeviceInfoSets[this.DevicePackageName]["DeviceId"];
                  this.DeviceModel = DeviceInfoHelper.DeviceInfoSets[this.DevicePackageName]["DeviceModel"];
                  this.DeviceModelBoot = DeviceInfoHelper.DeviceInfoSets[this.DevicePackageName]["DeviceModelBoot"];
                  this.DeviceModelIdentifier = DeviceInfoHelper.DeviceInfoSets[this.DevicePackageName]["DeviceModelIdentifier"];
                  this.FirmwareBrand = DeviceInfoHelper.DeviceInfoSets[this.DevicePackageName]["FirmwareBrand"];
                  this.FirmwareFingerprint = DeviceInfoHelper.DeviceInfoSets[this.DevicePackageName]["FirmwareFingerprint"];
                  this.FirmwareTags = DeviceInfoHelper.DeviceInfoSets[this.DevicePackageName]["FirmwareTags"];
                  this.FirmwareType = DeviceInfoHelper.DeviceInfoSets[this.DevicePackageName]["FirmwareType"];
                  this.HardwareManufacturer = DeviceInfoHelper.DeviceInfoSets[this.DevicePackageName]["HardwareManufacturer"];
                  this.HardwareModel = DeviceInfoHelper.DeviceInfoSets[this.DevicePackageName]["HardwareModel"];
              }
              else
              {
                  throw new ArgumentException("Invalid device info package! Check your auth.config file and make sure a valid DevicePackageName is set. For simple use set it to 'random'. If you have a custom device, then set it to 'custom'.");
              }
          }
  
          private WebProxy InitProxy()
          {
              if (!UseProxy) return null;
  
              WebProxy prox = new WebProxy(new System.Uri($"http://{UseProxyHost}:{UseProxyPort}"), false, null);
  
              if (UseProxyAuthentication)
                  prox.Credentials = new NetworkCredential(UseProxyUsername, UseProxyPassword);
  
              return prox;
          }
      }
  
      public class GlobalSettings
      {
          [JsonIgnore]
          public AuthSettings Auth = new AuthSettings();
          [JsonIgnore]
          public string GeneralConfigPath;
          [JsonIgnore]
          public string ProfileConfigPath;
          [JsonIgnore]
          public string ProfilePath;
  
          [JsonIgnore]
          public bool isGui;
  
          [DefaultValue("en")]
          public string TranslationLanguageCode;
          [DefaultValue(true)]
          public bool CheckForUpdates;
          //autoupdate
          [DefaultValue(true)]
          public bool AutoUpdate;
          [DefaultValue(true)]
          public bool TransferConfigAndAuthOnUpdate;
          //websockets
          [DefaultValue(false)]
          public bool UseWebsocket;
          [DefaultValue(14251)]
          public int WebSocketPort;
          //Telegram
          [DefaultValue(false)]
          public bool UseTelegramAPI;
          [DefaultValue(null)]
          public string TelegramAPIKey;
          [DefaultValue("12345")]
          public string TelegramPassword;
          //console options
          [DefaultValue(false)]
          public bool StartupWelcomeDelay;
          [DefaultValue(10)]
          public int AmountOfPokemonToDisplayOnStart;
          [DefaultValue(true)]
          public bool DetailedCountsBeforeRecycling;
          //pokemon
          [DefaultValue(true)]
          public bool CatchPokemon;
          [DefaultValue(3)]
          public int MaxBerriesToUsePerPokemon;
          //powerup
          [DefaultValue(false)]
          public bool AutomaticallyLevelUpPokemon;
          [DefaultValue(true)]
          public bool OnlyUpgradeFavorites;
          [DefaultValue((true))]
          public bool UseLevelUpList;
          [DefaultValue(5)]
          public int AmountOfTimesToUpgradeLoop;
          [DefaultValue(5000)]
          public int GetMinStarDustForLevelUp;
          [DefaultValue("iv")]
          public string LevelUpByCPorIv;
          [DefaultValue(1000)]
          public float UpgradePokemonCpMinimum;
          [DefaultValue(95)]
          public float UpgradePokemonIvMinimum;
          [DefaultValue("and")]
          public string UpgradePokemonMinimumStatsOperator;
          //position
          [DefaultValue(false)]
          public bool DisableHumanWalking;
          [DefaultValue(40.785092)]
          public double DefaultLatitude;
          [DefaultValue(-73.968286)]
          public double DefaultLongitude;
          [DefaultValue(5.0)]
          public double WalkingSpeedInKilometerPerHour;
          [DefaultValue(10)]
          public int MaxSpawnLocationOffset;
          //softban related
          [DefaultValue(false)]
          public bool FastSoftBanBypass;
          //delays
          [DefaultValue(5000)]
          public int DelayBetweenPlayerActions;
          [DefaultValue(2000)]
          public int DelayBetweenPokemonCatch;
          //dump stats
          [DefaultValue(false)]
          public bool DumpPokemonStats;
          //evolve
          [DefaultValue(95)]
          public float EvolveAboveIvValue;
          [DefaultValue(false)]
          public bool EvolveAllPokemonAboveIv;
          [DefaultValue(true)]
          public bool EvolveAllPokemonWithEnoughCandy;
          [DefaultValue(90.0)]
          public double EvolveKeptPokemonsAtStorageUsagePercentage;
          [DefaultValue(false)]
          public bool KeepPokemonsThatCanEvolve;
          //keeping
          [DefaultValue(1250)]
          public int KeepMinCp;
          [DefaultValue(90)]
          public float KeepMinIvPercentage;
          [DefaultValue(6)]
          public int KeepMinLvl;
          [DefaultValue("or")]
          public string KeepMinOperator;
          [DefaultValue(false)]
          public bool UseKeepMinLvl;
          [DefaultValue(false)]
          public bool PrioritizeIvOverCp;
          [DefaultValue(1)]
          public int KeepMinDuplicatePokemon;
          //gpx
          [DefaultValue(false)]
          public bool UseGpxPathing;
          [DefaultValue("GPXPath.GPX")]
          public string GpxFile;
          //recycle
          [DefaultValue(true)]
          public bool VerboseRecycling;
          [DefaultValue(90.0)]
          public double RecycleInventoryAtUsagePercentage;
          [DefaultValue(false)]
          public bool RandomizeRecycle;
          [DefaultValue(5)]
          public int RandomRecycleValue;
          [DefaultValue(false)]
          public bool DelayBetweenRecycleActions; // Jurann TODO: change this to int millis instead of bool
          //lucky, incense and berries
          [DefaultValue(true)]
          public bool UseEggIncubators;
          [DefaultValue(2)]
          public int UseEggIncubatorMinKm;
          [DefaultValue(false)]
          public bool UseLuckyEggConstantly;
          [DefaultValue(30)]
          public int UseLuckyEggsMinPokemonAmount;
          [DefaultValue(false)]
          public bool UseLuckyEggsWhileEvolving;
          [DefaultValue(false)]
          public bool UseIncenseConstantly;
          [DefaultValue(1000)]
          public int UseBerriesMinCp;
          [DefaultValue(90)]
          public float UseBerriesMinIv;
          [DefaultValue(0.20)]
          public double UseBerriesBelowCatchProbability;
          [DefaultValue("or")]
          public string UseBerriesOperator;
          //snipe
          [DefaultValue(false)]
          public bool UseSnipeLocationServer;
          [DefaultValue("localhost")]
          public string SnipeLocationServer;
          [DefaultValue(16969)]
          public int SnipeLocationServerPort;
          [DefaultValue(false)]
          public bool GetSniperInfoFromPokezz;
          [DefaultValue(true)]
          public bool GetOnlyVerifiedSniperInfoFromPokezz;
          [DefaultValue(true)]
          public bool GetSniperInfoFromPokeSnipers;
          [DefaultValue(true)]
          public bool GetSniperInfoFromPokeWatchers;
          [DefaultValue(true)]
          public bool GetSniperInfoFromSkiplagged;
          [DefaultValue(20)]
          public int MinPokeballsToSnipe;
          [DefaultValue(0)]
          public int MinPokeballsWhileSnipe;
          [DefaultValue(60000)]
          public int MinDelayBetweenSnipes;
          [DefaultValue(0.005)]
          public double SnipingScanOffset;
          [DefaultValue(false)]
          public bool SnipeAtPokestops;
          [DefaultValue(false)]
          public bool SnipeIgnoreUnknownIv;
          [DefaultValue(false)]
          public bool UseTransferIvForSnipe;
          [DefaultValue(false)]
          public bool SnipePokemonNotInPokedex;
          //rename
          [DefaultValue(false)]
          public bool RenamePokemon;
          [DefaultValue(true)]
          public bool RenameOnlyAboveIv;
          [DefaultValue("{1}_{0}")]
          public string RenameTemplate;
          //amounts
          [DefaultValue(6)]
          public int MaxPokeballsPerPokemon;
          [DefaultValue(1000)]
          public int MaxTravelDistanceInMeters;
          [DefaultValue(120)]
          public int TotalAmountOfPokeballsToKeep;
          [DefaultValue(80)]
          public int TotalAmountOfPotionsToKeep;
          [DefaultValue(60)]
          public int TotalAmountOfRevivesToKeep;
          [DefaultValue(50)]
          public int TotalAmountOfBerriesToKeep;
          //balls
          [DefaultValue(1000)]
          public int UseGreatBallAboveCp;
          [DefaultValue(1250)]
          public int UseUltraBallAboveCp;
          [DefaultValue(1500)]
          public int UseMasterBallAboveCp;
          [DefaultValue(85.0)]
          public double UseGreatBallAboveIv;
          [DefaultValue(95.0)]
          public double UseUltraBallAboveIv;
          [DefaultValue(0.2)]
          public double UseGreatBallBelowCatchProbability;
          [DefaultValue(0.1)]
          public double UseUltraBallBelowCatchProbability;
          [DefaultValue(0.05)]
          public double UseMasterBallBelowCatchProbability;
          //customizable catch
          [DefaultValue(true)]
          public bool EnableHumanizedThrows;
          [DefaultValue(40)]
          public int NiceThrowChance;
          [DefaultValue(30)]
          public int GreatThrowChance;
          [DefaultValue(10)]
          public int ExcellentThrowChance;
          [DefaultValue(90)]
          public int CurveThrowChance;
          [DefaultValue(90.00)]
          public double ForceGreatThrowOverIv;
          [DefaultValue(95.00)]
          public double ForceExcellentThrowOverIv;
          [DefaultValue(1000)]
          public int ForceGreatThrowOverCp;
          [DefaultValue(1500)]
          public int ForceExcellentThrowOverCp;
          //transfer
          [DefaultValue(false)]
          public bool TransferWeakPokemon;
          [DefaultValue(true)]
          public bool TransferDuplicatePokemon;
          [DefaultValue(true)]
          public bool TransferDuplicatePokemonOnCapture;
          //favorite
          [DefaultValue(95)]
          public float FavoriteMinIvPercentage;
          [DefaultValue(false)]
          public bool AutoFavoritePokemon;
          //notcatch
          [DefaultValue(false)]
          public bool UsePokemonToNotCatchFilter;
          [DefaultValue(false)]
          public bool UsePokemonSniperFilterOnly;
  
          [DefaultValue(false)]
          public bool UseOsmNavigation;
          [DefaultValue(100d)]
          public double OsmMinDistanceInMeter;
  
          public List<KeyValuePair<ItemId, int>> ItemRecycleFilter = new List<KeyValuePair<ItemId, int>>
          {
              new KeyValuePair<ItemId, int>(ItemId.ItemUnknown, 0),
              new KeyValuePair<ItemId, int>(ItemId.ItemLuckyEgg, 200),
              new KeyValuePair<ItemId, int>(ItemId.ItemIncenseOrdinary, 100),
              new KeyValuePair<ItemId, int>(ItemId.ItemIncenseSpicy, 100),
              new KeyValuePair<ItemId, int>(ItemId.ItemIncenseCool, 100),
              new KeyValuePair<ItemId, int>(ItemId.ItemIncenseFloral, 100),
              new KeyValuePair<ItemId, int>(ItemId.ItemTroyDisk, 100),
              new KeyValuePair<ItemId, int>(ItemId.ItemXAttack, 100),
              new KeyValuePair<ItemId, int>(ItemId.ItemXDefense, 100),
              new KeyValuePair<ItemId, int>(ItemId.ItemXMiracle, 100),
              new KeyValuePair<ItemId, int>(ItemId.ItemSpecialCamera, 100),
              new KeyValuePair<ItemId, int>(ItemId.ItemIncubatorBasicUnlimited, 100),
              new KeyValuePair<ItemId, int>(ItemId.ItemIncubatorBasic, 100),
              new KeyValuePair<ItemId, int>(ItemId.ItemPokemonStorageUpgrade, 100),
              new KeyValuePair<ItemId, int>(ItemId.ItemItemStorageUpgrade, 100)
          };
  
  
          public List<PokemonId> PokemonsNotToTransfer = new List<PokemonId>
          {
              //criteria: from SS Tier to A Tier + Regional Exclusive
              PokemonId.Venusaur,
              PokemonId.Charizard,
              PokemonId.Blastoise,
              //PokemonId.Nidoqueen,
              //PokemonId.Nidoking,
              PokemonId.Clefable,
              //PokemonId.Vileplume,
              //PokemonId.Golduck,
              //PokemonId.Arcanine,
              //PokemonId.Poliwrath,
              //PokemonId.Machamp,
              //PokemonId.Victreebel,
              //PokemonId.Golem,
              //PokemonId.Slowbro,
              //PokemonId.Farfetchd,
              PokemonId.Muk,
              //PokemonId.Exeggutor,
              //PokemonId.Lickitung,
              PokemonId.Chansey,
              //PokemonId.Kangaskhan,
              //PokemonId.MrMime,
              //PokemonId.Tauros,
              PokemonId.Gyarados,
              //PokemonId.Lapras,
              PokemonId.Ditto,
              //PokemonId.Vaporeon,
              //PokemonId.Jolteon,
              //PokemonId.Flareon,
              //PokemonId.Porygon,
              PokemonId.Snorlax,
              PokemonId.Articuno,
              PokemonId.Zapdos,
              PokemonId.Moltres,
              PokemonId.Dragonite,
              PokemonId.Mewtwo,
              PokemonId.Mew
          };
  
          public List<PokemonId> PokemonsToEvolve = new List<PokemonId>
          {
              /*NOTE: keep all the end-of-line commas exept for the last one or an exception will be thrown!
              criteria: 12 candies*/
              PokemonId.Caterpie,
              PokemonId.Weedle,
              PokemonId.Pidgey,
              /*criteria: 25 candies*/
              //PokemonId.Bulbasaur,
              //PokemonId.Charmander,
              //PokemonId.Squirtle,
              PokemonId.Rattata
              //PokemonId.NidoranFemale,
              //PokemonId.NidoranMale,
              //PokemonId.Oddish,
              //PokemonId.Poliwag,
              //PokemonId.Abra,
              //PokemonId.Machop,
              //PokemonId.Bellsprout,
              //PokemonId.Geodude,
              //PokemonId.Gastly,
              //PokemonId.Eevee,
              //PokemonId.Dratini,
              /*criteria: 50 candies commons*/
              //PokemonId.Spearow,
              //PokemonId.Ekans,
              //PokemonId.Zubat,
              //PokemonId.Paras,
              //PokemonId.Venonat,
              //PokemonId.Psyduck,
              //PokemonId.Slowpoke,
              //PokemonId.Doduo,
              //PokemonId.Drowzee,
              //PokemonId.Krabby,
              //PokemonId.Horsea,
              //PokemonId.Goldeen,
              //PokemonId.Staryu
          };
          public List<PokemonId> PokemonsToLevelUp = new List<PokemonId>
          {
              //criteria: from SS Tier to A Tier + Regional Exclusive
              PokemonId.Venusaur,
              PokemonId.Charizard,
              PokemonId.Blastoise,
              //PokemonId.Nidoqueen,
              //PokemonId.Nidoking,
              PokemonId.Clefable,
              //PokemonId.Vileplume,
              //PokemonId.Golduck,
              //PokemonId.Arcanine,
              //PokemonId.Poliwrath,
              //PokemonId.Machamp,
              //PokemonId.Victreebel,
              //PokemonId.Golem,
              //PokemonId.Slowbro,
              //PokemonId.Farfetchd,
              PokemonId.Muk,
              //PokemonId.Exeggutor,
              //PokemonId.Lickitung,
              PokemonId.Chansey,
              //PokemonId.Kangaskhan,
              //PokemonId.MrMime,
              //PokemonId.Tauros,
              PokemonId.Gyarados,
              //PokemonId.Lapras,
              PokemonId.Ditto,
              //PokemonId.Vaporeon,
              //PokemonId.Jolteon,
              //PokemonId.Flareon,
              //PokemonId.Porygon,
              PokemonId.Snorlax,
              PokemonId.Articuno,
              PokemonId.Zapdos,
              PokemonId.Moltres,
              PokemonId.Dragonite,
              PokemonId.Mewtwo,
              PokemonId.Mew
          };
          public List<PokemonId> PokemonsToIgnore = new List<PokemonId>
          {
              //criteria: most common
              PokemonId.Caterpie,
              PokemonId.Weedle,
              PokemonId.Pidgey,
              PokemonId.Rattata,
              PokemonId.Spearow,
              PokemonId.Zubat,
              PokemonId.Doduo
          };
  
          public Dictionary<PokemonId, TransferFilter> PokemonsTransferFilter = new Dictionary<PokemonId, TransferFilter>
          {
              //criteria: based on NY Central Park and Tokyo variety + sniping optimization
              {PokemonId.Golduck, new TransferFilter(1800, 6, false, 95, "or", 1)},
              {PokemonId.Farfetchd, new TransferFilter(1250, 6, false, 80, "or", 1)},
              {PokemonId.Krabby, new TransferFilter(1250, 6, false, 95, "or", 1)},
              {PokemonId.Kangaskhan, new TransferFilter(1500, 6, false, 60, "or", 1)},
              {PokemonId.Horsea, new TransferFilter(1250, 6, false, 95, "or", 1)},
              {PokemonId.Staryu, new TransferFilter(1250, 6, false, 95, "or", 1)},
              {PokemonId.MrMime, new TransferFilter(1250, 6, false, 40, "or", 1)},
              {PokemonId.Scyther, new TransferFilter(1800, 6, false, 80, "or", 1)},
              {PokemonId.Jynx, new TransferFilter(1250, 6, false, 95, "or", 1)},
              {PokemonId.Electabuzz, new TransferFilter(1250, 6, false, 80, "or", 1)},
              {PokemonId.Magmar, new TransferFilter(1500, 6, false, 80, "or", 1)},
              {PokemonId.Pinsir, new TransferFilter(1800, 6, false, 95, "or", 1)},
              {PokemonId.Tauros, new TransferFilter(1250, 6, false, 90, "or", 1)},
              {PokemonId.Magikarp, new TransferFilter(200, 6, false, 95, "or", 1)},
              {PokemonId.Gyarados, new TransferFilter(1250, 6, false, 90, "or", 1)},
              {PokemonId.Lapras, new TransferFilter(1800, 6, false, 80, "or", 1)},
              {PokemonId.Eevee, new TransferFilter(1250, 6, false, 95, "or", 1)},
              {PokemonId.Vaporeon, new TransferFilter(1500, 6, false, 90, "or", 1)},
              {PokemonId.Jolteon, new TransferFilter(1500, 6, false, 90, "or", 1)},
              {PokemonId.Flareon, new TransferFilter(1500, 6, false, 90, "or", 1)},
              {PokemonId.Porygon, new TransferFilter(1250, 6, false, 60, "or", 1)},
              {PokemonId.Snorlax, new TransferFilter(2600, 6, false, 90, "or", 1)},
              {PokemonId.Dragonite, new TransferFilter(2600, 6, false, 90, "or", 1)}
          };
  
          public SnipeSettings PokemonToSnipe = new SnipeSettings
          {
              Locations = new List<Location>
              {
                  new Location(38.55680748646112, -121.2383794784546), //Dratini Spot
                  new Location(-33.85901900, 151.21309800), //Magikarp Spot
                  new Location(47.5014969, -122.0959568), //Eevee Spot
                  new Location(51.5025343, -0.2055027) //Charmender Spot
              },
              Pokemon = new List<PokemonId>
              {
                  PokemonId.Venusaur,
                  PokemonId.Charizard,
                  PokemonId.Blastoise,
                  PokemonId.Beedrill,
                  PokemonId.Raichu,
                  PokemonId.Sandslash,
                  PokemonId.Nidoking,
                  PokemonId.Nidoqueen,
                  PokemonId.Clefable,
                  PokemonId.Ninetales,
                  PokemonId.Golbat,
                  PokemonId.Vileplume,
                  PokemonId.Golduck,
                  PokemonId.Primeape,
                  PokemonId.Arcanine,
                  PokemonId.Poliwrath,
                  PokemonId.Alakazam,
                  PokemonId.Machamp,
                  PokemonId.Golem,
                  PokemonId.Rapidash,
                  PokemonId.Slowbro,
                  PokemonId.Farfetchd,
                  PokemonId.Muk,
                  PokemonId.Cloyster,
                  PokemonId.Gengar,
                  PokemonId.Exeggutor,
                  PokemonId.Marowak,
                  PokemonId.Hitmonchan,
                  PokemonId.Lickitung,
                  PokemonId.Rhydon,
                  PokemonId.Chansey,
                  PokemonId.Kangaskhan,
                  PokemonId.Starmie,
                  PokemonId.MrMime,
                  PokemonId.Scyther,
                  PokemonId.Magmar,
                  PokemonId.Electabuzz,
                  PokemonId.Jynx,
                  PokemonId.Gyarados,
                  PokemonId.Lapras,
                  PokemonId.Ditto,
                  PokemonId.Vaporeon,
                  PokemonId.Jolteon,
                  PokemonId.Flareon,
                  PokemonId.Porygon,
                  PokemonId.Kabutops,
                  PokemonId.Aerodactyl,
                  PokemonId.Snorlax,
                  PokemonId.Articuno,
                  PokemonId.Zapdos,
                  PokemonId.Moltres,
                  PokemonId.Dragonite,
                  PokemonId.Mewtwo,
                  PokemonId.Mew
              }
          };
  
          public List<PokemonId> PokemonToUseMasterball = new List<PokemonId>
          {
              PokemonId.Articuno,
              PokemonId.Zapdos,
              PokemonId.Moltres,
              PokemonId.Mew,
              PokemonId.Mewtwo
          };
  
          public GlobalSettings()
          {
              InitializePropertyDefaultValues(this);
          }
  
          public void InitializePropertyDefaultValues(object obj)
          {
              FieldInfo[] fields = obj.GetType().GetFields();
  
              foreach (FieldInfo field in fields)
              {
                  var d = field.GetCustomAttribute<DefaultValueAttribute>();
  
                  if (d != null)
                      field.SetValue(obj, d.Value);
              }
          }
  
          public static GlobalSettings Default => new GlobalSettings();
  
          public static GlobalSettings Load(string path, bool boolSkipSave = false)
          {
              GlobalSettings settings = null;
              bool isGui = (AppDomain.CurrentDomain.GetAssemblies().SingleOrDefault(a => a.FullName.Contains("PoGo.NecroBot.GUI")) != null);
              var profilePath = Path.Combine(Directory.GetCurrentDirectory(), path);
              var profileConfigPath = Path.Combine(profilePath, "config");
              var configFile = Path.Combine(profileConfigPath, "config.json");
              var shouldExit = false;
  
              if (File.Exists(configFile))
              {
                  try
                  {
                      //if the file exists, load the settings
                      string input = "";
                      int count = 0;
                      while (true)
                      {
                          try
                          {
  
gt:                             input = File.ReadAllText(configFile);