internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: alltheplaces/alltheplaces

Issue:
Adidas
### Brand name

Adidas

### Wikidata ID

Q12358242

### Store finder url(s)

https://www.adidas.com/us/stores


Discussion:

Resolving patch:
diff --git a/locations/spiders/adidas.py b/locations/spiders/adidas.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/adidas.py
@@ -0,0 +1,24 @@
+import json
+
+from scrapy import Spider
+from scrapy.http import Response
+
+from locations.dict_parser import DictParser
+
+
+class AdidasSpider(Spider):
+    name = "adidas"
+    item_attributes = {"brand": "Adidas", "brand_wikidata": "Q3895"}
+    start_urls = [
+        "https://placesws.adidas-group.com/API/search?brand=adidas&geoengine=google&method=get&category=store&latlng=51%2C17&page=1&pagesize=5000&fields=name%2Cstreet1%2Cstreet2%2Caddressline%2Cbuildingname%2Cpostal_code%2Ccity%2Cstate%2Cstore_o+wner%2Ccountry%2Cstoretype%2Clongitude_google%2Clatitude_google%2Cstore_owner%2Cstate%2Cperformance%2Cbrand_store%2Cfactory_outlet%2Coriginals%2Cneo_label%2Cy3%2Cslvr%2Cchildren%2Cwoman%2Cfootwear%2Cfootball%2Cbasketball%2Coutdoor%2Cporsche_design%2Cmiadidas%2Cmiteam%2Cstella_mccartney%2Ceyewear%2Cmicoach%2Copening_ceremony%2Coperational_status%2Cfrom_date%2Cto_date%2Cdont_show_country&format=json&storetype=ownretail"
+    ]
+    custom_settings = {"ROBOTSTXT_OBEY": False}
+
+    def parse(self, response: Response, **kwargs):
+        data = json.loads(response.body.replace(b"\n", b"\\n").replace(b"\r", b"\\r").replace(b"\\2", b"\\\\2"))
+        for shop in data["wsResponse"]["result"]:
+            item = DictParser.parse(shop)
+            item["lat"] = shop["latitude_google"]
+            item["lon"] = shop["longitude_google"]
+            item["street_address"] = shop["street1"]
+            yield item


Test patch:
Repository: alltheplaces/alltheplaces

Issue:
Ron Jon Surf Shop
https://www.ronjonsurfshop.com/location/default.aspx


Discussion:
Paginated custom JSON API that returns all 13 locations in a single query per `https://www.ronjonsurfshop.com/ajax/store-locator?searchText=&pagesize=15&pageNumber=1`
Hey @davidhicks, I would like to work on this!!


Resolving patch:
diff --git a/locations/spiders/ron_jon_surf_shop.py b/locations/spiders/ron_jon_surf_shop.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/ron_jon_surf_shop.py
@@ -0,0 +1,18 @@
+from scrapy import Spider
+
+from locations.dict_parser import DictParser
+
+
+class RonJonSurfShopSpider(Spider):
+    name = "ron_jon_surf_shop"
+    item_attributes = {"brand": "Ron Jon Surf Shop", "brand_wikidata": "Q7363993"}
+    allowed_domains = ["www.ronjonsurfshop.com"]
+    start_urls = ["https://www.ronjonsurfshop.com/ajax/store-locator?searchText=&pagesize=15&pageNumber=1"]
+
+    def parse(self, response):
+        for data in response.json()["results"]:
+            item = DictParser.parse(data)
+
+            item["website"] = response.urljoin(data["url"])
+
+            yield item


Test patch:
Repository: alltheplaces/alltheplaces

Issue:
TacoTime
https://www.tacotime.com/locator/index.php?brand=tt


Discussion:
Hey, Can I give a try?
Definitely!
The locator map URL is now just https://www.tacotime.com/locator/
https://www.tacotime.com/sitemap.xml

Filter by `/stores`

