We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
CA: email issue
State: CA

(via contact)
I’d like to call your attention to an error on your email address listings for State Senators in California.  Your database lists an address in the form of senator.lastname@sen.ca.gov, whereas the correct email is senator.lastname@senator.ca.gov.
 
It does appear that Senate staffers are firstname.lastname@sen.ca.gov.
 
We’ve been using your service, and our advocates’ emails are bouncing back.



--- 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/ca/legislators.py`
Content:
```
1 import re
2 import collections
3 import unicodedata
4 from operator import methodcaller
5 
6 import lxml.html
7 
8 from billy.scrape.legislators import LegislatorScraper, Legislator
9 
10 
11 def parse_address(s, split=re.compile(r'[;,]\s{,3}').split):
12     '''
13     Extract address fields from text.
14     '''
15     # If the address isn't formatted correctly, skip for now.
16     if ';' not in s:
17         return []
18 
19     fields = 'city state_zip phone'.split()
20     vals = split(s)
21     res = []
22     while True:
23         try:
24             _field = fields.pop()
25             _value = vals.pop()
26         except IndexError:
27             break
28         else:
29             if _value.strip():
30                 res.append((_field, _value))
31     if vals:
32         res.append(('street', ', '.join(vals)))
33     return res
34 
35 
36 class CALegislatorScraper(LegislatorScraper):
37 
38     jurisdiction = 'ca'
39 
40     urls = {'upper': 'http://senate.ca.gov/senators',
41             'lower': 'http://assembly.ca.gov/assemblymembers'}
42 
43     def scrape(self, chamber, term):
44 
45         url = self.urls[chamber]
46         html = self.get(url).text
47         doc = lxml.html.fromstring(html)
48 
49         if chamber == 'lower':
50             rows = doc.xpath('//table/tbody/tr')
51             parse = self.parse_assembly
52         else:
53             rows = doc.xpath('//div[contains(@class, "views-row")]')
54             parse = self.parse_senate
55 
56         for tr in rows:
57             legislator = parse(tr, term, chamber)
58             if legislator is None:
59                 continue
60             if 'Vacant' in legislator['full_name']:
61                 continue
62 
63             legislator.add_source(url)
64             legislator['full_name'] = legislator['full_name'].strip()
65             self.save_legislator(legislator)
66 
67     def parse_senate(self, div, term, chamber):
68         name = div.xpath('.//h3/text()')[0]
69         if name.endswith(' (R)'):
70             party = 'Republican'
71         elif name.endswith(' (D)'):
72             party = 'Democratic'
73         else:
74             self.warning('skipping ' + name)
75             return None
76         name = name.split(' (')[0]
77 
78         district = div.xpath(
79             './/div[contains(@class, "senator-district")]/div/text()'
80         )[0].strip().lstrip('0')
81         photo_url = div.xpath('.//img/@src')[0]
82         url = div.xpath('.//a/@href')[0]
83 
84         leg = Legislator(term, chamber, full_name=name, party=party, district=district,
85                          photo_url=photo_url, url=url)
86 
87         # CA senators have working emails, but they're not putting them on
88         # their public pages anymore
89         email = self._construct_email(chamber, name)
90 
91         for addr in div.xpath('.//div[contains(@class, "views-field-field-senator-capitol-office")]//p'):
92             addr, phone = addr.text_content().split('; ')
93             leg.add_office(
94                 'capitol', 'Senate Office',
95                 address=addr.strip(), phone=phone.strip(), email=email)
96 
97         for addr in div.xpath('.//div[contains(@class, "views-field-field-senator-district-office")]//p'):
98             for addr in addr.text_content().strip().splitlines():
99                 try:
100                     addr, phone = addr.strip().replace(u'\xa0', ' ').split('; ')
101                     leg.add_office(
102                         'district', 'District Office',
103                         address=addr.strip(), phone=phone.strip())
104                 except ValueError:
105                     addr = addr.strip().replace(u'\xa0', ' ')
106                     leg.add_office('district', 'District Office', address=addr)
107 
108         return leg
109 
110     def parse_assembly(self, tr, term, chamber):
111         '''
112         Given a tr element, get specific data from it.
113         '''
114 
115         strip = methodcaller('strip')
116 
117         xpath = 'td[contains(@class, "views-field-field-%s-%s")]%s'
118 
119         xp = {
120             'url':       [('lname-sort', '/a[not(contains(text(), "edit"))]/@href')],
121             'district':  [('district', '/text()')],
122             'party':     [('party', '/text()')],
123             'full_name': [('office-information', '/a[not(contains(text(), "edit"))]/text()')],
124             'address':   [('office-information', '/h3/following-sibling::text()'),
125                           ('office-information', '/p/text()')]
126             }
127 
128         titles = {'upper': 'senator', 'lower': 'member'}
129 
130         funcs = {
131             'full_name': lambda s: re.sub( # "Assembly" is misspelled once
132                 r'Contact Assembl?y Member', '', s).strip(),
133             'address': parse_address,
134         }
135 
136         rubberstamp = lambda _: _
137         tr_xpath = tr.xpath
138         res = collections.defaultdict(list)
139         for k, xpath_info in xp.items():
140             for vals in xpath_info:
141                 f = funcs.get(k, rubberstamp)
142                 vals = (titles[chamber],) + vals
143                 vals = map(f, map(strip, tr_xpath(xpath % vals)))
144                 res[k].extend(vals)
145 
146         # Photo.
147         try:
148             res['photo_url'] = tr_xpath('td/p/img/@src')[0]
149         except IndexError:
150             pass
151 
152         # Remove junk from assembly member names.
153         junk = 'Contact Assembly Member '
154 
155         try:
156             res['full_name'] = res['full_name'].pop().replace(junk, '')
157         except IndexError:
158             return
159 
160         # Addresses.
161         addresses = res['address']
162         try:
163             addresses = map(dict, filter(None, addresses))
164         except ValueError:
165             # Sometimes legislators only have one address, in which
166             # case this awful hack is helpful.
167             addresses = map(dict, filter(None, [addresses]))
168 
169         for address in addresses[:]:
170 
171             # Toss results that don't have required keys.
172             if not set(['street', 'city', 'state_zip']) < set(address):
173                 if address in addresses:
174                     addresses.remove(address)
175 
176         # Re-key the addresses
177         offices = []
178         if addresses:
179             # Mariko Yamada's addresses wouldn't parse correctly as of
180             # 3/23/2013, so here we're forced to test whether any
181             # addresses were even found.
182             addresses[0].update(type='capitol', name='Capitol Office')
183             offices.append(addresses[0])
184 
185             # CA reps have working emails, but they're not putting them on
186             # their public pages anymore
187             offices[0]['email'] = \
188                   self._construct_email(chamber, res['full_name'])
189 
190             for office in addresses[1:]:
191                 office.update(type='district', name='District Office')
192                 offices.append(office)
193 
194             for office in offices:
195                 street = office['street']
196                 state_zip = re.sub(r'\s+', ' ', office['state_zip'])
197                 street = '%s\n%s, %s' % (street, office['city'], state_zip)
198                 office['address'] = street
199                 office['fax'] = None
200                 if 'email' not in office:
201                     office['email'] = None
202 
203                 del office['street'], office['city'], office['state_zip']
204 
205         res['offices'] = offices
206         del res['address']
207 
208         # Normalize party.
209         for party in res['party'][:]:
210             if party:
211                 if party == 'Democrat':
212                     party = 'Democratic'
213                 res['party'] = party
214                 break
215             else:
216                 res['party'] = None
217 
218         # Mariko Yamada also didn't have a url that lxml would parse
219         # as of 3/22/2013.
220         if res['url']:
221             res['url'] = res['url'].pop()
222         else:
223             del res['url']
224 
225         # strip leading zero
226         res['district'] = str(int(res['district'].pop()))
227 
228         # Add a source for the url.
229         leg = Legislator(term, chamber, **res)
230         leg.update(**res)
231 
232         return leg
233 
234     def _construct_email(self, chamber, full_name):
235         last_name = re.split(r'\s+', full_name)[-1].lower()
236 
237         # translate accents to non-accented versions for use in an
238         # email and drop apostrophes
239         last_name = ''.join(c for c in
240                             unicodedata.normalize('NFD', unicode(last_name))
241                             if unicodedata.category(c) != 'Mn')
242         last_name = last_name.replace("'", "")
243 
244         if chamber == 'lower':
245             return 'assemblymember.' +  last_name + '@assembly.ca.gov'
246         else:
247             return 'senator.' +  last_name + '@sen.ca.gov'
248         
249
```
--- 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/ca/legislators.py b/openstates/ca/legislators.py
--- a/openstates/ca/legislators.py
+++ b/openstates/ca/legislators.py
@@ -244,5 +244,4 @@
         if chamber == 'lower':
             return 'assemblymember.' +  last_name + '@assembly.ca.gov'
         else:
-            return 'senator.' +  last_name + '@sen.ca.gov'
-        
+            return 'senator.' +  last_name + '@senator.ca.gov'

{"golden_diff": "diff --git a/openstates/ca/legislators.py b/openstates/ca/legislators.py\n--- a/openstates/ca/legislators.py\n+++ b/openstates/ca/legislators.py\n@@ -244,5 +244,4 @@\n         if chamber == 'lower':\n             return 'assemblymember.' +  last_name + '@assembly.ca.gov'\n         else:\n-            return 'senator.' +  last_name + '@sen.ca.gov'\n-        \n+            return 'senator.' +  last_name + '@senator.ca.gov'\n", "issue": "CA: email issue\nState: CA\r\n\r\n(via contact)\r\nI\u2019d like to call your attention to an error on your email address listings for State Senators in California.  Your database lists an address in the form of senator.lastname@sen.ca.gov, whereas the correct email is senator.lastname@senator.ca.gov.\r\n \r\nIt does appear that Senate staffers are firstname.lastname@sen.ca.gov.\r\n \r\nWe\u2019ve been using your service, and our advocates\u2019 emails are bouncing back.\r\n\r\n\n", "before_files": [{"content": "import re\nimport collections\nimport unicodedata\nfrom operator import methodcaller\n\nimport lxml.html\n\nfrom billy.scrape.legislators import LegislatorScraper, Legislator\n\n\ndef parse_address(s, split=re.compile(r'[;,]\\s{,3}').split):\n    '''\n    Extract address fields from text.\n    '''\n    # If the address isn't formatted correctly, skip for now.\n    if ';' not in s:\n        return []\n\n    fields = 'city state_zip phone'.split()\n    vals = split(s)\n    res = []\n    while True:\n        try:\n            _field = fields.pop()\n            _value = vals.pop()\n        except IndexError:\n            break\n        else:\n            if _value.strip():\n                res.append((_field, _value))\n    if vals:\n        res.append(('street', ', '.join(vals)))\n    return res\n\n\nclass CALegislatorScraper(LegislatorScraper):\n\n    jurisdiction = 'ca'\n\n    urls = {'upper': 'http://senate.ca.gov/senators',\n            'lower': 'http://assembly.ca.gov/assemblymembers'}\n\n    def scrape(self, chamber, term):\n\n        url = self.urls[chamber]\n        html = self.get(url).text\n        doc = lxml.html.fromstring(html)\n\n        if chamber == 'lower':\n            rows = doc.xpath('//table/tbody/tr')\n            parse = self.parse_assembly\n        else:\n            rows = doc.xpath('//div[contains(@class, \"views-row\")]')\n            parse = self.parse_senate\n\n        for tr in rows:\n            legislator = parse(tr, term, chamber)\n            if legislator is None:\n                continue\n            if 'Vacant' in legislator['full_name']:\n                continue\n\n            legislator.add_source(url)\n            legislator['full_name'] = legislator['full_name'].strip()\n            self.save_legislator(legislator)\n\n    def parse_senate(self, div, term, chamber):\n        name = div.xpath('.//h3/text()')[0]\n        if name.endswith(' (R)'):\n            party = 'Republican'\n        elif name.endswith(' (D)'):\n            party = 'Democratic'\n        else:\n            self.warning('skipping ' + name)\n            return None\n        name = name.split(' (')[0]\n\n        district = div.xpath(\n            './/div[contains(@class, \"senator-district\")]/div/text()'\n        )[0].strip().lstrip('0')\n        photo_url = div.xpath('.//img/@src')[0]\n        url = div.xpath('.//a/@href')[0]\n\n        leg = Legislator(term, chamber, full_name=name, party=party, district=district,\n                         photo_url=photo_url, url=url)\n\n        # CA senators have working emails, but they're not putting them on\n        # their public pages anymore\n        email = self._construct_email(chamber, name)\n\n        for addr in div.xpath('.//div[contains(@class, \"views-field-field-senator-capitol-office\")]//p'):\n            addr, phone = addr.text_content().split('; ')\n            leg.add_office(\n                'capitol', 'Senate Office',\n                address=addr.strip(), phone=phone.strip(), email=email)\n\n        for addr in div.xpath('.//div[contains(@class, \"views-field-field-senator-district-office\")]//p'):\n            for addr in addr.text_content().strip().splitlines():\n                try:\n                    addr, phone = addr.strip().replace(u'\\xa0', ' ').split('; ')\n                    leg.add_office(\n                        'district', 'District Office',\n                        address=addr.strip(), phone=phone.strip())\n                except ValueError:\n                    addr = addr.strip().replace(u'\\xa0', ' ')\n                    leg.add_office('district', 'District Office', address=addr)\n\n        return leg\n\n    def parse_assembly(self, tr, term, chamber):\n        '''\n        Given a tr element, get specific data from it.\n        '''\n\n        strip = methodcaller('strip')\n\n        xpath = 'td[contains(@class, \"views-field-field-%s-%s\")]%s'\n\n        xp = {\n            'url':       [('lname-sort', '/a[not(contains(text(), \"edit\"))]/@href')],\n            'district':  [('district', '/text()')],\n            'party':     [('party', '/text()')],\n            'full_name': [('office-information', '/a[not(contains(text(), \"edit\"))]/text()')],\n            'address':   [('office-information', '/h3/following-sibling::text()'),\n                          ('office-information', '/p/text()')]\n            }\n\n        titles = {'upper': 'senator', 'lower': 'member'}\n\n        funcs = {\n            'full_name': lambda s: re.sub( # \"Assembly\" is misspelled once\n                r'Contact Assembl?y Member', '', s).strip(),\n            'address': parse_address,\n        }\n\n        rubberstamp = lambda _: _\n        tr_xpath = tr.xpath\n        res = collections.defaultdict(list)\n        for k, xpath_info in xp.items():\n            for vals in xpath_info:\n                f = funcs.get(k, rubberstamp)\n                vals = (titles[chamber],) + vals\n                vals = map(f, map(strip, tr_xpath(xpath % vals)))\n                res[k].extend(vals)\n\n        # Photo.\n        try:\n            res['photo_url'] = tr_xpath('td/p/img/@src')[0]\n        except IndexError:\n            pass\n\n        # Remove junk from assembly member names.\n        junk = 'Contact Assembly Member '\n\n        try:\n            res['full_name'] = res['full_name'].pop().replace(junk, '')\n        except IndexError:\n            return\n\n        # Addresses.\n        addresses = res['address']\n        try:\n            addresses = map(dict, filter(None, addresses))\n        except ValueError:\n            # Sometimes legislators only have one address, in which\n            # case this awful hack is helpful.\n            addresses = map(dict, filter(None, [addresses]))\n\n        for address in addresses[:]:\n\n            # Toss results that don't have required keys.\n            if not set(['street', 'city', 'state_zip']) < set(address):\n                if address in addresses:\n                    addresses.remove(address)\n\n        # Re-key the addresses\n        offices = []\n        if addresses:\n            # Mariko Yamada's addresses wouldn't parse correctly as of\n            # 3/23/2013, so here we're forced to test whether any\n            # addresses were even found.\n            addresses[0].update(type='capitol', name='Capitol Office')\n            offices.append(addresses[0])\n\n            # CA reps have working emails, but they're not putting them on\n            # their public pages anymore\n            offices[0]['email'] = \\\n                  self._construct_email(chamber, res['full_name'])\n\n            for office in addresses[1:]:\n                office.update(type='district', name='District Office')\n                offices.append(office)\n\n            for office in offices:\n                street = office['street']\n                state_zip = re.sub(r'\\s+', ' ', office['state_zip'])\n                street = '%s\\n%s, %s' % (street, office['city'], state_zip)\n                office['address'] = street\n                office['fax'] = None\n                if 'email' not in office:\n                    office['email'] = None\n\n                del office['street'], office['city'], office['state_zip']\n\n        res['offices'] = offices\n        del res['address']\n\n        # Normalize party.\n        for party in res['party'][:]:\n            if party:\n                if party == 'Democrat':\n                    party = 'Democratic'\n                res['party'] = party\n                break\n            else:\n                res['party'] = None\n\n        # Mariko Yamada also didn't have a url that lxml would parse\n        # as of 3/22/2013.\n        if res['url']:\n            res['url'] = res['url'].pop()\n        else:\n            del res['url']\n\n        # strip leading zero\n        res['district'] = str(int(res['district'].pop()))\n\n        # Add a source for the url.\n        leg = Legislator(term, chamber, **res)\n        leg.update(**res)\n\n        return leg\n\n    def _construct_email(self, chamber, full_name):\n        last_name = re.split(r'\\s+', full_name)[-1].lower()\n\n        # translate accents to non-accented versions for use in an\n        # email and drop apostrophes\n        last_name = ''.join(c for c in\n                            unicodedata.normalize('NFD', unicode(last_name))\n                            if unicodedata.category(c) != 'Mn')\n        last_name = last_name.replace(\"'\", \"\")\n\n        if chamber == 'lower':\n            return 'assemblymember.' +  last_name + '@assembly.ca.gov'\n        else:\n            return 'senator.' +  last_name + '@sen.ca.gov'\n        \n", "path": "openstates/ca/legislators.py"}], "after_files": [{"content": "import re\nimport collections\nimport unicodedata\nfrom operator import methodcaller\n\nimport lxml.html\n\nfrom billy.scrape.legislators import LegislatorScraper, Legislator\n\n\ndef parse_address(s, split=re.compile(r'[;,]\\s{,3}').split):\n    '''\n    Extract address fields from text.\n    '''\n    # If the address isn't formatted correctly, skip for now.\n    if ';' not in s:\n        return []\n\n    fields = 'city state_zip phone'.split()\n    vals = split(s)\n    res = []\n    while True:\n        try:\n            _field = fields.pop()\n            _value = vals.pop()\n        except IndexError:\n            break\n        else:\n            if _value.strip():\n                res.append((_field, _value))\n    if vals:\n        res.append(('street', ', '.join(vals)))\n    return res\n\n\nclass CALegislatorScraper(LegislatorScraper):\n\n    jurisdiction = 'ca'\n\n    urls = {'upper': 'http://senate.ca.gov/senators',\n            'lower': 'http://assembly.ca.gov/assemblymembers'}\n\n    def scrape(self, chamber, term):\n\n        url = self.urls[chamber]\n        html = self.get(url).text\n        doc = lxml.html.fromstring(html)\n\n        if chamber == 'lower':\n            rows = doc.xpath('//table/tbody/tr')\n            parse = self.parse_assembly\n        else:\n            rows = doc.xpath('//div[contains(@class, \"views-row\")]')\n            parse = self.parse_senate\n\n        for tr in rows:\n            legislator = parse(tr, term, chamber)\n            if legislator is None:\n                continue\n            if 'Vacant' in legislator['full_name']:\n                continue\n\n            legislator.add_source(url)\n            legislator['full_name'] = legislator['full_name'].strip()\n            self.save_legislator(legislator)\n\n    def parse_senate(self, div, term, chamber):\n        name = div.xpath('.//h3/text()')[0]\n        if name.endswith(' (R)'):\n            party = 'Republican'\n        elif name.endswith(' (D)'):\n            party = 'Democratic'\n        else:\n            self.warning('skipping ' + name)\n            return None\n        name = name.split(' (')[0]\n\n        district = div.xpath(\n            './/div[contains(@class, \"senator-district\")]/div/text()'\n        )[0].strip().lstrip('0')\n        photo_url = div.xpath('.//img/@src')[0]\n        url = div.xpath('.//a/@href')[0]\n\n        leg = Legislator(term, chamber, full_name=name, party=party, district=district,\n                         photo_url=photo_url, url=url)\n\n        # CA senators have working emails, but they're not putting them on\n        # their public pages anymore\n        email = self._construct_email(chamber, name)\n\n        for addr in div.xpath('.//div[contains(@class, \"views-field-field-senator-capitol-office\")]//p'):\n            addr, phone = addr.text_content().split('; ')\n            leg.add_office(\n                'capitol', 'Senate Office',\n                address=addr.strip(), phone=phone.strip(), email=email)\n\n        for addr in div.xpath('.//div[contains(@class, \"views-field-field-senator-district-office\")]//p'):\n            for addr in addr.text_content().strip().splitlines():\n                try:\n                    addr, phone = addr.strip().replace(u'\\xa0', ' ').split('; ')\n                    leg.add_office(\n                        'district', 'District Office',\n                        address=addr.strip(), phone=phone.strip())\n                except ValueError:\n                    addr = addr.strip().replace(u'\\xa0', ' ')\n                    leg.add_office('district', 'District Office', address=addr)\n\n        return leg\n\n    def parse_assembly(self, tr, term, chamber):\n        '''\n        Given a tr element, get specific data from it.\n        '''\n\n        strip = methodcaller('strip')\n\n        xpath = 'td[contains(@class, \"views-field-field-%s-%s\")]%s'\n\n        xp = {\n            'url':       [('lname-sort', '/a[not(contains(text(), \"edit\"))]/@href')],\n            'district':  [('district', '/text()')],\n            'party':     [('party', '/text()')],\n            'full_name': [('office-information', '/a[not(contains(text(), \"edit\"))]/text()')],\n            'address':   [('office-information', '/h3/following-sibling::text()'),\n                          ('office-information', '/p/text()')]\n            }\n\n        titles = {'upper': 'senator', 'lower': 'member'}\n\n        funcs = {\n            'full_name': lambda s: re.sub( # \"Assembly\" is misspelled once\n                r'Contact Assembl?y Member', '', s).strip(),\n            'address': parse_address,\n        }\n\n        rubberstamp = lambda _: _\n        tr_xpath = tr.xpath\n        res = collections.defaultdict(list)\n        for k, xpath_info in xp.items():\n            for vals in xpath_info:\n                f = funcs.get(k, rubberstamp)\n                vals = (titles[chamber],) + vals\n                vals = map(f, map(strip, tr_xpath(xpath % vals)))\n                res[k].extend(vals)\n\n        # Photo.\n        try:\n            res['photo_url'] = tr_xpath('td/p/img/@src')[0]\n        except IndexError:\n            pass\n\n        # Remove junk from assembly member names.\n        junk = 'Contact Assembly Member '\n\n        try:\n            res['full_name'] = res['full_name'].pop().replace(junk, '')\n        except IndexError:\n            return\n\n        # Addresses.\n        addresses = res['address']\n        try:\n            addresses = map(dict, filter(None, addresses))\n        except ValueError:\n            # Sometimes legislators only have one address, in which\n            # case this awful hack is helpful.\n            addresses = map(dict, filter(None, [addresses]))\n\n        for address in addresses[:]:\n\n            # Toss results that don't have required keys.\n            if not set(['street', 'city', 'state_zip']) < set(address):\n                if address in addresses:\n                    addresses.remove(address)\n\n        # Re-key the addresses\n        offices = []\n        if addresses:\n            # Mariko Yamada's addresses wouldn't parse correctly as of\n            # 3/23/2013, so here we're forced to test whether any\n            # addresses were even found.\n            addresses[0].update(type='capitol', name='Capitol Office')\n            offices.append(addresses[0])\n\n            # CA reps have working emails, but they're not putting them on\n            # their public pages anymore\n            offices[0]['email'] = \\\n                  self._construct_email(chamber, res['full_name'])\n\n            for office in addresses[1:]:\n                office.update(type='district', name='District Office')\n                offices.append(office)\n\n            for office in offices:\n                street = office['street']\n                state_zip = re.sub(r'\\s+', ' ', office['state_zip'])\n                street = '%s\\n%s, %s' % (street, office['city'], state_zip)\n                office['address'] = street\n                office['fax'] = None\n                if 'email' not in office:\n                    office['email'] = None\n\n                del office['street'], office['city'], office['state_zip']\n\n        res['offices'] = offices\n        del res['address']\n\n        # Normalize party.\n        for party in res['party'][:]:\n            if party:\n                if party == 'Democrat':\n                    party = 'Democratic'\n                res['party'] = party\n                break\n            else:\n                res['party'] = None\n\n        # Mariko Yamada also didn't have a url that lxml would parse\n        # as of 3/22/2013.\n        if res['url']:\n            res['url'] = res['url'].pop()\n        else:\n            del res['url']\n\n        # strip leading zero\n        res['district'] = str(int(res['district'].pop()))\n\n        # Add a source for the url.\n        leg = Legislator(term, chamber, **res)\n        leg.update(**res)\n\n        return leg\n\n    def _construct_email(self, chamber, full_name):\n        last_name = re.split(r'\\s+', full_name)[-1].lower()\n\n        # translate accents to non-accented versions for use in an\n        # email and drop apostrophes\n        last_name = ''.join(c for c in\n                            unicodedata.normalize('NFD', unicode(last_name))\n                            if unicodedata.category(c) != 'Mn')\n        last_name = last_name.replace(\"'\", \"\")\n\n        if chamber == 'lower':\n            return 'assemblymember.' +  last_name + '@assembly.ca.gov'\n        else:\n            return 'senator.' +  last_name + '@senator.ca.gov'\n", "path": "openstates/ca/legislators.py"}]}