public static Tuple <StandardChunkMetadata, bool> Parse(string x)
        {
            var parts  = x.Split('.');
            var split1 = Math.Max(x.IndexOf('n'), x.IndexOf('s'));
            var split2 = Math.Max(x.IndexOf('w'), x.IndexOf('e'));

            var lat  = Angle.Parse(x.Substring(0, split1 + 1));
            var lon  = Angle.Parse(x.Substring(split1 + 1, split2 - split1));
            var zoom = int.Parse(parts[0].Substring(split2 + 1));

            bool isImage = (parts[2][0] == 'i');

            var template = StandardChunkMetadata.GetRangeContaingPoint(lat, lon, zoom);

            var ggg = isImage ?
                      Imaging.Images.Current.GetFileName(template) :
                      Elevation.Heights.Current.GetFileName(template);

            if (ggg != x)
            {
                throw new InvalidOperationException();
            }

            return(new Tuple <StandardChunkMetadata, bool>(template, isImage));
        }
        public static StandardChunkMetadata GetRangeFromKey(long key)
        {
            if (key == 0)
            {
                return(null);
            }

            int zoomLevel = (int)(key % (MaxZoomLevel + 1));

            Angle frameSize = frameSizeForZoom[zoomLevel];

            int latNumPossible = (int)(usDeltaLat.Abs / frameSize.Abs);
            int lonNumPossible = (int)(usDeltaLon.Abs / frameSize.Abs);

            int encodedLat = (int)(key / (MaxZoomLevel + 1) % 0x100000000);
            int encodedLon = (int)(key / (MaxZoomLevel + 1) / 0x100000000);

            int sizeMultiplierLat = encodedLat - 3 * latNumPossible;
            int sizeMultiplierLon = encodedLon - 3 * lonNumPossible;

            Angle latLo = Angle.Add(Angle.Multiply(frameSize, sizeMultiplierLat), usMinLat);
            Angle lonLo = Angle.Add(Angle.Multiply(frameSize, sizeMultiplierLon), usMinLon);
            Angle latHi = Angle.Add(Angle.Multiply(frameSize, sizeMultiplierLat + 1), usMinLat);
            Angle lonHi = Angle.Add(Angle.Multiply(frameSize, sizeMultiplierLon + 1), usMinLon);
            StandardChunkMetadata ret = new StandardChunkMetadata(
                numPixelsForZoom + 1, numPixelsForZoom + 1,
                latLo, lonLo,
                latHi, lonHi,
                zoomLevel, key);

            return(ret);
        }
        public static StandardChunkMetadata ParseBase(string x)
        {
            var parts  = x.Split('.');
            var split1 = Math.Max(x.IndexOf('n'), x.IndexOf('s'));
            var split2 = Math.Max(x.IndexOf('w'), x.IndexOf('e'));

            var lat  = Angle.Parse(x.Substring(0, split1 + 1));
            var lon  = Angle.Parse(x.Substring(split1 + 1, split2 - split1));
            var zoom = int.Parse(parts[0].Substring(split2 + 1));

            return(StandardChunkMetadata.GetRangeContaingPoint(lat, lon, zoom));
        }