Resolving patch:
diff --git a/locations/spiders/taco_time.py b/locations/spiders/taco_time.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/taco_time.py
@@ -0,0 +1,15 @@
+from scrapy.spiders import SitemapSpider
+
+from locations.structured_data_spider import StructuredDataSpider
+
+
+class TacoTimeSpider(SitemapSpider, StructuredDataSpider):
+    name = "taco_time"
+    item_attributes = {
+        "brand": "Taco Time",
+        "brand_wikidata": "Q7673969",
+    }
+    sitemap_urls = ["https://www.tacotime.com/sitemap.xml"]
+    sitemap_rules = [
+        (r"/stores/", "parse_sd"),
+    ]


Test patch:
Repository: alltheplaces/alltheplaces

Issue:
CKB Bulgaria
### Brand name

Централна кооперативна банка

### Wikidata ID

Q2944755

### Store finder url(s)

type=1 and type=2 is `amenity=bank`
type=3 is `amenity=atm`

https://ccbank.bg/bg/branches_network/offices


Discussion:

Resolving patch:
diff --git a/locations/hours.py b/locations/hours.py
--- a/locations/hours.py
+++ b/locations/hours.py
@@ -85,6 +85,7 @@
     "Съ": "Sa",
     "Сб": "Sa",
     "Неделя": "Su",
+    "Нед": "Su",
     "нед": "Su",
     "Не": "Su",
     "Нд": "Su",
diff --git a/locations/spiders/ccbank_bg.py b/locations/spiders/ccbank_bg.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/ccbank_bg.py
@@ -0,0 +1,26 @@
+from scrapy import Spider
+
+from locations.categories import Categories, apply_category
+from locations.dict_parser import DictParser
+from locations.hours import DAYS_BG, OpeningHours
+
+
+class ccbankBGSpider(Spider):
+    name = "ccbank_bg"
+    item_attributes = {"brand": "Central Cooperative Bank", "brand_wikidata": "Q2944755"}
+    allowed_domains = ["ccbank.bg"]
+    start_urls = ["https://ccbank.bg/bg/branches_network/offices"]
+
+    def parse(self, response):
+        for data in response.json()["data"]:
+            item = DictParser.parse(data)
+
+            item["opening_hours"] = OpeningHours()
+            if data["workhours"]:
+                item["opening_hours"].add_ranges_from_string(data["workhours"].replace(" - ", ","), days=DAYS_BG)
+            if data["type"] == "3":
+                apply_category(Categories.ATM, item)
+            else:
+                apply_category(Categories.BANK, item)
+
+            yield item


Test patch:
Repository: alltheplaces/alltheplaces

Issue:
Technopolis Bulgaria
### Brand name

Технополис

### Wikidata ID

Q28056752

### Store finder url(s)

https://www.technopolis.bg/bg/mapbox/preferedstores.json


Discussion:

Resolving patch:
diff --git a/locations/spiders/technopolis_bg.py b/locations/spiders/technopolis_bg.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/technopolis_bg.py
@@ -0,0 +1,45 @@
+import scrapy
+
+from locations.categories import Categories, apply_category
+from locations.hours import DAYS_BG, OpeningHours, day_range, sanitise_day
+from locations.items import Feature
+
+
+class TechnopolisBGSpider(scrapy.Spider):
+    name = "technopolis_bg"
+    item_attributes = {"brand": "Technopolis", "brand_wikidata": "Q28056752", "country": "BG"}
+    allowed_domains = ["www.technopolis.bg"]
+    start_urls = ["https://www.technopolis.bg/bg/mapbox/preferedstores.json"]
+
+    def parse(self, response):
+        for location in response.json()["features"]:
+            item = Feature()
+            item["ref"] = location["id"]
+            item["name"] = location["properties"]["name"]
+            item["street_address"] = location["properties"]["contacts"]["address"]
+            item["postcode"] = location["properties"]["postal"]
+            item["city"] = location["properties"]["city"]
+            item["lat"] = location["geometry"]["coordinates"][1]
+            item["lon"] = location["geometry"]["coordinates"][0]
+            item["image"] = f"https://www.technopolis.bg/{location['image']}"
+
+            item["opening_hours"] = OpeningHours()
+
+            for worktime in (
+                location["properties"]["contacts"]["worktime"]
+                .replace("–", "-")
+                .replace(" - ", "-")
+                .replace("ч.", "")
+                .replace(": ", " ")
+                .replace(";", "")
+                .replace(".", ":")
+                .split("<br />")
+            ):
+                days = [sanitise_day(day, DAYS_BG) for day in worktime.split(" ")[0].split("-")]
+                hours = worktime.split(" ")[1].split("-")
+                if len(days) == 2:
+                    item["opening_hours"].add_days_range(day_range(days[0], days[1]), hours[0], hours[1])
+                else:
+                    item["opening_hours"].add_range(days[0], hours[0], hours[1])
+            apply_category(Categories.SHOP_ELECTRONICS, item)
+            yield item


