prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  bupa_gb spider is including closed branches
  The bupa_gb.py spider is returning a number of closed practices, as these still have web pages and are still listed in the sitemap. Current examples include:
  
  https://www.bupa.co.uk/dental/dental-care/practices/harleston
  https://www.bupa.co.uk/dental/dental-care/practices/leckhampton
  
  I think these can be reliably detected by checking if the name ends (case-insensitively) with "closed". So I'd suggest we drop any whose name matches /closed$/i. There are about 12 of these in total out of 388 branches.
  
  (Sorry, I can no longer run the code on my computer to implement and test this myself, since I'm unable to install a recent enough version of Python.)
  
  </issue>
  <code>
  [start of locations/items.py]
  1 # Define here the models for your scraped items
  2 #
  3 # See documentation in:
  4 # http://doc.scrapy.org/en/latest/topics/items.html
  5 
  6 import scrapy
  7 
  8 
  9 class Feature(scrapy.Item):
  10     lat = scrapy.Field()
  11     lon = scrapy.Field()
  12     geometry = scrapy.Field()
  13     name = scrapy.Field()
  14     branch = scrapy.Field()
  15     addr_full = scrapy.Field()
  16     housenumber = scrapy.Field()
  17     street = scrapy.Field()
  18     street_address = scrapy.Field()
  19     city = scrapy.Field()
  20     state = scrapy.Field()
  21     postcode = scrapy.Field()
  22     country = scrapy.Field()
  23     phone = scrapy.Field()
  24     email = scrapy.Field()
  25     website = scrapy.Field()
  26     twitter = scrapy.Field()
  27     facebook = scrapy.Field()
  28     opening_hours = scrapy.Field()
  29     image = scrapy.Field()
  30     ref = scrapy.Field()
  31     brand = scrapy.Field()
  32     brand_wikidata = scrapy.Field()
  33     operator = scrapy.Field()
  34     operator_wikidata = scrapy.Field()
  35     located_in = scrapy.Field()
  36     located_in_wikidata = scrapy.Field()
  37     nsi_id = scrapy.Field()
  38     extras = scrapy.Field()
  39 
  40     def __init__(self, *args, **kwargs):
  41         super().__init__(*args, **kwargs)
  42         if not self._values.get("extras"):
  43             self.__setitem__("extras", {})
  44 
  45 
  46 def get_lat_lon(item: Feature) -> (float, float):
  47     if geometry := item.get("geometry"):
  48         if isinstance(geometry, dict):
  49             if geometry.get("type") == "Point":
  50                 if coords := geometry.get("coordinates"):
  51                     try:
  52                         return float(coords[1]), float(coords[0])
  53                     except (TypeError, ValueError):
  54                         item["geometry"] = None
  55     else:
  56         try:
  57             return float(item.get("lat")), float(item.get("lon"))
  58         except (TypeError, ValueError):
  59             pass
  60     return None
  61 
  62 
  63 def set_lat_lon(item: Feature, lat: float, lon: float):
  64     item.pop("lat", None)
  65     item.pop("lon", None)
  66     if lat and lon:
  67         item["geometry"] = {
  68             "type": "Point",
  69             "coordinates": [lon, lat],
  70         }
  71     else:
  72         item["geometry"] = None
  73 
  74 
  75 def add_social_media(item: Feature, service: str, account: str):
  76     service = service.lower()
  77     if service in item.fields:
  78         item[service] = account
  79     else:
  80         item["extras"][f"contact:{service}"] = account
  81
  [end of locations/items.py]
  [start of locations/spiders/bupa_gb.py]
  1 from scrapy.spiders import SitemapSpider
  2 
  3 from locations.categories import Categories
  4 from locations.structured_data_spider import StructuredDataSpider
  5 
  6 
  7 class BupaGBSpider(SitemapSpider, StructuredDataSpider):
  8     name = "bupa_gb"
  9     item_attributes = {"brand": "Bupa", "brand_wikidata": "Q931628", "extras": Categories.DENTIST.value}
  10     sitemap_urls = ["https://www.bupa.co.uk/robots.txt"]
  11     sitemap_rules = [(r"/practices/([-\w]+)$", "parse_sd")]
  12 
  13     def post_process_item(self, item, response, ld_data, **kwargs):
  14         if "Total Dental Care" in item["name"]:
  15             item["brand"] = "Total Dental Care"
  16         yield item
  17
  [end of locations/spiders/bupa_gb.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/locations/items.py b/locations/items.py
  --- a/locations/items.py
  +++ b/locations/items.py
  @@ -2,6 +2,7 @@
   #
   # See documentation in:
   # http://doc.scrapy.org/en/latest/topics/items.html
  +from datetime import datetime
   
   import scrapy
   
  @@ -78,3 +79,7 @@
           item[service] = account
       else:
           item["extras"][f"contact:{service}"] = account
  +
  +
  +def set_closed(item: Feature, end_date: datetime = None):
  +    item["extras"]["end_date"] = end_date.strftime("%Y-%m-%d") if end_date else "yes"
  diff --git a/locations/spiders/bupa_gb.py b/locations/spiders/bupa_gb.py
  --- a/locations/spiders/bupa_gb.py
  +++ b/locations/spiders/bupa_gb.py
  @@ -1,6 +1,7 @@
   from scrapy.spiders import SitemapSpider
   
   from locations.categories import Categories
  +from locations.items import set_closed
   from locations.structured_data_spider import StructuredDataSpider
   
   
  @@ -13,4 +14,8 @@
       def post_process_item(self, item, response, ld_data, **kwargs):
           if "Total Dental Care" in item["name"]:
               item["brand"] = "Total Dental Care"
  +
  +        if item["name"].lower().endswith(" - closed"):
  +            set_closed(item)
  +
           yield item
  
verification_info: {"golden_diff": "diff --git a/locations/items.py b/locations/items.py\n--- a/locations/items.py\n+++ b/locations/items.py\n@@ -2,6 +2,7 @@\n #\n # See documentation in:\n # http://doc.scrapy.org/en/latest/topics/items.html\n+from datetime import datetime\n \n import scrapy\n \n@@ -78,3 +79,7 @@\n         item[service] = account\n     else:\n         item[\"extras\"][f\"contact:{service}\"] = account\n+\n+\n+def set_closed(item: Feature, end_date: datetime = None):\n+    item[\"extras\"][\"end_date\"] = end_date.strftime(\"%Y-%m-%d\") if end_date else \"yes\"\ndiff --git a/locations/spiders/bupa_gb.py b/locations/spiders/bupa_gb.py\n--- a/locations/spiders/bupa_gb.py\n+++ b/locations/spiders/bupa_gb.py\n@@ -1,6 +1,7 @@\n from scrapy.spiders import SitemapSpider\n \n from locations.categories import Categories\n+from locations.items import set_closed\n from locations.structured_data_spider import StructuredDataSpider\n \n \n@@ -13,4 +14,8 @@\n     def post_process_item(self, item, response, ld_data, **kwargs):\n         if \"Total Dental Care\" in item[\"name\"]:\n             item[\"brand\"] = \"Total Dental Care\"\n+\n+        if item[\"name\"].lower().endswith(\" - closed\"):\n+            set_closed(item)\n+\n         yield item\n", "issue": "bupa_gb spider is including closed branches\nThe bupa_gb.py spider is returning a number of closed practices, as these still have web pages and are still listed in the sitemap. Current examples include:\r\n\r\nhttps://www.bupa.co.uk/dental/dental-care/practices/harleston\r\nhttps://www.bupa.co.uk/dental/dental-care/practices/leckhampton\r\n\r\nI think these can be reliably detected by checking if the name ends (case-insensitively) with \"closed\". So I'd suggest we drop any whose name matches /closed$/i. There are about 12 of these in total out of 388 branches.\r\n\r\n(Sorry, I can no longer run the code on my computer to implement and test this myself, since I'm unable to install a recent enough version of Python.)\n", "before_files": [{"content": "# Define here the models for your scraped items\n#\n# See documentation in:\n# http://doc.scrapy.org/en/latest/topics/items.html\n\nimport scrapy\n\n\nclass Feature(scrapy.Item):\n    lat = scrapy.Field()\n    lon = scrapy.Field()\n    geometry = scrapy.Field()\n    name = scrapy.Field()\n    branch = scrapy.Field()\n    addr_full = scrapy.Field()\n    housenumber = scrapy.Field()\n    street = scrapy.Field()\n    street_address = scrapy.Field()\n    city = scrapy.Field()\n    state = scrapy.Field()\n    postcode = scrapy.Field()\n    country = scrapy.Field()\n    phone = scrapy.Field()\n    email = scrapy.Field()\n    website = scrapy.Field()\n    twitter = scrapy.Field()\n    facebook = scrapy.Field()\n    opening_hours = scrapy.Field()\n    image = scrapy.Field()\n    ref = scrapy.Field()\n    brand = scrapy.Field()\n    brand_wikidata = scrapy.Field()\n    operator = scrapy.Field()\n    operator_wikidata = scrapy.Field()\n    located_in = scrapy.Field()\n    located_in_wikidata = scrapy.Field()\n    nsi_id = scrapy.Field()\n    extras = scrapy.Field()\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        if not self._values.get(\"extras\"):\n            self.__setitem__(\"extras\", {})\n\n\ndef get_lat_lon(item: Feature) -> (float, float):\n    if geometry := item.get(\"geometry\"):\n        if isinstance(geometry, dict):\n            if geometry.get(\"type\") == \"Point\":\n                if coords := geometry.get(\"coordinates\"):\n                    try:\n                        return float(coords[1]), float(coords[0])\n                    except (TypeError, ValueError):\n                        item[\"geometry\"] = None\n    else:\n        try:\n            return float(item.get(\"lat\")), float(item.get(\"lon\"))\n        except (TypeError, ValueError):\n            pass\n    return None\n\n\ndef set_lat_lon(item: Feature, lat: float, lon: float):\n    item.pop(\"lat\", None)\n    item.pop(\"lon\", None)\n    if lat and lon:\n        item[\"geometry\"] = {\n            \"type\": \"Point\",\n            \"coordinates\": [lon, lat],\n        }\n    else:\n        item[\"geometry\"] = None\n\n\ndef add_social_media(item: Feature, service: str, account: str):\n    service = service.lower()\n    if service in item.fields:\n        item[service] = account\n    else:\n        item[\"extras\"][f\"contact:{service}\"] = account\n", "path": "locations/items.py"}, {"content": "from scrapy.spiders import SitemapSpider\n\nfrom locations.categories import Categories\nfrom locations.structured_data_spider import StructuredDataSpider\n\n\nclass BupaGBSpider(SitemapSpider, StructuredDataSpider):\n    name = \"bupa_gb\"\n    item_attributes = {\"brand\": \"Bupa\", \"brand_wikidata\": \"Q931628\", \"extras\": Categories.DENTIST.value}\n    sitemap_urls = [\"https://www.bupa.co.uk/robots.txt\"]\n    sitemap_rules = [(r\"/practices/([-\\w]+)$\", \"parse_sd\")]\n\n    def post_process_item(self, item, response, ld_data, **kwargs):\n        if \"Total Dental Care\" in item[\"name\"]:\n            item[\"brand\"] = \"Total Dental Care\"\n        yield item\n", "path": "locations/spiders/bupa_gb.py"}]}