public static async Task Start(Session session, CancellationToken cancellationToken)
        {
            while (true)
            {
                if (session.LogicSettings.UsePokeSnipersLocationServer)
                {
                    var st = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                    var t  = DateTime.Now.ToUniversalTime() - st;
                    var currentTimestamp = t.TotalMilliseconds;
                    var pokemonIds       = session.LogicSettings.PokemonToSnipe.Pokemon;

                    var formatter = new NumberFormatInfo {
                        NumberDecimalSeparator = "."
                    };

                    var offset = session.LogicSettings.SnipingScanOffset;
                    // 0.003 = half a mile; maximum 0.06 is 10 miles
                    if (offset < 0.001)
                    {
                        offset = 0.003;
                    }
                    if (offset > 0.06)
                    {
                        offset = 0.06;
                    }

                    ScanResult scanResult;
                    try
                    {
                        var request = WebRequest.CreateHttp(_pokeSniperURI);
                        request.Accept           = "application/json";
                        request.Method           = "GET";
                        request.Timeout          = session.LogicSettings.SnipeRequestTimeoutSeconds;
                        request.ReadWriteTimeout = 32000;

                        var resp     = request.GetResponse();
                        var reader   = new StreamReader(resp.GetResponseStream());
                        var fullresp = reader.ReadToEnd().Replace(" M", "Male").Replace(" F", "Female");

                        dynamic pokesniper = JsonConvert.DeserializeObject(fullresp);
                        JArray  results    = pokesniper.results;
                        SnipeLocations.Clear();

                        foreach (var result in results)
                        {
                            PokemonId id;
                            Enum.TryParse(result.Value <string>("name"), out id);
                            double iv;
                            Double.TryParse(result.Value <string>("iv"), out iv);
                            var a = new SniperInfo
                            {
                                Id                  = id,
                                IV                  = iv,
                                Latitude            = Convert.ToDouble(result.Value <string>("coords").Split(',')[0]),
                                Longitude           = Convert.ToDouble(result.Value <string>("coords").Split(',')[1]),
                                ExpirationTimestamp = DateTime.Now
                            };
                            SnipeLocations.Add(a);
                        }
                    }
                    catch (WebException ex)
                    {
                        if (ex.Status == WebExceptionStatus.ProtocolError &&
                            ex.Response != null)
                        {
                            var resp = (HttpWebResponse)ex.Response;
                            switch (resp.StatusCode)
                            {
                            case HttpStatusCode.NotFound:
                                session.EventDispatcher.Send(new WarnEvent {
                                    Message = session.Translation.GetTranslation(TranslationString.WebErrorNotFound)
                                });
                                break;

                            case HttpStatusCode.GatewayTimeout:
                                session.EventDispatcher.Send(new WarnEvent {
                                    Message = session.Translation.GetTranslation(TranslationString.WebErrorGatewayTimeout)
                                });
                                break;

                            case HttpStatusCode.BadGateway:
                                session.EventDispatcher.Send(new WarnEvent {
                                    Message = session.Translation.GetTranslation(TranslationString.WebErrorBadGateway)
                                });
                                break;

                            default:
                                session.EventDispatcher.Send(new WarnEvent {
                                    Message = ex.ToString()
                                });
                                break;
                            }
                        }
                        else if (ex.Status == WebExceptionStatus.Timeout)
                        {
                            session.EventDispatcher.Send(new WarnEvent {
                                Message = session.Translation.GetTranslation(TranslationString.SkipLaggedTimeout)
                            });
                        }
                        else
                        {
                            session.EventDispatcher.Send(new ErrorEvent {
                                Message = ex.ToString()
                            });
                        }

                        scanResult = new ScanResult {
                            Pokemon = new List <PokemonLocation>()
                        };
                    }
                    catch (Exception ex)
                    {
                        session.EventDispatcher.Send(new ErrorEvent {
                            Message = ex.ToString()
                        });
                        scanResult = new ScanResult {
                            Pokemon = new List <PokemonLocation>()
                        };
                    }
                    await Task.Delay(5000, cancellationToken);
                }
                else
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    try
                    {
                        var lClient = new TcpClient();
                        lClient.Connect(session.LogicSettings.SnipeLocationServer,
                                        session.LogicSettings.SnipeLocationServerPort);

                        var sr = new StreamReader(lClient.GetStream());

                        while (lClient.Connected)
                        {
                            var line = sr.ReadLine();
                            if (line == null)
                            {
                                throw new Exception("Unable to ReadLine from sniper socket");
                            }

                            var info = JsonConvert.DeserializeObject <SniperInfo>(line);

                            if (SnipeLocations.Any(x =>
                                                   Math.Abs(x.Latitude - info.Latitude) < 0.0001 &&
                                                   Math.Abs(x.Longitude - info.Longitude) < 0.0001))
                            {
                                // we might have different precisions from other sources
                                continue;
                            }

                            SnipeLocations.RemoveAll(x => DateTime.Now > x.TimeStampAdded.AddMinutes(15));
                            SnipeLocations.Add(info);
                        }
                    }
                    catch (SocketException)
                    {
                        // this is spammed to often. Maybe add it to debug log later
                    }
                    catch (Exception ex)
                    {
                        // most likely System.IO.IOException
                        session.EventDispatcher.Send(new ErrorEvent {
                            Message = ex.ToString()
                        });
                    }
                    await Task.Delay(5000, cancellationToken);
                }
            }
        }
        private static ScanResult PokeSniperScanForPokemon(ISession session, Location location)
        {
            var formatter = new NumberFormatInfo {
                NumberDecimalSeparator = "."
            };

            var offset = session.LogicSettings.SnipingScanOffset;

            // 0.003 = half a mile; maximum 0.06 is 10 miles
            if (offset < 0.001)
            {
                offset = 0.003;
            }
            if (offset > 0.06)
            {
                offset = 0.06;
            }

            ScanResult scanResult;

            try
            {
                var request = WebRequest.CreateHttp(_pokeSniperURI);
                request.Accept           = "application/json";
                request.Method           = "GET";
                request.UserAgent        = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36";
                request.Timeout          = session.LogicSettings.SnipeRequestTimeoutSeconds;
                request.ReadWriteTimeout = 32000;

                var resp     = request.GetResponse();
                var reader   = new StreamReader(resp.GetResponseStream());
                var fullresp = reader.ReadToEnd().Replace(" M", "Male").Replace(" F", "Female");

                dynamic pokesniper = JsonConvert.DeserializeObject(fullresp);
                JArray  results    = pokesniper.results;
                SnipeLocations.Clear();

                foreach (var result in results)
                {
                    PokemonId id;
                    Enum.TryParse(result.Value <string>("name"), out id);
                    double iv;
                    Double.TryParse(result.Value <string>("iv"), out iv);
                    var a = new SniperInfo
                    {
                        Id                  = id,
                        IV                  = iv,
                        Latitude            = Convert.ToDouble(result.Value <string>("coords").Split(',')[0]),
                        Longitude           = Convert.ToDouble(result.Value <string>("coords").Split(',')[1]),
                        ExpirationTimestamp = DateTime.Now
                    };
                    SnipeLocations.Add(a);
                }
            }
            catch (Exception ex)
            {
                // most likely System.IO.IOException
                session.EventDispatcher.Send(new ErrorEvent {
                    Message = ex.ToString()
                });
                scanResult = new ScanResult {
                    Pokemon = new List <PokemonLocation>()
                };
            }
            return(null);
        }