We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
PR failing since at least 2018-09-06
PR has been failing since 2018-09-06

Based on automated runs it appears that PR has not run successfully in 6 days (2018-09-06).


```
  00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Ram\u00f3n L. Cruz Burgos"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Angel Buler\u00edn Ramos"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "\u00c1ngel Mart\u00ednez Santiago"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Manuel A. Natal Albelo"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Eduardo Bhatia Gautier"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Zoe Laboy Alvarado"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "An\u00edbal Jos\u00e9 Torres Torres"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Carmelo J. R\u00edos Santiago"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Itzamar Pe\u00f1a Ram\u00edrez"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Carlos A. Bianchi Angler\u00f3"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Jos\u00e9 Vargas Vidot"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Angel Mart\u00ednez Santiago"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Eduardo Bhatia Gauthier"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Miguel Romero Lugo"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Margarita Nolasco Santiago"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Luis R. Ortiz Lugo"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Urayo\u00e1n Hern\u00e1ndez Alvarado"}
00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{"name": "Jos\u00e9 M. Varela Fern\u00e1ndez"}
loaded Open States pupa settings...
pr (scrape, import)
  people: {}
  committees: {}
  bills: {}
import jurisdictions...
import organizations...
import people...
import posts...
import memberships...
Traceback (most recent call last):
  File "/opt/openstates/venv-pupa//bin/pupa", line 11, in <module>
    load_entry_point('pupa', 'console_scripts', 'pupa')()
  File "/opt/openstates/venv-pupa/src/pupa/pupa/cli/__main__.py", line 68, in main
    subcommands[args.subcommand].handle(args, other)
  File "/opt/openstates/venv-pupa/src/pupa/pupa/cli/commands/update.py", line 260, in handle
    return self.do_handle(args, other, juris)
  File "/opt/openstates/venv-pupa/src/pupa/pupa/cli/commands/update.py", line 307, in do_handle
    report['import'] = self.do_import(juris, args)
  File "/opt/openstates/venv-pupa/src/pupa/pupa/cli/commands/update.py", line 211, in do_import
    report.update(membership_importer.import_directory(datadir))
  File "/opt/openstates/venv-pupa/src/pupa/pupa/importers/base.py", line 196, in import_directory
    return self.import_data(json_stream())
  File "/opt/openstates/venv-pupa/src/pupa/pupa/importers/base.py", line 233, in import_data
    obj_id, what = self.import_item(data)
  File "/opt/openstates/venv-pupa/src/pupa/pupa/importers/base.py", line 254, in import_item
    data = self.prepare_for_db(data)
  File "/opt/openstates/venv-pupa/src/pupa/pupa/importers/memberships.py", line 47, in prepare_for_db
    data['organization_id'] = self.org_importer.resolve_json_id(data['organization_id'])
  File "/opt/openstates/venv-pupa/src/pupa/pupa/importers/base.py", line 171, in resolve_json_id
    raise UnresolvedIdError(errmsg)
pupa.exceptions.UnresolvedIdError: cannot resolve pseudo id to Organization: ~{"classification": "party", "name": "Independiente"}
```

