We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Paper Metadata: 2023.findings-emnlp.1054
### Confirm that this is a metadata correction

- [X] I want to file corrections to make the metadata match the PDF file hosted on the ACL Anthology.

### Anthology ID

2023.findings-emnlp.1054

### Type of Paper Metadata Correction

- [X] Paper Title
- [ ] Paper Abstract
- [ ] Author Name(s)

### Correction to Paper Title

Please change the paper title appeared in Cite (ACL) and Cite (Informal) to "Measuring Pointwise 𝒱-Usable Information In-Context-ly"

### Correction to Paper Abstract

_No response_

### Correction to Author Name(s)

_No response_

--- 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/texmath.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 from lxml import etree
18 import csv
19 import logging as log
20 import os
21 from TexSoup import TexSoup
22 from TexSoup.data import TexCmd, TexText, TexGroup
23 
24 FUNCTION_NAMES = ("lim", "log")
25 TEX_TO_HTML = {
26     "mathrm": ("span", {"class": "font-weight-normal"}),
27     "textrm": ("span", {"class": "font-weight-normal"}),
28     "text": ("span", {"class": "font-weight-normal"}),
29     "mathbf": ("strong", {}),
30     "textbf": ("strong", {}),
31     "boldsymbol": ("strong", {}),
32     "mathit": ("em", {}),
33     "textit": ("em", {}),
34     "emph": ("em", {}),
35     "textsc": ("span", {"style": "font-variant: small-caps;"}),
36     "texttt": ("span", {"class": "text-monospace"}),
37     "textsubscript": ("sub", {}),
38     "textsuperscript": ("sup", {}),
39 }
40 REMOVED_COMMANDS = ("bf", "rm", "it", "sc")
41 
42 
43 def _append_text(text, trg):
44     if not text:
45         return
46     if len(trg):
47         if trg[-1].tail is not None:
48             trg[-1].tail += text
49         else:
50             trg[-1].tail = text
51     else:
52         if trg.text is not None:
53             trg.text += text
54         else:
55             trg.text = text
56 
57 
58 class TexMath:
59     """Interpreter and converter for TeX inline math expressions.
60 
61     This class uses TexSoup (https://github.com/alvinwan/TexSoup) to parse a TeX
62     expression and converts it to valid HTML.  The conversion combines a small
63     number of handwritten rules with a mapping of LaTeX math mode commands to
64     Unicode symbols (http://milde.users.sourceforge.net/LUCR/Math/).  Parts that
65     cannot be interpreted using this simple method are preserved as raw LaTeX.
66     """
67 
68     def __init__(self, symbolsfile=None):
69         self.cmd_map = {}
70         if symbolsfile is None:
71             symbolsfile = os.path.join(
72                 os.path.dirname(os.path.abspath(__file__)), "unimathsymbols.txt"
73             )
74         self.load_symbols(symbolsfile)
75 
76     def load_symbols(self, filename):
77         with open(filename, "r", encoding="utf8") as f:
78             reader = csv.reader(f, delimiter="^")
79             for row in reader:
80                 if row[0].startswith("#"):  # comment
81                     continue
82                 assert len(row) == 8, "Expect eight-column format"
83                 char, cmd = row[1], row[2]
84                 if cmd.startswith("\\"):
85                     self.cmd_map[cmd[1:]] = char
86                 if row[-1].startswith("= ") and ", " in row[-1]:
87                     # last column sometimes contains alternative command
88                     cmd = row[-1][2:].split(", ")[0]
89                     if cmd.startswith("\\"):
90                         self.cmd_map[cmd[1:]] = char
91 
92     def _parse(self, everything, trg):
93         """Parses a list of TeX constituents into an lxml.etree._Element.
94 
95         Arguments:
96             everything: An iterator over TeX constituents as provided by TexSoup
97             trg: The lxml.etree._Element to parse the expression into
98 
99         The approach of iterating over the TeX constituents roughly follows
100         <https://github.com/alvinwan/TexSoup/blob/master/examples/list_everything.py>.
101         """
102         sxscript = False  # Tracks whether we're in a subscript/superscript
103         for code in everything:
104             if isinstance(code, TexCmd):
105                 # code is a TeX command
106                 self._parse_command(code, trg)
107             elif isinstance(code, TexText) or isinstance(code, str):
108                 # code is text
109                 sxscript = self._parse_text(code, trg)
110             elif isinstance(code, TexGroup):
111                 # If in subscript/superscript, wrap the entire element in respective tag
112                 if sxscript:
113                     my_trg = etree.Element(sxscript)
114                     self._parse(code.contents, my_trg)
115                     trg.append(my_trg)
116                     sxscript = False
117                 # Otherwise, just parse it normally
118                 else:
119                     self._parse(code.contents, trg)
120             else:
121                 log.error(f"TeX-math parser got unhandled element: {type(code)}")
122 
123     def _parse_command(self, code, trg):
124         args = list(code.args)
125         name = str(code.name)
126         # Check if the command is in the list of known Unicode mappings
127         if name in self.cmd_map:
128             _append_text(self.cmd_map[name], trg)
129             self._parse(args, trg)
130         # Check if command + arguments is in the list of known Unicode mappings
131         # (this covers commands like "\mathcal{A}", which have their own entries)
132         elif str(code)[1:] in self.cmd_map:
133             _append_text(self.cmd_map[str(code)[1:]], trg)
134         # Check if command is a known function name (e.g. "log")
135         elif name in FUNCTION_NAMES:
136             sx = etree.Element("span")
137             sx.attrib["class"] = "tex-math-function"
138             sx.text = str(name)
139             trg.append(sx)
140             self._parse(args, trg)
141         # Handle fractions
142         elif name == "frac":
143             self._parse_fraction(args, trg)
144         # Handle commands with simple HTML tag substitutions
145         elif name in TEX_TO_HTML:
146             elem_name, elem_attrib = TEX_TO_HTML[name]
147             sx = etree.Element(elem_name, attrib=elem_attrib)
148             self._parse(args, sx)
149             trg.append(sx)
150         # Known, but unsupported formatting tags that will just be removed
151         elif name in REMOVED_COMMANDS and not args:
152             pass
153         # Give up, but preserve element
154         else:
155             log.warn(f"Unknown TeX-math command: {code}")
156             self._append_unparsed(code, trg)
157 
158     def _parse_fraction(self, args, trg):
159         if len(args) != 2:
160             log.warn(f"Couldn't parse \\frac: got {len(args)} arguments, expected 2")
161             self._append_unparsed({'name': 'frac', 'args': args}, trg)
162         else:
163             # Represent numerator of fraction as superscript
164             sx = etree.Element("sup")
165             self._parse([args[0]], sx)
166             trg.append(sx)
167             # Unicode symbol for fraction slash
168             _append_text("\u2044", trg)
169             # Represent denominator of fraction as subscript
170             sx = etree.Element("sub")
171             self._parse([args[1]], sx)
172             trg.append(sx)
173 
174     def _parse_text(self, code, trg):
175         text = str(code)
176         # TexSoup doesn't parse any non-alpha command as a command. Ex: \$
177         # However it does seperate them into their own text part. Ex: 'r\\&dd' -> ['r', '\\&', 'dd']
178         # Therefore try to do command mapping replacement of all text beginning with \ and of length 2
179         if len(text) == 2 and text[0] == '\\':
180             text = self.cmd_map.get(text[1], text)
181             _append_text(text, trg)
182             return
183         # parse ^ and _ (won't get recognized as separate nodes by TexSoup)
184         sxscript = False
185         if "^" in text or "_" in text:
186             buf = ""
187             for char in text:
188                 if char == "^" or char == "_":
189                     _append_text(buf, trg)
190                     buf = ""
191                     sxscript = "sup" if char == "^" else "sub"
192                 elif sxscript:
193                     sx = etree.Element(sxscript)
194                     sx.text = char
195                     trg.append(sx)
196                     sxscript = False
197                 else:
198                     buf += char
199             text = buf
200         # Append as text
201         _append_text(text, trg)
202         return sxscript
203 
204     def _append_unparsed(self, code, trg):
205         pre = etree.Element("span")
206         pre.attrib["class"] = "tex-math-unparsed"
207         pre.text = f"\\{code.name}{code.args}"
208         trg.append(pre)
209 
210     def etree_to_html(self, element):
211         result = etree.Element("span")
212         result.attrib["class"] = "tex-math"
213         result.tail = element.tail  # Preserve tail
214         self._parse(TexSoup(element.text).expr.all, result)
215         return result
216 
217     def to_html(self, element):
218         """Converts a TeX math expression to HTML markup."""
219         if isinstance(element, etree._Element):
220             return self.etree_to_html(element)
221         elif isinstance(element, str):
222             value = self.etree_to_html(etree.fromstring(f"<span>{element}</span>"))
223             return etree.tostring(value)
224         raise NotImplementedError(f"Cannot convert elements of type {type(element)}")
225 
226     def to_unicode(self, element):
227         """Converts a TeX math expression to a Unicode string.
228 
229         This will perform the same conversions as `to_html()`, but strip out the
230         HTML tags afterwards.
231         """
232         element = self.to_html(element)
233         return etree.tostring(element, encoding="unicode", method="text")
234
```
--- 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/texmath.py b/bin/anthology/texmath.py
--- a/bin/anthology/texmath.py
+++ b/bin/anthology/texmath.py
@@ -230,4 +230,4 @@
         HTML tags afterwards.
         """
         element = self.to_html(element)
-        return etree.tostring(element, encoding="unicode", method="text")
+        return etree.tostring(element, encoding="unicode", method="text", with_tail=False)

{"golden_diff": "diff --git a/bin/anthology/texmath.py b/bin/anthology/texmath.py\n--- a/bin/anthology/texmath.py\n+++ b/bin/anthology/texmath.py\n@@ -230,4 +230,4 @@\n         HTML tags afterwards.\n         \"\"\"\n         element = self.to_html(element)\n-        return etree.tostring(element, encoding=\"unicode\", method=\"text\")\n+        return etree.tostring(element, encoding=\"unicode\", method=\"text\", with_tail=False)\n", "issue": "Paper Metadata: 2023.findings-emnlp.1054\n### Confirm that this is a metadata correction\n\n- [X] I want to file corrections to make the metadata match the PDF file hosted on the ACL Anthology.\n\n### Anthology ID\n\n2023.findings-emnlp.1054\n\n### Type of Paper Metadata Correction\n\n- [X] Paper Title\n- [ ] Paper Abstract\n- [ ] Author Name(s)\n\n### Correction to Paper Title\n\nPlease change the paper title appeared in Cite (ACL) and Cite (Informal) to \"Measuring Pointwise \ud835\udcb1-Usable Information In-Context-ly\"\n\n### Correction to Paper Abstract\n\n_No response_\n\n### Correction to Author Name(s)\n\n_No response_\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\nfrom lxml import etree\nimport csv\nimport logging as log\nimport os\nfrom TexSoup import TexSoup\nfrom TexSoup.data import TexCmd, TexText, TexGroup\n\nFUNCTION_NAMES = (\"lim\", \"log\")\nTEX_TO_HTML = {\n    \"mathrm\": (\"span\", {\"class\": \"font-weight-normal\"}),\n    \"textrm\": (\"span\", {\"class\": \"font-weight-normal\"}),\n    \"text\": (\"span\", {\"class\": \"font-weight-normal\"}),\n    \"mathbf\": (\"strong\", {}),\n    \"textbf\": (\"strong\", {}),\n    \"boldsymbol\": (\"strong\", {}),\n    \"mathit\": (\"em\", {}),\n    \"textit\": (\"em\", {}),\n    \"emph\": (\"em\", {}),\n    \"textsc\": (\"span\", {\"style\": \"font-variant: small-caps;\"}),\n    \"texttt\": (\"span\", {\"class\": \"text-monospace\"}),\n    \"textsubscript\": (\"sub\", {}),\n    \"textsuperscript\": (\"sup\", {}),\n}\nREMOVED_COMMANDS = (\"bf\", \"rm\", \"it\", \"sc\")\n\n\ndef _append_text(text, trg):\n    if not text:\n        return\n    if len(trg):\n        if trg[-1].tail is not None:\n            trg[-1].tail += text\n        else:\n            trg[-1].tail = text\n    else:\n        if trg.text is not None:\n            trg.text += text\n        else:\n            trg.text = text\n\n\nclass TexMath:\n    \"\"\"Interpreter and converter for TeX inline math expressions.\n\n    This class uses TexSoup (https://github.com/alvinwan/TexSoup) to parse a TeX\n    expression and converts it to valid HTML.  The conversion combines a small\n    number of handwritten rules with a mapping of LaTeX math mode commands to\n    Unicode symbols (http://milde.users.sourceforge.net/LUCR/Math/).  Parts that\n    cannot be interpreted using this simple method are preserved as raw LaTeX.\n    \"\"\"\n\n    def __init__(self, symbolsfile=None):\n        self.cmd_map = {}\n        if symbolsfile is None:\n            symbolsfile = os.path.join(\n                os.path.dirname(os.path.abspath(__file__)), \"unimathsymbols.txt\"\n            )\n        self.load_symbols(symbolsfile)\n\n    def load_symbols(self, filename):\n        with open(filename, \"r\", encoding=\"utf8\") as f:\n            reader = csv.reader(f, delimiter=\"^\")\n            for row in reader:\n                if row[0].startswith(\"#\"):  # comment\n                    continue\n                assert len(row) == 8, \"Expect eight-column format\"\n                char, cmd = row[1], row[2]\n                if cmd.startswith(\"\\\\\"):\n                    self.cmd_map[cmd[1:]] = char\n                if row[-1].startswith(\"= \") and \", \" in row[-1]:\n                    # last column sometimes contains alternative command\n                    cmd = row[-1][2:].split(\", \")[0]\n                    if cmd.startswith(\"\\\\\"):\n                        self.cmd_map[cmd[1:]] = char\n\n    def _parse(self, everything, trg):\n        \"\"\"Parses a list of TeX constituents into an lxml.etree._Element.\n\n        Arguments:\n            everything: An iterator over TeX constituents as provided by TexSoup\n            trg: The lxml.etree._Element to parse the expression into\n\n        The approach of iterating over the TeX constituents roughly follows\n        <https://github.com/alvinwan/TexSoup/blob/master/examples/list_everything.py>.\n        \"\"\"\n        sxscript = False  # Tracks whether we're in a subscript/superscript\n        for code in everything:\n            if isinstance(code, TexCmd):\n                # code is a TeX command\n                self._parse_command(code, trg)\n            elif isinstance(code, TexText) or isinstance(code, str):\n                # code is text\n                sxscript = self._parse_text(code, trg)\n            elif isinstance(code, TexGroup):\n                # If in subscript/superscript, wrap the entire element in respective tag\n                if sxscript:\n                    my_trg = etree.Element(sxscript)\n                    self._parse(code.contents, my_trg)\n                    trg.append(my_trg)\n                    sxscript = False\n                # Otherwise, just parse it normally\n                else:\n                    self._parse(code.contents, trg)\n            else:\n                log.error(f\"TeX-math parser got unhandled element: {type(code)}\")\n\n    def _parse_command(self, code, trg):\n        args = list(code.args)\n        name = str(code.name)\n        # Check if the command is in the list of known Unicode mappings\n        if name in self.cmd_map:\n            _append_text(self.cmd_map[name], trg)\n            self._parse(args, trg)\n        # Check if command + arguments is in the list of known Unicode mappings\n        # (this covers commands like \"\\mathcal{A}\", which have their own entries)\n        elif str(code)[1:] in self.cmd_map:\n            _append_text(self.cmd_map[str(code)[1:]], trg)\n        # Check if command is a known function name (e.g. \"log\")\n        elif name in FUNCTION_NAMES:\n            sx = etree.Element(\"span\")\n            sx.attrib[\"class\"] = \"tex-math-function\"\n            sx.text = str(name)\n            trg.append(sx)\n            self._parse(args, trg)\n        # Handle fractions\n        elif name == \"frac\":\n            self._parse_fraction(args, trg)\n        # Handle commands with simple HTML tag substitutions\n        elif name in TEX_TO_HTML:\n            elem_name, elem_attrib = TEX_TO_HTML[name]\n            sx = etree.Element(elem_name, attrib=elem_attrib)\n            self._parse(args, sx)\n            trg.append(sx)\n        # Known, but unsupported formatting tags that will just be removed\n        elif name in REMOVED_COMMANDS and not args:\n            pass\n        # Give up, but preserve element\n        else:\n            log.warn(f\"Unknown TeX-math command: {code}\")\n            self._append_unparsed(code, trg)\n\n    def _parse_fraction(self, args, trg):\n        if len(args) != 2:\n            log.warn(f\"Couldn't parse \\\\frac: got {len(args)} arguments, expected 2\")\n            self._append_unparsed({'name': 'frac', 'args': args}, trg)\n        else:\n            # Represent numerator of fraction as superscript\n            sx = etree.Element(\"sup\")\n            self._parse([args[0]], sx)\n            trg.append(sx)\n            # Unicode symbol for fraction slash\n            _append_text(\"\\u2044\", trg)\n            # Represent denominator of fraction as subscript\n            sx = etree.Element(\"sub\")\n            self._parse([args[1]], sx)\n            trg.append(sx)\n\n    def _parse_text(self, code, trg):\n        text = str(code)\n        # TexSoup doesn't parse any non-alpha command as a command. Ex: \\$\n        # However it does seperate them into their own text part. Ex: 'r\\\\&dd' -> ['r', '\\\\&', 'dd']\n        # Therefore try to do command mapping replacement of all text beginning with \\ and of length 2\n        if len(text) == 2 and text[0] == '\\\\':\n            text = self.cmd_map.get(text[1], text)\n            _append_text(text, trg)\n            return\n        # parse ^ and _ (won't get recognized as separate nodes by TexSoup)\n        sxscript = False\n        if \"^\" in text or \"_\" in text:\n            buf = \"\"\n            for char in text:\n                if char == \"^\" or char == \"_\":\n                    _append_text(buf, trg)\n                    buf = \"\"\n                    sxscript = \"sup\" if char == \"^\" else \"sub\"\n                elif sxscript:\n                    sx = etree.Element(sxscript)\n                    sx.text = char\n                    trg.append(sx)\n                    sxscript = False\n                else:\n                    buf += char\n            text = buf\n        # Append as text\n        _append_text(text, trg)\n        return sxscript\n\n    def _append_unparsed(self, code, trg):\n        pre = etree.Element(\"span\")\n        pre.attrib[\"class\"] = \"tex-math-unparsed\"\n        pre.text = f\"\\\\{code.name}{code.args}\"\n        trg.append(pre)\n\n    def etree_to_html(self, element):\n        result = etree.Element(\"span\")\n        result.attrib[\"class\"] = \"tex-math\"\n        result.tail = element.tail  # Preserve tail\n        self._parse(TexSoup(element.text).expr.all, result)\n        return result\n\n    def to_html(self, element):\n        \"\"\"Converts a TeX math expression to HTML markup.\"\"\"\n        if isinstance(element, etree._Element):\n            return self.etree_to_html(element)\n        elif isinstance(element, str):\n            value = self.etree_to_html(etree.fromstring(f\"<span>{element}</span>\"))\n            return etree.tostring(value)\n        raise NotImplementedError(f\"Cannot convert elements of type {type(element)}\")\n\n    def to_unicode(self, element):\n        \"\"\"Converts a TeX math expression to a Unicode string.\n\n        This will perform the same conversions as `to_html()`, but strip out the\n        HTML tags afterwards.\n        \"\"\"\n        element = self.to_html(element)\n        return etree.tostring(element, encoding=\"unicode\", method=\"text\")\n", "path": "bin/anthology/texmath.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\nfrom lxml import etree\nimport csv\nimport logging as log\nimport os\nfrom TexSoup import TexSoup\nfrom TexSoup.data import TexCmd, TexText, TexGroup\n\nFUNCTION_NAMES = (\"lim\", \"log\")\nTEX_TO_HTML = {\n    \"mathrm\": (\"span\", {\"class\": \"font-weight-normal\"}),\n    \"textrm\": (\"span\", {\"class\": \"font-weight-normal\"}),\n    \"text\": (\"span\", {\"class\": \"font-weight-normal\"}),\n    \"mathbf\": (\"strong\", {}),\n    \"textbf\": (\"strong\", {}),\n    \"boldsymbol\": (\"strong\", {}),\n    \"mathit\": (\"em\", {}),\n    \"textit\": (\"em\", {}),\n    \"emph\": (\"em\", {}),\n    \"textsc\": (\"span\", {\"style\": \"font-variant: small-caps;\"}),\n    \"texttt\": (\"span\", {\"class\": \"text-monospace\"}),\n    \"textsubscript\": (\"sub\", {}),\n    \"textsuperscript\": (\"sup\", {}),\n}\nREMOVED_COMMANDS = (\"bf\", \"rm\", \"it\", \"sc\")\n\n\ndef _append_text(text, trg):\n    if not text:\n        return\n    if len(trg):\n        if trg[-1].tail is not None:\n            trg[-1].tail += text\n        else:\n            trg[-1].tail = text\n    else:\n        if trg.text is not None:\n            trg.text += text\n        else:\n            trg.text = text\n\n\nclass TexMath:\n    \"\"\"Interpreter and converter for TeX inline math expressions.\n\n    This class uses TexSoup (https://github.com/alvinwan/TexSoup) to parse a TeX\n    expression and converts it to valid HTML.  The conversion combines a small\n    number of handwritten rules with a mapping of LaTeX math mode commands to\n    Unicode symbols (http://milde.users.sourceforge.net/LUCR/Math/).  Parts that\n    cannot be interpreted using this simple method are preserved as raw LaTeX.\n    \"\"\"\n\n    def __init__(self, symbolsfile=None):\n        self.cmd_map = {}\n        if symbolsfile is None:\n            symbolsfile = os.path.join(\n                os.path.dirname(os.path.abspath(__file__)), \"unimathsymbols.txt\"\n            )\n        self.load_symbols(symbolsfile)\n\n    def load_symbols(self, filename):\n        with open(filename, \"r\", encoding=\"utf8\") as f:\n            reader = csv.reader(f, delimiter=\"^\")\n            for row in reader:\n                if row[0].startswith(\"#\"):  # comment\n                    continue\n                assert len(row) == 8, \"Expect eight-column format\"\n                char, cmd = row[1], row[2]\n                if cmd.startswith(\"\\\\\"):\n                    self.cmd_map[cmd[1:]] = char\n                if row[-1].startswith(\"= \") and \", \" in row[-1]:\n                    # last column sometimes contains alternative command\n                    cmd = row[-1][2:].split(\", \")[0]\n                    if cmd.startswith(\"\\\\\"):\n                        self.cmd_map[cmd[1:]] = char\n\n    def _parse(self, everything, trg):\n        \"\"\"Parses a list of TeX constituents into an lxml.etree._Element.\n\n        Arguments:\n            everything: An iterator over TeX constituents as provided by TexSoup\n            trg: The lxml.etree._Element to parse the expression into\n\n        The approach of iterating over the TeX constituents roughly follows\n        <https://github.com/alvinwan/TexSoup/blob/master/examples/list_everything.py>.\n        \"\"\"\n        sxscript = False  # Tracks whether we're in a subscript/superscript\n        for code in everything:\n            if isinstance(code, TexCmd):\n                # code is a TeX command\n                self._parse_command(code, trg)\n            elif isinstance(code, TexText) or isinstance(code, str):\n                # code is text\n                sxscript = self._parse_text(code, trg)\n            elif isinstance(code, TexGroup):\n                # If in subscript/superscript, wrap the entire element in respective tag\n                if sxscript:\n                    my_trg = etree.Element(sxscript)\n                    self._parse(code.contents, my_trg)\n                    trg.append(my_trg)\n                    sxscript = False\n                # Otherwise, just parse it normally\n                else:\n                    self._parse(code.contents, trg)\n            else:\n                log.error(f\"TeX-math parser got unhandled element: {type(code)}\")\n\n    def _parse_command(self, code, trg):\n        args = list(code.args)\n        name = str(code.name)\n        # Check if the command is in the list of known Unicode mappings\n        if name in self.cmd_map:\n            _append_text(self.cmd_map[name], trg)\n            self._parse(args, trg)\n        # Check if command + arguments is in the list of known Unicode mappings\n        # (this covers commands like \"\\mathcal{A}\", which have their own entries)\n        elif str(code)[1:] in self.cmd_map:\n            _append_text(self.cmd_map[str(code)[1:]], trg)\n        # Check if command is a known function name (e.g. \"log\")\n        elif name in FUNCTION_NAMES:\n            sx = etree.Element(\"span\")\n            sx.attrib[\"class\"] = \"tex-math-function\"\n            sx.text = str(name)\n            trg.append(sx)\n            self._parse(args, trg)\n        # Handle fractions\n        elif name == \"frac\":\n            self._parse_fraction(args, trg)\n        # Handle commands with simple HTML tag substitutions\n        elif name in TEX_TO_HTML:\n            elem_name, elem_attrib = TEX_TO_HTML[name]\n            sx = etree.Element(elem_name, attrib=elem_attrib)\n            self._parse(args, sx)\n            trg.append(sx)\n        # Known, but unsupported formatting tags that will just be removed\n        elif name in REMOVED_COMMANDS and not args:\n            pass\n        # Give up, but preserve element\n        else:\n            log.warn(f\"Unknown TeX-math command: {code}\")\n            self._append_unparsed(code, trg)\n\n    def _parse_fraction(self, args, trg):\n        if len(args) != 2:\n            log.warn(f\"Couldn't parse \\\\frac: got {len(args)} arguments, expected 2\")\n            self._append_unparsed({'name': 'frac', 'args': args}, trg)\n        else:\n            # Represent numerator of fraction as superscript\n            sx = etree.Element(\"sup\")\n            self._parse([args[0]], sx)\n            trg.append(sx)\n            # Unicode symbol for fraction slash\n            _append_text(\"\\u2044\", trg)\n            # Represent denominator of fraction as subscript\n            sx = etree.Element(\"sub\")\n            self._parse([args[1]], sx)\n            trg.append(sx)\n\n    def _parse_text(self, code, trg):\n        text = str(code)\n        # TexSoup doesn't parse any non-alpha command as a command. Ex: \\$\n        # However it does seperate them into their own text part. Ex: 'r\\\\&dd' -> ['r', '\\\\&', 'dd']\n        # Therefore try to do command mapping replacement of all text beginning with \\ and of length 2\n        if len(text) == 2 and text[0] == '\\\\':\n            text = self.cmd_map.get(text[1], text)\n            _append_text(text, trg)\n            return\n        # parse ^ and _ (won't get recognized as separate nodes by TexSoup)\n        sxscript = False\n        if \"^\" in text or \"_\" in text:\n            buf = \"\"\n            for char in text:\n                if char == \"^\" or char == \"_\":\n                    _append_text(buf, trg)\n                    buf = \"\"\n                    sxscript = \"sup\" if char == \"^\" else \"sub\"\n                elif sxscript:\n                    sx = etree.Element(sxscript)\n                    sx.text = char\n                    trg.append(sx)\n                    sxscript = False\n                else:\n                    buf += char\n            text = buf\n        # Append as text\n        _append_text(text, trg)\n        return sxscript\n\n    def _append_unparsed(self, code, trg):\n        pre = etree.Element(\"span\")\n        pre.attrib[\"class\"] = \"tex-math-unparsed\"\n        pre.text = f\"\\\\{code.name}{code.args}\"\n        trg.append(pre)\n\n    def etree_to_html(self, element):\n        result = etree.Element(\"span\")\n        result.attrib[\"class\"] = \"tex-math\"\n        result.tail = element.tail  # Preserve tail\n        self._parse(TexSoup(element.text).expr.all, result)\n        return result\n\n    def to_html(self, element):\n        \"\"\"Converts a TeX math expression to HTML markup.\"\"\"\n        if isinstance(element, etree._Element):\n            return self.etree_to_html(element)\n        elif isinstance(element, str):\n            value = self.etree_to_html(etree.fromstring(f\"<span>{element}</span>\"))\n            return etree.tostring(value)\n        raise NotImplementedError(f\"Cannot convert elements of type {type(element)}\")\n\n    def to_unicode(self, element):\n        \"\"\"Converts a TeX math expression to a Unicode string.\n\n        This will perform the same conversions as `to_html()`, but strip out the\n        HTML tags afterwards.\n        \"\"\"\n        element = self.to_html(element)\n        return etree.tostring(element, encoding=\"unicode\", method=\"text\", with_tail=False)\n", "path": "bin/anthology/texmath.py"}]}