Test patch:
Repository: alltheplaces/alltheplaces

Issue:
Rocket
### Brand name

Rocket

### Wikidata ID

Q121513516

### Store finder url(s)

https://rocketstores.com/rocket-stations/


Discussion:
`https://rocketstores.com/wp-json/stations/v1/locations?MinLong=-128.42634771874998&MaxLong=-107.55232428125&MinLat=31.420274450318118&MaxLat=35.90778546631802` returns location information for 313 stations.

Resolving patch:
diff --git a/locations/spiders/rocket_us.py b/locations/spiders/rocket_us.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/rocket_us.py
@@ -0,0 +1,29 @@
+from scrapy import Spider
+
+from locations.categories import Categories, apply_category
+from locations.items import Feature
+
+
+class RocketUSSpider(Spider):
+    name = "rocket_us"
+    item_attributes = {"brand": "Rocket", "brand_wikidata": "Q121513516"}
+    start_urls = ["https://rocketstores.com/wp-json/stations/v1/locations"]
+
+    def parse(self, response, **kwargs):
+        for location in response.json()["stations"]:
+            item = Feature()
+            item["ref"] = location["ID"]
+            item["lat"] = location["latitude"]
+            item["lon"] = location["longitude"]
+            item["branch"] = location["store_name"]
+            item["street_address"] = location["address"]
+            item["city"] = location["city"]
+            item["state"] = location["state"]
+            item["postcode"] = location["zip"]
+            item["country"] = location["country"]
+            item["phone"] = location["phone_number"]
+            item["located_in"] = location["brand"]["name"]
+
+            apply_category(Categories.SHOP_CONVENIENCE, item)
+
+            yield item


Test patch:
Repository: alltheplaces/alltheplaces

Issue:
Nordsee
Fast food seafood in Europe

http://www.international.nordsee.com/en/filialen


Discussion:
JSON response containing all locations: `https://www.nordsee.com/en/?type=2001`

Resolving patch:
diff --git a/locations/spiders/nordsee_de.py b/locations/spiders/nordsee_de.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/nordsee_de.py
@@ -0,0 +1,31 @@
+from scrapy import Selector, Spider
+from scrapy.http import JsonRequest
+
+from locations.dict_parser import DictParser
+from locations.hours import OpeningHours
+
+
+class NordseeDESpider(Spider):
+    name = "nordsee_de"
+    item_attributes = {"brand": "Nordsee", "brand_wikidata": "Q74866"}
+    allowed_domains = ["www.nordsee.com"]
+    start_urls = ["https://www.nordsee.com/en/?type=2001"]
+
+    def start_requests(self):
+        for url in self.start_urls:
+            yield JsonRequest(url=url)
+
+    def parse(self, response):
+        for location in response.json()["stores"]:
+            item = DictParser.parse(location)
+            item["ref"] = location["uid"]
+            item["street_address"] = item.pop("housenumber", None)
+            item["opening_hours"] = OpeningHours()
+            for day_abbrev, hours_range in location.get("opening").items():
+                if isinstance(hours_range, str):
+                    item["opening_hours"].add_range(day_abbrev.title(), *hours_range.split(" - ", 1), "%H:%M")
+            item["website"] = (
+                "https://www.nordsee.com"
+                + Selector(text=location["listItem"]).xpath('//a[@class="storeListItem__link"]/@href').get()
+            )
+            yield item