Visit http://bobsled.openstates.org for more info.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `openstates/pr/people.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 import re
3 from pupa.scrape import Person, Scraper
4 from openstates.utils import LXMLMixin, validate_phone_number
5 
6 
7 class PRPersonScraper(Scraper, LXMLMixin):
8     def scrape(self, chamber=None):
9         term = self.jurisdiction.legislative_sessions[-1]['identifier']
10         chambers = [chamber] if chamber is not None else ['upper', 'lower']
11         for chamber in chambers:
12             yield from getattr(self, 'scrape_' + chamber + '_chamber')(term)
13 
14     def scrape_upper_chamber(self, term):
15         url = 'https://senado.pr.gov/Pages/Senadores.aspx'
16 
17         doc = self.lxmlize(url)
18         links = self.get_nodes(doc, '//ul[@class="senadores-list"]/li/a/@href')
19 
20         for link in links:
21             senator_page = self.lxmlize(link)
22             profile_links = self.get_nodes(senator_page, '//ul[@class="profiles-links"]/li')
23 
24             name_text = self.get_node(senator_page, '//span[@class="name"]').text_content().strip()
25             name = re.sub(r'^Hon\.', '', name_text, flags=re.IGNORECASE).strip()
26             party = profile_links[0].text_content().strip()
27             photo_url = self.get_node(senator_page, '//div[@class="avatar"]//img/@src')
28 
29             if profile_links[1].text_content().strip() == "Senador por Distrito":
30                 district_text = self.get_node(
31                     senator_page,
32                     '//div[@class="module-distrito"]//span[@class="headline"]').text_content()
33                 district = district_text.replace('DISTRITO', '', 1).replace('\u200b', '').strip()
34             elif profile_links[1].text_content().strip() == "Senador por Acumulación":
35                 district = "At-Large"
36 
37             phone_node = self.get_node(senator_page, '//a[@class="contact-data tel"]')
38             phone = phone_node.text_content().strip()
39             email_node = self.get_node(senator_page, '//a[@class="contact-data email"]')
40             email = email_node.text_content().replace('\u200b', '').strip()
41 
42             person = Person(primary_org='upper',
43                             district=district,
44                             name=name,
45                             party=party,
46                             image=photo_url)
47             person.add_contact_detail(type='email',
48                                       value=email,
49                                       note='Capitol Office')
50             person.add_contact_detail(type='voice',
51                                       value=phone,
52                                       note='Capitol Office')
53             person.add_link(link)
54             person.add_source(link)
55 
56             yield person
57 
58     def scrape_lower_chamber(self, term):
59         # E-mail contact is now hidden behind webforms. Sadness.
60 
61         party_map = {'PNP': 'Partido Nuevo Progresista',
62                      'PPD': u'Partido Popular Democr\xe1tico',
63                      'PIP': u'Partido Independentista Puertorrique\u00F1o',
64                      }
65 
66         url = 'http://www.tucamarapr.org/dnncamara/ComposiciondelaCamara/Biografia.aspx'
67         page = self.lxmlize(url)
68 
69         member_nodes = self.get_nodes(page, '//li[@class="selectionRep"]')
70         for member_node in member_nodes:
71             member_info = member_node.text_content().strip().split("\n")
72 
73             name = re.sub(r'^Hon\.', '', member_info[0]).strip()
74             district_text = member_info[-1].strip()
75             if district_text == 'Representante por Acumulación':
76                 district = 'At-Large'
77             else:
78                 district = district_text.replace("Representante del Distrito ", "").strip()
79             photo_url = self.get_node(member_node, './/img/@src')
80 
81             rep_link = self.get_node(member_node, ".//a/@href")
82             rep_page = self.lxmlize(rep_link)
83 
84             party_node = self.get_node(rep_page, '//span[@class="partyBio"]')
85             party_text = party_node.text_content().strip()
86             party = party_map[party_text]
87 
88             address = self.get_node(rep_page, '//h6').text.strip().split("\n")[0].strip()
89 
90             # Only grabs the first validated phone number found.
91             # Typically, representatives have multiple phone numbers.
92             phone_node = self.get_node(
93                 rep_page,
94                 '//span[@class="data-type" and contains(text(), "Tel.")]')
95             phone = None
96             possible_phones = phone_node.text.strip().split("\n")
97             for phone_attempt in possible_phones:
98                 # Don't keep searching phone numbers if a good one is found.
99                 if phone:
100                     break
101 
102                 phone_text = re.sub(r'^Tel\.[\s]*', '', phone_attempt).strip()
103                 if validate_phone_number(phone_text):
104                     phone = phone_text
105 
106             fax_node = self.get_node(
107                 rep_page,
108                 '//span[@class="data-type" and contains(text(), "Fax.")]')
109             fax = None
110             if fax_node:
111                 fax_text = fax_node.text.strip()
112                 fax_text = re.sub(r'^Fax\.[\s]*', '', fax_text).strip()
113                 if validate_phone_number(fax_text):
114                     fax = fax_text
115 
116             person = Person(primary_org='lower',
117                             district=district,
118                             name=name,
119                             party=party,
120                             image=photo_url)
121 
122             person.add_link(rep_link)
123             person.add_source(rep_link)
124             person.add_source(url)
125 
126             if address:
127                 person.add_contact_detail(type='address',
128                                           value=address,
129                                           note='Capitol Office')
130             if phone:
131                 person.add_contact_detail(type='voice',
132                                           value=phone,
133                                           note='Capitol Office')
134             if fax:
135                 person.add_contact_detail(type='fax',
136                                           value=fax,
137                                           note='Capitol Office')
138 
139             yield person
140
```
--- 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/openstates/pr/people.py b/openstates/pr/people.py
--- a/openstates/pr/people.py
+++ b/openstates/pr/people.py
@@ -24,6 +24,10 @@
             name_text = self.get_node(senator_page, '//span[@class="name"]').text_content().strip()
             name = re.sub(r'^Hon\.', '', name_text, flags=re.IGNORECASE).strip()
             party = profile_links[0].text_content().strip()
+            # Translate to English since being an Independent is a universal construct
+            if party == "Independiente":
+                party = "Independent"
+
             photo_url = self.get_node(senator_page, '//div[@class="avatar"]//img/@src')
 
             if profile_links[1].text_content().strip() == "Senador por Distrito":

{"golden_diff": "diff --git a/openstates/pr/people.py b/openstates/pr/people.py\n--- a/openstates/pr/people.py\n+++ b/openstates/pr/people.py\n@@ -24,6 +24,10 @@\n             name_text = self.get_node(senator_page, '//span[@class=\"name\"]').text_content().strip()\n             name = re.sub(r'^Hon\\.', '', name_text, flags=re.IGNORECASE).strip()\n             party = profile_links[0].text_content().strip()\n+            # Translate to English since being an Independent is a universal construct\n+            if party == \"Independiente\":\n+                party = \"Independent\"\n+\n             photo_url = self.get_node(senator_page, '//div[@class=\"avatar\"]//img/@src')\n \n             if profile_links[1].text_content().strip() == \"Senador por Distrito\":\n", "issue": "PR failing since at least 2018-09-06\nPR has been failing since 2018-09-06\n\nBased on automated runs it appears that PR has not run successfully in 6 days (2018-09-06).\n\n\n```\n  00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Ram\\u00f3n L. Cruz Burgos\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Angel Buler\\u00edn Ramos\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"\\u00c1ngel Mart\\u00ednez Santiago\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Manuel A. Natal Albelo\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Eduardo Bhatia Gautier\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Zoe Laboy Alvarado\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"An\\u00edbal Jos\\u00e9 Torres Torres\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Carmelo J. R\\u00edos Santiago\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Itzamar Pe\\u00f1a Ram\\u00edrez\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Carlos A. Bianchi Angler\\u00f3\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Jos\\u00e9 Vargas Vidot\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Angel Mart\\u00ednez Santiago\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Eduardo Bhatia Gauthier\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Miguel Romero Lugo\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Margarita Nolasco Santiago\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Luis R. Ortiz Lugo\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Urayo\\u00e1n Hern\\u00e1ndez Alvarado\"}\n00:38:39 ERROR pupa: cannot resolve pseudo id to Person: ~{\"name\": \"Jos\\u00e9 M. Varela Fern\\u00e1ndez\"}\nloaded Open States pupa settings...\npr (scrape, import)\n  people: {}\n  committees: {}\n  bills: {}\nimport jurisdictions...\nimport organizations...\nimport people...\nimport posts...\nimport memberships...\nTraceback (most recent call last):\n  File \"/opt/openstates/venv-pupa//bin/pupa\", line 11, in <module>\n    load_entry_point('pupa', 'console_scripts', 'pupa')()\n  File \"/opt/openstates/venv-pupa/src/pupa/pupa/cli/__main__.py\", line 68, in main\n    subcommands[args.subcommand].handle(args, other)\n  File \"/opt/openstates/venv-pupa/src/pupa/pupa/cli/commands/update.py\", line 260, in handle\n    return self.do_handle(args, other, juris)\n  File \"/opt/openstates/venv-pupa/src/pupa/pupa/cli/commands/update.py\", line 307, in do_handle\n    report['import'] = self.do_import(juris, args)\n  File \"/opt/openstates/venv-pupa/src/pupa/pupa/cli/commands/update.py\", line 211, in do_import\n    report.update(membership_importer.import_directory(datadir))\n  File \"/opt/openstates/venv-pupa/src/pupa/pupa/importers/base.py\", line 196, in import_directory\n    return self.import_data(json_stream())\n  File \"/opt/openstates/venv-pupa/src/pupa/pupa/importers/base.py\", line 233, in import_data\n    obj_id, what = self.import_item(data)\n  File \"/opt/openstates/venv-pupa/src/pupa/pupa/importers/base.py\", line 254, in import_item\n    data = self.prepare_for_db(data)\n  File \"/opt/openstates/venv-pupa/src/pupa/pupa/importers/memberships.py\", line 47, in prepare_for_db\n    data['organization_id'] = self.org_importer.resolve_json_id(data['organization_id'])\n  File \"/opt/openstates/venv-pupa/src/pupa/pupa/importers/base.py\", line 171, in resolve_json_id\n    raise UnresolvedIdError(errmsg)\npupa.exceptions.UnresolvedIdError: cannot resolve pseudo id to Organization: ~{\"classification\": \"party\", \"name\": \"Independiente\"}\n```\n\nVisit http://bobsled.openstates.org for more info.\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\nimport re\nfrom pupa.scrape import Person, Scraper\nfrom openstates.utils import LXMLMixin, validate_phone_number\n\n\nclass PRPersonScraper(Scraper, LXMLMixin):\n    def scrape(self, chamber=None):\n        term = self.jurisdiction.legislative_sessions[-1]['identifier']\n        chambers = [chamber] if chamber is not None else ['upper', 'lower']\n        for chamber in chambers:\n            yield from getattr(self, 'scrape_' + chamber + '_chamber')(term)\n\n    def scrape_upper_chamber(self, term):\n        url = 'https://senado.pr.gov/Pages/Senadores.aspx'\n\n        doc = self.lxmlize(url)\n        links = self.get_nodes(doc, '//ul[@class=\"senadores-list\"]/li/a/@href')\n\n        for link in links:\n            senator_page = self.lxmlize(link)\n            profile_links = self.get_nodes(senator_page, '//ul[@class=\"profiles-links\"]/li')\n\n            name_text = self.get_node(senator_page, '//span[@class=\"name\"]').text_content().strip()\n            name = re.sub(r'^Hon\\.', '', name_text, flags=re.IGNORECASE).strip()\n            party = profile_links[0].text_content().strip()\n            photo_url = self.get_node(senator_page, '//div[@class=\"avatar\"]//img/@src')\n\n            if profile_links[1].text_content().strip() == \"Senador por Distrito\":\n                district_text = self.get_node(\n                    senator_page,\n                    '//div[@class=\"module-distrito\"]//span[@class=\"headline\"]').text_content()\n                district = district_text.replace('DISTRITO', '', 1).replace('\\u200b', '').strip()\n            elif profile_links[1].text_content().strip() == \"Senador por Acumulaci\u00f3n\":\n                district = \"At-Large\"\n\n            phone_node = self.get_node(senator_page, '//a[@class=\"contact-data tel\"]')\n            phone = phone_node.text_content().strip()\n            email_node = self.get_node(senator_page, '//a[@class=\"contact-data email\"]')\n            email = email_node.text_content().replace('\\u200b', '').strip()\n\n            person = Person(primary_org='upper',\n                            district=district,\n                            name=name,\n                            party=party,\n                            image=photo_url)\n            person.add_contact_detail(type='email',\n                                      value=email,\n                                      note='Capitol Office')\n            person.add_contact_detail(type='voice',\n                                      value=phone,\n                                      note='Capitol Office')\n            person.add_link(link)\n            person.add_source(link)\n\n            yield person\n\n    def scrape_lower_chamber(self, term):\n        # E-mail contact is now hidden behind webforms. Sadness.\n\n        party_map = {'PNP': 'Partido Nuevo Progresista',\n                     'PPD': u'Partido Popular Democr\\xe1tico',\n                     'PIP': u'Partido Independentista Puertorrique\\u00F1o',\n                     }\n\n        url = 'http://www.tucamarapr.org/dnncamara/ComposiciondelaCamara/Biografia.aspx'\n        page = self.lxmlize(url)\n\n        member_nodes = self.get_nodes(page, '//li[@class=\"selectionRep\"]')\n        for member_node in member_nodes:\n            member_info = member_node.text_content().strip().split(\"\\n\")\n\n            name = re.sub(r'^Hon\\.', '', member_info[0]).strip()\n            district_text = member_info[-1].strip()\n            if district_text == 'Representante por Acumulaci\u00f3n':\n                district = 'At-Large'\n            else:\n                district = district_text.replace(\"Representante del Distrito \", \"\").strip()\n            photo_url = self.get_node(member_node, './/img/@src')\n\n            rep_link = self.get_node(member_node, \".//a/@href\")\n            rep_page = self.lxmlize(rep_link)\n\n            party_node = self.get_node(rep_page, '//span[@class=\"partyBio\"]')\n            party_text = party_node.text_content().strip()\n            party = party_map[party_text]\n\n            address = self.get_node(rep_page, '//h6').text.strip().split(\"\\n\")[0].strip()\n\n            # Only grabs the first validated phone number found.\n            # Typically, representatives have multiple phone numbers.\n            phone_node = self.get_node(\n                rep_page,\n                '//span[@class=\"data-type\" and contains(text(), \"Tel.\")]')\n            phone = None\n            possible_phones = phone_node.text.strip().split(\"\\n\")\n            for phone_attempt in possible_phones:\n                # Don't keep searching phone numbers if a good one is found.\n                if phone:\n                    break\n\n                phone_text = re.sub(r'^Tel\\.[\\s]*', '', phone_attempt).strip()\n                if validate_phone_number(phone_text):\n                    phone = phone_text\n\n            fax_node = self.get_node(\n                rep_page,\n                '//span[@class=\"data-type\" and contains(text(), \"Fax.\")]')\n            fax = None\n            if fax_node:\n                fax_text = fax_node.text.strip()\n                fax_text = re.sub(r'^Fax\\.[\\s]*', '', fax_text).strip()\n                if validate_phone_number(fax_text):\n                    fax = fax_text\n\n            person = Person(primary_org='lower',\n                            district=district,\n                            name=name,\n                            party=party,\n                            image=photo_url)\n\n            person.add_link(rep_link)\n            person.add_source(rep_link)\n            person.add_source(url)\n\n            if address:\n                person.add_contact_detail(type='address',\n                                          value=address,\n                                          note='Capitol Office')\n            if phone:\n                person.add_contact_detail(type='voice',\n                                          value=phone,\n                                          note='Capitol Office')\n            if fax:\n                person.add_contact_detail(type='fax',\n                                          value=fax,\n                                          note='Capitol Office')\n\n            yield person\n", "path": "openstates/pr/people.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\nimport re\nfrom pupa.scrape import Person, Scraper\nfrom openstates.utils import LXMLMixin, validate_phone_number\n\n\nclass PRPersonScraper(Scraper, LXMLMixin):\n    def scrape(self, chamber=None):\n        term = self.jurisdiction.legislative_sessions[-1]['identifier']\n        chambers = [chamber] if chamber is not None else ['upper', 'lower']\n        for chamber in chambers:\n            yield from getattr(self, 'scrape_' + chamber + '_chamber')(term)\n\n    def scrape_upper_chamber(self, term):\n        url = 'https://senado.pr.gov/Pages/Senadores.aspx'\n\n        doc = self.lxmlize(url)\n        links = self.get_nodes(doc, '//ul[@class=\"senadores-list\"]/li/a/@href')\n\n        for link in links:\n            senator_page = self.lxmlize(link)\n            profile_links = self.get_nodes(senator_page, '//ul[@class=\"profiles-links\"]/li')\n\n            name_text = self.get_node(senator_page, '//span[@class=\"name\"]').text_content().strip()\n            name = re.sub(r'^Hon\\.', '', name_text, flags=re.IGNORECASE).strip()\n            party = profile_links[0].text_content().strip()\n            # Translate to English since being an Independent is a universal construct\n            if party == \"Independiente\":\n                party = \"Independent\"\n\n            photo_url = self.get_node(senator_page, '//div[@class=\"avatar\"]//img/@src')\n\n            if profile_links[1].text_content().strip() == \"Senador por Distrito\":\n                district_text = self.get_node(\n                    senator_page,\n                    '//div[@class=\"module-distrito\"]//span[@class=\"headline\"]').text_content()\n                district = district_text.replace('DISTRITO', '', 1).replace('\\u200b', '').strip()\n            elif profile_links[1].text_content().strip() == \"Senador por Acumulaci\u00f3n\":\n                district = \"At-Large\"\n\n            phone_node = self.get_node(senator_page, '//a[@class=\"contact-data tel\"]')\n            phone = phone_node.text_content().strip()\n            email_node = self.get_node(senator_page, '//a[@class=\"contact-data email\"]')\n            email = email_node.text_content().replace('\\u200b', '').strip()\n\n            person = Person(primary_org='upper',\n                            district=district,\n                            name=name,\n                            party=party,\n                            image=photo_url)\n            person.add_contact_detail(type='email',\n                                      value=email,\n                                      note='Capitol Office')\n            person.add_contact_detail(type='voice',\n                                      value=phone,\n                                      note='Capitol Office')\n            person.add_link(link)\n            person.add_source(link)\n\n            yield person\n\n    def scrape_lower_chamber(self, term):\n        # E-mail contact is now hidden behind webforms. Sadness.\n\n        party_map = {'PNP': 'Partido Nuevo Progresista',\n                     'PPD': u'Partido Popular Democr\\xe1tico',\n                     'PIP': u'Partido Independentista Puertorrique\\u00F1o',\n                     }\n\n        url = 'http://www.tucamarapr.org/dnncamara/ComposiciondelaCamara/Biografia.aspx'\n        page = self.lxmlize(url)\n\n        member_nodes = self.get_nodes(page, '//li[@class=\"selectionRep\"]')\n        for member_node in member_nodes:\n            member_info = member_node.text_content().strip().split(\"\\n\")\n\n            name = re.sub(r'^Hon\\.', '', member_info[0]).strip()\n            district_text = member_info[-1].strip()\n            if district_text == 'Representante por Acumulaci\u00f3n':\n                district = 'At-Large'\n            else:\n                district = district_text.replace(\"Representante del Distrito \", \"\").strip()\n            photo_url = self.get_node(member_node, './/img/@src')\n\n            rep_link = self.get_node(member_node, \".//a/@href\")\n            rep_page = self.lxmlize(rep_link)\n\n            party_node = self.get_node(rep_page, '//span[@class=\"partyBio\"]')\n            party_text = party_node.text_content().strip()\n            party = party_map[party_text]\n\n            address = self.get_node(rep_page, '//h6').text.strip().split(\"\\n\")[0].strip()\n\n            # Only grabs the first validated phone number found.\n            # Typically, representatives have multiple phone numbers.\n            phone_node = self.get_node(\n                rep_page,\n                '//span[@class=\"data-type\" and contains(text(), \"Tel.\")]')\n            phone = None\n            possible_phones = phone_node.text.strip().split(\"\\n\")\n            for phone_attempt in possible_phones:\n                # Don't keep searching phone numbers if a good one is found.\n                if phone:\n                    break\n\n                phone_text = re.sub(r'^Tel\\.[\\s]*', '', phone_attempt).strip()\n                if validate_phone_number(phone_text):\n                    phone = phone_text\n\n            fax_node = self.get_node(\n                rep_page,\n                '//span[@class=\"data-type\" and contains(text(), \"Fax.\")]')\n            fax = None\n            if fax_node:\n                fax_text = fax_node.text.strip()\n                fax_text = re.sub(r'^Fax\\.[\\s]*', '', fax_text).strip()\n                if validate_phone_number(fax_text):\n                    fax = fax_text\n\n            person = Person(primary_org='lower',\n                            district=district,\n                            name=name,\n                            party=party,\n                            image=photo_url)\n\n            person.add_link(rep_link)\n            person.add_source(rep_link)\n            person.add_source(url)\n\n            if address:\n                person.add_contact_detail(type='address',\n                                          value=address,\n                                          note='Capitol Office')\n            if phone:\n                person.add_contact_detail(type='voice',\n                                          value=phone,\n                                          note='Capitol Office')\n            if fax:\n                person.add_contact_detail(type='fax',\n                                          value=fax,\n                                          note='Capitol Office')\n\n            yield person\n", "path": "openstates/pr/people.py"}]}