We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Update srtm.py
prevent from bug when nx,ny fall on the sea


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lib/cartopy/io/srtm.py`
Content:
```
1 # (C) British Crown Copyright 2011 - 2012, Met Office
2 #
3 # This file is part of cartopy.
4 #
5 # cartopy is free software: you can redistribute it and/or modify it under
6 # the terms of the GNU Lesser General Public License as published by the
7 # Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # cartopy is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public License
16 # along with cartopy.  If not, see <http://www.gnu.org/licenses/>.
17 
18 
19 """
20 The Shuttle Radar Topography Mission (SRTM) is an international research
21 effort that obtained digital elevation models on a near-global scale from
22 56S to 60N, to generate the most complete high-resolution digital topographic
23 database of Earth prior to the release of the ASTER GDEM in 2009.
24 
25    - Wikipedia (August 2012)
26 
27 """
28 import json
29 import os
30 
31 import numpy as np
32 import six
33 
34 from cartopy import config
35 import cartopy.crs as ccrs
36 from cartopy.io import fh_getter, Downloader
37 
38 
39 def srtm(lon, lat):
40     """
41     Return (elevation, crs, extent) for the given longitude latitude.
42     Elevation is in meters.
43     """
44     fname = SRTM3_retrieve(lon, lat)
45     if fname is None:
46         raise ValueError('No srtm tile found for those coordinates.')
47     return read_SRTM3(fname)
48 
49 
50 def add_shading(elevation, azimuth, altitude):
51     """Adds shading to SRTM elevation data, using azimuth and altitude
52     of the sun.
53 
54     :type elevation: numpy.ndarray
55     :param elevation: SRTM elevation data (in meters)
56     :type azimuth: float
57     :param azimuth: azimuth of the Sun (in degrees)
58     :type altitude: float
59     :param altitude: altitude of the Sun (in degrees)
60 
61     :rtype: numpy.ndarray
62     :return: shaded SRTM relief map.
63     """
64     azimuth = np.deg2rad(azimuth)
65     altitude = np.deg2rad(altitude)
66     x, y = np.gradient(elevation)
67     slope = np.pi/2. - np.arctan(np.sqrt(x*x + y*y))
68     # -x here because of pixel orders in the SRTM tile
69     aspect = np.arctan2(-x, y)
70     shaded = np.sin(altitude) * np.sin(slope)\
71         + np.cos(altitude) * np.cos(slope)\
72         * np.cos((azimuth - np.pi/2.) - aspect)
73     return shaded
74 
75 
76 def fill_gaps(elevation, max_distance=10):
77     """Fills gaps in SRTM elevation data for which the distance from
78     missing pixel to nearest existing one is smaller than `max_distance`.
79 
80     This function requires osgeo/gdal to work.
81 
82     :type elevation: numpy.ndarray
83     :param elevation: SRTM elevation data (in meters)
84     :type max_distance: int
85     :param max_distance: maximal distance (in pixels) between a missing point
86     and the nearest valid one.
87 
88     :rtype: numpy.ndarray
89     :return: SRTM elevation data with filled gaps..
90     """
91     # Lazily import osgeo - it is only an optional dependency for cartopy.
92     from osgeo import gdal
93     from osgeo import gdal_array
94 
95     src_ds = gdal_array.OpenArray(elevation)
96     srcband = src_ds.GetRasterBand(1)
97     dstband = srcband
98     maskband = srcband
99     smoothing_iterations = 0
100     options = []
101     gdal.FillNodata(dstband, maskband,
102                     max_distance, smoothing_iterations, options,
103                     callback=None)
104     elevation = dstband.ReadAsArray()
105     return elevation
106 
107 
108 def srtm_composite(lon_min, lat_min, nx, ny):
109 
110     # XXX nx and ny have got confused in the code (numpy array ordering?).
111     # However, the interface works well.
112 
113     bottom_left_ll = (lon_min, lat_min)
114     shape = np.array([1201, 1201])
115     img = np.empty(shape * (nx, ny))
116 
117     for i in range(nx):
118         for j in range(ny):
119             x_img_slice = slice(i * shape[0], (i + 1) * shape[0])
120             y_img_slice = slice(j * shape[1], (j + 1) * shape[1])
121 
122             tile_img, crs, extent = srtm(bottom_left_ll[0] + j,
123                                          bottom_left_ll[1] + i)
124             img[x_img_slice, y_img_slice] = tile_img
125 
126     extent = (bottom_left_ll[0], bottom_left_ll[0] + ny,
127               bottom_left_ll[1], bottom_left_ll[1] + nx)
128 
129     return img, crs, extent
130 
131 
132 def read_SRTM3(fh):
133     fh, fname = fh_getter(fh, needs_filename=True)
134     if fname.endswith('.zip'):
135         from zipfile import ZipFile
136         zfh = ZipFile(fh, 'rb')
137         fh = zfh.open(os.path.basename(fname[:-4]), 'r')
138 
139     elev = np.fromfile(fh, dtype=np.dtype('>i2'))
140     elev.shape = (1201, 1201)
141 
142     fname = os.path.basename(fname)
143     y_dir, y, x_dir, x = fname[0], int(fname[1:3]), fname[3], int(fname[4:7])
144 
145     if y_dir == 'S':
146         y *= -1
147 
148     if x_dir == 'W':
149         x *= -1
150 
151     # xxx extent may need to be wider by half a pixel
152     return elev[::-1, ...], ccrs.PlateCarree(), [x, x + 1, y, y + 1]
153 
154 
155 def SRTM3_retrieve(lon, lat):
156     x = '%s%03d' % ('E' if lon > 0 else 'W', abs(int(lon)))
157     y = '%s%02d' % ('N' if lat > 0 else 'S', abs(int(lat)))
158 
159     srtm_downloader = Downloader.from_config(('SRTM', 'SRTM3'))
160     return srtm_downloader.path({'config': config, 'x': x, 'y': y})
161 
162 
163 class SRTM3Downloader(Downloader):
164     """
165     Provides a SRTM3 download mechanism.
166 
167     """
168     FORMAT_KEYS = ('config', 'x', 'y')
169 
170     _JSON_SRTM3_LOOKUP = os.path.join(os.path.dirname(__file__),
171                                       'srtm.json')
172     _SRTM3_LOOKUP_URL = json.load(open(_JSON_SRTM3_LOOKUP, 'r'))
173     """
174     The SRTM3 url lookup dictionary maps keys such as 'N43E043' to the url
175     of the file to download.
176 
177     """
178 
179     def __init__(self,
180                  target_path_template,
181                  pre_downloaded_path_template='',
182                  ):
183         # adds some SRTM3 defaults to the __init__ of a Downloader
184         # namely, the URl is determined on the fly using the
185         # ``SRTM3Downloader._SRTM3_LOOKUP_URL`` dictionary
186         Downloader.__init__(self, None,
187                             target_path_template,
188                             pre_downloaded_path_template)
189 
190     def url(self, format_dict):
191         # override the url method, looking up the url from the
192         # ``SRTM3Downloader._SRTM3_LOOKUP_URL`` dictionary
193         key = u'{y}{x}'.format(**format_dict)
194         url = SRTM3Downloader._SRTM3_LOOKUP_URL.get(key, None)
195         return url
196 
197     def acquire_resource(self, target_path, format_dict):
198         from zipfile import ZipFile
199 
200         target_dir = os.path.dirname(target_path)
201         if not os.path.isdir(target_dir):
202             os.makedirs(target_dir)
203 
204         url = self.url(format_dict)
205 
206         srtm_online = self._urlopen(url)
207         zfh = ZipFile(six.BytesIO(srtm_online.read()), 'r')
208 
209         zip_member_path = u'{y}{x}.hgt'.format(**format_dict)
210         member = zfh.getinfo(zip_member_path)
211         with open(target_path, 'wb') as fh:
212             fh.write(zfh.open(member).read())
213 
214         srtm_online.close()
215         zfh.close()
216 
217         return target_path
218 
219     @staticmethod
220     def _create_srtm3_dict():
221         """
222         Returns a dictionary mapping srtm filename to the URL of the file.
223 
224         This is slow as it must query the SRTM server to identify the
225         continent from which the tile comes. Hence a json file with this
226         content exists in ``SRTM3Downloader._JSON_SRTM3_LOOKUP``.
227 
228         The json file was created with::
229 
230             import cartopy.io.srtm as srtm
231             import json
232             fh = open(srtm.SRTM3Downloader._JSON_SRTM3_LOOKUP, 'w')
233             json.dump(srtm.SRTM3Downloader._create_srtm3_dict(), fh)
234 
235         """
236         # lazy imports. In most situations, these are not
237         # dependencies of cartopy.
238         if six.PY3:
239             from urllib.request import urlopen
240         else:
241             from urllib2 import urlopen
242         from BeautifulSoup import BeautifulSoup
243 
244         files = {}
245 
246         for continent in ['Australia', 'Africa', 'Eurasia', 'Islands',
247                           'North_America', 'South_America']:
248 
249             url = "http://dds.cr.usgs.gov/srtm/version2_1/SRTM3/%s" % continent
250             f = urlopen(url)
251             html = f.read()
252             soup = BeautifulSoup(html)
253 
254             for link in soup('li'):
255                 name = str(link.text)
256                 if name != ' Parent Directory':
257                     # remove the '.hgt.zip'
258                     files[name[:-8]] = url + '/' + name
259             f.close()
260         return files
261 
262     @classmethod
263     def default_downloader(cls):
264         """
265         Returns a typical downloader for this class. In general, this static
266         method is used to create the default configuration in cartopy.config
267 
268         """
269         default_spec = ('SRTM', 'SRTM3', '{y}{x}.hgt')
270         target_path_template = os.path.join('{config[data_dir]}',
271                                             *default_spec)
272         pre_path_template = os.path.join('{config[pre_existing_data_dir]}',
273                                          *default_spec)
274         return cls(target_path_template=target_path_template,
275                    pre_downloaded_path_template=pre_path_template)
276 
277 
278 # add a generic SRTM downloader to the config 'downloaders' section.
279 config['downloaders'].setdefault(('SRTM', 'SRTM3'),
280                                  SRTM3Downloader.default_downloader())
281
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/lib/cartopy/io/srtm.py b/lib/cartopy/io/srtm.py
--- a/lib/cartopy/io/srtm.py
+++ b/lib/cartopy/io/srtm.py
@@ -119,14 +119,18 @@
             x_img_slice = slice(i * shape[0], (i + 1) * shape[0])
             y_img_slice = slice(j * shape[1], (j + 1) * shape[1])
 
