We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Spider costco is broken
During the global build at 2021-08-18-14-42-26, spider **costco** failed with **0 features** and **2 errors**.

Here's [the log](https://data.alltheplaces.xyz/runs/2021-08-18-14-42-26/logs/costco.txt) and [the output](https://data.alltheplaces.xyz/runs/2021-08-18-14-42-26/output/costco.geojson) ([on a map](https://data.alltheplaces.xyz/map.html?show=https://data.alltheplaces.xyz/runs/2021-08-18-14-42-26/output/costco.geojson))

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `locations/spiders/costco.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 import scrapy
3 import json
4 import re
5 from urllib.parse import urlencode
6 
7 from locations.items import GeojsonPointItem
8 
9 DAYS_NAME = {
10     'm': 'Mo',
11     'mon': 'Mo',
12     't': 'Tu',
13     'w': 'We',
14     's': 'Th',
15     'f': 'Fr',
16     'f ': 'Fr',
17     'sun': 'Su',
18     'sat': 'Sa',
19     'daily': '',
20 }
21 
22 
23 class CostcoSpider(scrapy.Spider):
24     name = "costco"
25     item_attributes = {'brand': 'Costco', 'brand_wikidata': 'Q715583'}
26     allowed_domains = ['www.costco.com']
27     start_urls = (
28         'https://www.costco.com/warehouse-locations',
29     )
30     custom_settings = {
31         'USER_AGENT': 'Mozilla/5.0',
32     }
33 
34     download_delay = 0.5
35 
36     def parse(self, response):
37         url = 'https://www.costco.com/AjaxWarehouseBrowseLookupView?'
38 
39         params = {
40             "langId": "-1",
41             # "storeId": "10301",
42             "numOfWarehouses": "50",  # max allowed
43             "hasGas": "false",
44             "hasTires": "false",
45             "hasFood": "false",
46             "hasHearing": "false",
47             "hasPharmacy": "false",
48             "hasOptical": "false",
49             "hasBusiness": "false",
50             "hasPhotoCenter": "false",
51             "tiresCheckout": "0",
52             "isTransferWarehouse": "false",
53             "populateWarehouseDetails": "true",
54             "warehousePickupCheckout": "false",
55             "countryCode": "US",
56         }
57 
58         with open('./locations/searchable_points/us_centroids_100mile_radius.csv') as points:
59             next(points)
60             for point in points:
61                 _, lat, lon = point.strip().split(',')
62                 params.update({"latitude": lat, "longitude": lon})
63                 yield scrapy.Request(url=url + urlencode(params), callback=self.parse_ajax)
64 
65     def store_hours(self, store_hours):
66         opening_hours = []
67 
68         if not store_hours:
69             return None
70 
71         for day_info in store_hours:
72             if day_info.lower().find('close') > -1:
73                 continue
74 
75             match = re.match(
76                 r'^(\w+)-?[\.:]?([A-Za-z]*)\.? *(\d{1,2}):(\d{2}) ?(am|pm|) *- +(\d{1,2}):(\d{2}) ?(am|pm|hrs\.)$', day_info)
77             if not match:
78                 self.logger.warn("Couldn't match hours: %s", day_info)
79 
80             try:
81                 day_from, day_to, fr_hr, fr_min, fr_ampm, to_hr, to_min, to_ampm = match.groups()
82             except ValueError:
83                 self.logger.warn("Couldn't match hours: %s", day_info)
84                 raise
85 
86             day_from = DAYS_NAME[day_from.lower()]
87             day_to = DAYS_NAME[day_to.lower()] if day_to else day_from
88 
89             if day_from != day_to:
90                 day_str = '{}-{}'.format(day_from, day_to)
91             else:
92                 day_str = '{}'.format(day_from)
93 
94             day_hours = '%s %02d:%02d-%02d:%02d' % (
95                 day_str,
96                 int(fr_hr) + 12 if fr_ampm == 'pm' else int(fr_hr),
97                 int(fr_min),
98                 int(to_hr) + 12 if to_ampm == 'pm' else int(to_hr),
99                 int(to_min),
100             )
101 
102             opening_hours.append(day_hours.strip())
103 
104         return '; '.join(opening_hours)
105 
106     def _clean_text(self, text):
107         return re.sub("[\r\n\t]", "", text).strip()
108 
109     def parse_ajax(self, response):
110         body = json.loads(response.body_as_unicode())
111 
112         for store in body[1:]:
113             if store["distance"] < 110:
114                 # only process stores that are within 110 miles of query point
115                 # (to reduce processing a ton of duplicates)
116                 ref = store['identifier']
117                 department = store['specialtyDepartments']
118 
119                 fuels = {}
120                 if 'gasPrices' in store:
121                     fuels = {
122                         'fuel:diesel': 'diesel' in store['gasPrices'],
123                         'fuel:octane_87': 'regular' in store['gasPrices'],
124                         'fuel:octane_91': 'premium' in store['gasPrices']
125                     }
126 
127                 properties = {
128                     'lat': store.get('latitude'),
129                     'lon': store.get('longitude'),
130                     'ref': ref,
131                     'phone': self._clean_text(store.get('phone')),
132                     'name': f"Costco {store['locationName']}",
133                     'addr_full': store['address1'],
134                     'city': store['city'],
135                     'state': store['state'],
136                     'postcode': store.get('zipCode'),
137                     'country': store.get('country'),
138                     'website': 'https://www.costco.com/warehouse-locations/store-{}.html'.format(ref),
139                     'extras': {
140                         'shop': 'supermarket',
141                         'number': store["displayName"],
142                         'amenity:fuel': store['hasGasDepartment'],
143                         'amenity:pharmacy': store['hasPharmacyDepartment'],
144                         'atm': any('ATM' == d['name'] for d in department) or None,
145                         'fuel:propane': any('Propane' == d['name'] for d in department) or None,
146                         **fuels
147                     }
148                 }
149 
150                 hours = store.get('warehouseHours')
151                 if hours:
152                     try:
153                         properties["opening_hours"] = self.store_hours(hours)
154                     except:
155                         pass
156 
157                 yield GeojsonPointItem(**properties)
158
```
--- 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/locations/spiders/costco.py b/locations/spiders/costco.py
--- a/locations/spiders/costco.py
+++ b/locations/spiders/costco.py
@@ -28,7 +28,7 @@
         'https://www.costco.com/warehouse-locations',
     )
     custom_settings = {
-        'USER_AGENT': 'Mozilla/5.0',
+        'USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
     }
 
     download_delay = 0.5

