We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
GA votes need name matching
The GA state senate is missing votes (e.g., [GAV00006507](https://openstates.org/ga/votes/GAV00006507/) doesn't have a single vote) **and** the state Assembly is missing votes (e.g., [GAV00006524](https://openstates.org/ga/votes/GAV00006524/) doesn't have a single vote). This appears quite widespread for the current term in GA, that votes seem to be missing on nearly every motion.

**Addendum.** The problem appears to be the clerks record votes as "LAST NAME, district number" which messes up the vote parsing. But if we simply remove the ", district number" part of the string, the votes are identified with the legislator correctly, which seems to fix the problem.

--- 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/ga/bills.py`
Content:
```
1 from collections import defaultdict
2 
3 from pupa.scrape import Scraper, Bill, VoteEvent
4 
5 from .util import get_client, get_url, backoff, SESSION_SITE_IDS
6 
7 #         Methods (7):
8 #            GetLegislationDetail(xs:int LegislationId, )
9 #
10 #            GetLegislationDetailByDescription(ns2:DocumentType DocumentType,
11 #                                              xs:int Number, xs:int SessionId)
12 #
13 #            GetLegislationForSession(xs:int SessionId, )
14 #
15 #            GetLegislationRange(ns2:LegislationIndexRangeSet Range, )
16 #
17 #            GetLegislationRanges(xs:int SessionId,
18 #                           ns2:DocumentType DocumentType, xs:int RangeSize, )
19 #
20 #            GetLegislationSearchResultsPaged(ns2:LegislationSearchConstraints
21 #                                               Constraints, xs:int PageSize,
22 #                                               xs:int StartIndex, )
23 #            GetTitles()
24 
25 
26 member_cache = {}
27 SOURCE_URL = 'http://www.legis.ga.gov/Legislation/en-US/display/{session}/{bid}'
28 
29 
30 class GABillScraper(Scraper):
31     lservice = get_client('Legislation').service
32     vservice = get_client('Votes').service
33     mservice = get_client('Members').service
34     lsource = get_url('Legislation')
35     msource = get_url('Members')
36     vsource = get_url('Votes')
37 
38     def get_member(self, member_id):
39         if member_id in member_cache:
40             return member_cache[member_id]
41 
42         mem = backoff(self.mservice.GetMember, member_id)
43         member_cache[member_id] = mem
44         return mem
45 
46     def scrape(self, session=None, chamber=None):
47         bill_type_map = {
48             'B': 'bill',
49             'R': 'resolution',
50             'JR': 'joint resolution',
51             'CR': 'concurrent resolution',
52         }
53 
54         chamber_map = {
55             'H': 'lower',
56             'S': 'upper',
57             'J': 'joint',
58             'E': 'legislature',  # Effective date
59         }
60 
61         action_code_map = {
62             'HI': None,
63             'SI': None,
64             'HH': None,
65             'SH': None,
66             'HPF': ['introduction'],
67             'HDSAS': None,
68             'SPF': ['introduction'],
69             'HSR': ['reading-2'],
70             'SSR': ['reading-2'],
71             'HFR': ['reading-1'],
72             'SFR': ['reading-1'],
73             'HRECM': ['withdrawal', 'referral-committee'],
74             'SRECM': ['withdrawal', 'referral-committee'],
75             'SW&C': ['withdrawal', 'referral-committee'],
76             'HW&C': ['withdrawal', 'referral-committee'],
77             'HRA': ['passage'],
78             'SRA': ['passage'],
79             'HPA': ['passage'],
80             'HRECO': None,
81             'SPA': ['passage'],
82             'HTABL': None,  # 'House Tabled' - what is this?
83             'SDHAS': None,
84             'HCFR': ['committee-passage-favorable'],
85             'SCFR': ['committee-passage-favorable'],
86             'HRAR': ['referral-committee'],
87             'SRAR': ['referral-committee'],
88             'STR': ['reading-3'],
89             'SAHAS': None,
90             'SE': ['passage'],
91             'SR': ['referral-committee'],
92             'HTRL': ['reading-3', 'failure'],
93             'HTR': ['reading-3'],
94             'S3RLT': ['reading-3', 'failure'],
95             'HASAS': None,
96             'S3RPP': None,
97             'STAB': None,
98             'SRECO': None,
99             'SAPPT': None,
100             'HCA': None,
101             'HNOM': None,
102             'HTT': None,
103             'STT': None,
104             'SRECP': None,
105             'SCRA': None,
106             'SNOM': None,
107             'S2R': ['reading-2'],
108             'H2R': ['reading-2'],
109             'SENG': ['passage'],
110             'HENG': ['passage'],
111             'HPOST': None,
112             'HCAP': None,
113             'SDSG': ['executive-signature'],
114             'SSG': ['executive-receipt'],
115             'Signed Gov': ['executive-signature'],
116             'HDSG': ['executive-signature'],
117             'HSG': ['executive-receipt'],
118             'EFF': None,
119             'HRP': None,
120             'STH': None,
121             'HTS': None,
122         }
123 
124         if not session:
125             session = self.latest_session()
126             self.info('no session specified, using %s', session)
127         sid = SESSION_SITE_IDS[session]
128 
129         legislation = backoff(
130             self.lservice.GetLegislationForSession,
131             sid
132         )['LegislationIndex']
133 
134         for leg in legislation:
135             lid = leg['Id']
136             instrument = backoff(self.lservice.GetLegislationDetail, lid)
137             history = [x for x in instrument['StatusHistory'][0]]
138 
139             actions = reversed([{
140                 'code': x['Code'],
141                 'action': x['Description'],
142                 '_guid': x['Id'],
143                 'date': x['Date']
144             } for x in history])
145 
146             guid = instrument['Id']
147 
148             # A little bit hacky.
149             bill_prefix = instrument['DocumentType']
150             bill_chamber = chamber_map[bill_prefix[0]]
151             bill_type = bill_type_map[bill_prefix[1:]]
152 
153             bill_id = '%s %s' % (
154                 bill_prefix,
155                 instrument['Number'],
156             )
157             if instrument['Suffix']:
158                 bill_id += instrument['Suffix']
159 
160             title = instrument['Caption']
161             description = instrument['Summary']
162 
163             if title is None:
164                 continue
165 
166             bill = Bill(
167                 bill_id, legislative_session=session, chamber=bill_chamber, title=title,
168                 classification=bill_type)
169             bill.add_abstract(description, note='description')
170             bill.extras = {'guid': guid}
171 
172             if instrument['Votes']:
173                 for vote_ in instrument['Votes']:
174                     _, vote_ = vote_
175                     vote_ = backoff(self.vservice.GetVote, vote_[0]['VoteId'])
176 
177                     vote = VoteEvent(
178                         start_date=vote_['Date'].strftime('%Y-%m-%d'),
179                         motion_text=vote_['Caption'] or 'Vote on Bill',
180                         chamber={'House': 'lower', 'Senate': 'upper'}[vote_['Branch']],
181                         result='pass' if vote_['Yeas'] > vote_['Nays'] else 'fail',
182                         classification='passage',
183                         bill=bill,
184                     )
185                     vote.set_count('yes', vote_['Yeas'])
186                     vote.set_count('no', vote_['Nays'])
187                     vote.set_count('other', vote_['Excused'] + vote_['NotVoting'])
188 
189                     vote.add_source(self.vsource)
190 
191                     methods = {'Yea': 'yes', 'Nay': 'no'}
192 
193                     for vdetail in vote_['Votes'][0]:
194                         whom = vdetail['Member']
195                         how = vdetail['MemberVoted']
196                         vote.vote(methods.get(how, 'other'), whom['Name'])
197 
198                     yield vote
199 
200             ccommittees = defaultdict(list)
201             committees = instrument['Committees']
202             if committees:
203                 for committee in committees[0]:
204                     ccommittees[{
205                         'House': 'lower',
206                         'Senate': 'upper',
207                     }[committee['Type']]].append(committee['Name'])
208 
209             for action in actions:
210                 action_chamber = chamber_map[action['code'][0]]
211 
212                 try:
213                     action_types = action_code_map[action['code']]
214                 except KeyError:
215                     error_msg = 'Code {code} for action {action} not recognized.'.format(
216                         code=action['code'], action=action['action'])
217 
218                     self.logger.warning(error_msg)
219 
220                     action_types = None
221 
222                 committees = []
223                 if action_types and any(('committee' in x for x in action_types)):
224                     committees = [str(x) for x in ccommittees.get(
225                         action_chamber, [])]
226 
227                 act = bill.add_action(
228                     action['action'], action['date'].strftime('%Y-%m-%d'),
229                     classification=action_types,
230                     chamber=action_chamber)
231                 for committee in committees:
232                     act.add_related_entity(committee, 'organization')
233                 act.extras = {
234                     'code': action['code'],
235                     'guid': action['_guid'],
236                 }
237 
238             sponsors = []
239             if instrument['Authors']:
240                 sponsors = instrument['Authors']['Sponsorship']
241                 if 'Sponsors' in instrument and instrument['Sponsors']:
242                     sponsors += instrument['Sponsors']['Sponsorship']
243 
244             sponsors = [
245                 (x['Type'], self.get_member(x['MemberId'])) for x in sponsors
246             ]
247 
248             for typ, sponsor in sponsors:
249                 name = '{First} {Last}'.format(**dict(sponsor['Name']))
250                 bill.add_sponsorship(
251                     name,
252                     entity_type='person',
253                     classification='primary' if 'Author' in typ else 'secondary',
254                     primary='Author' in typ,
255                 )
256 
257             for version in instrument['Versions']['DocumentDescription']:
258                 name, url, doc_id, version_id = [
259                     version[x] for x in [
260                         'Description',
261                         'Url',
262                         'Id',
263                         'Version'
264                     ]
265                 ]
266                 # link = bill.add_version_link(
267                 #     name, url, media_type='application/pdf')
268                 # link['extras'] = {
269                 #     '_internal_document_id': doc_id,
270                 #     '_version_id': version_id
271                 # }
272 
273             bill.add_source(self.msource)
274             bill.add_source(self.lsource)
275             bill.add_source(SOURCE_URL.format(**{
276                 'session': session,
277                 'bid': guid,
278             }))
279 
280             yield bill
281
```
--- 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/ga/bills.py b/openstates/ga/bills.py
--- a/openstates/ga/bills.py
+++ b/openstates/ga/bills.py
@@ -1,3 +1,4 @@
+import re
 from collections import defaultdict
 
 from pupa.scrape import Scraper, Bill, VoteEvent
@@ -26,6 +27,8 @@
 member_cache = {}
 SOURCE_URL = 'http://www.legis.ga.gov/Legislation/en-US/display/{session}/{bid}'
 
+vote_name_pattern = re.compile(r'(.*), (\d+(?:ST|ND|RD|TH))', re.IGNORECASE)
+
 
 class GABillScraper(Scraper):
     lservice = get_client('Legislation').service
@@ -193,7 +196,10 @@
                     for vdetail in vote_['Votes'][0]:
                         whom = vdetail['Member']
                         how = vdetail['MemberVoted']
-                        vote.vote(methods.get(how, 'other'), whom['Name'])
+                        if whom['Name'] == 'VACANT':
+                            continue
+                        name, district = vote_name_pattern.search(whom['Name']).groups()
+                        vote.vote(methods.get(how, 'other'), name, note=district)
 
                     yield vote

{"golden_diff": "diff --git a/openstates/ga/bills.py b/openstates/ga/bills.py\n--- a/openstates/ga/bills.py\n+++ b/openstates/ga/bills.py\n@@ -1,3 +1,4 @@\n+import re\n from collections import defaultdict\n \n from pupa.scrape import Scraper, Bill, VoteEvent\n@@ -26,6 +27,8 @@\n member_cache = {}\n SOURCE_URL = 'http://www.legis.ga.gov/Legislation/en-US/display/{session}/{bid}'\n \n+vote_name_pattern = re.compile(r'(.*), (\\d+(?:ST|ND|RD|TH))', re.IGNORECASE)\n+\n \n class GABillScraper(Scraper):\n     lservice = get_client('Legislation').service\n@@ -193,7 +196,10 @@\n                     for vdetail in vote_['Votes'][0]:\n                         whom = vdetail['Member']\n                         how = vdetail['MemberVoted']\n-                        vote.vote(methods.get(how, 'other'), whom['Name'])\n+                        if whom['Name'] == 'VACANT':\n+                            continue\n+                        name, district = vote_name_pattern.search(whom['Name']).groups()\n+                        vote.vote(methods.get(how, 'other'), name, note=district)\n \n                     yield vote\n", "issue": "GA votes need name matching\nThe GA state senate is missing votes (e.g., [GAV00006507](https://openstates.org/ga/votes/GAV00006507/) doesn't have a single vote) **and** the state Assembly is missing votes (e.g., [GAV00006524](https://openstates.org/ga/votes/GAV00006524/) doesn't have a single vote). This appears quite widespread for the current term in GA, that votes seem to be missing on nearly every motion.\r\n\r\n**Addendum.** The problem appears to be the clerks record votes as \"LAST NAME, district number\" which messes up the vote parsing. But if we simply remove the \", district number\" part of the string, the votes are identified with the legislator correctly, which seems to fix the problem.\n", "before_files": [{"content": "from collections import defaultdict\n\nfrom pupa.scrape import Scraper, Bill, VoteEvent\n\nfrom .util import get_client, get_url, backoff, SESSION_SITE_IDS\n\n#         Methods (7):\n#            GetLegislationDetail(xs:int LegislationId, )\n#\n#            GetLegislationDetailByDescription(ns2:DocumentType DocumentType,\n#                                              xs:int Number, xs:int SessionId)\n#\n#            GetLegislationForSession(xs:int SessionId, )\n#\n#            GetLegislationRange(ns2:LegislationIndexRangeSet Range, )\n#\n#            GetLegislationRanges(xs:int SessionId,\n#                           ns2:DocumentType DocumentType, xs:int RangeSize, )\n#\n#            GetLegislationSearchResultsPaged(ns2:LegislationSearchConstraints\n#                                               Constraints, xs:int PageSize,\n#                                               xs:int StartIndex, )\n#            GetTitles()\n\n\nmember_cache = {}\nSOURCE_URL = 'http://www.legis.ga.gov/Legislation/en-US/display/{session}/{bid}'\n\n\nclass GABillScraper(Scraper):\n    lservice = get_client('Legislation').service\n    vservice = get_client('Votes').service\n    mservice = get_client('Members').service\n    lsource = get_url('Legislation')\n    msource = get_url('Members')\n    vsource = get_url('Votes')\n\n    def get_member(self, member_id):\n        if member_id in member_cache:\n            return member_cache[member_id]\n\n        mem = backoff(self.mservice.GetMember, member_id)\n        member_cache[member_id] = mem\n        return mem\n\n    def scrape(self, session=None, chamber=None):\n        bill_type_map = {\n            'B': 'bill',\n            'R': 'resolution',\n            'JR': 'joint resolution',\n            'CR': 'concurrent resolution',\n        }\n\n        chamber_map = {\n            'H': 'lower',\n            'S': 'upper',\n            'J': 'joint',\n            'E': 'legislature',  # Effective date\n        }\n\n        action_code_map = {\n            'HI': None,\n            'SI': None,\n            'HH': None,\n            'SH': None,\n            'HPF': ['introduction'],\n            'HDSAS': None,\n            'SPF': ['introduction'],\n            'HSR': ['reading-2'],\n            'SSR': ['reading-2'],\n            'HFR': ['reading-1'],\n            'SFR': ['reading-1'],\n            'HRECM': ['withdrawal', 'referral-committee'],\n            'SRECM': ['withdrawal', 'referral-committee'],\n            'SW&C': ['withdrawal', 'referral-committee'],\n            'HW&C': ['withdrawal', 'referral-committee'],\n            'HRA': ['passage'],\n            'SRA': ['passage'],\n            'HPA': ['passage'],\n            'HRECO': None,\n            'SPA': ['passage'],\n            'HTABL': None,  # 'House Tabled' - what is this?\n            'SDHAS': None,\n            'HCFR': ['committee-passage-favorable'],\n            'SCFR': ['committee-passage-favorable'],\n            'HRAR': ['referral-committee'],\n            'SRAR': ['referral-committee'],\n            'STR': ['reading-3'],\n            'SAHAS': None,\n            'SE': ['passage'],\n            'SR': ['referral-committee'],\n            'HTRL': ['reading-3', 'failure'],\n            'HTR': ['reading-3'],\n            'S3RLT': ['reading-3', 'failure'],\n            'HASAS': None,\n            'S3RPP': None,\n            'STAB': None,\n            'SRECO': None,\n            'SAPPT': None,\n            'HCA': None,\n            'HNOM': None,\n            'HTT': None,\n            'STT': None,\n            'SRECP': None,\n            'SCRA': None,\n            'SNOM': None,\n            'S2R': ['reading-2'],\n            'H2R': ['reading-2'],\n            'SENG': ['passage'],\n            'HENG': ['passage'],\n            'HPOST': None,\n            'HCAP': None,\n            'SDSG': ['executive-signature'],\n            'SSG': ['executive-receipt'],\n            'Signed Gov': ['executive-signature'],\n            'HDSG': ['executive-signature'],\n            'HSG': ['executive-receipt'],\n            'EFF': None,\n            'HRP': None,\n            'STH': None,\n            'HTS': None,\n        }\n\n        if not session:\n            session = self.latest_session()\n            self.info('no session specified, using %s', session)\n        sid = SESSION_SITE_IDS[session]\n\n        legislation = backoff(\n            self.lservice.GetLegislationForSession,\n            sid\n        )['LegislationIndex']\n\n        for leg in legislation:\n            lid = leg['Id']\n            instrument = backoff(self.lservice.GetLegislationDetail, lid)\n            history = [x for x in instrument['StatusHistory'][0]]\n\n            actions = reversed([{\n                'code': x['Code'],\n                'action': x['Description'],\n                '_guid': x['Id'],\n                'date': x['Date']\n            } for x in history])\n\n            guid = instrument['Id']\n\n            # A little bit hacky.\n            bill_prefix = instrument['DocumentType']\n            bill_chamber = chamber_map[bill_prefix[0]]\n            bill_type = bill_type_map[bill_prefix[1:]]\n\n            bill_id = '%s %s' % (\n                bill_prefix,\n                instrument['Number'],\n            )\n            if instrument['Suffix']:\n                bill_id += instrument['Suffix']\n\n            title = instrument['Caption']\n            description = instrument['Summary']\n\n            if title is None:\n                continue\n\n            bill = Bill(\n                bill_id, legislative_session=session, chamber=bill_chamber, title=title,\n                classification=bill_type)\n            bill.add_abstract(description, note='description')\n            bill.extras = {'guid': guid}\n\n            if instrument['Votes']:\n                for vote_ in instrument['Votes']:\n                    _, vote_ = vote_\n                    vote_ = backoff(self.vservice.GetVote, vote_[0]['VoteId'])\n\n                    vote = VoteEvent(\n                        start_date=vote_['Date'].strftime('%Y-%m-%d'),\n                        motion_text=vote_['Caption'] or 'Vote on Bill',\n                        chamber={'House': 'lower', 'Senate': 'upper'}[vote_['Branch']],\n                        result='pass' if vote_['Yeas'] > vote_['Nays'] else 'fail',\n                        classification='passage',\n                        bill=bill,\n                    )\n                    vote.set_count('yes', vote_['Yeas'])\n                    vote.set_count('no', vote_['Nays'])\n                    vote.set_count('other', vote_['Excused'] + vote_['NotVoting'])\n\n                    vote.add_source(self.vsource)\n\n                    methods = {'Yea': 'yes', 'Nay': 'no'}\n\n                    for vdetail in vote_['Votes'][0]:\n                        whom = vdetail['Member']\n                        how = vdetail['MemberVoted']\n                        vote.vote(methods.get(how, 'other'), whom['Name'])\n\n                    yield vote\n\n            ccommittees = defaultdict(list)\n            committees = instrument['Committees']\n            if committees:\n                for committee in committees[0]:\n                    ccommittees[{\n                        'House': 'lower',\n                        'Senate': 'upper',\n                    }[committee['Type']]].append(committee['Name'])\n\n            for action in actions:\n                action_chamber = chamber_map[action['code'][0]]\n\n                try:\n                    action_types = action_code_map[action['code']]\n                except KeyError:\n                    error_msg = 'Code {code} for action {action} not recognized.'.format(\n                        code=action['code'], action=action['action'])\n\n                    self.logger.warning(error_msg)\n\n                    action_types = None\n\n                committees = []\n                if action_types and any(('committee' in x for x in action_types)):\n                    committees = [str(x) for x in ccommittees.get(\n                        action_chamber, [])]\n\n                act = bill.add_action(\n                    action['action'], action['date'].strftime('%Y-%m-%d'),\n                    classification=action_types,\n                    chamber=action_chamber)\n                for committee in committees:\n                    act.add_related_entity(committee, 'organization')\n                act.extras = {\n                    'code': action['code'],\n                    'guid': action['_guid'],\n                }\n\n            sponsors = []\n            if instrument['Authors']:\n                sponsors = instrument['Authors']['Sponsorship']\n                if 'Sponsors' in instrument and instrument['Sponsors']:\n                    sponsors += instrument['Sponsors']['Sponsorship']\n\n            sponsors = [\n                (x['Type'], self.get_member(x['MemberId'])) for x in sponsors\n            ]\n\n            for typ, sponsor in sponsors:\n                name = '{First} {Last}'.format(**dict(sponsor['Name']))\n                bill.add_sponsorship(\n                    name,\n                    entity_type='person',\n                    classification='primary' if 'Author' in typ else 'secondary',\n                    primary='Author' in typ,\n                )\n\n            for version in instrument['Versions']['DocumentDescription']:\n                name, url, doc_id, version_id = [\n                    version[x] for x in [\n                        'Description',\n                        'Url',\n                        'Id',\n                        'Version'\n                    ]\n                ]\n                # link = bill.add_version_link(\n                #     name, url, media_type='application/pdf')\n                # link['extras'] = {\n                #     '_internal_document_id': doc_id,\n                #     '_version_id': version_id\n                # }\n\n            bill.add_source(self.msource)\n            bill.add_source(self.lsource)\n            bill.add_source(SOURCE_URL.format(**{\n                'session': session,\n                'bid': guid,\n            }))\n\n            yield bill\n", "path": "openstates/ga/bills.py"}], "after_files": [{"content": "import re\nfrom collections import defaultdict\n\nfrom pupa.scrape import Scraper, Bill, VoteEvent\n\nfrom .util import get_client, get_url, backoff, SESSION_SITE_IDS\n\n#         Methods (7):\n#            GetLegislationDetail(xs:int LegislationId, )\n#\n#            GetLegislationDetailByDescription(ns2:DocumentType DocumentType,\n#                                              xs:int Number, xs:int SessionId)\n#\n#            GetLegislationForSession(xs:int SessionId, )\n#\n#            GetLegislationRange(ns2:LegislationIndexRangeSet Range, )\n#\n#            GetLegislationRanges(xs:int SessionId,\n#                           ns2:DocumentType DocumentType, xs:int RangeSize, )\n#\n#            GetLegislationSearchResultsPaged(ns2:LegislationSearchConstraints\n#                                               Constraints, xs:int PageSize,\n#                                               xs:int StartIndex, )\n#            GetTitles()\n\n\nmember_cache = {}\nSOURCE_URL = 'http://www.legis.ga.gov/Legislation/en-US/display/{session}/{bid}'\n\nvote_name_pattern = re.compile(r'(.*), (\\d+(?:ST|ND|RD|TH))', re.IGNORECASE)\n\n\nclass GABillScraper(Scraper):\n    lservice = get_client('Legislation').service\n    vservice = get_client('Votes').service\n    mservice = get_client('Members').service\n    lsource = get_url('Legislation')\n    msource = get_url('Members')\n    vsource = get_url('Votes')\n\n    def get_member(self, member_id):\n        if member_id in member_cache:\n            return member_cache[member_id]\n\n        mem = backoff(self.mservice.GetMember, member_id)\n        member_cache[member_id] = mem\n        return mem\n\n    def scrape(self, session=None, chamber=None):\n        bill_type_map = {\n            'B': 'bill',\n            'R': 'resolution',\n            'JR': 'joint resolution',\n            'CR': 'concurrent resolution',\n        }\n\n        chamber_map = {\n            'H': 'lower',\n            'S': 'upper',\n            'J': 'joint',\n            'E': 'legislature',  # Effective date\n        }\n\n        action_code_map = {\n            'HI': None,\n            'SI': None,\n            'HH': None,\n            'SH': None,\n            'HPF': ['introduction'],\n            'HDSAS': None,\n            'SPF': ['introduction'],\n            'HSR': ['reading-2'],\n            'SSR': ['reading-2'],\n            'HFR': ['reading-1'],\n            'SFR': ['reading-1'],\n            'HRECM': ['withdrawal', 'referral-committee'],\n            'SRECM': ['withdrawal', 'referral-committee'],\n            'SW&C': ['withdrawal', 'referral-committee'],\n            'HW&C': ['withdrawal', 'referral-committee'],\n            'HRA': ['passage'],\n            'SRA': ['passage'],\n            'HPA': ['passage'],\n            'HRECO': None,\n            'SPA': ['passage'],\n            'HTABL': None,  # 'House Tabled' - what is this?\n            'SDHAS': None,\n            'HCFR': ['committee-passage-favorable'],\n            'SCFR': ['committee-passage-favorable'],\n            'HRAR': ['referral-committee'],\n            'SRAR': ['referral-committee'],\n            'STR': ['reading-3'],\n            'SAHAS': None,\n            'SE': ['passage'],\n            'SR': ['referral-committee'],\n            'HTRL': ['reading-3', 'failure'],\n            'HTR': ['reading-3'],\n            'S3RLT': ['reading-3', 'failure'],\n            'HASAS': None,\n            'S3RPP': None,\n            'STAB': None,\n            'SRECO': None,\n            'SAPPT': None,\n            'HCA': None,\n            'HNOM': None,\n            'HTT': None,\n            'STT': None,\n            'SRECP': None,\n            'SCRA': None,\n            'SNOM': None,\n            'S2R': ['reading-2'],\n            'H2R': ['reading-2'],\n            'SENG': ['passage'],\n            'HENG': ['passage'],\n            'HPOST': None,\n            'HCAP': None,\n            'SDSG': ['executive-signature'],\n            'SSG': ['executive-receipt'],\n            'Signed Gov': ['executive-signature'],\n            'HDSG': ['executive-signature'],\n            'HSG': ['executive-receipt'],\n            'EFF': None,\n            'HRP': None,\n            'STH': None,\n            'HTS': None,\n        }\n\n        if not session:\n            session = self.latest_session()\n            self.info('no session specified, using %s', session)\n        sid = SESSION_SITE_IDS[session]\n\n        legislation = backoff(\n            self.lservice.GetLegislationForSession,\n            sid\n        )['LegislationIndex']\n\n        for leg in legislation:\n            lid = leg['Id']\n            instrument = backoff(self.lservice.GetLegislationDetail, lid)\n            history = [x for x in instrument['StatusHistory'][0]]\n\n            actions = reversed([{\n                'code': x['Code'],\n                'action': x['Description'],\n                '_guid': x['Id'],\n                'date': x['Date']\n            } for x in history])\n\n            guid = instrument['Id']\n\n            # A little bit hacky.\n            bill_prefix = instrument['DocumentType']\n            bill_chamber = chamber_map[bill_prefix[0]]\n            bill_type = bill_type_map[bill_prefix[1:]]\n\n            bill_id = '%s %s' % (\n                bill_prefix,\n                instrument['Number'],\n            )\n            if instrument['Suffix']:\n                bill_id += instrument['Suffix']\n\n            title = instrument['Caption']\n            description = instrument['Summary']\n\n            if title is None:\n                continue\n\n            bill = Bill(\n                bill_id, legislative_session=session, chamber=bill_chamber, title=title,\n                classification=bill_type)\n            bill.add_abstract(description, note='description')\n            bill.extras = {'guid': guid}\n\n            if instrument['Votes']:\n                for vote_ in instrument['Votes']:\n                    _, vote_ = vote_\n                    vote_ = backoff(self.vservice.GetVote, vote_[0]['VoteId'])\n\n                    vote = VoteEvent(\n                        start_date=vote_['Date'].strftime('%Y-%m-%d'),\n                        motion_text=vote_['Caption'] or 'Vote on Bill',\n                        chamber={'House': 'lower', 'Senate': 'upper'}[vote_['Branch']],\n                        result='pass' if vote_['Yeas'] > vote_['Nays'] else 'fail',\n                        classification='passage',\n                        bill=bill,\n                    )\n                    vote.set_count('yes', vote_['Yeas'])\n                    vote.set_count('no', vote_['Nays'])\n                    vote.set_count('other', vote_['Excused'] + vote_['NotVoting'])\n\n                    vote.add_source(self.vsource)\n\n                    methods = {'Yea': 'yes', 'Nay': 'no'}\n\n                    for vdetail in vote_['Votes'][0]:\n                        whom = vdetail['Member']\n                        how = vdetail['MemberVoted']\n                        if whom['Name'] == 'VACANT':\n                            continue\n                        name, district = vote_name_pattern.search(whom['Name']).groups()\n                        vote.vote(methods.get(how, 'other'), name, note=district)\n\n                    yield vote\n\n            ccommittees = defaultdict(list)\n            committees = instrument['Committees']\n            if committees:\n                for committee in committees[0]:\n                    ccommittees[{\n                        'House': 'lower',\n                        'Senate': 'upper',\n                    }[committee['Type']]].append(committee['Name'])\n\n            for action in actions:\n                action_chamber = chamber_map[action['code'][0]]\n\n                try:\n                    action_types = action_code_map[action['code']]\n                except KeyError:\n                    error_msg = 'Code {code} for action {action} not recognized.'.format(\n                        code=action['code'], action=action['action'])\n\n                    self.logger.warning(error_msg)\n\n                    action_types = None\n\n                committees = []\n                if action_types and any(('committee' in x for x in action_types)):\n                    committees = [str(x) for x in ccommittees.get(\n                        action_chamber, [])]\n\n                act = bill.add_action(\n                    action['action'], action['date'].strftime('%Y-%m-%d'),\n                    classification=action_types,\n                    chamber=action_chamber)\n                for committee in committees:\n                    act.add_related_entity(committee, 'organization')\n                act.extras = {\n                    'code': action['code'],\n                    'guid': action['_guid'],\n                }\n\n            sponsors = []\n            if instrument['Authors']:\n                sponsors = instrument['Authors']['Sponsorship']\n                if 'Sponsors' in instrument and instrument['Sponsors']:\n                    sponsors += instrument['Sponsors']['Sponsorship']\n\n            sponsors = [\n                (x['Type'], self.get_member(x['MemberId'])) for x in sponsors\n            ]\n\n            for typ, sponsor in sponsors:\n                name = '{First} {Last}'.format(**dict(sponsor['Name']))\n                bill.add_sponsorship(\n                    name,\n                    entity_type='person',\n                    classification='primary' if 'Author' in typ else 'secondary',\n                    primary='Author' in typ,\n                )\n\n            for version in instrument['Versions']['DocumentDescription']:\n                name, url, doc_id, version_id = [\n                    version[x] for x in [\n                        'Description',\n                        'Url',\n                        'Id',\n                        'Version'\n                    ]\n                ]\n                # link = bill.add_version_link(\n                #     name, url, media_type='application/pdf')\n                # link['extras'] = {\n                #     '_internal_document_id': doc_id,\n                #     '_version_id': version_id\n                # }\n\n            bill.add_source(self.msource)\n            bill.add_source(self.lsource)\n            bill.add_source(SOURCE_URL.format(**{\n                'session': session,\n                'bid': guid,\n            }))\n\n            yield bill\n", "path": "openstates/ga/bills.py"}]}