Test patch:
Repository: alltheplaces/alltheplaces

Issue:
Karstadt
German department store

https://www.karstadt.de/filialfinder


Discussion:
Uberall store locator with key: `yQ7AVSxcAEpMdcx1mMWkSEwH8SenmY`

Resolving patch:
diff --git a/locations/spiders/karstadt_de.py b/locations/spiders/karstadt_de.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/karstadt_de.py
@@ -0,0 +1,7 @@
+from locations.storefinders.uberall import UberallSpider
+
+
+class KarstadtDESpider(UberallSpider):
+    name = "karstadt_de"
+    item_attributes = {"brand": "Karstadt", "brand_wikidata": "Q182910"}
+    key = "yQ7AVSxcAEpMdcx1mMWkSEwH8SenmY"


Test patch:
Repository: alltheplaces/alltheplaces

Issue:
Pure Barre
http://purebarre.com/locations/


Discussion:
@iandees I dont see hours for this one. 
This issue hasn't been worked on in a while. I'm removing the assignment so others can work on it. If you're still working on it, please reassign yourself and reference a pull request or branch where you're doing your work.
Single API call to `https://members.purebarre.com/api/brands/purebarre/locations?open_status=external` appears to return all location data in JSON format.

Resolving patch:
diff --git a/locations/spiders/pure_barre_us.py b/locations/spiders/pure_barre_us.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/pure_barre_us.py
@@ -0,0 +1,26 @@
+from scrapy import Spider
+from scrapy.http import JsonRequest
+
+from locations.dict_parser import DictParser
+
+
+class PureBarreUSSpider(Spider):
+    name = "pure_barre_us"
+    item_attributes = {"brand": "Pure Barre", "brand_wikidata": "Q86707084"}
+    allowed_domains = ["members.purebarre.com"]
+    start_urls = ["https://members.purebarre.com/api/brands/purebarre/locations?open_status=external"]
+
+    def start_requests(self):
+        for url in self.start_urls:
+            yield JsonRequest(url=url)
+
+    def parse(self, response):
+        for location in response.json()["locations"]:
+            if location.get("coming_soon") or location.get("open_status") != "open":
+                continue
+            item = DictParser.parse(location)
+            item["ref"] = location.get("seq")
+            item.pop("addr_full", None)
+            item["street_address"] = ", ".join(filter(None, [location.get("address"), location.get("address2")]))
+            item["website"] = location.get("site_url")
+            yield item


Test patch:
Repository: alltheplaces/alltheplaces

Issue:
George Webb
https://www.georgewebb.com/locations?query=54701 (increase radius on search for results)


Discussion:
All locations appear to provided in XML format at `https://georgewebb.com/hwstorelocation/storeload`

Resolving patch:
diff --git a/locations/spiders/george_webb_us.py b/locations/spiders/george_webb_us.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/george_webb_us.py
@@ -0,0 +1,27 @@
+from scrapy.spiders import XMLFeedSpider
+
+from locations.items import Feature
+
+
+class GeorgeWebbUSSpider(XMLFeedSpider):
+    name = "george_webb_us"
+    item_attributes = {"brand": "George Webb", "brand_wikidata": "Q5546110"}
+    allowed_domains = ["georgewebb.com"]
+    start_urls = ["https://georgewebb.com/hwstorelocation/storeload"]
+    iterator = "xml"
+    itertag = "marker"
+
+    def parse_node(self, response, node):
+        properties = {
+            "ref": node.xpath(".//@phone").get(),
+            "name": node.xpath(".//@name").get(),
+            "street_address": node.xpath(".//@address").get(),
+            "city": node.xpath(".//@city").get(),
+            "state": node.xpath(".//@state").get(),
+            "country": node.xpath(".//@country").get(),
+            "lat": node.xpath(".//@lat").get(),
+            "lon": node.xpath(".//@lng").get(),
+            "phone": node.xpath(".//@phone").get(),
+            "email": node.xpath(".//@email").get(),
+        }
+        yield Feature(**properties)


