We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Spider att is broken
During the global build at 2021-06-02-14-42-40, spider **att** failed with **0 features** and **5433 errors**.

Here's [the log](https://data.alltheplaces.xyz/runs/2021-06-02-14-42-40/logs/att.txt) and [the output](https://data.alltheplaces.xyz/runs/2021-06-02-14-42-40/output/att.geojson) ([on a map](https://data.alltheplaces.xyz/map.html?show=https://data.alltheplaces.xyz/runs/2021-06-02-14-42-40/output/att.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/att.py`
Content:
```
1 import scrapy
2 import json
3 import re
4 from locations.items import GeojsonPointItem
5 from locations.hours import OpeningHours
6 
7 
8 DAY_MAPPING = {
9     "MONDAY": "Mo",
10     "TUESDAY": "Tu",
11     "WEDNESDAY": "We",
12     "THURSDAY": "Th",
13     "FRIDAY": "Fr",
14     "SATURDAY": "Sa",
15     "SUNDAY": "Su"
16 }
17 
18 
19 class ATTScraper(scrapy.Spider):
20     name = "att"
21     item_attributes = { 'brand': "AT&T", 'brand_wikidata': "Q35476" }
22     allowed_domains = ['www.att.com']
23     start_urls = (
24         'https://www.att.com/stores/us',
25     )
26     download_delay = 0.2
27 
28     def parse_hours(self, store_hours):
29         opening_hours = OpeningHours()
30         store_data = json.loads(store_hours)
31 
32         for store_day in store_data:
33             if len(store_day["intervals"]) < 1:
34                 continue
35             day = DAY_MAPPING[store_day["day"]]
36             open_time = str(store_day["intervals"][0]["start"])
37             if open_time == '0':
38                 open_time = '0000'
39             close_time = str(store_day["intervals"][0]["end"])
40             if close_time == '0':
41                 close_time = '2359'
42             opening_hours.add_range(day=day,
43                                     open_time=open_time,
44                                     close_time=close_time,
45                                     time_format='%H%M'
46                                     )
47 
48         return opening_hours.as_opening_hours()
49 
50     def parse(self, response):
51         urls = response.xpath('//a[@class="Directory-listLink"]/@href').extract()
52         is_store_list = response.xpath('//a[@class="Teaser-titleLink"]/@href').extract()
53 
54         if not urls and is_store_list:
55             urls = response.xpath('//a[@class="Teaser-titleLink"]/@href').extract()
56         for url in urls:
57             if url.count('/') >= 2:
58                 yield scrapy.Request(response.urljoin(url), callback=self.parse_store)
59             else:
60                 yield scrapy.Request(response.urljoin(url))
61 
62     def parse_store(self, response):
63         ref = re.search(r'.+/(.+?)/?(?:\.html|$)', response.url).group(1)
64 
65         properties = {
66             'ref': ref,
67             'name': response.xpath('normalize-space(//span[@class="LocationName-brand"]/text())').extract_first(),
68             'addr_full': response.xpath('normalize-space(//meta[@itemprop="streetAddress"]/@content)').extract_first(),
69             'city': response.xpath('normalize-space(//meta[@itemprop="addressLocality"]/@content)').extract_first(),
70             'state': response.xpath('normalize-space(//abbr[@itemprop="addressRegion"]/text())').extract_first(),
71             'postcode': response.xpath('normalize-space(//span[@itemprop="postalCode"]/text())').extract_first(),
72             'country': response.xpath('normalize-space(//abbr[@itemprop="addressCountry"]/text())').extract_first(),
73             'phone': response.xpath('normalize-space(//span[@itemprop="telephone"]//text())').extract_first(),
74             'website': response.url,
75             'lat': response.xpath('normalize-space(//meta[@itemprop="latitude"]/@content)').extract_first(),
76             'lon': response.xpath('normalize-space(//meta[@itemprop="longitude"]/@content)').extract_first(),
77         }
78 
79         hours = response.xpath('//span[@class="c-location-hours-today js-location-hours"]/@data-days').extract_first()
80         properties['opening_hours'] = self.parse_hours(hours)
81 
82         yield GeojsonPointItem(**properties)
83
```
--- 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/att.py b/locations/spiders/att.py
--- a/locations/spiders/att.py
+++ b/locations/spiders/att.py
@@ -76,7 +76,7 @@
             'lon': response.xpath('normalize-space(//meta[@itemprop="longitude"]/@content)').extract_first(),
         }
 