{"golden_diff": "diff --git a/locations/spiders/costco.py b/locations/spiders/costco.py\n--- a/locations/spiders/costco.py\n+++ b/locations/spiders/costco.py\n@@ -28,7 +28,7 @@\n         'https://www.costco.com/warehouse-locations',\n     )\n     custom_settings = {\n-        'USER_AGENT': 'Mozilla/5.0',\n+        'USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',\n     }\n \n     download_delay = 0.5\n", "issue": "Spider costco is broken\nDuring the global build at 2021-08-18-14-42-26, spider **costco** failed with **0 features** and **2 errors**.\n\nHere's [the log](https://data.alltheplaces.xyz/runs/2021-08-18-14-42-26/logs/costco.txt) and [the output](https://data.alltheplaces.xyz/runs/2021-08-18-14-42-26/output/costco.geojson) ([on a map](https://data.alltheplaces.xyz/map.html?show=https://data.alltheplaces.xyz/runs/2021-08-18-14-42-26/output/costco.geojson))\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\nimport scrapy\nimport json\nimport re\nfrom urllib.parse import urlencode\n\nfrom locations.items import GeojsonPointItem\n\nDAYS_NAME = {\n    'm': 'Mo',\n    'mon': 'Mo',\n    't': 'Tu',\n    'w': 'We',\n    's': 'Th',\n    'f': 'Fr',\n    'f ': 'Fr',\n    'sun': 'Su',\n    'sat': 'Sa',\n    'daily': '',\n}\n\n\nclass CostcoSpider(scrapy.Spider):\n    name = \"costco\"\n    item_attributes = {'brand': 'Costco', 'brand_wikidata': 'Q715583'}\n    allowed_domains = ['www.costco.com']\n    start_urls = (\n        'https://www.costco.com/warehouse-locations',\n    )\n    custom_settings = {\n        'USER_AGENT': 'Mozilla/5.0',\n    }\n\n    download_delay = 0.5\n\n    def parse(self, response):\n        url = 'https://www.costco.com/AjaxWarehouseBrowseLookupView?'\n\n        params = {\n            \"langId\": \"-1\",\n            # \"storeId\": \"10301\",\n            \"numOfWarehouses\": \"50\",  # max allowed\n            \"hasGas\": \"false\",\n            \"hasTires\": \"false\",\n            \"hasFood\": \"false\",\n            \"hasHearing\": \"false\",\n            \"hasPharmacy\": \"false\",\n            \"hasOptical\": \"false\",\n            \"hasBusiness\": \"false\",\n            \"hasPhotoCenter\": \"false\",\n            \"tiresCheckout\": \"0\",\n            \"isTransferWarehouse\": \"false\",\n            \"populateWarehouseDetails\": \"true\",\n            \"warehousePickupCheckout\": \"false\",\n            \"countryCode\": \"US\",\n        }\n\n        with open('./locations/searchable_points/us_centroids_100mile_radius.csv') as points:\n            next(points)\n            for point in points:\n                _, lat, lon = point.strip().split(',')\n                params.update({\"latitude\": lat, \"longitude\": lon})\n                yield scrapy.Request(url=url + urlencode(params), callback=self.parse_ajax)\n\n    def store_hours(self, store_hours):\n        opening_hours = []\n\n        if not store_hours:\n            return None\n\n        for day_info in store_hours:\n            if day_info.lower().find('close') > -1:\n                continue\n\n            match = re.match(\n                r'^(\\w+)-?[\\.:]?([A-Za-z]*)\\.? *(\\d{1,2}):(\\d{2}) ?(am|pm|) *- +(\\d{1,2}):(\\d{2}) ?(am|pm|hrs\\.)$', day_info)\n            if not match:\n                self.logger.warn(\"Couldn't match hours: %s\", day_info)\n\n            try:\n                day_from, day_to, fr_hr, fr_min, fr_ampm, to_hr, to_min, to_ampm = match.groups()\n            except ValueError:\n                self.logger.warn(\"Couldn't match hours: %s\", day_info)\n                raise\n\n            day_from = DAYS_NAME[day_from.lower()]\n            day_to = DAYS_NAME[day_to.lower()] if day_to else day_from\n\n            if day_from != day_to:\n                day_str = '{}-{}'.format(day_from, day_to)\n            else:\n                day_str = '{}'.format(day_from)\n\n            day_hours = '%s %02d:%02d-%02d:%02d' % (\n                day_str,\n                int(fr_hr) + 12 if fr_ampm == 'pm' else int(fr_hr),\n                int(fr_min),\n                int(to_hr) + 12 if to_ampm == 'pm' else int(to_hr),\n                int(to_min),\n            )\n\n            opening_hours.append(day_hours.strip())\n\n        return '; '.join(opening_hours)\n\n    def _clean_text(self, text):\n        return re.sub(\"[\\r\\n\\t]\", \"\", text).strip()\n\n    def parse_ajax(self, response):\n        body = json.loads(response.body_as_unicode())\n\n        for store in body[1:]:\n            if store[\"distance\"] < 110:\n                # only process stores that are within 110 miles of query point\n                # (to reduce processing a ton of duplicates)\n                ref = store['identifier']\n                department = store['specialtyDepartments']\n\n                fuels = {}\n                if 'gasPrices' in store:\n                    fuels = {\n                        'fuel:diesel': 'diesel' in store['gasPrices'],\n                        'fuel:octane_87': 'regular' in store['gasPrices'],\n                        'fuel:octane_91': 'premium' in store['gasPrices']\n                    }\n\n                properties = {\n                    'lat': store.get('latitude'),\n                    'lon': store.get('longitude'),\n                    'ref': ref,\n                    'phone': self._clean_text(store.get('phone')),\n                    'name': f\"Costco {store['locationName']}\",\n                    'addr_full': store['address1'],\n                    'city': store['city'],\n                    'state': store['state'],\n                    'postcode': store.get('zipCode'),\n                    'country': store.get('country'),\n                    'website': 'https://www.costco.com/warehouse-locations/store-{}.html'.format(ref),\n                    'extras': {\n                        'shop': 'supermarket',\n                        'number': store[\"displayName\"],\n                        'amenity:fuel': store['hasGasDepartment'],\n                        'amenity:pharmacy': store['hasPharmacyDepartment'],\n                        'atm': any('ATM' == d['name'] for d in department) or None,\n                        'fuel:propane': any('Propane' == d['name'] for d in department) or None,\n                        **fuels\n                    }\n                }\n\n                hours = store.get('warehouseHours')\n                if hours:\n                    try:\n                        properties[\"opening_hours\"] = self.store_hours(hours)\n                    except:\n                        pass\n\n                yield GeojsonPointItem(**properties)\n", "path": "locations/spiders/costco.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\nimport scrapy\nimport json\nimport re\nfrom urllib.parse import urlencode\n\nfrom locations.items import GeojsonPointItem\n\nDAYS_NAME = {\n    'm': 'Mo',\n    'mon': 'Mo',\n    't': 'Tu',\n    'w': 'We',\n    's': 'Th',\n    'f': 'Fr',\n    'f ': 'Fr',\n    'sun': 'Su',\n    'sat': 'Sa',\n    'daily': '',\n}\n\n\nclass CostcoSpider(scrapy.Spider):\n    name = \"costco\"\n    item_attributes = {'brand': 'Costco', 'brand_wikidata': 'Q715583'}\n    allowed_domains = ['www.costco.com']\n    start_urls = (\n        'https://www.costco.com/warehouse-locations',\n    )\n    custom_settings = {\n        'USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',\n    }\n\n    download_delay = 0.5\n\n    def parse(self, response):\n        url = 'https://www.costco.com/AjaxWarehouseBrowseLookupView?'\n\n        params = {\n            \"langId\": \"-1\",\n            # \"storeId\": \"10301\",\n            \"numOfWarehouses\": \"50\",  # max allowed\n            \"hasGas\": \"false\",\n            \"hasTires\": \"false\",\n            \"hasFood\": \"false\",\n            \"hasHearing\": \"false\",\n            \"hasPharmacy\": \"false\",\n            \"hasOptical\": \"false\",\n            \"hasBusiness\": \"false\",\n            \"hasPhotoCenter\": \"false\",\n            \"tiresCheckout\": \"0\",\n            \"isTransferWarehouse\": \"false\",\n            \"populateWarehouseDetails\": \"true\",\n            \"warehousePickupCheckout\": \"false\",\n            \"countryCode\": \"US\",\n        }\n\n        with open('./locations/searchable_points/us_centroids_100mile_radius.csv') as points:\n            next(points)\n            for point in points:\n                _, lat, lon = point.strip().split(',')\n                params.update({\"latitude\": lat, \"longitude\": lon})\n                yield scrapy.Request(url=url + urlencode(params), callback=self.parse_ajax)\n\n    def store_hours(self, store_hours):\n        opening_hours = []\n\n        if not store_hours:\n            return None\n\n        for day_info in store_hours:\n            if day_info.lower().find('close') > -1:\n                continue\n\n            match = re.match(\n                r'^(\\w+)-?[\\.:]?([A-Za-z]*)\\.? *(\\d{1,2}):(\\d{2}) ?(am|pm|) *- +(\\d{1,2}):(\\d{2}) ?(am|pm|hrs\\.)$', day_info)\n            if not match:\n                self.logger.warn(\"Couldn't match hours: %s\", day_info)\n\n            try:\n                day_from, day_to, fr_hr, fr_min, fr_ampm, to_hr, to_min, to_ampm = match.groups()\n            except ValueError:\n                self.logger.warn(\"Couldn't match hours: %s\", day_info)\n                raise\n\n            day_from = DAYS_NAME[day_from.lower()]\n            day_to = DAYS_NAME[day_to.lower()] if day_to else day_from\n\n            if day_from != day_to:\n                day_str = '{}-{}'.format(day_from, day_to)\n            else:\n                day_str = '{}'.format(day_from)\n\n            day_hours = '%s %02d:%02d-%02d:%02d' % (\n                day_str,\n                int(fr_hr) + 12 if fr_ampm == 'pm' else int(fr_hr),\n                int(fr_min),\n                int(to_hr) + 12 if to_ampm == 'pm' else int(to_hr),\n                int(to_min),\n            )\n\n            opening_hours.append(day_hours.strip())\n\n        return '; '.join(opening_hours)\n\n    def _clean_text(self, text):\n        return re.sub(\"[\\r\\n\\t]\", \"\", text).strip()\n\n    def parse_ajax(self, response):\n        body = json.loads(response.body_as_unicode())\n\n        for store in body[1:]:\n            if store[\"distance\"] < 110:\n                # only process stores that are within 110 miles of query point\n                # (to reduce processing a ton of duplicates)\n                ref = store['identifier']\n                department = store['specialtyDepartments']\n\n                fuels = {}\n                if 'gasPrices' in store:\n                    fuels = {\n                        'fuel:diesel': 'diesel' in store['gasPrices'],\n                        'fuel:octane_87': 'regular' in store['gasPrices'],\n                        'fuel:octane_91': 'premium' in store['gasPrices']\n                    }\n\n                properties = {\n                    'lat': store.get('latitude'),\n                    'lon': store.get('longitude'),\n                    'ref': ref,\n                    'phone': self._clean_text(store.get('phone')),\n                    'name': f\"Costco {store['locationName']}\",\n                    'addr_full': store['address1'],\n                    'city': store['city'],\n                    'state': store['state'],\n                    'postcode': store.get('zipCode'),\n                    'country': store.get('country'),\n                    'website': 'https://www.costco.com/warehouse-locations/store-{}.html'.format(ref),\n                    'extras': {\n                        'shop': 'supermarket',\n                        'number': store[\"displayName\"],\n                        'amenity:fuel': store['hasGasDepartment'],\n                        'amenity:pharmacy': store['hasPharmacyDepartment'],\n                        'atm': any('ATM' == d['name'] for d in department) or None,\n                        'fuel:propane': any('Propane' == d['name'] for d in department) or None,\n                        **fuels\n                    }\n                }\n\n                hours = store.get('warehouseHours')\n                if hours:\n                    try:\n                        properties[\"opening_hours\"] = self.store_hours(hours)\n                    except:\n                        pass\n\n                yield GeojsonPointItem(**properties)\n", "path": "locations/spiders/costco.py"}]}