We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Missing author data on early CL journals
Authors are part of the titles, rather than having author fields. See for example: https://aclweb.org/anthology/events/cl-1979/
J79-J83 should be "American Journal of Computational Linguistics"
and changed its name only in 1984. The name "Computational Linguistics" is hard-coded, so I'm not sure if this is an easy change.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bin/anthology/papers.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright 2019 Marcel Bollmann <marcel@bollmann.me>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 #     http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 
17 import logging as log
18 from .people import PersonName
19 from .utils import (
20     infer_attachment_url,
21     remove_extra_whitespace,
22     is_journal,
23     is_volume_id,
24     to_volume_id,
25 )
26 from . import data
27 
28 # For BibTeX export
29 from .formatter import bibtex_encode, bibtex_make_entry
30 
31 # Names of XML elements that may appear multiple times
32 _LIST_ELEMENTS = ("attachment", "author", "editor", "video", "revision", "erratum")
33 
34 
35 class Paper:
36     def __init__(self, paper_id, top_level_id, formatter):
37         self.formatter = formatter
38         self.parent_volume = None
39         self.paper_id = paper_id
40         self.top_level_id = top_level_id
41         self.attrib = {}
42         self._bibkey = False
43 
44     def from_xml(xml_element, *args):
45         paper = Paper(xml_element.get("id"), *args)
46         paper._parse_element(xml_element)
47         paper.attrib["title"] = paper.get_title("plain")
48         if "booktitle" in paper.attrib:
49             paper.attrib["booktitle"] = paper.get_booktitle("plain")
50         if "editor" in paper.attrib:
51             if paper.is_volume:
52                 if "author" in paper.attrib:
53                     log.warn(
54                         "Paper {} has both <editor> and <author>; ignoring <author>".format(
55                             paper.full_id
56                         )
57                     )
58                 # Proceedings editors are considered authors for their front matter
59                 paper.attrib["author"] = paper.attrib["editor"]
60                 del paper.attrib["editor"]
61             else:
62                 log.warn(
63                     "Paper {} has <editor> but is not a proceedings volume; ignoring <editor>".format(
64                         paper.full_id
65                     )
66                 )
67         if "year" not in paper.attrib:
68             paper._infer_year()
69         if "pages" in paper.attrib:
70             if paper.attrib["pages"] is not None:
71                 paper._interpret_pages()
72             else:
73                 del paper.attrib["pages"]
74         return paper
75 
76     def _parse_element(self, paper_element):
77         # read & store values
78         if "href" in paper_element.attrib:
79             self.attrib["attrib_href"] = paper_element.get("href")
80             self.attrib["url"] = paper_element.get("href")
81         elif not (self.is_volume and is_journal(self.full_id)):
82             # Generate a URL, except for top-level journal entries
83             self.attrib["url"] = data.ANTHOLOGY_URL.format(self.full_id)
84         for element in paper_element:
85             # parse value
86             tag = element.tag.lower()
87             if tag in ("abstract", "title", "booktitle"):
88                 tag = "xml_{}".format(tag)
89                 value = element
90             elif tag == "attachment":
91                 value = {
92                     "filename": element.text,
93                     "type": element.get("type", "attachment"),
94                     "url": infer_attachment_url(element.text),
95                 }
96             elif tag in ("author", "editor"):
97                 value = PersonName.from_element(element)
98             elif tag in ("erratum", "revision"):
99                 if tag == "revision" and "revision" not in self.attrib:
100                     # Explicitly construct URL of original version of the paper
101                     # -- this is a bit hacky, but it's not given in the XML
102                     # explicitly
103                     self.attrib["revision"] = [
104                         {
105                             "value": "{}v1".format(self.full_id),
106                             "id": "1",
107                             "url": data.ANTHOLOGY_URL.format(
108                                 "{}v1".format(self.full_id)
109                             ),
110                         }
111                     ]
112                 value = {
113                     "value": element.text,
114                     "id": element.get("id"),
115                     "url": data.ANTHOLOGY_URL.format(element.text),
116                 }
117             elif tag == "mrf":
118                 value = {"filename": element.text, "src": element.get("src")}
119             elif tag == "video":
120                 # Treat videos the same way as other attachments
121                 tag = "attachment"
122                 value = {
123                     "filename": element.get("href"),
124                     "type": element.get("tag", "video"),
125                     "url": infer_attachment_url(element.get("href")),
126                 }
127             elif tag in ("dataset", "software"):
128                 value = {
129                     "filename": element.text,
130                     "type": tag,
131                     "url": infer_attachment_url(element.text),
132                 }
133                 tag = "attachment"
134             else:
135                 value = element.text
136             # store value
137             if tag == "url":
138                 continue  # We basically have to ignore this for now
139             if tag in _LIST_ELEMENTS:
140                 try:
141                     self.attrib[tag].append(value)
142                 except KeyError:
143                     self.attrib[tag] = [value]
144             else:
145                 if tag in self.attrib:
146                     log.warning(
147                         "{}: Unexpected multiple occurrence of '{}' element".format(
148                             self.full_id, tag
149                         )
150                     )
151                 self.attrib[tag] = value
152 
153     def _infer_year(self):
154         """Infer the year from the volume ID.
155 
156         Many paper entries do not explicitly contain their year.  This function assumes
157         that the paper's volume identifier follows the format 'xyy', where x is
158         some letter and yy are the last two digits of the year of publication.
159         """
160         assert (
161             len(self.top_level_id) == 3
162         ), "Couldn't infer year: unknown volume ID format"
163         digits = self.top_level_id[1:]
164         if int(digits) >= 60:
165             year = "19{}".format(digits)
166         else:
167             year = "20{}".format(digits)
168         self.attrib["year"] = year
169 
170     def _interpret_pages(self):
171         """Splits up 'pages' field into first and last page, if possible.
172 
173         This is used for metadata in the generated HTML."""
174         for s in ("--", "-", "–"):
175             if self.attrib["pages"].count(s) == 1:
176                 self.attrib["page_first"], self.attrib["page_last"] = self.attrib[
177                     "pages"
178                 ].split(s)
179                 self.attrib["pages"] = self.attrib["pages"].replace(s, "–")
180                 return
181 
182     @property
183     def is_volume(self):
184         """Determines if this paper is a regular paper or a proceedings volume.
185 
186         By default, each paper ID of format 'x000' will be treated as (the front
187         matter of) a proceedings volume, unless the XML is of type workshop,
188         where each paper ID of format 'xx00' is treated as one volume.
189         """
190         return is_volume_id(self.full_id)
191 
192     @property
193     def full_id(self):
194         return "{}-{}".format(self.top_level_id, self.paper_id)
195 
196     @property
197     def bibkey(self):
198         if not self._bibkey:
199             self._bibkey = self.full_id  # fallback
200         return self._bibkey
201 
202     @bibkey.setter
203     def bibkey(self, value):
204         self._bibkey = value
205 
206     @property
207     def bibtype(self):
208         if is_journal(self.full_id):
209             return "article"
210         elif self.is_volume:
211             return "proceedings"
212         else:
213             return "inproceedings"
214 
215     @property
216     def parent_volume_id(self):
217         if self.parent_volume is not None:
218             return self.parent_volume.full_id
219         return None
220 
221     def get(self, name, default=None):
222         try:
223             return self.attrib[name]
224         except KeyError:
225             return default
226 
227     def get_title(self, form="xml"):
228         """Returns the paper title, optionally formatting it.
229 
230         Accepted formats:
231           - xml:   Include any contained XML tags unchanged
232           - plain: Strip all XML tags, returning only plain text
233           - html:  Convert XML tags into valid HTML tags
234           - latex: Convert XML tags into LaTeX commands
235         """
236         return self.formatter(self.get("xml_title"), form)
237 
238     def get_abstract(self, form="xml"):
239         """Returns the abstract, optionally formatting it.
240 
241         See `get_title()` for details.
242         """
243         return self.formatter(self.get("xml_abstract"), form, allow_url=True)
244 
245     def get_booktitle(self, form="xml"):
246         """Returns the booktitle, optionally formatting it.
247 
248         See `get_title()` for details.
249         """
250         return self.formatter(self.get("xml_booktitle"), form)
251 
252     def as_bibtex(self):
253         """Return the BibTeX entry for this paper."""
254         # Build BibTeX entry
255         bibkey = self.bibkey
256         bibtype = self.bibtype
257         entries = [("title", self.get_title(form="latex"))]
258         for people in ("author", "editor"):
259             if people in self.attrib:
260                 entries.append(
261                     (people, "  and  ".join(p.as_bibtex() for p in self.get(people)))
262                 )
263         if is_journal(self.full_id):
264             entries.append(
265                 ("journal", bibtex_encode(self.parent_volume.get("meta_journal_title")))
266             )
267             journal_volume = self.parent_volume.get(
268                 "meta_volume", self.parent_volume.get("volume")
269             )
270             if journal_volume:
271                 entries.append(("volume", journal_volume))
272             journal_issue = self.parent_volume.get(
273                 "meta_issue", self.parent_volume.get("issue")
274             )
275             if journal_issue:
276                 entries.append(("number", journal_issue))
277         else:
278             # not is_journal(self.full_id)
279             if "xml_booktitle" in self.attrib:
280                 entries.append(("booktitle", self.get_booktitle(form="latex")))
281             elif bibtype != "proceedings":
282                 entries.append(
283                     ("booktitle", self.parent_volume.get_title(form="latex"))
284                 )
285         for entry in ("month", "year", "address", "publisher"):
286             if entry in self.attrib:
287                 entries.append((entry, bibtex_encode(self.get(entry))))
288         for entry in ("url", "doi"):
289             if entry in self.attrib:
290                 # don't want latex escapes such as
291                 # doi = "10.1162/coli{\_}a{\_}00008",
292                 entries.append((entry, self.get(entry)))
293         if "pages" in self.attrib:
294             entries.append(("pages", self.get("pages").replace("–", "--")))
295         if "xml_abstract" in self.attrib:
296             entries.append(("abstract", self.get_abstract(form="latex")))
297 
298         # Serialize it
299         return bibtex_make_entry(bibkey, bibtype, entries)
300 
301     def as_dict(self):
302         value = self.attrib
303         value["paper_id"] = self.paper_id
304         value["parent_volume_id"] = self.parent_volume_id
305         value["bibkey"] = self.bibkey
306         value["bibtype"] = self.bibtype
307         return value
308 
309     def items(self):
310         return self.attrib.items()
311
```

Path: `bin/anthology/data.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright 2019 Marcel Bollmann <marcel@bollmann.me>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 #     http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 
17 ################################################################################
18 # This file contains all constants and functions that have hardcoded data (such
19 # as URLs or journal titles) which does not come from the XML.  This is to
20 # provide a single file where such hardcoded data can be looked up and/or
21 # changed.
22 ################################################################################
23 
24 ANTHOLOGY_URL = "https://www.aclweb.org/anthology/{}"
25 ATTACHMENT_URL = "https://www.aclweb.org/anthology/attachments/{}"
26 
27 
28 def get_journal_title(top_level_id, volume_title):
29     if top_level_id[0] == "J":
30         return "Computational Linguistics"
31     elif top_level_id[0] == "Q":
32         return "Transactions of the Association for Computational Linguistics"
33     else:
34         return volume_title
35
```
--- 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/bin/anthology/data.py b/bin/anthology/data.py
--- a/bin/anthology/data.py
+++ b/bin/anthology/data.py
@@ -27,7 +27,10 @@
 
 def get_journal_title(top_level_id, volume_title):
     if top_level_id[0] == "J":
-        return "Computational Linguistics"
+        if int(top_level_id[1:3]) <= 83:
+            return "American Journal of Computational Linguistics"
+        else:
+            return "Computational Linguistics"
     elif top_level_id[0] == "Q":
         return "Transactions of the Association for Computational Linguistics"
     else:
diff --git a/bin/anthology/papers.py b/bin/anthology/papers.py
--- a/bin/anthology/papers.py
+++ b/bin/anthology/papers.py
@@ -282,7 +282,7 @@
                 entries.append(
                     ("booktitle", self.parent_volume.get_title(form="latex"))
                 )
-        for entry in ("month", "year", "address", "publisher"):
+        for entry in ("month", "year", "address", "publisher", "note"):
             if entry in self.attrib:
                 entries.append((entry, bibtex_encode(self.get(entry))))
         for entry in ("url", "doi"):
@@ -292,6 +292,8 @@
                 entries.append((entry, self.get(entry)))
         if "pages" in self.attrib:
             entries.append(("pages", self.get("pages").replace("–", "--")))
+        if "note" in self.attrib:
+            entries.append(("note", self.get("note")))
         if "xml_abstract" in self.attrib:
             entries.append(("abstract", self.get_abstract(form="latex")))

{"golden_diff": "diff --git a/bin/anthology/data.py b/bin/anthology/data.py\n--- a/bin/anthology/data.py\n+++ b/bin/anthology/data.py\n@@ -27,7 +27,10 @@\n \n def get_journal_title(top_level_id, volume_title):\n     if top_level_id[0] == \"J\":\n-        return \"Computational Linguistics\"\n+        if int(top_level_id[1:3]) <= 83:\n+            return \"American Journal of Computational Linguistics\"\n+        else:\n+            return \"Computational Linguistics\"\n     elif top_level_id[0] == \"Q\":\n         return \"Transactions of the Association for Computational Linguistics\"\n     else:\ndiff --git a/bin/anthology/papers.py b/bin/anthology/papers.py\n--- a/bin/anthology/papers.py\n+++ b/bin/anthology/papers.py\n@@ -282,7 +282,7 @@\n                 entries.append(\n                     (\"booktitle\", self.parent_volume.get_title(form=\"latex\"))\n                 )\n-        for entry in (\"month\", \"year\", \"address\", \"publisher\"):\n+        for entry in (\"month\", \"year\", \"address\", \"publisher\", \"note\"):\n             if entry in self.attrib:\n                 entries.append((entry, bibtex_encode(self.get(entry))))\n         for entry in (\"url\", \"doi\"):\n@@ -292,6 +292,8 @@\n                 entries.append((entry, self.get(entry)))\n         if \"pages\" in self.attrib:\n             entries.append((\"pages\", self.get(\"pages\").replace(\"\u2013\", \"--\")))\n+        if \"note\" in self.attrib:\n+            entries.append((\"note\", self.get(\"note\")))\n         if \"xml_abstract\" in self.attrib:\n             entries.append((\"abstract\", self.get_abstract(form=\"latex\")))\n", "issue": "Missing author data on early CL journals\nAuthors are part of the titles, rather than having author fields. See for example: https://aclweb.org/anthology/events/cl-1979/\nJ79-J83 should be \"American Journal of Computational Linguistics\"\nand changed its name only in 1984. The name \"Computational Linguistics\" is hard-coded, so I'm not sure if this is an easy change.\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright 2019 Marcel Bollmann <marcel@bollmann.me>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport logging as log\nfrom .people import PersonName\nfrom .utils import (\n    infer_attachment_url,\n    remove_extra_whitespace,\n    is_journal,\n    is_volume_id,\n    to_volume_id,\n)\nfrom . import data\n\n# For BibTeX export\nfrom .formatter import bibtex_encode, bibtex_make_entry\n\n# Names of XML elements that may appear multiple times\n_LIST_ELEMENTS = (\"attachment\", \"author\", \"editor\", \"video\", \"revision\", \"erratum\")\n\n\nclass Paper:\n    def __init__(self, paper_id, top_level_id, formatter):\n        self.formatter = formatter\n        self.parent_volume = None\n        self.paper_id = paper_id\n        self.top_level_id = top_level_id\n        self.attrib = {}\n        self._bibkey = False\n\n    def from_xml(xml_element, *args):\n        paper = Paper(xml_element.get(\"id\"), *args)\n        paper._parse_element(xml_element)\n        paper.attrib[\"title\"] = paper.get_title(\"plain\")\n        if \"booktitle\" in paper.attrib:\n            paper.attrib[\"booktitle\"] = paper.get_booktitle(\"plain\")\n        if \"editor\" in paper.attrib:\n            if paper.is_volume:\n                if \"author\" in paper.attrib:\n                    log.warn(\n                        \"Paper {} has both <editor> and <author>; ignoring <author>\".format(\n                            paper.full_id\n                        )\n                    )\n                # Proceedings editors are considered authors for their front matter\n                paper.attrib[\"author\"] = paper.attrib[\"editor\"]\n                del paper.attrib[\"editor\"]\n            else:\n                log.warn(\n                    \"Paper {} has <editor> but is not a proceedings volume; ignoring <editor>\".format(\n                        paper.full_id\n                    )\n                )\n        if \"year\" not in paper.attrib:\n            paper._infer_year()\n        if \"pages\" in paper.attrib:\n            if paper.attrib[\"pages\"] is not None:\n                paper._interpret_pages()\n            else:\n                del paper.attrib[\"pages\"]\n        return paper\n\n    def _parse_element(self, paper_element):\n        # read & store values\n        if \"href\" in paper_element.attrib:\n            self.attrib[\"attrib_href\"] = paper_element.get(\"href\")\n            self.attrib[\"url\"] = paper_element.get(\"href\")\n        elif not (self.is_volume and is_journal(self.full_id)):\n            # Generate a URL, except for top-level journal entries\n            self.attrib[\"url\"] = data.ANTHOLOGY_URL.format(self.full_id)\n        for element in paper_element:\n            # parse value\n            tag = element.tag.lower()\n            if tag in (\"abstract\", \"title\", \"booktitle\"):\n                tag = \"xml_{}\".format(tag)\n                value = element\n            elif tag == \"attachment\":\n                value = {\n                    \"filename\": element.text,\n                    \"type\": element.get(\"type\", \"attachment\"),\n                    \"url\": infer_attachment_url(element.text),\n                }\n            elif tag in (\"author\", \"editor\"):\n                value = PersonName.from_element(element)\n            elif tag in (\"erratum\", \"revision\"):\n                if tag == \"revision\" and \"revision\" not in self.attrib:\n                    # Explicitly construct URL of original version of the paper\n                    # -- this is a bit hacky, but it's not given in the XML\n                    # explicitly\n                    self.attrib[\"revision\"] = [\n                        {\n                            \"value\": \"{}v1\".format(self.full_id),\n                            \"id\": \"1\",\n                            \"url\": data.ANTHOLOGY_URL.format(\n                                \"{}v1\".format(self.full_id)\n                            ),\n                        }\n                    ]\n                value = {\n                    \"value\": element.text,\n                    \"id\": element.get(\"id\"),\n                    \"url\": data.ANTHOLOGY_URL.format(element.text),\n                }\n            elif tag == \"mrf\":\n                value = {\"filename\": element.text, \"src\": element.get(\"src\")}\n            elif tag == \"video\":\n                # Treat videos the same way as other attachments\n                tag = \"attachment\"\n                value = {\n                    \"filename\": element.get(\"href\"),\n                    \"type\": element.get(\"tag\", \"video\"),\n                    \"url\": infer_attachment_url(element.get(\"href\")),\n                }\n            elif tag in (\"dataset\", \"software\"):\n                value = {\n                    \"filename\": element.text,\n                    \"type\": tag,\n                    \"url\": infer_attachment_url(element.text),\n                }\n                tag = \"attachment\"\n            else:\n                value = element.text\n            # store value\n            if tag == \"url\":\n                continue  # We basically have to ignore this for now\n            if tag in _LIST_ELEMENTS:\n                try:\n                    self.attrib[tag].append(value)\n                except KeyError:\n                    self.attrib[tag] = [value]\n            else:\n                if tag in self.attrib:\n                    log.warning(\n                        \"{}: Unexpected multiple occurrence of '{}' element\".format(\n                            self.full_id, tag\n                        )\n                    )\n                self.attrib[tag] = value\n\n    def _infer_year(self):\n        \"\"\"Infer the year from the volume ID.\n\n        Many paper entries do not explicitly contain their year.  This function assumes\n        that the paper's volume identifier follows the format 'xyy', where x is\n        some letter and yy are the last two digits of the year of publication.\n        \"\"\"\n        assert (\n            len(self.top_level_id) == 3\n        ), \"Couldn't infer year: unknown volume ID format\"\n        digits = self.top_level_id[1:]\n        if int(digits) >= 60:\n            year = \"19{}\".format(digits)\n        else:\n            year = \"20{}\".format(digits)\n        self.attrib[\"year\"] = year\n\n    def _interpret_pages(self):\n        \"\"\"Splits up 'pages' field into first and last page, if possible.\n\n        This is used for metadata in the generated HTML.\"\"\"\n        for s in (\"--\", \"-\", \"\u2013\"):\n            if self.attrib[\"pages\"].count(s) == 1:\n                self.attrib[\"page_first\"], self.attrib[\"page_last\"] = self.attrib[\n                    \"pages\"\n                ].split(s)\n                self.attrib[\"pages\"] = self.attrib[\"pages\"].replace(s, \"\u2013\")\n                return\n\n    @property\n    def is_volume(self):\n        \"\"\"Determines if this paper is a regular paper or a proceedings volume.\n\n        By default, each paper ID of format 'x000' will be treated as (the front\n        matter of) a proceedings volume, unless the XML is of type workshop,\n        where each paper ID of format 'xx00' is treated as one volume.\n        \"\"\"\n        return is_volume_id(self.full_id)\n\n    @property\n    def full_id(self):\n        return \"{}-{}\".format(self.top_level_id, self.paper_id)\n\n    @property\n    def bibkey(self):\n        if not self._bibkey:\n            self._bibkey = self.full_id  # fallback\n        return self._bibkey\n\n    @bibkey.setter\n    def bibkey(self, value):\n        self._bibkey = value\n\n    @property\n    def bibtype(self):\n        if is_journal(self.full_id):\n            return \"article\"\n        elif self.is_volume:\n            return \"proceedings\"\n        else:\n            return \"inproceedings\"\n\n    @property\n    def parent_volume_id(self):\n        if self.parent_volume is not None:\n            return self.parent_volume.full_id\n        return None\n\n    def get(self, name, default=None):\n        try:\n            return self.attrib[name]\n        except KeyError:\n            return default\n\n    def get_title(self, form=\"xml\"):\n        \"\"\"Returns the paper title, optionally formatting it.\n\n        Accepted formats:\n          - xml:   Include any contained XML tags unchanged\n          - plain: Strip all XML tags, returning only plain text\n          - html:  Convert XML tags into valid HTML tags\n          - latex: Convert XML tags into LaTeX commands\n        \"\"\"\n        return self.formatter(self.get(\"xml_title\"), form)\n\n    def get_abstract(self, form=\"xml\"):\n        \"\"\"Returns the abstract, optionally formatting it.\n\n        See `get_title()` for details.\n        \"\"\"\n        return self.formatter(self.get(\"xml_abstract\"), form, allow_url=True)\n\n    def get_booktitle(self, form=\"xml\"):\n        \"\"\"Returns the booktitle, optionally formatting it.\n\n        See `get_title()` for details.\n        \"\"\"\n        return self.formatter(self.get(\"xml_booktitle\"), form)\n\n    def as_bibtex(self):\n        \"\"\"Return the BibTeX entry for this paper.\"\"\"\n        # Build BibTeX entry\n        bibkey = self.bibkey\n        bibtype = self.bibtype\n        entries = [(\"title\", self.get_title(form=\"latex\"))]\n        for people in (\"author\", \"editor\"):\n            if people in self.attrib:\n                entries.append(\n                    (people, \"  and  \".join(p.as_bibtex() for p in self.get(people)))\n                )\n        if is_journal(self.full_id):\n            entries.append(\n                (\"journal\", bibtex_encode(self.parent_volume.get(\"meta_journal_title\")))\n            )\n            journal_volume = self.parent_volume.get(\n                \"meta_volume\", self.parent_volume.get(\"volume\")\n            )\n            if journal_volume:\n                entries.append((\"volume\", journal_volume))\n            journal_issue = self.parent_volume.get(\n                \"meta_issue\", self.parent_volume.get(\"issue\")\n            )\n            if journal_issue:\n                entries.append((\"number\", journal_issue))\n        else:\n            # not is_journal(self.full_id)\n            if \"xml_booktitle\" in self.attrib:\n                entries.append((\"booktitle\", self.get_booktitle(form=\"latex\")))\n            elif bibtype != \"proceedings\":\n                entries.append(\n                    (\"booktitle\", self.parent_volume.get_title(form=\"latex\"))\n                )\n        for entry in (\"month\", \"year\", \"address\", \"publisher\"):\n            if entry in self.attrib:\n                entries.append((entry, bibtex_encode(self.get(entry))))\n        for entry in (\"url\", \"doi\"):\n            if entry in self.attrib:\n                # don't want latex escapes such as\n                # doi = \"10.1162/coli{\\_}a{\\_}00008\",\n                entries.append((entry, self.get(entry)))\n        if \"pages\" in self.attrib:\n            entries.append((\"pages\", self.get(\"pages\").replace(\"\u2013\", \"--\")))\n        if \"xml_abstract\" in self.attrib:\n            entries.append((\"abstract\", self.get_abstract(form=\"latex\")))\n\n        # Serialize it\n        return bibtex_make_entry(bibkey, bibtype, entries)\n\n    def as_dict(self):\n        value = self.attrib\n        value[\"paper_id\"] = self.paper_id\n        value[\"parent_volume_id\"] = self.parent_volume_id\n        value[\"bibkey\"] = self.bibkey\n        value[\"bibtype\"] = self.bibtype\n        return value\n\n    def items(self):\n        return self.attrib.items()\n", "path": "bin/anthology/papers.py"}, {"content": "# -*- coding: utf-8 -*-\n#\n# Copyright 2019 Marcel Bollmann <marcel@bollmann.me>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n################################################################################\n# This file contains all constants and functions that have hardcoded data (such\n# as URLs or journal titles) which does not come from the XML.  This is to\n# provide a single file where such hardcoded data can be looked up and/or\n# changed.\n################################################################################\n\nANTHOLOGY_URL = \"https://www.aclweb.org/anthology/{}\"\nATTACHMENT_URL = \"https://www.aclweb.org/anthology/attachments/{}\"\n\n\ndef get_journal_title(top_level_id, volume_title):\n    if top_level_id[0] == \"J\":\n        return \"Computational Linguistics\"\n    elif top_level_id[0] == \"Q\":\n        return \"Transactions of the Association for Computational Linguistics\"\n    else:\n        return volume_title\n", "path": "bin/anthology/data.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright 2019 Marcel Bollmann <marcel@bollmann.me>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport logging as log\nfrom .people import PersonName\nfrom .utils import (\n    infer_attachment_url,\n    remove_extra_whitespace,\n    is_journal,\n    is_volume_id,\n    to_volume_id,\n)\nfrom . import data\n\n# For BibTeX export\nfrom .formatter import bibtex_encode, bibtex_make_entry\n\n# Names of XML elements that may appear multiple times\n_LIST_ELEMENTS = (\"attachment\", \"author\", \"editor\", \"video\", \"revision\", \"erratum\")\n\n\nclass Paper:\n    def __init__(self, paper_id, top_level_id, formatter):\n        self.formatter = formatter\n        self.parent_volume = None\n        self.paper_id = paper_id\n        self.top_level_id = top_level_id\n        self.attrib = {}\n        self._bibkey = False\n\n    def from_xml(xml_element, *args):\n        paper = Paper(xml_element.get(\"id\"), *args)\n        paper._parse_element(xml_element)\n        paper.attrib[\"title\"] = paper.get_title(\"plain\")\n        if \"booktitle\" in paper.attrib:\n            paper.attrib[\"booktitle\"] = paper.get_booktitle(\"plain\")\n        if \"editor\" in paper.attrib:\n            if paper.is_volume:\n                if \"author\" in paper.attrib:\n                    log.warn(\n                        \"Paper {} has both <editor> and <author>; ignoring <author>\".format(\n                            paper.full_id\n                        )\n                    )\n                # Proceedings editors are considered authors for their front matter\n                paper.attrib[\"author\"] = paper.attrib[\"editor\"]\n                del paper.attrib[\"editor\"]\n            else:\n                log.warn(\n                    \"Paper {} has <editor> but is not a proceedings volume; ignoring <editor>\".format(\n                        paper.full_id\n                    )\n                )\n        if \"year\" not in paper.attrib:\n            paper._infer_year()\n        if \"pages\" in paper.attrib:\n            if paper.attrib[\"pages\"] is not None:\n                paper._interpret_pages()\n            else:\n                del paper.attrib[\"pages\"]\n        return paper\n\n    def _parse_element(self, paper_element):\n        # read & store values\n        if \"href\" in paper_element.attrib:\n            self.attrib[\"attrib_href\"] = paper_element.get(\"href\")\n            self.attrib[\"url\"] = paper_element.get(\"href\")\n        elif not (self.is_volume and is_journal(self.full_id)):\n            # Generate a URL, except for top-level journal entries\n            self.attrib[\"url\"] = data.ANTHOLOGY_URL.format(self.full_id)\n        for element in paper_element:\n            # parse value\n            tag = element.tag.lower()\n            if tag in (\"abstract\", \"title\", \"booktitle\"):\n                tag = \"xml_{}\".format(tag)\n                value = element\n            elif tag == \"attachment\":\n                value = {\n                    \"filename\": element.text,\n                    \"type\": element.get(\"type\", \"attachment\"),\n                    \"url\": infer_attachment_url(element.text),\n                }\n            elif tag in (\"author\", \"editor\"):\n                value = PersonName.from_element(element)\n            elif tag in (\"erratum\", \"revision\"):\n                if tag == \"revision\" and \"revision\" not in self.attrib:\n                    # Explicitly construct URL of original version of the paper\n                    # -- this is a bit hacky, but it's not given in the XML\n                    # explicitly\n                    self.attrib[\"revision\"] = [\n                        {\n                            \"value\": \"{}v1\".format(self.full_id),\n                            \"id\": \"1\",\n                            \"url\": data.ANTHOLOGY_URL.format(\n                                \"{}v1\".format(self.full_id)\n                            ),\n                        }\n                    ]\n                value = {\n                    \"value\": element.text,\n                    \"id\": element.get(\"id\"),\n                    \"url\": data.ANTHOLOGY_URL.format(element.text),\n                }\n            elif tag == \"mrf\":\n                value = {\"filename\": element.text, \"src\": element.get(\"src\")}\n            elif tag == \"video\":\n                # Treat videos the same way as other attachments\n                tag = \"attachment\"\n                value = {\n                    \"filename\": element.get(\"href\"),\n                    \"type\": element.get(\"tag\", \"video\"),\n                    \"url\": infer_attachment_url(element.get(\"href\")),\n                }\n            elif tag in (\"dataset\", \"software\"):\n                value = {\n                    \"filename\": element.text,\n                    \"type\": tag,\n                    \"url\": infer_attachment_url(element.text),\n                }\n                tag = \"attachment\"\n            else:\n                value = element.text\n            # store value\n            if tag == \"url\":\n                continue  # We basically have to ignore this for now\n            if tag in _LIST_ELEMENTS:\n                try:\n                    self.attrib[tag].append(value)\n                except KeyError:\n                    self.attrib[tag] = [value]\n            else:\n                if tag in self.attrib:\n                    log.warning(\n                        \"{}: Unexpected multiple occurrence of '{}' element\".format(\n                            self.full_id, tag\n                        )\n                    )\n                self.attrib[tag] = value\n\n    def _infer_year(self):\n        \"\"\"Infer the year from the volume ID.\n\n        Many paper entries do not explicitly contain their year.  This function assumes\n        that the paper's volume identifier follows the format 'xyy', where x is\n        some letter and yy are the last two digits of the year of publication.\n        \"\"\"\n        assert (\n            len(self.top_level_id) == 3\n        ), \"Couldn't infer year: unknown volume ID format\"\n        digits = self.top_level_id[1:]\n        if int(digits) >= 60:\n            year = \"19{}\".format(digits)\n        else:\n            year = \"20{}\".format(digits)\n        self.attrib[\"year\"] = year\n\n    def _interpret_pages(self):\n        \"\"\"Splits up 'pages' field into first and last page, if possible.\n\n        This is used for metadata in the generated HTML.\"\"\"\n        for s in (\"--\", \"-\", \"\u2013\"):\n            if self.attrib[\"pages\"].count(s) == 1:\n                self.attrib[\"page_first\"], self.attrib[\"page_last\"] = self.attrib[\n                    \"pages\"\n                ].split(s)\n                self.attrib[\"pages\"] = self.attrib[\"pages\"].replace(s, \"\u2013\")\n                return\n\n    @property\n    def is_volume(self):\n        \"\"\"Determines if this paper is a regular paper or a proceedings volume.\n\n        By default, each paper ID of format 'x000' will be treated as (the front\n        matter of) a proceedings volume, unless the XML is of type workshop,\n        where each paper ID of format 'xx00' is treated as one volume.\n        \"\"\"\n        return is_volume_id(self.full_id)\n\n    @property\n    def full_id(self):\n        return \"{}-{}\".format(self.top_level_id, self.paper_id)\n\n    @property\n    def bibkey(self):\n        if not self._bibkey:\n            self._bibkey = self.full_id  # fallback\n        return self._bibkey\n\n    @bibkey.setter\n    def bibkey(self, value):\n        self._bibkey = value\n\n    @property\n    def bibtype(self):\n        if is_journal(self.full_id):\n            return \"article\"\n        elif self.is_volume:\n            return \"proceedings\"\n        else:\n            return \"inproceedings\"\n\n    @property\n    def parent_volume_id(self):\n        if self.parent_volume is not None:\n            return self.parent_volume.full_id\n        return None\n\n    def get(self, name, default=None):\n        try:\n            return self.attrib[name]\n        except KeyError:\n            return default\n\n    def get_title(self, form=\"xml\"):\n        \"\"\"Returns the paper title, optionally formatting it.\n\n        Accepted formats:\n          - xml:   Include any contained XML tags unchanged\n          - plain: Strip all XML tags, returning only plain text\n          - html:  Convert XML tags into valid HTML tags\n          - latex: Convert XML tags into LaTeX commands\n        \"\"\"\n        return self.formatter(self.get(\"xml_title\"), form)\n\n    def get_abstract(self, form=\"xml\"):\n        \"\"\"Returns the abstract, optionally formatting it.\n\n        See `get_title()` for details.\n        \"\"\"\n        return self.formatter(self.get(\"xml_abstract\"), form, allow_url=True)\n\n    def get_booktitle(self, form=\"xml\"):\n        \"\"\"Returns the booktitle, optionally formatting it.\n\n        See `get_title()` for details.\n        \"\"\"\n        return self.formatter(self.get(\"xml_booktitle\"), form)\n\n    def as_bibtex(self):\n        \"\"\"Return the BibTeX entry for this paper.\"\"\"\n        # Build BibTeX entry\n        bibkey = self.bibkey\n        bibtype = self.bibtype\n        entries = [(\"title\", self.get_title(form=\"latex\"))]\n        for people in (\"author\", \"editor\"):\n            if people in self.attrib:\n                entries.append(\n                    (people, \"  and  \".join(p.as_bibtex() for p in self.get(people)))\n                )\n        if is_journal(self.full_id):\n            entries.append(\n                (\"journal\", bibtex_encode(self.parent_volume.get(\"meta_journal_title\")))\n            )\n            journal_volume = self.parent_volume.get(\n                \"meta_volume\", self.parent_volume.get(\"volume\")\n            )\n            if journal_volume:\n                entries.append((\"volume\", journal_volume))\n            journal_issue = self.parent_volume.get(\n                \"meta_issue\", self.parent_volume.get(\"issue\")\n            )\n            if journal_issue:\n                entries.append((\"number\", journal_issue))\n        else:\n            # not is_journal(self.full_id)\n            if \"xml_booktitle\" in self.attrib:\n                entries.append((\"booktitle\", self.get_booktitle(form=\"latex\")))\n            elif bibtype != \"proceedings\":\n                entries.append(\n                    (\"booktitle\", self.parent_volume.get_title(form=\"latex\"))\n                )\n        for entry in (\"month\", \"year\", \"address\", \"publisher\", \"note\"):\n            if entry in self.attrib:\n                entries.append((entry, bibtex_encode(self.get(entry))))\n        for entry in (\"url\", \"doi\"):\n            if entry in self.attrib:\n                # don't want latex escapes such as\n                # doi = \"10.1162/coli{\\_}a{\\_}00008\",\n                entries.append((entry, self.get(entry)))\n        if \"pages\" in self.attrib:\n            entries.append((\"pages\", self.get(\"pages\").replace(\"\u2013\", \"--\")))\n        if \"note\" in self.attrib:\n            entries.append((\"note\", self.get(\"note\")))\n        if \"xml_abstract\" in self.attrib:\n            entries.append((\"abstract\", self.get_abstract(form=\"latex\")))\n\n        # Serialize it\n        return bibtex_make_entry(bibkey, bibtype, entries)\n\n    def as_dict(self):\n        value = self.attrib\n        value[\"paper_id\"] = self.paper_id\n        value[\"parent_volume_id\"] = self.parent_volume_id\n        value[\"bibkey\"] = self.bibkey\n        value[\"bibtype\"] = self.bibtype\n        return value\n\n    def items(self):\n        return self.attrib.items()\n", "path": "bin/anthology/papers.py"}, {"content": "# -*- coding: utf-8 -*-\n#\n# Copyright 2019 Marcel Bollmann <marcel@bollmann.me>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n################################################################################\n# This file contains all constants and functions that have hardcoded data (such\n# as URLs or journal titles) which does not come from the XML.  This is to\n# provide a single file where such hardcoded data can be looked up and/or\n# changed.\n################################################################################\n\nANTHOLOGY_URL = \"https://www.aclweb.org/anthology/{}\"\nATTACHMENT_URL = \"https://www.aclweb.org/anthology/attachments/{}\"\n\n\ndef get_journal_title(top_level_id, volume_title):\n    if top_level_id[0] == \"J\":\n        if int(top_level_id[1:3]) <= 83:\n            return \"American Journal of Computational Linguistics\"\n        else:\n            return \"Computational Linguistics\"\n    elif top_level_id[0] == \"Q\":\n        return \"Transactions of the Association for Computational Linguistics\"\n    else:\n        return volume_title\n", "path": "bin/anthology/data.py"}]}