public float haversine(Server serv){
			//http://www.stormconsultancy.co.uk/blog/development/code-snippets/the-haversine-formula-in-c-and-sql/
			//modified by me a little
			//@returns angular distance
			Contract.Requires(serv != null);
			Contract.Requires(!(float.IsNaN(serv.lat)|| float.IsNegativeInfinity(serv.lat)|| float.IsPositiveInfinity(serv.lat)));
			Contract.Requires(!(float.IsNaN(serv.lon) || float.IsNegativeInfinity(serv.lon) || float.IsPositiveInfinity(serv.lon)));
			double dLat = (serv.lat-lat)/180*Math.PI;
			double dLon = (serv.lon-lon)/180*Math.PI;
 
			double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) +
				Math.Cos(lat/180*Math.PI) *Math.Cos(serv.lon/180*Math.PI) *
				Math.Sin(dLon / 2) * Math.Sin(dLon / 2);
			return (float)(2 * Math.Asin(Math.Min(1, Math.Sqrt(a))));
		}
		public async Task<float> measureUploadSpeed(Server server, int size = 1024*482){
			Contract.Requires(server != null);
			Contract.Requires(size >= 0);
			var prefix = new[]{
				(byte) '&',
				(byte) 'c',
				(byte) 'o',
				(byte) 'n',
				(byte) 't',
				(byte) 'e',
				(byte) 'n',
				(byte) 't',
				(byte) '0',
				(byte) '=',
			};
			stage = Stage.UPLOAD;

			var req = HttpWebRequest.Create(new Uri(server.uri, "upload.php")) as HttpWebRequest;
			req.Method = "POST";
			req.ContentType = "application/x-www-form-urlencoded";
			req.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore);
			req.ContentLength = countOfPieces*(defaultSize + prefix.Length);
			req.KeepAlive = true;

			req.Credentials = CredentialCache.DefaultCredentials;
			req.Proxy = hch.Proxy;

			emitProgressEvent(0);
			using (var str = req.GetRequestStream()) {
				using (var ums = new RangedRandomBytesStream(defaultSize, (byte)'A', (byte)'z'))
				{
					int j = 0;
                    EventedStream.dataLoadListener evtListener = (o, bytes) => emitProgressEvent(100 * (j + bytes / defaultSize) / countOfPieces);
                    ums.onLoading += evtListener;
                    sw.Restart();
					for (; j < countOfPieces; j++)
					{
						prefix[8] = (byte)('0' + j);
						await str.WriteAsync(prefix, 0, prefix.Length);
						await str.FlushAsync();
						await ums.CopyToAsync(str);
                        ums.Position = 0;
						await str.FlushAsync();
					}
					sw.Stop();
                    ums.onLoading -= evtListener;
                }
			}

			await req.GetResponseAsync().ContinueWith(t => t.Result.GetResponseStream().Close());
			float speed = (float) (req.ContentLength/(sw.Elapsed.TotalSeconds));
			emitProgressEvent(100);
			emitMeasuredEvent(speed);
			return speed;
		}
		protected async Task<Server> convertServersXMLToFilteredServersList(XmlNodeList servers){
			Contract.Requires(servers != null);
			if (servers.Count == 0) return null;
			closestKnownServer = new Server(servers[0]);
			closestKnownServer.dist=haversine(closestKnownServer);
			this.servers.Add(closestKnownServer);
			var pingTasks = new List<Task>();

			for (int i = 1; i < servers.Count;i++){
				Server server;
				try {
					server = new Server(servers[i]);
				} catch {
					continue;
				}
				server.dist = haversine(server);

				if (closestKnownServer.dist - server.dist > distTreshold) {
					closestKnownServer = server;
					this.servers.Add(server);
					this.servers.RemoveAt(0);
				}
				else if (Math.Abs(closestKnownServer.dist - server.dist) <= distTreshold) {
					this.servers.Add(server);
					//BUG: we need to enable it but it causes hang
					pingTasks.Add(
						Task.Run(async () =>{
							await server.ping();
							if (closestKnownServer.latency > server.latency) {
								closestKnownServer = server;
								this.servers.RemoveAt(0);
							}
						})
					);
				}
			}
			await Task.WhenAll(pingTasks);//bug : it writes it has finished before it is really finished
			return closestKnownServer;
		}
		public async Task<float> measureDownloadSpeed(Server server,int size=100){
			Contract.Requires(server != null);
			Contract.Requires(size >= 0);
			stage = Stage.DOWNLOAD;
			var uri = new Uri(server.uri, "random" + "4000x4000" + ".jpg");

			var speed=await measureDownloadSpeed(uri);
			emitProgressEvent(100);//uri = null . WHY?????
			emitMeasuredEvent(speed);
			return speed;
		}
		protected void convertServersXMLToServersList(XmlNodeList servers){
			Contract.Requires(servers != null);
			for (int i = 1; i < servers.Count;i++){
				var server = new Server(servers[i]);
				this.servers.Add(server);
			}
		}