-            tile_img, crs, extent = srtm(bottom_left_ll[0] + j,
-                                         bottom_left_ll[1] + i)
-            img[x_img_slice, y_img_slice] = tile_img
+            try:
+                tile_img, _, _ = srtm(bottom_left_ll[0] + j,
+                                      bottom_left_ll[1] + i)
+            except ValueError:
+                img[x_img_slice, y_img_slice] = 0
+            else:
+                img[x_img_slice, y_img_slice] = tile_img
 
     extent = (bottom_left_ll[0], bottom_left_ll[0] + ny,
               bottom_left_ll[1], bottom_left_ll[1] + nx)
 
-    return img, crs, extent
+    return img, ccrs.PlateCarree(), extent
 
 
 def read_SRTM3(fh):
@@ -153,11 +157,22 @@
 
 
 def SRTM3_retrieve(lon, lat):
+    """
+    Return the path of a .hgt file for the given SRTM location.
+
+    If no such .hgt file exists (because it is over the ocean)
+    None will be returned.
+
+    """
     x = '%s%03d' % ('E' if lon > 0 else 'W', abs(int(lon)))
     y = '%s%02d' % ('N' if lat > 0 else 'S', abs(int(lat)))
 
     srtm_downloader = Downloader.from_config(('SRTM', 'SRTM3'))
