prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  ID: scrape fails on substitute representative
  Once #2053 is merged, the people scraper is blowing up reading https://legislature.idaho.gov/house/membership/ .  
  Search down to "Scanlin", who you'll find is a "substitute" representative.  There's a parsing problem because the scraper expects the name to be bold and the party to not be; in this case "Substitute" is bold only.
  
  For a description of what a "Substitute" is, see http://www.spokesman.com/blogs/boise/2014/mar/16/idahos-legislative-substitute-law-unique/ 
  
  Just fixing this would leave two legislators in that district, where, as in Highlander, "there can be only one".  Representative Kloc, who Scanlin is substituting for, is directly above him.
  
  Assuming that his roll call votes, committee memberships, etc. are registered to the substitute, I believe a fully correct fix for this would involve:
  - lookahead for a "Substitute", skipping the current legislator if the next legislator is a substitute.
  - rewriting the line parser to skip "Substitute" and just use the text (not bold format) for name/party parsing.
  
  
  </issue>
  <code>
  [start of openstates/id/people.py]
  1 import re
  2 import lxml.html
  3 from pupa.scrape import Scraper, Person
  4 
  5 BASE_URL = 'https://legislature.idaho.gov/%s/membership/'
  6 CHAMBERS = {'upper': 'senate', 'lower': 'house'}
  7 PARTY = {
  8     '(R)': 'Republican',
  9     '(D)': 'Democratic',
  10 }
  11 
  12 phone_patterns = {
  13     'office': re.compile(r'Statehouse'),
  14     'business': re.compile(r'Bus'),
  15     'home': re.compile(r'Home'),
  16 }
  17 
  18 parse_phone_pattern = re.compile(r'tel:(?:\+1)?(\d{10}$)')
  19 fax_pattern = re.compile(r'fax\s+\((\d{3})\)\s+(\d{3})-(\d{4})', re.IGNORECASE)
  20 address_pattern = re.compile(r', \d{5}')
  21 address_replace_pattern = re.compile(r'(\d{5})')
  22 
  23 
  24 def get_phones(el):
  25     phones = {}
  26     for link in el.xpath('p/a[@class = "mob-tel"]'):
  27         prefix = link.getprevious().tail
  28         for label, pattern in phone_patterns.items():
  29             if pattern.search(prefix) is not None:
  30                 phones[label] = parse_phone(link.get('href'))
  31     return phones
  32 
  33 
  34 def parse_phone(phone):
  35     res = parse_phone_pattern.search(phone)
  36     if res is not None:
  37         return res.groups()[0]
  38 
  39 
  40 def get_fax(el):
  41     res = fax_pattern.search(el.text_content())
  42     if res is not None:
  43         return ''.join(res.groups())
  44 
  45 
  46 def get_address(el):
  47     for br in el.xpath('p/br'):
  48         piece = (br.tail or '').strip()
  49         res = address_pattern.search(piece)
  50         if res is not None:
  51             return address_replace_pattern.sub(r'ID \1', piece).strip()
  52 
  53 
  54 class IDPersonScraper(Scraper):
  55     """Legislator data seems to be available for the current term only."""
  56     jurisdiction = 'id'
  57 
  58     def scrape(self, chamber=None):
  59         if chamber:
  60             yield from self.scrape_chamber(chamber)
  61         else:
  62             yield from self.scrape_chamber('upper')
  63             yield from self.scrape_chamber('lower')
  64 
  65     def scrape_chamber(self, chamber):
  66         """
  67         Scrapes legislators for the current term only
  68         """
  69         # self.validate_term(term, latest_only=True)
  70         url = BASE_URL % CHAMBERS[chamber].lower()
  71         index = self.get(url, verify=False).text
  72         html = lxml.html.fromstring(index)
  73         html.make_links_absolute(url)
  74 
  75         rows = html.xpath('//div[contains(@class, "row-equal-height")]')
  76 
  77         for row in rows:
  78             img_url = row.xpath('.//img/@src')[0]
  79 
  80             inner = row.xpath('.//div[@class="vc-column-innner-wrapper"]')[1]
  81             if 'Resigned' in inner.text_content():
  82                 continue
  83 
  84             name = inner.xpath('p/strong')[0].text.replace(u'\xa0', ' ').strip()
  85             name = re.sub('\s+', ' ', name)
  86             party = PARTY[inner.xpath('p/strong')[0].tail.strip()]
  87             email = inner.xpath('p/strong/a')[0].text
  88             district = inner.xpath('p/a')[0].text.replace('District ', '')
  89 
  90             person_url = inner.xpath('p/a/@href')[0]
  91             # skip roles for now
  92             role = ''
  93             # for com in inner.xpath('p/a[contains(@href, "committees")]'):
  94             #     role = com.tail.strip()
  95 
  96             person = Person(name=name, district=district,
  97                             party=party, primary_org=chamber,
  98                             image=img_url, role=role)
  99             phones = get_phones(inner)
  100             phone = phones.get('home') or phones.get('business')
  101             office_phone = phones.get('office')
  102             address = get_address(inner)
  103             fax = get_fax(inner)
  104             if address:
  105                 person.add_contact_detail(type='address', value=address,
  106                                           note='District Office')
  107             if phone:
  108                 person.add_contact_detail(type='voice', value=phone,
  109                                           note='District Office')
  110             if fax:
  111                 person.add_contact_detail(type='fax', value=fax,
  112                                           note='District Office')
  113             if email:
  114                 person.add_contact_detail(type='email', value=email,
  115                                           note='District Office')
  116             if office_phone:
  117                 person.add_contact_detail(type='voice', value=office_phone,
  118                                           note='Capitol Office')
  119             person.add_source(url)
  120             person.add_link(person_url)
  121             yield person
  122
  [end of openstates/id/people.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/openstates/id/people.py b/openstates/id/people.py
  --- a/openstates/id/people.py
  +++ b/openstates/id/people.py
  @@ -78,7 +78,8 @@
               img_url = row.xpath('.//img/@src')[0]
   
               inner = row.xpath('.//div[@class="vc-column-innner-wrapper"]')[1]
  -            if 'Resigned' in inner.text_content():
  +            inner_text = inner.text_content()
  +            if 'Resigned' in inner_text or 'Substitute' in inner_text:
                   continue
   
               name = inner.xpath('p/strong')[0].text.replace(u'\xa0', ' ').strip()
  
verification_info: {"golden_diff": "diff --git a/openstates/id/people.py b/openstates/id/people.py\n--- a/openstates/id/people.py\n+++ b/openstates/id/people.py\n@@ -78,7 +78,8 @@\n             img_url = row.xpath('.//img/@src')[0]\n \n             inner = row.xpath('.//div[@class=\"vc-column-innner-wrapper\"]')[1]\n-            if 'Resigned' in inner.text_content():\n+            inner_text = inner.text_content()\n+            if 'Resigned' in inner_text or 'Substitute' in inner_text:\n                 continue\n \n             name = inner.xpath('p/strong')[0].text.replace(u'\\xa0', ' ').strip()\n", "issue": "ID: scrape fails on substitute representative\nOnce #2053 is merged, the people scraper is blowing up reading https://legislature.idaho.gov/house/membership/ .  \r\nSearch down to \"Scanlin\", who you'll find is a \"substitute\" representative.  There's a parsing problem because the scraper expects the name to be bold and the party to not be; in this case \"Substitute\" is bold only.\r\n\r\nFor a description of what a \"Substitute\" is, see http://www.spokesman.com/blogs/boise/2014/mar/16/idahos-legislative-substitute-law-unique/ \r\n\r\nJust fixing this would leave two legislators in that district, where, as in Highlander, \"there can be only one\".  Representative Kloc, who Scanlin is substituting for, is directly above him.\r\n\r\nAssuming that his roll call votes, committee memberships, etc. are registered to the substitute, I believe a fully correct fix for this would involve:\r\n- lookahead for a \"Substitute\", skipping the current legislator if the next legislator is a substitute.\r\n- rewriting the line parser to skip \"Substitute\" and just use the text (not bold format) for name/party parsing.\r\n\n", "before_files": [{"content": "import re\nimport lxml.html\nfrom pupa.scrape import Scraper, Person\n\nBASE_URL = 'https://legislature.idaho.gov/%s/membership/'\nCHAMBERS = {'upper': 'senate', 'lower': 'house'}\nPARTY = {\n    '(R)': 'Republican',\n    '(D)': 'Democratic',\n}\n\nphone_patterns = {\n    'office': re.compile(r'Statehouse'),\n    'business': re.compile(r'Bus'),\n    'home': re.compile(r'Home'),\n}\n\nparse_phone_pattern = re.compile(r'tel:(?:\\+1)?(\\d{10}$)')\nfax_pattern = re.compile(r'fax\\s+\\((\\d{3})\\)\\s+(\\d{3})-(\\d{4})', re.IGNORECASE)\naddress_pattern = re.compile(r', \\d{5}')\naddress_replace_pattern = re.compile(r'(\\d{5})')\n\n\ndef get_phones(el):\n    phones = {}\n    for link in el.xpath('p/a[@class = \"mob-tel\"]'):\n        prefix = link.getprevious().tail\n        for label, pattern in phone_patterns.items():\n            if pattern.search(prefix) is not None:\n                phones[label] = parse_phone(link.get('href'))\n    return phones\n\n\ndef parse_phone(phone):\n    res = parse_phone_pattern.search(phone)\n    if res is not None:\n        return res.groups()[0]\n\n\ndef get_fax(el):\n    res = fax_pattern.search(el.text_content())\n    if res is not None:\n        return ''.join(res.groups())\n\n\ndef get_address(el):\n    for br in el.xpath('p/br'):\n        piece = (br.tail or '').strip()\n        res = address_pattern.search(piece)\n        if res is not None:\n            return address_replace_pattern.sub(r'ID \\1', piece).strip()\n\n\nclass IDPersonScraper(Scraper):\n    \"\"\"Legislator data seems to be available for the current term only.\"\"\"\n    jurisdiction = 'id'\n\n    def scrape(self, chamber=None):\n        if chamber:\n            yield from self.scrape_chamber(chamber)\n        else:\n            yield from self.scrape_chamber('upper')\n            yield from self.scrape_chamber('lower')\n\n    def scrape_chamber(self, chamber):\n        \"\"\"\n        Scrapes legislators for the current term only\n        \"\"\"\n        # self.validate_term(term, latest_only=True)\n        url = BASE_URL % CHAMBERS[chamber].lower()\n        index = self.get(url, verify=False).text\n        html = lxml.html.fromstring(index)\n        html.make_links_absolute(url)\n\n        rows = html.xpath('//div[contains(@class, \"row-equal-height\")]')\n\n        for row in rows:\n            img_url = row.xpath('.//img/@src')[0]\n\n            inner = row.xpath('.//div[@class=\"vc-column-innner-wrapper\"]')[1]\n            if 'Resigned' in inner.text_content():\n                continue\n\n            name = inner.xpath('p/strong')[0].text.replace(u'\\xa0', ' ').strip()\n            name = re.sub('\\s+', ' ', name)\n            party = PARTY[inner.xpath('p/strong')[0].tail.strip()]\n            email = inner.xpath('p/strong/a')[0].text\n            district = inner.xpath('p/a')[0].text.replace('District ', '')\n\n            person_url = inner.xpath('p/a/@href')[0]\n            # skip roles for now\n            role = ''\n            # for com in inner.xpath('p/a[contains(@href, \"committees\")]'):\n            #     role = com.tail.strip()\n\n            person = Person(name=name, district=district,\n                            party=party, primary_org=chamber,\n                            image=img_url, role=role)\n            phones = get_phones(inner)\n            phone = phones.get('home') or phones.get('business')\n            office_phone = phones.get('office')\n            address = get_address(inner)\n            fax = get_fax(inner)\n            if address:\n                person.add_contact_detail(type='address', value=address,\n                                          note='District Office')\n            if phone:\n                person.add_contact_detail(type='voice', value=phone,\n                                          note='District Office')\n            if fax:\n                person.add_contact_detail(type='fax', value=fax,\n                                          note='District Office')\n            if email:\n                person.add_contact_detail(type='email', value=email,\n                                          note='District Office')\n            if office_phone:\n                person.add_contact_detail(type='voice', value=office_phone,\n                                          note='Capitol Office')\n            person.add_source(url)\n            person.add_link(person_url)\n            yield person\n", "path": "openstates/id/people.py"}]}