-        hours = response.xpath('//span[@class="c-location-hours-today js-location-hours"]/@data-days').extract_first()
+        hours = response.xpath('//span[@class="c-hours-today js-hours-today"]/@data-days').extract_first()
         properties['opening_hours'] = self.parse_hours(hours)
 
         yield GeojsonPointItem(**properties)

{"golden_diff": "diff --git a/locations/spiders/att.py b/locations/spiders/att.py\n--- a/locations/spiders/att.py\n+++ b/locations/spiders/att.py\n@@ -76,7 +76,7 @@\n             'lon': response.xpath('normalize-space(//meta[@itemprop=\"longitude\"]/@content)').extract_first(),\n         }\n \n-        hours = response.xpath('//span[@class=\"c-location-hours-today js-location-hours\"]/@data-days').extract_first()\n+        hours = response.xpath('//span[@class=\"c-hours-today js-hours-today\"]/@data-days').extract_first()\n         properties['opening_hours'] = self.parse_hours(hours)\n \n         yield GeojsonPointItem(**properties)\n", "issue": "Spider att is broken\nDuring the global build at 2021-06-02-14-42-40, spider **att** failed with **0 features** and **5433 errors**.\n\nHere's [the log](https://data.alltheplaces.xyz/runs/2021-06-02-14-42-40/logs/att.txt) and [the output](https://data.alltheplaces.xyz/runs/2021-06-02-14-42-40/output/att.geojson) ([on a map](https://data.alltheplaces.xyz/map.html?show=https://data.alltheplaces.xyz/runs/2021-06-02-14-42-40/output/att.geojson))\n", "before_files": [{"content": "import scrapy\nimport json\nimport re\nfrom locations.items import GeojsonPointItem\nfrom locations.hours import OpeningHours\n\n\nDAY_MAPPING = {\n    \"MONDAY\": \"Mo\",\n    \"TUESDAY\": \"Tu\",\n    \"WEDNESDAY\": \"We\",\n    \"THURSDAY\": \"Th\",\n    \"FRIDAY\": \"Fr\",\n    \"SATURDAY\": \"Sa\",\n    \"SUNDAY\": \"Su\"\n}\n\n\nclass ATTScraper(scrapy.Spider):\n    name = \"att\"\n    item_attributes = { 'brand': \"AT&T\", 'brand_wikidata': \"Q35476\" }\n    allowed_domains = ['www.att.com']\n    start_urls = (\n        'https://www.att.com/stores/us',\n    )\n    download_delay = 0.2\n\n    def parse_hours(self, store_hours):\n        opening_hours = OpeningHours()\n        store_data = json.loads(store_hours)\n\n        for store_day in store_data:\n            if len(store_day[\"intervals\"]) < 1:\n                continue\n            day = DAY_MAPPING[store_day[\"day\"]]\n            open_time = str(store_day[\"intervals\"][0][\"start\"])\n            if open_time == '0':\n                open_time = '0000'\n            close_time = str(store_day[\"intervals\"][0][\"end\"])\n            if close_time == '0':\n                close_time = '2359'\n            opening_hours.add_range(day=day,\n                                    open_time=open_time,\n                                    close_time=close_time,\n                                    time_format='%H%M'\n                                    )\n\n        return opening_hours.as_opening_hours()\n\n    def parse(self, response):\n        urls = response.xpath('//a[@class=\"Directory-listLink\"]/@href').extract()\n        is_store_list = response.xpath('//a[@class=\"Teaser-titleLink\"]/@href').extract()\n\n        if not urls and is_store_list:\n            urls = response.xpath('//a[@class=\"Teaser-titleLink\"]/@href').extract()\n        for url in urls:\n            if url.count('/') >= 2:\n                yield scrapy.Request(response.urljoin(url), callback=self.parse_store)\n            else:\n                yield scrapy.Request(response.urljoin(url))\n\n    def parse_store(self, response):\n        ref = re.search(r'.+/(.+?)/?(?:\\.html|$)', response.url).group(1)\n\n        properties = {\n            'ref': ref,\n            'name': response.xpath('normalize-space(//span[@class=\"LocationName-brand\"]/text())').extract_first(),\n            'addr_full': response.xpath('normalize-space(//meta[@itemprop=\"streetAddress\"]/@content)').extract_first(),\n            'city': response.xpath('normalize-space(//meta[@itemprop=\"addressLocality\"]/@content)').extract_first(),\n            'state': response.xpath('normalize-space(//abbr[@itemprop=\"addressRegion\"]/text())').extract_first(),\n            'postcode': response.xpath('normalize-space(//span[@itemprop=\"postalCode\"]/text())').extract_first(),\n            'country': response.xpath('normalize-space(//abbr[@itemprop=\"addressCountry\"]/text())').extract_first(),\n            'phone': response.xpath('normalize-space(//span[@itemprop=\"telephone\"]//text())').extract_first(),\n            'website': response.url,\n            'lat': response.xpath('normalize-space(//meta[@itemprop=\"latitude\"]/@content)').extract_first(),\n            'lon': response.xpath('normalize-space(//meta[@itemprop=\"longitude\"]/@content)').extract_first(),\n        }\n\n        hours = response.xpath('//span[@class=\"c-location-hours-today js-location-hours\"]/@data-days').extract_first()\n        properties['opening_hours'] = self.parse_hours(hours)\n\n        yield GeojsonPointItem(**properties)\n", "path": "locations/spiders/att.py"}], "after_files": [{"content": "import scrapy\nimport json\nimport re\nfrom locations.items import GeojsonPointItem\nfrom locations.hours import OpeningHours\n\n\nDAY_MAPPING = {\n    \"MONDAY\": \"Mo\",\n    \"TUESDAY\": \"Tu\",\n    \"WEDNESDAY\": \"We\",\n    \"THURSDAY\": \"Th\",\n    \"FRIDAY\": \"Fr\",\n    \"SATURDAY\": \"Sa\",\n    \"SUNDAY\": \"Su\"\n}\n\n\nclass ATTScraper(scrapy.Spider):\n    name = \"att\"\n    item_attributes = { 'brand': \"AT&T\", 'brand_wikidata': \"Q35476\" }\n    allowed_domains = ['www.att.com']\n    start_urls = (\n        'https://www.att.com/stores/us',\n    )\n    download_delay = 0.2\n\n    def parse_hours(self, store_hours):\n        opening_hours = OpeningHours()\n        store_data = json.loads(store_hours)\n\n        for store_day in store_data:\n            if len(store_day[\"intervals\"]) < 1:\n                continue\n            day = DAY_MAPPING[store_day[\"day\"]]\n            open_time = str(store_day[\"intervals\"][0][\"start\"])\n            if open_time == '0':\n                open_time = '0000'\n            close_time = str(store_day[\"intervals\"][0][\"end\"])\n            if close_time == '0':\n                close_time = '2359'\n            opening_hours.add_range(day=day,\n                                    open_time=open_time,\n                                    close_time=close_time,\n                                    time_format='%H%M'\n                                    )\n\n        return opening_hours.as_opening_hours()\n\n    def parse(self, response):\n        urls = response.xpath('//a[@class=\"Directory-listLink\"]/@href').extract()\n        is_store_list = response.xpath('//a[@class=\"Teaser-titleLink\"]/@href').extract()\n\n        if not urls and is_store_list:\n            urls = response.xpath('//a[@class=\"Teaser-titleLink\"]/@href').extract()\n        for url in urls:\n            if url.count('/') >= 2:\n                yield scrapy.Request(response.urljoin(url), callback=self.parse_store)\n            else:\n                yield scrapy.Request(response.urljoin(url))\n\n    def parse_store(self, response):\n        ref = re.search(r'.+/(.+?)/?(?:\\.html|$)', response.url).group(1)\n\n        properties = {\n            'ref': ref,\n            'name': response.xpath('normalize-space(//span[@class=\"LocationName-brand\"]/text())').extract_first(),\n            'addr_full': response.xpath('normalize-space(//meta[@itemprop=\"streetAddress\"]/@content)').extract_first(),\n            'city': response.xpath('normalize-space(//meta[@itemprop=\"addressLocality\"]/@content)').extract_first(),\n            'state': response.xpath('normalize-space(//abbr[@itemprop=\"addressRegion\"]/text())').extract_first(),\n            'postcode': response.xpath('normalize-space(//span[@itemprop=\"postalCode\"]/text())').extract_first(),\n            'country': response.xpath('normalize-space(//abbr[@itemprop=\"addressCountry\"]/text())').extract_first(),\n            'phone': response.xpath('normalize-space(//span[@itemprop=\"telephone\"]//text())').extract_first(),\n            'website': response.url,\n            'lat': response.xpath('normalize-space(//meta[@itemprop=\"latitude\"]/@content)').extract_first(),\n            'lon': response.xpath('normalize-space(//meta[@itemprop=\"longitude\"]/@content)').extract_first(),\n        }\n\n        hours = response.xpath('//span[@class=\"c-hours-today js-hours-today\"]/@data-days').extract_first()\n        properties['opening_hours'] = self.parse_hours(hours)\n\n        yield GeojsonPointItem(**properties)\n", "path": "locations/spiders/att.py"}]}