Test patch:
Repository: alltheplaces/alltheplaces

Issue:
Remedy'sRx
https://www.remedys.ca/en/find-a-pharmacy


Discussion:
New website has a combined store locator for Remedy'sRx, Guardian and IDA pharmacies in Canada.

Single request to API returning all location data as JSON data: `https://www.guardian-ida-remedysrx.ca/api/sitecore/Pharmacy/Pharmacies?id=%7B73B789E3-C922-483E-9E5A-C1D2BC52D6D4%7D`

Resolving patch:
diff --git a/locations/spiders/mckesson_ca.py b/locations/spiders/mckesson_ca.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/mckesson_ca.py
@@ -0,0 +1,51 @@
+from scrapy import Spider
+from scrapy.http import JsonRequest
+
+from locations.dict_parser import DictParser
+from locations.hours import DAYS_EN, DAYS_FR, OpeningHours
+
+
+class McKessonCASpider(Spider):
+    name = "mckesson_ca"
+    allowed_domains = [
+        "www.guardian-ida-remedysrx.ca",
+        "www.uniprix.com",
+    ]
+    start_urls = [
+        "https://www.guardian-ida-remedysrx.ca/api/sitecore/Pharmacy/Pharmacies?id=%7B73B789E3-C922-483E-9E5A-C1D2BC52D6D4%7D",
+        "https://www.uniprix.com/api/sitecore/Pharmacy/Pharmacies?id=%7B1D46A582-AF24-4EC2-87BA-AFFC76B73967%7D",
+    ]
+    brands = {
+        "G": {"brand": "Guardian", "brand_wikidata": "Q65553864"},
+        "I": {"brand": "I.D.A.", "brand_wikidata": "Q65553883"},
+        "R": {"brand": "Remedy'sRx", "brand_wikidata": "Q65553833"},
+        "UM": {"brand": "Uniprix", "brand_wikidata": "Q683265"},
+        "UQ": {"brand": "Uniprix", "brand_wikidata": "Q683265"},
+        "UX": {"brand": "Uniprix", "brand_wikidata": "Q683265"},
+    }
+
+    def start_requests(self):
+        for url in self.start_urls:
+            yield JsonRequest(url=url)
+
+    def parse(self, response):
+        for location in response.json()["pharmacies"]:
+            item = DictParser.parse(location)
+            item.update(self.brands[location["banner"]])
+            if location["banner"] in ["G", "I", "R"]:
+                item["website"] = "https://www.guardian-ida-remedysrx.ca" + location["detailUrl"]
+            if location["banner"] in ["UM", "UQ", "UX"]:
+                item["website"] = "https://www.uniprix.com" + location["detailUrl"]
+            item["opening_hours"] = OpeningHours()
+            for day_hours in location["storeOpeningHours"]:
+                if day_hours["isClose"] or day_hours["isNotAvailable"]:
+                    continue
+                if day_hours["displayLanguage"]["Name"] == "en":
+                    item["opening_hours"].add_range(
+                        DAYS_EN[day_hours["day"]], day_hours["startTime"], day_hours["endTime"], "%H:%M:%S"
+                    )
+                elif day_hours["displayLanguage"]["Name"] == "fr":
+                    item["opening_hours"].add_range(
+                        DAYS_FR[day_hours["day"]], day_hours["startTime"], day_hours["endTime"], "%H:%M:%S"
+                    )
+            yield item


Test patch:
Repository: alltheplaces/alltheplaces

Issue:
Gadis
https://www.gadis.es/localizador.php


Discussion:
API call returning all location data as JSON data: `https://www.gadisa.es/api/centro/sec::gadis`

