public GeoInfo(GeoInfo geoInfo)
 {
     this.IpAddress = geoInfo.IpAddress;
     this.IpAddressBlock = geoInfo.IpAddressBlock;
     this.Country = geoInfo.Country;
     this.City = geoInfo.City;
     this.Region = geoInfo.Region;
     this.District = geoInfo.District;
     this.Latitude = geoInfo.Latitude;
     this.Longitude = geoInfo.Longitude;
     this.Expires = geoInfo.Expires;
 }
 /// <returns>Узел региона, в котором находится точка, соответствующая переданной геоинформации. Определяется по названию региона.</returns>
 public static IPublishedContent GetRegionNode(GeoInfo geoInfo)
 {
     try {
         if (geoInfo == null) return null;
         var regionizedGeoInfo = Regionize(geoInfo);
         var umbracoHelper = new UmbracoHelper(UmbracoContext.Current);
         var regionNode = umbracoHelper.TypedContentSingleAtXPath(String.Format("/root/pubMainPage/pubRegionalMeans/regRegion[./ipGeoBaseName[text()='{0}']]",
             regionizedGeoInfo.Region));
         return regionNode;
     } catch {
         return null;
     }
 }
 /// <summary>
 /// На сайте Etechno регионом считается "территориальный субъект", т. е., например, для СПб это Ленинградская область, IpGeoBase же
 /// в соответствии с Конституцией возвращает для него СПб. Нужно исправить города федерального значения.
 /// </summary>
 /// <param name="geoInfo"></param>
 public static GeoInfo Regionize(GeoInfo geoInfo)
 {
     if (geoInfo == null) return null;
     var result = new GeoInfo(geoInfo);
     switch (result.Region) {
         case "Санкт-Петербург": result.Region = "Ленинградская область"; break;
         case "Москва": result.Region = "Московская область"; break;
         case "Севастополь": result.Region = "Республика Крым"; break;
         default: result.Region = result.Region; break;
     }
     return result;
 }
 /// <returns>Узел офиса из имеющихся в городе, ближайший к точке, соответствущей переданному аргументу.</returns>
 public static IPublishedContent GetNearestOffice(IPublishedContent region, GeoInfo geoInfo)
 {
     if (region == null) return null;
     if (geoInfo == null || geoInfo.Latitude == null || geoInfo.Longitude == null) {
         return region.Descendants("regOffice").FirstOrDefault();
     }
     var targetLat = geoInfo.Latitude.Value;
     var targetLong = geoInfo.Longitude.Value;
     var yacPattern = new System.Text.RegularExpressions.Regex(@"\[(.*)\]\|(.*)");
     return region.Descendants("regOffice").OrderBy(x => {
         var match = yacPattern.Match(x.GetPropertyValue<string>("coords"));
         if (match.Success) {
             var officeCoords = match.Groups[1].Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(y => y.Trim()).ToArray();
             if (officeCoords.Length > 1) {
                 decimal officeLat, officeLong;
                 if (Decimal.TryParse(officeCoords[0], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out officeLat)) {
                     if (Decimal.TryParse(officeCoords[1], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out officeLong)) {
                         return GetMetric(officeLat, officeLong, targetLat, targetLong);
                     }
                 }
             }
         }
         return Double.MaxValue;
     }).FirstOrDefault();
 }