-    return srtm_downloader.path({'config': config, 'x': x, 'y': y})
+    params = {'config': config, 'x': x, 'y': y}
+    if srtm_downloader.url(params) is None:
+        return None
+    else:
+        return srtm_downloader.path({'config': config, 'x': x, 'y': y})
 
 
 class SRTM3Downloader(Downloader):

{"golden_diff": "diff --git a/lib/cartopy/io/srtm.py b/lib/cartopy/io/srtm.py\n--- a/lib/cartopy/io/srtm.py\n+++ b/lib/cartopy/io/srtm.py\n@@ -119,14 +119,18 @@\n             x_img_slice = slice(i * shape[0], (i + 1) * shape[0])\n             y_img_slice = slice(j * shape[1], (j + 1) * shape[1])\n \n-            tile_img, crs, extent = srtm(bottom_left_ll[0] + j,\n-                                         bottom_left_ll[1] + i)\n-            img[x_img_slice, y_img_slice] = tile_img\n+            try:\n+                tile_img, _, _ = srtm(bottom_left_ll[0] + j,\n+                                      bottom_left_ll[1] + i)\n+            except ValueError:\n+                img[x_img_slice, y_img_slice] = 0\n+            else:\n+                img[x_img_slice, y_img_slice] = tile_img\n \n     extent = (bottom_left_ll[0], bottom_left_ll[0] + ny,\n               bottom_left_ll[1], bottom_left_ll[1] + nx)\n \n-    return img, crs, extent\n+    return img, ccrs.PlateCarree(), extent\n \n \n def read_SRTM3(fh):\n@@ -153,11 +157,22 @@\n \n \n def SRTM3_retrieve(lon, lat):\n+    \"\"\"\n+    Return the path of a .hgt file for the given SRTM location.\n+\n+    If no such .hgt file exists (because it is over the ocean)\n+    None will be returned.\n+\n+    \"\"\"\n     x = '%s%03d' % ('E' if lon > 0 else 'W', abs(int(lon)))\n     y = '%s%02d' % ('N' if lat > 0 else 'S', abs(int(lat)))\n \n     srtm_downloader = Downloader.from_config(('SRTM', 'SRTM3'))\n-    return srtm_downloader.path({'config': config, 'x': x, 'y': y})\n+    params = {'config': config, 'x': x, 'y': y}\n+    if srtm_downloader.url(params) is None:\n+        return None\n+    else:\n+        return srtm_downloader.path({'config': config, 'x': x, 'y': y})\n \n \n class SRTM3Downloader(Downloader):\n", "issue": "Update srtm.py\nprevent from bug when nx,ny fall on the sea\n\n", "before_files": [{"content": "# (C) British Crown Copyright 2011 - 2012, Met Office\n#\n# This file is part of cartopy.\n#\n# cartopy is free software: you can redistribute it and/or modify it under\n# the terms of the GNU Lesser General Public License as published by the\n# Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# cartopy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public License\n# along with cartopy.  If not, see <http://www.gnu.org/licenses/>.\n\n\n\"\"\"\nThe Shuttle Radar Topography Mission (SRTM) is an international research\neffort that obtained digital elevation models on a near-global scale from\n56S to 60N, to generate the most complete high-resolution digital topographic\ndatabase of Earth prior to the release of the ASTER GDEM in 2009.\n\n   - Wikipedia (August 2012)\n\n\"\"\"\nimport json\nimport os\n\nimport numpy as np\nimport six\n\nfrom cartopy import config\nimport cartopy.crs as ccrs\nfrom cartopy.io import fh_getter, Downloader\n\n\ndef srtm(lon, lat):\n    \"\"\"\n    Return (elevation, crs, extent) for the given longitude latitude.\n    Elevation is in meters.\n    \"\"\"\n    fname = SRTM3_retrieve(lon, lat)\n    if fname is None:\n        raise ValueError('No srtm tile found for those coordinates.')\n    return read_SRTM3(fname)\n\n\ndef add_shading(elevation, azimuth, altitude):\n    \"\"\"Adds shading to SRTM elevation data, using azimuth and altitude\n    of the sun.\n\n    :type elevation: numpy.ndarray\n    :param elevation: SRTM elevation data (in meters)\n    :type azimuth: float\n    :param azimuth: azimuth of the Sun (in degrees)\n    :type altitude: float\n    :param altitude: altitude of the Sun (in degrees)\n\n    :rtype: numpy.ndarray\n    :return: shaded SRTM relief map.\n    \"\"\"\n    azimuth = np.deg2rad(azimuth)\n    altitude = np.deg2rad(altitude)\n    x, y = np.gradient(elevation)\n    slope = np.pi/2. - np.arctan(np.sqrt(x*x + y*y))\n    # -x here because of pixel orders in the SRTM tile\n    aspect = np.arctan2(-x, y)\n    shaded = np.sin(altitude) * np.sin(slope)\\\n        + np.cos(altitude) * np.cos(slope)\\\n        * np.cos((azimuth - np.pi/2.) - aspect)\n    return shaded\n\n\ndef fill_gaps(elevation, max_distance=10):\n    \"\"\"Fills gaps in SRTM elevation data for which the distance from\n    missing pixel to nearest existing one is smaller than `max_distance`.\n\n    This function requires osgeo/gdal to work.\n\n    :type elevation: numpy.ndarray\n    :param elevation: SRTM elevation data (in meters)\n    :type max_distance: int\n    :param max_distance: maximal distance (in pixels) between a missing point\n    and the nearest valid one.\n\n    :rtype: numpy.ndarray\n    :return: SRTM elevation data with filled gaps..\n    \"\"\"\n    # Lazily import osgeo - it is only an optional dependency for cartopy.\n    from osgeo import gdal\n    from osgeo import gdal_array\n\n    src_ds = gdal_array.OpenArray(elevation)\n    srcband = src_ds.GetRasterBand(1)\n    dstband = srcband\n    maskband = srcband\n    smoothing_iterations = 0\n    options = []\n    gdal.FillNodata(dstband, maskband,\n                    max_distance, smoothing_iterations, options,\n                    callback=None)\n    elevation = dstband.ReadAsArray()\n    return elevation\n\n\ndef srtm_composite(lon_min, lat_min, nx, ny):\n\n    # XXX nx and ny have got confused in the code (numpy array ordering?).\n    # However, the interface works well.\n\n    bottom_left_ll = (lon_min, lat_min)\n    shape = np.array([1201, 1201])\n    img = np.empty(shape * (nx, ny))\n\n    for i in range(nx):\n        for j in range(ny):\n            x_img_slice = slice(i * shape[0], (i + 1) * shape[0])\n            y_img_slice = slice(j * shape[1], (j + 1) * shape[1])\n\n            tile_img, crs, extent = srtm(bottom_left_ll[0] + j,\n                                         bottom_left_ll[1] + i)\n            img[x_img_slice, y_img_slice] = tile_img\n\n    extent = (bottom_left_ll[0], bottom_left_ll[0] + ny,\n              bottom_left_ll[1], bottom_left_ll[1] + nx)\n\n    return img, crs, extent\n\n\ndef read_SRTM3(fh):\n    fh, fname = fh_getter(fh, needs_filename=True)\n    if fname.endswith('.zip'):\n        from zipfile import ZipFile\n        zfh = ZipFile(fh, 'rb')\n        fh = zfh.open(os.path.basename(fname[:-4]), 'r')\n\n    elev = np.fromfile(fh, dtype=np.dtype('>i2'))\n    elev.shape = (1201, 1201)\n\n    fname = os.path.basename(fname)\n    y_dir, y, x_dir, x = fname[0], int(fname[1:3]), fname[3], int(fname[4:7])\n\n    if y_dir == 'S':\n        y *= -1\n\n    if x_dir == 'W':\n        x *= -1\n\n    # xxx extent may need to be wider by half a pixel\n    return elev[::-1, ...], ccrs.PlateCarree(), [x, x + 1, y, y + 1]\n\n\ndef SRTM3_retrieve(lon, lat):\n    x = '%s%03d' % ('E' if lon > 0 else 'W', abs(int(lon)))\n    y = '%s%02d' % ('N' if lat > 0 else 'S', abs(int(lat)))\n\n    srtm_downloader = Downloader.from_config(('SRTM', 'SRTM3'))\n    return srtm_downloader.path({'config': config, 'x': x, 'y': y})\n\n\nclass SRTM3Downloader(Downloader):\n    \"\"\"\n    Provides a SRTM3 download mechanism.\n\n    \"\"\"\n    FORMAT_KEYS = ('config', 'x', 'y')\n\n    _JSON_SRTM3_LOOKUP = os.path.join(os.path.dirname(__file__),\n                                      'srtm.json')\n    _SRTM3_LOOKUP_URL = json.load(open(_JSON_SRTM3_LOOKUP, 'r'))\n    \"\"\"\n    The SRTM3 url lookup dictionary maps keys such as 'N43E043' to the url\n    of the file to download.\n\n    \"\"\"\n\n    def __init__(self,\n                 target_path_template,\n                 pre_downloaded_path_template='',\n                 ):\n        # adds some SRTM3 defaults to the __init__ of a Downloader\n        # namely, the URl is determined on the fly using the\n        # ``SRTM3Downloader._SRTM3_LOOKUP_URL`` dictionary\n        Downloader.__init__(self, None,\n                            target_path_template,\n                            pre_downloaded_path_template)\n\n    def url(self, format_dict):\n        # override the url method, looking up the url from the\n        # ``SRTM3Downloader._SRTM3_LOOKUP_URL`` dictionary\n        key = u'{y}{x}'.format(**format_dict)\n        url = SRTM3Downloader._SRTM3_LOOKUP_URL.get(key, None)\n        return url\n\n    def acquire_resource(self, target_path, format_dict):\n        from zipfile import ZipFile\n\n        target_dir = os.path.dirname(target_path)\n        if not os.path.isdir(target_dir):\n            os.makedirs(target_dir)\n\n        url = self.url(format_dict)\n\n        srtm_online = self._urlopen(url)\n        zfh = ZipFile(six.BytesIO(srtm_online.read()), 'r')\n\n        zip_member_path = u'{y}{x}.hgt'.format(**format_dict)\n        member = zfh.getinfo(zip_member_path)\n        with open(target_path, 'wb') as fh:\n            fh.write(zfh.open(member).read())\n\n        srtm_online.close()\n        zfh.close()\n\n        return target_path\n\n    @staticmethod\n    def _create_srtm3_dict():\n        \"\"\"\n        Returns a dictionary mapping srtm filename to the URL of the file.\n\n        This is slow as it must query the SRTM server to identify the\n        continent from which the tile comes. Hence a json file with this\n        content exists in ``SRTM3Downloader._JSON_SRTM3_LOOKUP``.\n\n        The json file was created with::\n\n            import cartopy.io.srtm as srtm\n            import json\n            fh = open(srtm.SRTM3Downloader._JSON_SRTM3_LOOKUP, 'w')\n            json.dump(srtm.SRTM3Downloader._create_srtm3_dict(), fh)\n\n        \"\"\"\n        # lazy imports. In most situations, these are not\n        # dependencies of cartopy.\n        if six.PY3:\n            from urllib.request import urlopen\n        else:\n            from urllib2 import urlopen\n        from BeautifulSoup import BeautifulSoup\n\n        files = {}\n\n        for continent in ['Australia', 'Africa', 'Eurasia', 'Islands',\n                          'North_America', 'South_America']:\n\n            url = \"http://dds.cr.usgs.gov/srtm/version2_1/SRTM3/%s\" % continent\n            f = urlopen(url)\n            html = f.read()\n            soup = BeautifulSoup(html)\n\n            for link in soup('li'):\n                name = str(link.text)\n                if name != ' Parent Directory':\n                    # remove the '.hgt.zip'\n                    files[name[:-8]] = url + '/' + name\n            f.close()\n        return files\n\n    @classmethod\n    def default_downloader(cls):\n        \"\"\"\n        Returns a typical downloader for this class. In general, this static\n        method is used to create the default configuration in cartopy.config\n\n        \"\"\"\n        default_spec = ('SRTM', 'SRTM3', '{y}{x}.hgt')\n        target_path_template = os.path.join('{config[data_dir]}',\n                                            *default_spec)\n        pre_path_template = os.path.join('{config[pre_existing_data_dir]}',\n                                         *default_spec)\n        return cls(target_path_template=target_path_template,\n                   pre_downloaded_path_template=pre_path_template)\n\n\n# add a generic SRTM downloader to the config 'downloaders' section.\nconfig['downloaders'].setdefault(('SRTM', 'SRTM3'),\n                                 SRTM3Downloader.default_downloader())\n", "path": "lib/cartopy/io/srtm.py"}], "after_files": [{"content": "# (C) British Crown Copyright 2011 - 2012, Met Office\n#\n# This file is part of cartopy.\n#\n# cartopy is free software: you can redistribute it and/or modify it under\n# the terms of the GNU Lesser General Public License as published by the\n# Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# cartopy is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU Lesser General Public License for more details.\n#\n# You should have received a copy of the GNU Lesser General Public License\n# along with cartopy.  If not, see <http://www.gnu.org/licenses/>.\n\n\n\"\"\"\nThe Shuttle Radar Topography Mission (SRTM) is an international research\neffort that obtained digital elevation models on a near-global scale from\n56S to 60N, to generate the most complete high-resolution digital topographic\ndatabase of Earth prior to the release of the ASTER GDEM in 2009.\n\n   - Wikipedia (August 2012)\n\n\"\"\"\nimport json\nimport os\n\nimport numpy as np\nimport six\n\nfrom cartopy import config\nimport cartopy.crs as ccrs\nfrom cartopy.io import fh_getter, Downloader\n\n\ndef srtm(lon, lat):\n    \"\"\"\n    Return (elevation, crs, extent) for the given longitude latitude.\n    Elevation is in meters.\n    \"\"\"\n    fname = SRTM3_retrieve(lon, lat)\n    if fname is None:\n        raise ValueError('No srtm tile found for those coordinates.')\n    return read_SRTM3(fname)\n\n\ndef add_shading(elevation, azimuth, altitude):\n    \"\"\"Adds shading to SRTM elevation data, using azimuth and altitude\n    of the sun.\n\n    :type elevation: numpy.ndarray\n    :param elevation: SRTM elevation data (in meters)\n    :type azimuth: float\n    :param azimuth: azimuth of the Sun (in degrees)\n    :type altitude: float\n    :param altitude: altitude of the Sun (in degrees)\n\n    :rtype: numpy.ndarray\n    :return: shaded SRTM relief map.\n    \"\"\"\n    azimuth = np.deg2rad(azimuth)\n    altitude = np.deg2rad(altitude)\n    x, y = np.gradient(elevation)\n    slope = np.pi/2. - np.arctan(np.sqrt(x*x + y*y))\n    # -x here because of pixel orders in the SRTM tile\n    aspect = np.arctan2(-x, y)\n    shaded = np.sin(altitude) * np.sin(slope)\\\n        + np.cos(altitude) * np.cos(slope)\\\n        * np.cos((azimuth - np.pi/2.) - aspect)\n    return shaded\n\n\ndef fill_gaps(elevation, max_distance=10):\n    \"\"\"Fills gaps in SRTM elevation data for which the distance from\n    missing pixel to nearest existing one is smaller than `max_distance`.\n\n    This function requires osgeo/gdal to work.\n\n    :type elevation: numpy.ndarray\n    :param elevation: SRTM elevation data (in meters)\n    :type max_distance: int\n    :param max_distance: maximal distance (in pixels) between a missing point\n    and the nearest valid one.\n\n    :rtype: numpy.ndarray\n    :return: SRTM elevation data with filled gaps..\n    \"\"\"\n    # Lazily import osgeo - it is only an optional dependency for cartopy.\n    from osgeo import gdal\n    from osgeo import gdal_array\n\n    src_ds = gdal_array.OpenArray(elevation)\n    srcband = src_ds.GetRasterBand(1)\n    dstband = srcband\n    maskband = srcband\n    smoothing_iterations = 0\n    options = []\n    gdal.FillNodata(dstband, maskband,\n                    max_distance, smoothing_iterations, options,\n                    callback=None)\n    elevation = dstband.ReadAsArray()\n    return elevation\n\n\ndef srtm_composite(lon_min, lat_min, nx, ny):\n\n    # XXX nx and ny have got confused in the code (numpy array ordering?).\n    # However, the interface works well.\n\n    bottom_left_ll = (lon_min, lat_min)\n    shape = np.array([1201, 1201])\n    img = np.empty(shape * (nx, ny))\n\n    for i in range(nx):\n        for j in range(ny):\n            x_img_slice = slice(i * shape[0], (i + 1) * shape[0])\n            y_img_slice = slice(j * shape[1], (j + 1) * shape[1])\n\n            try:\n                tile_img, _, _ = srtm(bottom_left_ll[0] + j,\n                                      bottom_left_ll[1] + i)\n            except ValueError:\n                img[x_img_slice, y_img_slice] = 0\n            else:\n                img[x_img_slice, y_img_slice] = tile_img\n\n    extent = (bottom_left_ll[0], bottom_left_ll[0] + ny,\n              bottom_left_ll[1], bottom_left_ll[1] + nx)\n\n    return img, ccrs.PlateCarree(), extent\n\n\ndef read_SRTM3(fh):\n    fh, fname = fh_getter(fh, needs_filename=True)\n    if fname.endswith('.zip'):\n        from zipfile import ZipFile\n        zfh = ZipFile(fh, 'rb')\n        fh = zfh.open(os.path.basename(fname[:-4]), 'r')\n\n    elev = np.fromfile(fh, dtype=np.dtype('>i2'))\n    elev.shape = (1201, 1201)\n\n    fname = os.path.basename(fname)\n    y_dir, y, x_dir, x = fname[0], int(fname[1:3]), fname[3], int(fname[4:7])\n\n    if y_dir == 'S':\n        y *= -1\n\n    if x_dir == 'W':\n        x *= -1\n\n    # xxx extent may need to be wider by half a pixel\n    return elev[::-1, ...], ccrs.PlateCarree(), [x, x + 1, y, y + 1]\n\n\ndef SRTM3_retrieve(lon, lat):\n    \"\"\"\n    Return the path of a .hgt file for the given SRTM location.\n\n    If no such .hgt file exists (because it is over the ocean)\n    None will be returned.\n\n    \"\"\"\n    x = '%s%03d' % ('E' if lon > 0 else 'W', abs(int(lon)))\n    y = '%s%02d' % ('N' if lat > 0 else 'S', abs(int(lat)))\n\n    srtm_downloader = Downloader.from_config(('SRTM', 'SRTM3'))\n    params = {'config': config, 'x': x, 'y': y}\n    if srtm_downloader.url(params) is None:\n        return None\n    else:\n        return srtm_downloader.path({'config': config, 'x': x, 'y': y})\n\n\nclass SRTM3Downloader(Downloader):\n    \"\"\"\n    Provides a SRTM3 download mechanism.\n\n    \"\"\"\n    FORMAT_KEYS = ('config', 'x', 'y')\n\n    _JSON_SRTM3_LOOKUP = os.path.join(os.path.dirname(__file__),\n                                      'srtm.json')\n    _SRTM3_LOOKUP_URL = json.load(open(_JSON_SRTM3_LOOKUP, 'r'))\n    \"\"\"\n    The SRTM3 url lookup dictionary maps keys such as 'N43E043' to the url\n    of the file to download.\n\n    \"\"\"\n\n    def __init__(self,\n                 target_path_template,\n                 pre_downloaded_path_template='',\n                 ):\n        # adds some SRTM3 defaults to the __init__ of a Downloader\n        # namely, the URl is determined on the fly using the\n        # ``SRTM3Downloader._SRTM3_LOOKUP_URL`` dictionary\n        Downloader.__init__(self, None,\n                            target_path_template,\n                            pre_downloaded_path_template)\n\n    def url(self, format_dict):\n        # override the url method, looking up the url from the\n        # ``SRTM3Downloader._SRTM3_LOOKUP_URL`` dictionary\n        key = u'{y}{x}'.format(**format_dict)\n        url = SRTM3Downloader._SRTM3_LOOKUP_URL.get(key, None)\n        return url\n\n    def acquire_resource(self, target_path, format_dict):\n        from zipfile import ZipFile\n\n        target_dir = os.path.dirname(target_path)\n        if not os.path.isdir(target_dir):\n            os.makedirs(target_dir)\n\n        url = self.url(format_dict)\n\n        srtm_online = self._urlopen(url)\n        zfh = ZipFile(six.BytesIO(srtm_online.read()), 'r')\n\n        zip_member_path = u'{y}{x}.hgt'.format(**format_dict)\n        member = zfh.getinfo(zip_member_path)\n        with open(target_path, 'wb') as fh:\n            fh.write(zfh.open(member).read())\n\n        srtm_online.close()\n        zfh.close()\n\n        return target_path\n\n    @staticmethod\n    def _create_srtm3_dict():\n        \"\"\"\n        Returns a dictionary mapping srtm filename to the URL of the file.\n\n        This is slow as it must query the SRTM server to identify the\n        continent from which the tile comes. Hence a json file with this\n        content exists in ``SRTM3Downloader._JSON_SRTM3_LOOKUP``.\n\n        The json file was created with::\n\n            import cartopy.io.srtm as srtm\n            import json\n            fh = open(srtm.SRTM3Downloader._JSON_SRTM3_LOOKUP, 'w')\n            json.dump(srtm.SRTM3Downloader._create_srtm3_dict(), fh)\n\n        \"\"\"\n        # lazy imports. In most situations, these are not\n        # dependencies of cartopy.\n        if six.PY3:\n            from urllib.request import urlopen\n        else:\n            from urllib2 import urlopen\n        from BeautifulSoup import BeautifulSoup\n\n        files = {}\n\n        for continent in ['Australia', 'Africa', 'Eurasia', 'Islands',\n                          'North_America', 'South_America']:\n\n            url = \"http://dds.cr.usgs.gov/srtm/version2_1/SRTM3/%s\" % continent\n            f = urlopen(url)\n            html = f.read()\n            soup = BeautifulSoup(html)\n\n            for link in soup('li'):\n                name = str(link.text)\n                if name != ' Parent Directory':\n                    # remove the '.hgt.zip'\n                    files[name[:-8]] = url + '/' + name\n            f.close()\n        return files\n\n    @classmethod\n    def default_downloader(cls):\n        \"\"\"\n        Returns a typical downloader for this class. In general, this static\n        method is used to create the default configuration in cartopy.config\n\n        \"\"\"\n        default_spec = ('SRTM', 'SRTM3', '{y}{x}.hgt')\n        target_path_template = os.path.join('{config[data_dir]}',\n                                            *default_spec)\n        pre_path_template = os.path.join('{config[pre_existing_data_dir]}',\n                                         *default_spec)\n        return cls(target_path_template=target_path_template,\n                   pre_downloaded_path_template=pre_path_template)\n\n\n# add a generic SRTM downloader to the config 'downloaders' section.\nconfig['downloaders'].setdefault(('SRTM', 'SRTM3'),\n                                 SRTM3Downloader.default_downloader())\n", "path": "lib/cartopy/io/srtm.py"}]}