Resolving patch:
diff --git a/locations/spiders/gadisa_es.py b/locations/spiders/gadisa_es.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/gadisa_es.py
@@ -0,0 +1,50 @@
+from scrapy import Spider
+from scrapy.http import JsonRequest
+
+from locations.dict_parser import DictParser
+from locations.hours import DAYS_ES, DELIMITERS_ES, OpeningHours
+from locations.items import Feature
+
+
+class GadisaESSpider(Spider):
+    name = "gadisa_es"
+    allowed_domains = ["www.gadisa.es"]
+    start_urls = [
+        "https://www.gadisa.es/api/centro/sec::cashifa",
+        "https://www.gadisa.es/api/centro/sec::claudio",
+        "https://www.gadisa.es/api/centro/sec::gadis",
+    ]
+    brands = {
+        "CASACLAUDIO": {"brand": "Casa Claudio", "brand_wikidata": "Q123370107"},
+        "CASHIFA": {"brand": "Cash IFA", "brand_wikidata": "Q123369964"},
+        "CLAUDIO": {"brand": "Claudio", "brand_wikidata": "Q123369953"},
+        "GADIS": {"brand": "Gadis", "brand_wikidata": "Q114398305"},
+    }
+
+    def start_requests(self):
+        for url in self.start_urls:
+            yield JsonRequest(url=url)
+
+    def parse(self, response):
+        for location in response.json():
+            if location["coordenada"] == "0,0":
+                # Invalid location
+                continue
+            properties = {
+                "ref": location["id"],
+                "name": location["nombre"],
+                "lat": location["coordenada"].split(",", 1)[0],
+                "lon": location["coordenada"].split(",", 1)[1],
+                "street_address": location["dir"],
+                "city": location["pob"],
+                "state": location["prov"],
+                "postcode": location["cp"],
+                "phone": location["tel"],
+                "opening_hours": OpeningHours(),
+            }
+            properties.update(self.brands[location["sec"]])
+            if location.get("horario"):
+                properties["opening_hours"].add_ranges_from_string(
+                    ranges_string=location["horario"], days=DAYS_ES, delimiters=DELIMITERS_ES
+                )
+            yield Feature(**properties)


Test patch:
Repository: alltheplaces/alltheplaces

Issue:
Modern Market
https://www.modernmarket.com/locations


Discussion:
All locations returned in a single API request to `https://modernmarket.com/api/restaurants`. JSON format returned.

Resolving patch:
diff --git a/locations/spiders/modern_market_us.py b/locations/spiders/modern_market_us.py
new file mode 100644
--- /dev/null
+++ b/locations/spiders/modern_market_us.py
@@ -0,0 +1,40 @@
+from scrapy import Spider
+from scrapy.http import JsonRequest
+
+from locations.categories import Extras, apply_yes_no
+from locations.dict_parser import DictParser
+from locations.hours import OpeningHours
+
+
+class ModernMarketUSSpider(Spider):
+    name = "modern_market_us"
+    item_attributes = {"brand": "Modern Market", "brand_wikidata": "Q123370165"}
+    allowed_domains = ["modernmarket.com"]
+    start_urls = ["https://modernmarket.com/api/restaurants"]
+
+    def start_requests(self):
+        for url in self.start_urls:
+            yield JsonRequest(url=url)
+
+    def parse(self, response):
+        for location in response.json()["restaurants"]:
+            if "COMING SOON" in location["name"].upper():
+                continue
+            item = DictParser.parse(location)
+            item["street_address"] = ", ".join(
+                filter(None, [location.get("streetaddress"), location.get("streetaddress2")])
+            )
+            apply_yes_no(Extras.DELIVERY, item, location.get("candeliver"), False)
+            apply_yes_no(Extras.DRIVE_THROUGH, item, location.get("supportsdrivethru"), False)
+            item["opening_hours"] = OpeningHours()
+            for calendar in location.get("calendar"):
+                if calendar["type"] == "business":
+                    if len(calendar["ranges"]) >= 7:
+                        for i in range(0, 6, 1):
+                            item["opening_hours"].add_range(
+                                calendar["ranges"][i]["weekday"],
+                                calendar["ranges"][i]["start"].split(" ", 1)[1],
+                                calendar["ranges"][i]["end"].split(" ", 1)[1],
+                            )
+                    break
+            yield item


Test patch: