From f02b5af858f27a79207b5e7316d6d04a60646cf8 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Fri, 5 Feb 2016 23:52:43 +0100 Subject: [PATCH] fixed some bugs in gtk 3.18 and added some experimental stuff that DOES NOT WORK YET! --- data/media/style.css | 16 +- uberwriter/Texsymbols.json | 0 uberwriter/UberwriterInlinePreview.py | 74 +- uberwriter/UberwriterWindow.py | 24 +- uberwriter/plugins/bibtex/__init__.py | 1 + uberwriter/plugins/bibtex/bibtex.glade | 57 + uberwriter/plugins/bibtex/bibtex.glade~ | 99 + uberwriter/plugins/bibtex/bibtex.py | 75 + uberwriter/plugins/bibtex/bibtex_item.glade | 55 + uberwriter/plugins/bibtex/bibtex_item.glade~ | 48 + .../plugins/bibtex/bibtexparser/__init__.py | 91 + .../bibtex/bibtexparser/bibdatabase.py | 57 + .../plugins/bibtex/bibtexparser/bparser.py | 422 +++ .../plugins/bibtex/bibtexparser/bwriter.py | 136 + .../bibtex/bibtexparser/customization.py | 255 ++ .../plugins/bibtex/bibtexparser/latexenc.py | 2643 +++++++++++++++++ .../bibtex/fuzzywuzzy/StringMatcher.py | 79 + .../plugins/bibtex/fuzzywuzzy/__init__.py | 2 + uberwriter/plugins/bibtex/fuzzywuzzy/fuzz.py | 263 ++ .../plugins/bibtex/fuzzywuzzy/process.py | 227 ++ .../bibtex/fuzzywuzzy/string_processing.py | 34 + uberwriter/plugins/bibtex/fuzzywuzzy/utils.py | 94 + uberwriter/plugins/bibtex/gi_composites.py | 276 ++ uberwriter/plugins/ubercsv/csvtomd | 1 + .../uberquation/equation_widget.glade~ | 109 + .../plugins/uberquation/icons/Rightarrow | 10 + uberwriter/plugins/uberquation/icons/^{0} | 12 + uberwriter/plugins/uberquation/icons/_{0} | 12 + uberwriter/plugins/uberquation/icons/alpha | 10 + uberwriter/plugins/uberquation/icons/beta | 10 + .../plugins/uberquation/icons/int_{0}^{1}{2} | 16 + uberwriter/plugins/uberquation/icons/rarrow | 5 + 32 files changed, 5171 insertions(+), 42 deletions(-) create mode 100644 uberwriter/Texsymbols.json create mode 100644 uberwriter/plugins/bibtex/__init__.py create mode 100644 uberwriter/plugins/bibtex/bibtex.glade create mode 100644 uberwriter/plugins/bibtex/bibtex.glade~ create mode 100644 uberwriter/plugins/bibtex/bibtex.py create mode 100644 uberwriter/plugins/bibtex/bibtex_item.glade create mode 100644 uberwriter/plugins/bibtex/bibtex_item.glade~ create mode 100644 uberwriter/plugins/bibtex/bibtexparser/__init__.py create mode 100644 uberwriter/plugins/bibtex/bibtexparser/bibdatabase.py create mode 100644 uberwriter/plugins/bibtex/bibtexparser/bparser.py create mode 100644 uberwriter/plugins/bibtex/bibtexparser/bwriter.py create mode 100644 uberwriter/plugins/bibtex/bibtexparser/customization.py create mode 100644 uberwriter/plugins/bibtex/bibtexparser/latexenc.py create mode 100644 uberwriter/plugins/bibtex/fuzzywuzzy/StringMatcher.py create mode 100644 uberwriter/plugins/bibtex/fuzzywuzzy/__init__.py create mode 100644 uberwriter/plugins/bibtex/fuzzywuzzy/fuzz.py create mode 100644 uberwriter/plugins/bibtex/fuzzywuzzy/process.py create mode 100644 uberwriter/plugins/bibtex/fuzzywuzzy/string_processing.py create mode 100644 uberwriter/plugins/bibtex/fuzzywuzzy/utils.py create mode 100644 uberwriter/plugins/bibtex/gi_composites.py create mode 160000 uberwriter/plugins/ubercsv/csvtomd create mode 100644 uberwriter/plugins/uberquation/equation_widget.glade~ create mode 100644 uberwriter/plugins/uberquation/icons/Rightarrow create mode 100644 uberwriter/plugins/uberquation/icons/^{0} create mode 100644 uberwriter/plugins/uberquation/icons/_{0} create mode 100644 uberwriter/plugins/uberquation/icons/alpha create mode 100644 uberwriter/plugins/uberquation/icons/beta create mode 100644 uberwriter/plugins/uberquation/icons/int_{0}^{1}{2} create mode 100644 uberwriter/plugins/uberquation/icons/rarrow diff --git a/data/media/style.css b/data/media/style.css index 90dbbd1..84a795a 100644 --- a/data/media/style.css +++ b/data/media/style.css @@ -16,6 +16,7 @@ bind "p" { "toggle-preview" () }; bind "w" { "close-window" () }; bind "f" { "toggle-search" () }; + bind "b" { "toggle-bibtex" () }; bind "r" { "toggle-search-replace" () }; bind "f" { "toggle-search-replace" () }; bind "F11" { "toggle-fullscreen" () }; @@ -42,15 +43,17 @@ } #UberwriterWindow.small .uberwriter-editor { - font: Inconsolata 12; + font: Fira Mono 10; } #UberwriterWindow.medium .uberwriter-editor { - font: Inconsolata 15; + font: Fira Mono 15; } #UberwriterWindow.large .uberwriter-editor { - font: Inconsolata 17; + /*font: Inconsolata 17; + */ + font: Fira Mono 12; } #UberwriterWindow GtkAlignment { @@ -58,6 +61,10 @@ margin-bottom: 60px; } +#titlebar_revealer { + padding: 0; +} + #UberwriterWindow.dark_mode { background: #333; } @@ -65,7 +72,6 @@ #UberwriterWindow.dark_mode .uberwriter-editor { color: #CCC; background: @dark_bg; - -GtkWidget-cursor-color: shade(#4D9FCE, 0.9); } @@ -178,7 +184,7 @@ } #LexikonBubble { - font: serif 12; + font: serif 10; background: #FFF; border-radius: 4px; margin: 5px; diff --git a/uberwriter/Texsymbols.json b/uberwriter/Texsymbols.json new file mode 100644 index 0000000..e69de29 diff --git a/uberwriter/UberwriterInlinePreview.py b/uberwriter/UberwriterInlinePreview.py index 84689cb..4d030bd 100644 --- a/uberwriter/UberwriterInlinePreview.py +++ b/uberwriter/UberwriterInlinePreview.py @@ -24,6 +24,7 @@ import subprocess import tempfile import threading +from pprint import pprint from gi.repository import Gtk, Gdk, GdkPixbuf, GObject from uberwriter_lib import LatexToPNG @@ -48,12 +49,20 @@ GObject.threads_init() # Still needed? import telnetlib +import subprocess + class DictAccessor(object): - def __init__( self, host='localhost', port=2628, timeout=60 ): + + def __init__( self, host='pan.alephnull.com', port=2628, timeout=60 ): self.tn = telnetlib.Telnet( host, port ) self.timeout = timeout self.login_response = self.tn.expect( [ self.reEndResponse ], self.timeout )[ 2 ] - bytes + + + def getOnline(self, word): + p = subprocess.Popen(['dict', '-d', 'wn', word], stdout=subprocess.PIPE) + return p.communicate()[0] + def runCommand( self, cmd ): self.tn.write( cmd.encode('utf-8') + b'\r\n' ) return self.tn.expect( [ self.reEndResponse ], self.timeout )[ 2 ] @@ -89,12 +98,16 @@ class DictAccessor(object): d = database w = word.replace( '"', r'\"' ) dsplit = self.runCommand( 'DEFINE %s "%s"' % ( d, w ) ).splitlines( True ) + # dsplit = self.getOnline(word).splitlines() + dlist = list( ) if dsplit[ -1 ].startswith( b'250 ok' ) and dsplit[ 0 ].startswith( b'1' ): dlines = dsplit[ 1:-1 ] dtext = b''.join( dlines ) dlist = self.reDefinition.findall( dtext ) - #dlist = [ dtext ] + # print(dlist) + dlist = [ dtext ] + # dlist = dsplit # not using the localhost telnet connection return dlist def close( self ): @@ -112,12 +125,12 @@ class DictAccessor(object): lines = re.sub('\s+', ' ', lines).strip() lines = re.split(r'( adv | adj | n | v |^adv |^adj |^n |^v )', lines) res = [] - act_res = {} + act_res = {'defs': [], 'class': 'none', 'num': 'None'} for l in lines: l = l.strip() if len(l) == 0: continue - if l in ['adv', 'adj','n','v']: + if l in ['adv', 'adj', 'n', 'v']: if act_res: res.append(act_res.copy()) act_res = {} @@ -154,6 +167,7 @@ class DictAccessor(object): if act_def and 'description' in act_def: act_res['defs'].append(act_def.copy()) + pprint(act_res) res.append(act_res.copy()) return res @@ -261,41 +275,45 @@ class UberwriterInlinePreview(): self.popover = None def open_popover_with_widget(self, widget): - # a = self.TextBuffer.create_child_anchor(self.TextBuffer.get_iter_at_mark(self.ClickMark)) - a = Gtk.Window.new(Gtk.WindowType.POPUP) - a.set_transient_for(self.TextView.get_toplevel()) - a.grab_focus() - a.set_name("QuickPreviewPopup") - # a.set_attached_to(self.TextView) - a.move(300, 300) - a.set_modal(True) - def close(widget, event, *args): - if(event.keyval == Gdk.KEY_Escape): - widget.destroy() - a.connect('key-press-event', close) + a = self.TextBuffer.create_child_anchor(self.TextBuffer.get_iter_at_mark(self.ClickMark)) + lbl = Gtk.Label('') + self.TextView.add_child_at_anchor(lbl, a) + lbl.show() + # a = Gtk.Window.new(Gtk.WindowType.POPUP) + # a.set_transient_for(self.TextView.get_toplevel()) + # a.grab_focus() + # a.set_name("QuickPreviewPopup") + # # a.set_attached_to(self.TextView) + # a.move(300, 300) + # a.set_modal(True) + # def close(widget, event, *args): + # if(event.keyval == Gdk.KEY_Escape): + # widget.destroy() + # a.connect('key-press-event', close) b = Gtk.Grid.new() alignment = Gtk.Alignment() alignment.props.margin_bottom = 5 alignment.props.margin_top = 5 alignment.props.margin_left = 4 alignment.add(widget) - a.add(alignment) # self.TextView.add_child_in_window(b, Gtk.TextWindowType.WIDGET, 200, 200) # b.attach(Gtk.Label.new("test 123"), 0, 0, 1, 1) # b.show_all() - a.show_all() - # self.popover = Gtk.Popover.new(b) - # dismiss, rect = popover.get_pointing_to() - # rect.y = rect.y - 20 - # popover.set_pointing_to(rect) + # a.show_all() + self.popover = Gtk.Popover.new(lbl) + self.popover.add(alignment) + # a.add(alignment) + dismiss, rect = self.popover.get_pointing_to() + rect.y = rect.y - 20 + self.popover.set_pointing_to(rect) # widget = Gtk.Label.new("testasds a;12j3 21 lk3j213") - # widget.show_all() + widget.show_all() # b.attach(widget, 0, 1, 1, 1) - # self.popover.set_modal(False) - # self.popover.show_all() - # print(self.popover) - # popover.set_property('width-request', 50) + self.popover.set_modal(True) + self.popover.show_all() + print(self.popover) + self.popover.set_property('width-request', 50) def click_move_button(self, widget, event): if event.button == 3: diff --git a/uberwriter/UberwriterWindow.py b/uberwriter/UberwriterWindow.py index e7f91ed..131a529 100644 --- a/uberwriter/UberwriterWindow.py +++ b/uberwriter/UberwriterWindow.py @@ -61,7 +61,7 @@ from uberwriter_lib import Window from uberwriter_lib import helpers from .AboutUberwriterDialog import AboutUberwriterDialog from .UberwriterAdvancedExportDialog import UberwriterAdvancedExportDialog - +from .plugins.bibtex import BibTex # Some Globals # TODO move them somewhere for better # accesibility from other files @@ -79,6 +79,7 @@ class UberwriterWindow(Window): 'save-file-as': (GObject.SIGNAL_ACTION, None, ()), 'new-file': (GObject.SIGNAL_ACTION, None, ()), 'toggle-focusmode': (GObject.SIGNAL_ACTION, None, ()), + 'toggle-bibtex': (GObject.SIGNAL_ACTION, None, ()), 'toggle-fullscreen': (GObject.SIGNAL_ACTION, None, ()), 'toggle-spellcheck': (GObject.SIGNAL_ACTION, None, ()), 'toggle-preview': (GObject.SIGNAL_ACTION, None, ()), @@ -865,8 +866,8 @@ class UberwriterWindow(Window): self.update_line_and_char_count() - def override_headerbar_background(self, widget, cr): + # Not needed in Gtk 3.18 anymore apparentlys if(widget.get_window().get_state() & self.testbits): bg_color = self.get_style_context().get_background_color(Gtk.StateFlags.ACTIVE) alloc = widget.get_allocation() @@ -901,7 +902,10 @@ class UberwriterWindow(Window): cr.fill() def use_experimental_features(self, val): - self.auto_correct = UberwriterAutoCorrect(self.TextEditor, self.TextBuffer) + try: + self.auto_correct = UberwriterAutoCorrect(self.TextEditor, self.TextBuffer) + except: + logger.debug("Couldn't install autocorrect.") def finish_initializing(self, builder): # pylint: disable=E1002 @@ -933,7 +937,7 @@ class UberwriterWindow(Window): self.use_headerbar = True if self.use_headerbar == True: - self.hb_revealer = Gtk.Revealer() + self.hb_revealer = Gtk.Revealer(name='titlebar_revealer') self.hb = Gtk.HeaderBar() self.hb_revealer.add(self.hb) self.hb_revealer.props.transition_duration = 1000 @@ -956,7 +960,7 @@ class UberwriterWindow(Window): self.hb.pack_start(bbtn) self.hb.pack_end(btn_settings) self.hb.show_all() - self.testbits = Gdk.WindowState.TILED | Gdk.WindowState.MAXIMIZED + self.testbits = Gdk.WindowState.MAXIMIZED self.connect('draw', self.override_headerbar_background) self.title_end = " – UberWriter" @@ -1145,11 +1149,13 @@ class UberwriterWindow(Window): self.gtk_settings = Gtk.Settings.get_default() self.load_settings(builder) - self.connect_after('realize', self.color_window) + self.plugins = [BibTex(self)] - def color_window(self, widget, data=None): - window_gdk = self.get_window() - window_gdk.set_background(Gdk.Color(0, 1, 0)) + # self.connect_after('realize', self.color_window) + + # def color_window(self, widget, data=None): + # window_gdk = self.get_window() + # window_gdk.set_background(Gdk.Color(0, 1, 0)) def alt_mod(self, widget, event, data=None): # TODO: Click and open when alt is pressed diff --git a/uberwriter/plugins/bibtex/__init__.py b/uberwriter/plugins/bibtex/__init__.py new file mode 100644 index 0000000..0f10e9a --- /dev/null +++ b/uberwriter/plugins/bibtex/__init__.py @@ -0,0 +1 @@ +from .bibtex import BibTex \ No newline at end of file diff --git a/uberwriter/plugins/bibtex/bibtex.glade b/uberwriter/plugins/bibtex/bibtex.glade new file mode 100644 index 0000000..c656c6d --- /dev/null +++ b/uberwriter/plugins/bibtex/bibtex.glade @@ -0,0 +1,57 @@ + + + + + + False + True + center-on-parent + center + + + True + False + vertical + + + True + True + edit-find-symbolic + False + False + + + False + True + 0 + + + + + True + True + in + + + True + False + + + True + False + False + + + + + + + True + True + 1 + + + + + + diff --git a/uberwriter/plugins/bibtex/bibtex.glade~ b/uberwriter/plugins/bibtex/bibtex.glade~ new file mode 100644 index 0000000..8aa2ad8 --- /dev/null +++ b/uberwriter/plugins/bibtex/bibtex.glade~ @@ -0,0 +1,99 @@ + + + + + + False + True + center-on-parent + center + + + True + False + vertical + + + True + True + edit-find-symbolic + False + False + + + False + True + 0 + + + + + True + True + in + + + True + False + + + True + False + False + + + + + + + True + True + 1 + + + + + + + diff --git a/uberwriter/plugins/bibtex/bibtex.py b/uberwriter/plugins/bibtex/bibtex.py new file mode 100644 index 0000000..6194585 --- /dev/null +++ b/uberwriter/plugins/bibtex/bibtex.py @@ -0,0 +1,75 @@ +from gi.repository import Gtk, Gio + +from . import bibtexparser +from . import fuzzywuzzy + +from .gi_composites import GtkTemplate + + +@GtkTemplate(ui='/home/wolfv/Programs/uberwriter/uberwriter/plugins/bibtex/bibtex_item.glade') +class BibTexItem(Gtk.Box): + + __gtype_name__ = 'BibTexItem' + + title_label = GtkTemplate.Child() + author_label = GtkTemplate.Child() + other_label = GtkTemplate.Child() + + def __init__(self, data): + super(Gtk.Box, self).__init__() + # This must occur *after* you initialize your base + self.init_template() + self.title_label.set_text(data['title']) + self.author_label.set_text(data.get('author')) + self.other_label.set_text(data.get('year') if data.get('year') else 'N/A') + + +class BibTex(object): + """docstring for Handler""" + + def open_bibtex(self, event, *args): + self.match() + self.window.show_all() + # self.window.set_transient(True) + # self.window.set_modal(True) + + def get_widget_for_box(self, word): + return Gtk.Label(word) + + def real_row_activated(self, row, data=None): + print("A row was activated!!") + self.app.TextBuffer.insert_at_cursor('[@' + data + ']') + self.close() + print(data) + + def row_activated(self, widget, row, data=None): + # row.activate() + return + + def match(self, word=None): + self.rows = [] + for i in self.bib_db.entries: + row = Gtk.ListBoxRow() + item = BibTexItem(i) + row.add(item) + row.set_activatable(True) + row.connect('activate', self.real_row_activated, i['ID']) + self.rows.append(row) + self.listview.add(row) + + # self.listview.add(Gtk.Label('test')) + # self.listview.bind_model(a, self.get_widget_for_box) + self.listview.show_all() + + def __init__(self, app): + self.app = app + self.app.connect('toggle_bibtex', self.open_bibtex) + with open('/home/wolfv/ownCloud/Studium/Semester Project/Report/listb.bib') as f: + self.bib_db = bibtexparser.load(f) + + builder = Gtk.Builder() + builder.add_from_file('/home/wolfv/Programs/uberwriter/uberwriter/plugins/bibtex/bibtex.glade') + self.window = builder.get_object('bibtex_window') + self.window.set_transient_for(self.app) + self.window.set_modal(True) + self.listview = builder.get_object('listbox') \ No newline at end of file diff --git a/uberwriter/plugins/bibtex/bibtex_item.glade b/uberwriter/plugins/bibtex/bibtex_item.glade new file mode 100644 index 0000000..6f60e03 --- /dev/null +++ b/uberwriter/plugins/bibtex/bibtex_item.glade @@ -0,0 +1,55 @@ + + + + + + diff --git a/uberwriter/plugins/bibtex/bibtex_item.glade~ b/uberwriter/plugins/bibtex/bibtex_item.glade~ new file mode 100644 index 0000000..bec5c09 --- /dev/null +++ b/uberwriter/plugins/bibtex/bibtex_item.glade~ @@ -0,0 +1,48 @@ + + + + + + diff --git a/uberwriter/plugins/bibtex/bibtexparser/__init__.py b/uberwriter/plugins/bibtex/bibtexparser/__init__.py new file mode 100644 index 0000000..e36a239 --- /dev/null +++ b/uberwriter/plugins/bibtex/bibtexparser/__init__.py @@ -0,0 +1,91 @@ +""" +BibTeX is a bibliographic data file format. + +The :mod:`bibtexparser` module provides parsing and writing of BibTeX files functionality. The API is similar to the +:mod:`json` module. The parsed data is returned as a simple :class:`BibDatabase` object with the main attribute being +:attr:`entries` representing bibliographic sources such as books and journal articles. + +Parsing is a simple as:: + + >>>> import bibtexparser + >>>> with open('bibtex.bib') as bibtex_file: + >>>> bibtex_database = bibtexparser.load(bibtex_file) + +And writing:: + + >>>> import bibtexparser + >>>> with open('bibtex.bib', 'w') as bibtex_file: + >>>> bibtexparser.dump(bibtex_database, bibtex_file) + +""" +__all__ = [ + 'loads', 'load', 'dumps', 'dump', 'bibdatabase', + 'bparser', 'bwriter', 'latexenc', 'customization', +] +__version__ = '0.6.2' + +from . import bibdatabase, bparser, bwriter, latexenc, customization + + +def loads(bibtex_str, parser=None): + """ + Load :class:`BibDatabase` object from a string + + :param bibtex_str: input BibTeX string to be parsed + :type bibtex_str: str or unicode + :param parser: custom parser to use (optional) + :type parser: BibTexParser + :return: bibliographic database object + :rtype: BibDatabase + """ + if parser is None: + parser = bparser.BibTexParser() + return parser.parse(bibtex_str) + + +def load(bibtex_file, parser=None): + """ + Load :class:`BibDatabase` object from a file + + :param bibtex_file: input file to be parsed + :type bibtex_file: file + :param parser: custom parser to use (optional) + :type parser: BibTexParser + :return: bibliographic database object + :rtype: BibDatabase + """ + if parser is None: + parser = bparser.BibTexParser() + return parser.parse_file(bibtex_file) + + +def dumps(bib_database, writer=None): + """ + Dump :class:`BibDatabase` object to a BibTeX string + + :param bib_database: bibliographic database object + :type bib_database: BibDatabase + :param writer: custom writer to use (optional) (not yet implemented) + :type writer: BibTexWriter + :return: BibTeX string + :rtype: unicode + """ + if writer is None: + writer = bwriter.BibTexWriter() + return writer.write(bib_database) + + +def dump(bib_database, bibtex_file, writer=None): + """ + Save :class:`BibDatabase` object as a BibTeX text file + + :param bib_database: bibliographic database object + :type bib_database: BibDatabase + :param bibtex_file: file to write to + :type bibtex_file: file + :param writer: custom writer to use (optional) (not yet implemented) + :type writer: BibTexWriter + """ + if writer is None: + writer = bwriter.BibTexWriter() + bibtex_file.write(writer.write(bib_database)) diff --git a/uberwriter/plugins/bibtex/bibtexparser/bibdatabase.py b/uberwriter/plugins/bibtex/bibtexparser/bibdatabase.py new file mode 100644 index 0000000..6f71b4f --- /dev/null +++ b/uberwriter/plugins/bibtex/bibtexparser/bibdatabase.py @@ -0,0 +1,57 @@ +from collections import OrderedDict +import sys + + +if sys.version_info.major == 2: + TEXT_TYPE = unicode +else: + TEXT_TYPE = str + + +class BibDatabase(object): + """ + A bibliographic database object following the data structure of a BibTeX file. + """ + def __init__(self): + #: List of BibTeX entries, for example `@book{...}`, `@article{...}`, etc. Each entry is a simple dict with + #: BibTeX field-value pairs, for example `'author': 'Bird, R.B. and Armstrong, R.C. and Hassager, O.'` Each + #: entry will always have the following dict keys (in addition to other BibTeX fields): + #: - `ID` (BibTeX key) + #: - `ENTRYTYPE` (entry type in lowercase, e.g. `book`, `article` etc.) + self.entries = [] + self._entries_dict = {} + #: List of BibTeX comment (`@comment{...}`) blocks. + self.comments = [] + #: OrderedDict of BibTeX string definitions (`@string{...}`). In order of definition. + self.strings = OrderedDict() # Not sure if order is import, keep order just in case + #: List of BibTeX preamble (`@preamble{...}`) blocks. + self.preambles = [] + + def get_entry_list(self): + """Get a list of bibtex entries. + + :returns: BibTeX entries + :rtype: list + .. deprecated:: 0.5.6 + Use :attr:`entries` instead. + """ + return self.entries + + @staticmethod + def entry_sort_key(entry, fields): + result = [] + for field in fields: + result.append(TEXT_TYPE(entry.get(field, '')).lower()) # Sorting always as string + return tuple(result) + + def get_entry_dict(self): + """Return a dictionary of BibTeX entries. + The dict key is the BibTeX entry key + """ + # If the hash has never been made, make it + if not self._entries_dict: + for entry in self.entries: + self._entries_dict[entry['ID']] = entry + return self._entries_dict + + entries_dict = property(get_entry_dict) diff --git a/uberwriter/plugins/bibtex/bibtexparser/bparser.py b/uberwriter/plugins/bibtex/bibtexparser/bparser.py new file mode 100644 index 0000000..7cdcf9e --- /dev/null +++ b/uberwriter/plugins/bibtex/bibtexparser/bparser.py @@ -0,0 +1,422 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Original source: github.com/okfn/bibserver +# Authors: +# markmacgillivray +# Etienne Posthumus (epoz) +# Francois Boulogne + +import sys +import logging +import io +import re +from .bibdatabase import BibDatabase + +logger = logging.getLogger(__name__) + +__all__ = ['BibTexParser'] + + +if sys.version_info >= (3, 0): + from io import StringIO + ustr = str +else: + from StringIO import StringIO + ustr = unicode + + +class BibTexParser(object): + """ + A parser for reading BibTeX bibliographic data files. + + Example:: + + from bibtexparser.bparser import BibTexParser + + bibtex_str = ... + + parser = BibTexParser() + parser.ignore_nonstandard_types = False + parser.homogenise_fields = False + bib_database = bibtexparser.loads(bibtex_str, parser) + """ + + def __new__(cls, data=None, + customization=None, + ignore_nonstandard_types=True, + homogenise_fields=True): + """ + To catch the old API structure in which creating the parser would immediately parse and return data. + """ + + if data is None: + return super(BibTexParser, cls).__new__(cls) + else: + # For backwards compatibility: if data is given, parse and return the `BibDatabase` object instead of the + # parser. + parser = BibTexParser() + parser.customization = customization + parser.ignore_nonstandard_types = ignore_nonstandard_types + parser.homogenise_fields = homogenise_fields + return parser.parse(data) + + def __init__(self): + """ + Creates a parser for rading BibTeX files + + :return: parser + :rtype: `BibTexParser` + """ + self.bib_database = BibDatabase() + #: Callback function to process BibTeX entries after parsing, for example to create a list from a string with + #: multiple values. By default all BibTeX values are treated as simple strings. Default: `None`. + self.customization = None + + #: Ignore non-standard BibTeX types (`book`, `article`, etc). Default: `True`. + self.ignore_nonstandard_types = True + + #: Sanitise BibTeX field names, for example change `url` to `link` etc. Field names are always converted to + #: lowercase names. Default: `True`. + self.homogenise_fields = True + + # On some sample data files, the character encoding detection simply + # hangs We are going to default to utf8, and mandate it. + self.encoding = 'utf8' + + # pre-defined set of key changes + self.alt_dict = { + 'keyw': 'keyword', + 'keywords': 'keyword', + 'authors': 'author', + 'editors': 'editor', + 'url': 'link', + 'urls': 'link', + 'links': 'link', + 'subjects': 'subject' + } + + self.replace_all_re = re.compile(r'((?P
"?)\s*(#|^)\s*(?P[^\d\W]\w*)\s*(#|$)\s*(?P"?))', re.UNICODE)
+
+    def _bibtex_file_obj(self, bibtex_str):
+        # Some files have Byte-order marks inserted at the start
+        byte = '\xef\xbb\xbf'
+        if not isinstance(byte, ustr):
+            byte = ustr('\xef\xbb\xbf', self.encoding, 'ignore')
+        if bibtex_str[:3] == byte:
+            bibtex_str = bibtex_str[3:]
+        return StringIO(bibtex_str)
+
+    def parse(self, bibtex_str):
+        """Parse a BibTeX string into an object
+
+        :param bibtex_str: BibTeX string
+        :type: str or unicode
+        :return: bibliographic database
+        :rtype: BibDatabase
+        """
+        self.bibtex_file_obj = self._bibtex_file_obj(bibtex_str)
+        self._parse_records(customization=self.customization)
+        return self.bib_database
+
+    def parse_file(self, file):
+        """Parse a BibTeX file into an object
+
+        :param file: BibTeX file or file-like object
+        :type: file
+        :return: bibliographic database
+        :rtype: BibDatabase
+        """
+        return self.parse(file.read())
+
+    def _parse_records(self, customization=None):
+        """Parse the bibtex into a list of records.
+
+        :param customization: a function
+        """
+        def _add_parsed_record(record, records):
+            """
+            Atomic function to parse a record
+            and append the result in records
+            """
+            if record != "":
+                logger.debug('The record is not empty. Let\'s parse it.')
+                parsed = self._parse_record(record, customization=customization)
+                if parsed:
+                    logger.debug('Store the result of the parsed record')
+                    records.append(parsed)
+                else:
+                    logger.debug('Nothing returned from the parsed record!')
+            else:
+                logger.debug('The record is empty')
+
+        records = []
+        record = ""
+        # read each line, bundle them up until they form an object, then send for parsing
+        for linenumber, line in enumerate(self.bibtex_file_obj):
+            logger.debug('Inspect line %s', linenumber)
+            if line.strip().startswith('@'):
+                # Remove leading whitespaces
+                line = line.lstrip()
+                logger.debug('Line starts with @')
+                # Parse previous record
+                _add_parsed_record(record, records)
+                # Start new record
+                logger.debug('The record is set to empty')
+                record = ""
+            # Keep adding lines to the record
+            record += line
+
+        # catch any remaining record and send it for parsing
+        _add_parsed_record(record, records)
+        logger.debug('Set the list of entries')
+        self.bib_database.entries = records
+
+    def _parse_record(self, record, customization=None):
+        """Parse a record.
+
+        * tidy whitespace and other rubbish
+        * parse out the bibtype and citekey
+        * find all the key-value pairs it contains
+
+        :param record: a record
+        :param customization: a function
+
+        :returns: dict --
+        """
+        d = {}
+
+        if not record.startswith('@'):
+            logger.debug('The record does not start with @. Return empty dict.')
+            return {}
+
+        # if a comment record, add to bib_database.comments
+        if record.lower().startswith('@comment'):
+            logger.debug('The record startswith @comment')
+            logger.debug('Store comment in list of comments')
+
+            self.bib_database.comments.append(re.search('\{(.*)\}', record, re.DOTALL).group(1))
+
+            logger.debug('Return an empty dict')
+            return {}
+
+        # if a preamble record, add to bib_database.preambles
+        if record.lower().startswith('@preamble'):
+            logger.debug('The record startswith @preamble')
+            logger.debug('Store preamble in list of preambles')
+
+            self.bib_database.preambles.append(re.search('\{(.*)\}', record, re.DOTALL).group(1))
+
+            logger.debug('Return an empty dict')
+            return {}
+
+        # prepare record
+        record = '\n'.join([i.strip() for i in record.split('\n')])
+        if '}\n' in record:
+            logger.debug('}\\n detected in the record. Clean up.')
+            record = record.replace('\r\n', '\n').replace('\r', '\n').rstrip('\n')
+            # treat the case for which the last line of the record
+            # does not have a coma
+            if record.endswith('}\n}') or record.endswith('}}'):
+                logger.debug('Missing coma in the last line of the record. Fix it.')
+                record = re.sub('}(\n|)}$', '},\n}', record)
+
+        # if a string record, put it in the replace_dict
+        if record.lower().startswith('@string'):
+            logger.debug('The record startswith @string')
+            key, val = [i.strip().strip('{').strip('}').replace('\n', ' ') for i in record.split('{', 1)[1].strip('}').strip('\n').strip(',').split('=')]
+            key = key.lower()  # key is case insensitive
+            val = self._string_subst_partial(val)
+            if val.startswith('"') or val.lower() not in self.bib_database.strings:
+                self.bib_database.strings[key] = val.strip('"')
+            else:
+                self.bib_database.strings[key] = self.bib_database.strings[val.lower()]
+            logger.debug('Return a dict')
+            return d
+
+        # for each line in record
+        logger.debug('Split the record of its lines and treat them')
+        kvs = [i.strip() for i in re.split(',\s*\n|\n\s*,', record)]
+        inkey = ""
+        inval = ""
+        for kv in kvs:
+            logger.debug('Inspect: %s', kv)
+            # TODO: We may check that the keyword belongs to a known type
+            if kv.startswith('@') and not inkey:
+                # it is the start of the record - set the bibtype and citekey (id)
+                logger.debug('Line starts with @ and the key is not stored yet.')
+                bibtype, id = kv.split('{', 1)
+                bibtype = self._add_key(bibtype)
+                id = id.lstrip().strip('}').strip(',')
+                logger.debug('bibtype = %s', bibtype)
+                logger.debug('id = %s', id)
+                if self.ignore_nonstandard_types and bibtype not in ('article',
+                                                                     'book',
+                                                                     'booklet',
+                                                                     'conference',
+                                                                     'inbook',
+                                                                     'incollection',
+                                                                     'inproceedings',
+                                                                     'manual',
+                                                                     'mastersthesis',
+                                                                     'misc',
+                                                                     'phdthesis',
+                                                                     'proceedings',
+                                                                     'techreport',
+                                                                     'unpublished'):
+                    logger.warning('Entry type %s not standard. Not considered.', bibtype)
+                    break
+            elif '=' in kv and not inkey:
+                # it is a line with a key value pair on it
+                logger.debug('Line contains a key-pair value and the key is not stored yet.')
+                key, val = [i.strip() for i in kv.split('=', 1)]
+                key = self._add_key(key)
+                val = self._string_subst_partial(val)
+                # if it looks like the value spans lines, store details for next loop
+                if (val.count('{') != val.count('}')) or (val.startswith('"') and not val.replace('}', '').endswith('"')):
+                    logger.debug('The line is not ending the record.')
+                    inkey = key
+                    inval = val
+                else:
+                    logger.debug('The line is the end of the record.')
+                    d[key] = self._add_val(val)
+            elif inkey:
+                logger.debug('Continues the previous line to complete the key pair value...')
+                # if this line continues the value from a previous line, append
+                inval += ', ' + kv
+                # if it looks like this line finishes the value, store it and clear for next loop
+                if (inval.startswith('{') and inval.endswith('}')) or (inval.startswith('"') and inval.endswith('"')):
+                    logger.debug('This line represents the end of the current key-pair value')
+                    d[inkey] = self._add_val(inval)
+                    inkey = ""
+                    inval = ""
+                else:
+                    logger.debug('This line does NOT represent the end of the current key-pair value')
+
+        logger.debug('All lines have been treated')
+        if not d:
+            logger.debug('The dict is empty, return it.')
+            return d
+
+        d['ENTRYTYPE'] = bibtype
+        d['ID'] = id
+
+        if customization is None:
+            logger.debug('No customization to apply, return dict')
+            return d
+        else:
+            # apply any customizations to the record object then return it
+            logger.debug('Apply customizations and return dict')
+            return customization(d)
+
+    def _strip_quotes(self, val):
+        """Strip double quotes enclosing string
+
+        :param val: a value
+        :type val: string
+        :returns: string -- value
+        """
+        logger.debug('Strip quotes')
+        val = val.strip()
+        if val.startswith('"') and val.endswith('"'):
+            return val[1:-1]
+        return val
+
+    def _strip_braces(self, val):
+        """Strip braces enclosing string
+
+        :param val: a value
+        :type val: string
+        :returns: string -- value
+        """
+        logger.debug('Strip braces')
+        val = val.strip()
+        if val.startswith('{') and val.endswith('}') and self._full_span(val):
+            return val[1:-1]
+        return val
+
+    def _full_span(self, val):
+        cnt = 0
+        for i in range(0, len(val)):
+                if val[i] == '{':
+                        cnt += 1
+                elif val[i] == '}':
+                        cnt -= 1
+                if cnt == 0:
+                        break
+        if i == len(val) - 1:
+                return True
+        else:
+                return False
+
+    def _string_subst(self, val):
+        """ Substitute string definitions
+
+        :param val: a value
+        :type val: string
+        :returns: string -- value
+        """
+        logger.debug('Substitute string definitions')
+        if not val:
+            return ''
+        for k in list(self.bib_database.strings.keys()):
+            if val.lower() == k:
+                val = self.bib_database.strings[k]
+        if not isinstance(val, ustr):
+            val = ustr(val, self.encoding, 'ignore')
+
+        return val
+
+    def _string_subst_partial(self, val):
+        """ Substitute string definitions inside larger expressions
+
+        :param val: a value
+        :type val: string
+        :returns: string -- value
+        """
+        def repl(m):
+            k = m.group('id')
+            replacement = self.bib_database.strings[k.lower()] if k.lower() in self.bib_database.strings else k
+            pre = '"' if m.group('pre') != '"' else ''
+            post = '"' if m.group('post') != '"' else ''
+            return pre + replacement + post
+
+        logger.debug('Substitute string definitions inside larger expressions')
+        if '#' not in val:
+            return val
+
+        # TODO?: Does not match two subsequent variables or strings, such as  "start" # foo # bar # "end"  or  "start" # "end".
+        # TODO:  Does not support braces instead of quotes, e.g.: {start} # foo # {bar}
+        # TODO:  Does not support strings like: "te#s#t"
+        return self.replace_all_re.sub(repl, val)
+
+    def _add_val(self, val):
+        """ Clean instring before adding to dictionary
+
+        :param val: a value
+        :type val: string
+        :returns: string -- value
+        """
+        if not val or val == "{}":
+            return ''
+        val = self._strip_braces(val)
+        val = self._strip_quotes(val)
+        val = self._strip_braces(val)
+        val = self._string_subst(val)
+        return val
+
+    def _add_key(self, key):
+        """ Add a key and homogeneize alternative forms.
+
+        :param key: a key
+        :type key: string
+        :returns: string -- value
+        """
+        key = key.strip().strip('@').lower()
+        if self.homogenise_fields:
+            if key in list(self.alt_dict.keys()):
+                key = self.alt_dict[key]
+        if not isinstance(key, ustr):
+            return ustr(key, 'utf-8')
+        else:
+            return key
diff --git a/uberwriter/plugins/bibtex/bibtexparser/bwriter.py b/uberwriter/plugins/bibtex/bibtexparser/bwriter.py
new file mode 100644
index 0000000..65472a4
--- /dev/null
+++ b/uberwriter/plugins/bibtex/bibtexparser/bwriter.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Author: Francois Boulogne
+# License:
+
+import logging
+from .bibdatabase import BibDatabase
+
+logger = logging.getLogger(__name__)
+
+__all__ = ['BibTexWriter']
+
+
+def to_bibtex(parsed):
+    """
+    Convenience function for backwards compatibility.
+    """
+    return BibTexWriter().write(parsed)
+
+
+class BibTexWriter(object):
+    """
+    Writer to convert a :class:`BibDatabase` object to a string or file formatted as a BibTeX file.
+
+    Example::
+
+        from bibtexparser.bwriter import BibTexWriter
+
+        bib_database = ...
+
+        writer = BibTexWriter()
+        writer.contents = ['comments', 'entries']
+        writer.indent = '  '
+        writer.order_entries_by = ('ENTRYTYPE', 'author', 'year')
+        bibtex_str = bibtexparser.dumps(bib_database, writer)
+
+    """
+
+    _valid_contents = ['entries', 'comments', 'preambles', 'strings']
+
+    def __init__(self):
+        #: List of BibTeX elements to write, valid values are `entries`, `comments`, `preambles`, `strings`.
+        self.contents = ['comments', 'preambles', 'strings', 'entries']
+        #: Character(s) for indenting BibTeX field-value pairs. Default: single space.
+        self.indent = ' '
+        #: Align values. Determines the maximal number of characters used in any fieldname and aligns all values
+        #    according to that by filling up with single spaces. Default: False
+        self.align_values = False
+        #: Characters(s) for separating BibTeX entries. Default: new line.
+        self.entry_separator = '\n'
+        #: Tuple of fields for ordering BibTeX entries. Set to `None` to disable sorting. Default: BibTeX key `('ID', )`.
+        self.order_entries_by = ('ID', )
+        #: Tuple of fields for display order in a single BibTeX entry. Fields not listed here will be displayed
+        #: alphabetically at the end. Set to '[]' for alphabetical order. Default: '[]'
+        self.display_order = []
+        #: BibTeX syntax allows comma first syntax
+        #: (common in functional languages), use this to enable
+        #: comma first syntax as the bwritter output
+        self.comma_first = False
+
+        #: internal variable used if self.align_values = True
+        self._max_field_width = 0
+
+
+    def write(self, bib_database):
+        """
+        Converts a bibliographic database to a BibTeX-formatted string.
+
+        :param bib_database: bibliographic database to be converted to a BibTeX string
+        :type bib_database: BibDatabase
+        :return: BibTeX-formatted string
+        :rtype: str or unicode
+        """
+        bibtex = ''
+        for content in self.contents:
+            try:
+                # Add each element set (entries, comments)
+                bibtex += getattr(self, '_' + content + '_to_bibtex')(bib_database)
+            except AttributeError:
+                logger.warning("BibTeX item '{}' does not exist and will not be written. Valid items are {}."
+                               .format(content, self._valid_contents))
+        return bibtex
+
+    def _entries_to_bibtex(self, bib_database):
+        bibtex = ''
+        if self.order_entries_by:
+            # TODO: allow sort field does not exist for entry
+            entries = sorted(bib_database.entries, key=lambda x: BibDatabase.entry_sort_key(x, self.order_entries_by))
+        else:
+            entries = bib_database.entries
+
+        if self.align_values:
+            # determine maximum field width to be used
+            widths = [max(map(len, entry.keys())) for entry in entries]
+            self._max_field_width = max(widths)
+
+        for entry in entries:
+            bibtex += self._entry_to_bibtex(entry)
+        return bibtex
+
+    def _entry_to_bibtex(self, entry):
+        bibtex = ''
+        # Write BibTeX key
+        bibtex += '@' + entry['ENTRYTYPE'] + '{' + entry['ID']
+
+        # create display_order of fields for this entry
+        # first those keys which are both in self.display_order and in entry.keys
+        display_order = [i for i in self.display_order if i in entry]
+        # then all the other fields sorted alphabetically
+        more_fields = [i for i in sorted(entry) if i not in self.display_order]
+        display_order += [i for i in sorted(entry) if i not in self.display_order]
+
+        # Write field = value lines
+        for field in [i for i in display_order if i not in ['ENTRYTYPE', 'ID']]:
+            try:
+                if self.comma_first:
+                    bibtex += "\n" + self.indent + ", " + "{0:<{1}}".format(field, self._max_field_width) + " = {" + entry[field] + "}"
+                else:
+                    bibtex += ",\n" + self.indent + "{0:<{1}}".format(field, self._max_field_width) + " = {" + entry[field] + "}"
+            except TypeError:
+                raise TypeError(u"The field %s in entry %s must be a string"
+                                % (field, entry['ID']))
+        bibtex += "\n}\n" + self.entry_separator
+        return bibtex
+
+    def _comments_to_bibtex(self, bib_database):
+        return ''.join(['@comment{{{0}}}\n{1}'.format(comment, self.entry_separator)
+                        for comment in bib_database.comments])
+
+    def _preambles_to_bibtex(self, bib_database):
+        return ''.join(['@preamble{{{0}}}\n{1}'.format(preamble, self.entry_separator)
+                        for preamble in bib_database.preambles])
+
+    def _strings_to_bibtex(self, bib_database):
+        return ''.join(['@string{{{0} = "{1}"}}\n{2}'.format(name, value, self.entry_separator)
+                        for name, value in bib_database.strings.items()])
diff --git a/uberwriter/plugins/bibtex/bibtexparser/customization.py b/uberwriter/plugins/bibtex/bibtexparser/customization.py
new file mode 100644
index 0000000..9b46025
--- /dev/null
+++ b/uberwriter/plugins/bibtex/bibtexparser/customization.py
@@ -0,0 +1,255 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+A set of functions useful for customizing bibtex fields.
+You can find inspiration from these functions to design yours.
+Each of them takes a record and return the modified record.
+"""
+
+import itertools
+import re
+import logging
+
+from .latexenc import unicode_to_latex, unicode_to_crappy_latex1, unicode_to_crappy_latex2, string_to_latex, protect_uppercase
+
+logger = logging.getLogger(__name__)
+
+__all__ = ['getnames', 'author', 'editor', 'journal', 'keyword', 'link',
+           'page_double_hyphen', 'doi', 'type', 'convert_to_unicode',
+           'homogeneize_latex_encoding']
+
+
+def getnames(names):
+    """Make people names as surname, firstnames
+    or surname, initials. Should eventually combine up the two.
+
+    :param names: a list of names
+    :type names: list
+    :returns: list -- Correctly formated names
+    """
+    tidynames = []
+    for namestring in names:
+        namestring = namestring.strip()
+        if len(namestring) < 1:
+            continue
+        if ',' in namestring:
+            namesplit = namestring.split(',', 1)
+            last = namesplit[0].strip()
+            firsts = [i.strip() for i in namesplit[1].split()]
+        else:
+            namesplit = namestring.split()
+            last = namesplit.pop()
+            firsts = [i.replace('.', '. ').strip() for i in namesplit]
+        if last in ['jnr', 'jr', 'junior']:
+            last = firsts.pop()
+        for item in firsts:
+            if item in ['ben', 'van', 'der', 'de', 'la', 'le']:
+                last = firsts.pop() + ' ' + last
+        tidynames.append(last + ", " + ' '.join(firsts))
+    return tidynames
+
+
+def author(record):
+    """
+    Split author field into a list of "Name, Surname".
+
+    :param record: the record.
+    :type record: dict
+    :returns: dict -- the modified record.
+
+    """
+    if "author" in record:
+        if record["author"]:
+            record["author"] = getnames([i.strip() for i in record["author"].replace('\n', ' ').split(" and ")])
+        else:
+            del record["author"]
+    return record
+
+
+def editor(record):
+    """
+    Turn the editor field into a dict composed of the original editor name
+    and a editor id (without coma or blank).
+
+    :param record: the record.
+    :type record: dict
+    :returns: dict -- the modified record.
+
+    """
+    if "editor" in record:
+        if record["editor"]:
+            record["editor"] = getnames([i.strip() for i in record["editor"].replace('\n', ' ').split(" and ")])
+            # convert editor to object
+            record["editor"] = [{"name": i, "ID": i.replace(',', '').replace(' ', '').replace('.', '')} for i in record["editor"]]
+        else:
+            del record["editor"]
+    return record
+
+
+def page_double_hyphen(record):
+    """
+    Separate pages by a double hyphen (--).
+
+    :param record: the record.
+    :type record: dict
+    :returns: dict -- the modified record.
+
+    """
+    if "pages" in record:
+        # hyphen, non-breaking hyphen, en dash, em dash, hyphen-minus, minus sign
+        separators = [u'‐', u'‑', u'–', u'—', u'-', u'−']
+        for separator in separators:
+            if separator in record["pages"]:
+                p = [i.strip().strip(separator) for i in record["pages"].split(separator)]
+                record["pages"] = p[0] + '--' + p[-1]
+    return record
+
+
+def type(record):
+    """
+    Put the type into lower case.
+
+    :param record: the record.
+    :type record: dict
+    :returns: dict -- the modified record.
+
+    """
+    if "type" in record:
+        record["type"] = record["type"].lower()
+    return record
+
+
+def journal(record):
+    """
+    Turn the journal field into a dict composed of the original journal name
+    and a journal id (without coma or blank).
+
+    :param record: the record.
+    :type record: dict
+    :returns: dict -- the modified record.
+
+    """
+    if "journal" in record:
+        # switch journal to object
+        if record["journal"]:
+            record["journal"] = {"name": record["journal"], "ID": record["journal"].replace(',', '').replace(' ', '').replace('.', '')}
+
+    return record
+
+
+def keyword(record, sep=',|;'):
+    """
+    Split keyword field into a list.
+
+    :param record: the record.
+    :type record: dict
+    :param sep: pattern used for the splitting regexp.
+    :type record: string, optional
+    :returns: dict -- the modified record.
+
+    """
+    if "keyword" in record:
+        record["keyword"] = [i.strip() for i in re.split(sep, record["keyword"].replace('\n', ''))]
+
+    return record
+
+
+def link(record):
+    """
+
+    :param record: the record.
+    :type record: dict
+    :returns: dict -- the modified record.
+
+    """
+    if "link" in record:
+        links = [i.strip().replace("  ", " ") for i in record["link"].split('\n')]
+        record['link'] = []
+        for link in links:
+            parts = link.split(" ")
+            linkobj = {"url": parts[0]}
+            if len(parts) > 1:
+                linkobj["anchor"] = parts[1]
+            if len(parts) > 2:
+                linkobj["format"] = parts[2]
+            if len(linkobj["url"]) > 0:
+                record["link"].append(linkobj)
+
+    return record
+
+
+def doi(record):
+    """
+
+    :param record: the record.
+    :type record: dict
+    :returns: dict -- the modified record.
+
+    """
+    if 'doi' in record:
+        if 'link' not in record:
+            record['link'] = []
+        nodoi = True
+        for item in record['link']:
+            if 'doi' in item:
+                nodoi = False
+        if nodoi:
+            link = record['doi']
+            if link.startswith('10'):
+                link = 'http://dx.doi.org/' + link
+            record['link'].append({"url": link, "anchor": "doi"})
+    return record
+
+
+def convert_to_unicode(record):
+    """
+    Convert accent from latex to unicode style.
+
+    :param record: the record.
+    :type record: dict
+    :returns: dict -- the modified record.
+    """
+    for val in record:
+        if '\\' in record[val] or '{' in record[val]:
+            for k, v in itertools.chain(unicode_to_crappy_latex1, unicode_to_latex):
+                if v in record[val]:
+                    record[val] = record[val].replace(v, k)
+
+        # If there is still very crappy items
+        if '\\' in record[val]:
+            for k, v in unicode_to_crappy_latex2:
+                if v in record[val]:
+                    parts = record[val].split(str(v))
+                    for key, record[val] in enumerate(parts):
+                        if key+1 < len(parts) and len(parts[key+1]) > 0:
+                            # Change order to display accents
+                            parts[key] = parts[key] + parts[key+1][0]
+                            parts[key+1] = parts[key+1][1:]
+                    record[val] = k.join(parts)
+    return record
+
+
+def homogeneize_latex_encoding(record):
+    """
+    Homogeneize the latex enconding style for bibtex
+
+    This function is experimental.
+
+    :param record: the record.
+    :type record: dict
+    :returns: dict -- the modified record.
+    """
+    # First, we convert everything to unicode
+    record = convert_to_unicode(record)
+    # And then, we fall back
+    for val in record:
+        if val not in ('ID',):
+            logger.debug('Apply string_to_latex to: %s', val)
+            record[val] = string_to_latex(record[val])
+            if val == 'title':
+                logger.debug('Protect uppercase in title')
+                logger.debug('Before: %s', record[val])
+                record[val] = protect_uppercase(record[val])
+                logger.debug('After: %s', record[val])
+    return record
diff --git a/uberwriter/plugins/bibtex/bibtexparser/latexenc.py b/uberwriter/plugins/bibtex/bibtexparser/latexenc.py
new file mode 100644
index 0000000..b919a24
--- /dev/null
+++ b/uberwriter/plugins/bibtex/bibtexparser/latexenc.py
@@ -0,0 +1,2643 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Original source: github.com/okfn/bibserver
+# Authors:
+# markmacgillivray
+# Etienne Posthumus (epoz)
+# Francois Boulogne 
+
+import re
+import sys
+
+__all__ = ['string_to_latex', 'protect_uppercase', 'unicode_to_latex',
+           'unicode_to_crappy_latex1', 'unicode_to_crappy_latex2']
+
+
+def string_to_latex(string):
+    """
+    Convert a string to its latex equivalent
+    """
+    escape = [' ', '{', '}']
+
+    new = []
+    for char in string:
+        if char in escape:
+            new.append(char)
+        else:
+            new.append(unicode_to_latex_map.get(char, char))
+    return ''.join(new)
+
+
+def protect_uppercase(string):
+    """
+    Protect uppercase letters for bibtex
+
+    :param string: string to convert
+    :returns: string
+    """
+    string = re.sub('([^{]|^)([A-Z])([^}]|$)', '\g<1>{\g<2>}\g<3>', string)
+    return string
+
+
+# list of latex conversions from
+# https://gist.github.com/798549
+# this list contrains crappy accents
+# like \`{e} which is not advised for bibtex
+# http://tex.stackexchange.com/questions/57743/how-to-write-a-and-other-umlauts-and-accented-letters-in-bibliography/57745#57745
+# Correct accent are in unicode_to_latex
+unicode_to_latex = []
+unicode_to_latex_map = {}
+unicode_to_crappy_latex1 = []
+unicode_to_crappy_latex2 = []
+
+def prepare_unicode_to_latex():
+    global unicode_to_latex
+    global unicode_to_latex_map
+    global unicode_to_crappy_latex1
+    global unicode_to_crappy_latex2
+
+    to_crappy1 = (
+        ("\u00C0", "\\`{A}"),
+        ("\u00C1", "\\'{A}"),
+        ("\u00C2", "\\^{A}"),
+        ("\u00C3", "\\~{A}"),
+        ("\u00C4", "\\\"{A}"),
+        ("\u00C5", "\\AA "),
+        ("\u00C6", "\\AE "),
+        ("\u00C7", "\\c{C}"),
+        ("\u00C8", "\\`{E}"),
+        ("\u00C9", "\\'{E}"),
+        ("\u00CA", "\\^{E}"),
+        ("\u00CB", "\\\"{E}"),
+        ("\u00CC", "\\`{I}"),
+        ("\u00CD", "\\'{I}"),
+        ("\u00CE", "\\^{I}"),
+        ("\u00CF", "\\\"{I}"),
+        ("\u00D0", "\\DH "),
+        ("\u00D1", "\\~{N}"),
+        ("\u00D2", "\\`{O}"),
+        ("\u00D3", "\\'{O}"),
+        ("\u00D4", "\\^{O}"),
+        ("\u00D5", "\\~{O}"),
+        ("\u00D6", "\\\"{O}"),
+        ("\u00D7", "\\texttimes "),
+        ("\u00D8", "\\O "),
+        ("\u00D9", "\\`{U}"),
+        ("\u00DA", "\\'{U}"),
+        ("\u00DB", "\\^{U}"),
+        ("\u00DC", "\\\"{U}"),
+        ("\u00DD", "\\'{Y}"),
+        ("\u00DE", "\\TH "),
+        ("\u00DF", "\\ss "),
+        ("\u00E0", "\\`{a}"),
+        ("\u00E1", "\\'{a}"),
+        ("\u00E2", "\\^{a}"),
+        ("\u00E3", "\\~{a}"),
+        ("\u00E4", "\\\"{a}"),
+        ("\u00E5", "\\aa "),
+        ("\u00E6", "\\ae "),
+        ("\u00E7", "\\c{c}"),
+        ("\u00E8", "\\`{e}"),
+        ("\u00E9", "\\'{e}"),
+        ("\u00EA", "\\^{e}"),
+        ("\u00EB", "\\\"{e}"),
+        ("\u00EC", "\\`{\\i}"),
+        ("\u00ED", "\\'{\\i}"),
+        ("\u00EE", "\\^{\\i}"),
+        ("\u00EF", "\\\"{\\i}"),
+        ("\u00F0", "\\dh "),
+        ("\u00F1", "\\~{n}"),
+        ("\u00F2", "\\`{o}"),
+        ("\u00F3", "\\'{o}"),
+        ("\u00F4", "\\^{o}"),
+        ("\u00F5", "\\~{o}"),
+        ("\u00F6", "\\\"{o}"),
+        ("\u00F7", "\\div "),
+        ("\u00F8", "\\o "),
+        ("\u00F9", "\\`{u}"),
+        ("\u00FA", "\\'{u}"),
+        ("\u00FB", "\\^{u}"),
+        ("\u00FC", "\\\"{u}"),
+        ("\u00FD", "\\'{y}"),
+        ("\u00FE", "\\th "),
+        ("\u00FF", "\\\"{y}"),
+        ("\u0100", "\\={A}"),
+        ("\u0101", "\\={a}"),
+        ("\u0102", "\\u{A}"),
+        ("\u0103", "\\u{a}"),
+        ("\u0104", "\\k{A}"),
+        ("\u0105", "\\k{a}"),
+        ("\u0106", "\\'{C}"),
+        ("\u0107", "\\'{c}"),
+        ("\u0108", "\\^{C}"),
+        ("\u0109", "\\^{c}"),
+        ("\u010A", "\\.{C}"),
+        ("\u010B", "\\.{c}"),
+        ("\u010C", "\\v{C}"),
+        ("\u010D", "\\v{c}"),
+        ("\u010E", "\\v{D}"),
+        ("\u010F", "\\v{d}"),
+        ("\u0110", "\\DJ "),
+        ("\u0111", "\\dj "),
+        ("\u0112", "\\={E}"),
+        ("\u0113", "\\={e}"),
+        ("\u0114", "\\u{E}"),
+        ("\u0115", "\\u{e}"),
+        ("\u0116", "\\.{E}"),
+        ("\u0117", "\\.{e}"),
+        ("\u0118", "\\k{E}"),
+        ("\u0119", "\\k{e}"),
+        ("\u011A", "\\v{E}"),
+        ("\u011B", "\\v{e}"),
+        ("\u011C", "\\^{G}"),
+        ("\u011D", "\\^{g}"),
+        ("\u011E", "\\u{G}"),
+        ("\u011F", "\\u{g}"),
+        ("\u0120", "\\.{G}"),
+        ("\u0121", "\\.{g}"),
+        ("\u0122", "\\c{G}"),
+        ("\u0123", "\\c{g}"),
+        ("\u0124", "\\^{H}"),
+        ("\u0125", "\\^{h}"),
+        ("\u0126", "{\\fontencoding{LELA}\\selectfont\\char40}"),
+        ("\u0127", "\\Elzxh "),
+        ("\u0128", "\\~{I}"),
+        ("\u0129", "\\~{\\i}"),
+        ("\u012A", "\\={I}"),
+        ("\u012B", "\\={\\i}"),
+        ("\u012C", "\\u{I}"),
+        ("\u012D", "\\u{\\i}"),
+        ("\u012E", "\\k{I}"),
+        ("\u012F", "\\k{i}"),
+        ("\u0130", "\\.{I}"),
+        ("\u0131", "\\i "),
+#        (u"\u0132", "IJ"),
+#        (u"\u0133", "ij"),
+        ("\u0134", "\\^{J}"),
+        ("\u0135", "\\^{\\j}"),
+        ("\u0136", "\\c{K}"),
+        ("\u0137", "\\c{k}"),
+        ("\u0138", "{\\fontencoding{LELA}\\selectfont\\char91}"),
+        ("\u0139", "\\'{L}"),
+        ("\u013A", "\\'{l}"),
+        ("\u013B", "\\c{L}"),
+        ("\u013C", "\\c{l}"),
+        ("\u013D", "\\v{L}"),
+        ("\u013E", "\\v{l}"),
+        ("\u013F", "{\\fontencoding{LELA}\\selectfont\\char201}"),
+        ("\u0140", "{\\fontencoding{LELA}\\selectfont\\char202}"),
+        ("\u0141", "\\L "),
+        ("\u0142", "\\l "),
+        ("\u0143", "\\'{N}"),
+        ("\u0144", "\\'{n}"),
+        ("\u0145", "\\c{N}"),
+        ("\u0146", "\\c{n}"),
+        ("\u0147", "\\v{N}"),
+        ("\u0148", "\\v{n}"),
+        ("\u0149", "'n"),
+        ("\u014A", "\\NG "),
+        ("\u014B", "\\ng "),
+        ("\u014C", "\\={O}"),
+        ("\u014D", "\\={o}"),
+        ("\u014E", "\\u{O}"),
+        ("\u014F", "\\u{o}"),
+        ("\u0150", "\\H{O}"),
+        ("\u0151", "\\H{o}"),
+        ("\u0152", "\\OE "),
+        ("\u0153", "\\oe "),
+        ("\u0154", "\\'{R}"),
+        ("\u0155", "\\'{r}"),
+        ("\u0156", "\\c{R}"),
+        ("\u0157", "\\c{r}"),
+        ("\u0158", "\\v{R}"),
+        ("\u0159", "\\v{r}"),
+        ("\u015A", "\\'{S}"),
+        ("\u015B", "\\'{s}"),
+        ("\u015C", "\\^{S}"),
+        ("\u015D", "\\^{s}"),
+        ("\u015E", "\\c{S}"),
+        ("\u015F", "\\c{s}"),
+        ("\u0160", "\\v{S}"),
+        ("\u0161", "\\v{s}"),
+        ("\u0162", "\\c{T}"),
+        ("\u0163", "\\c{t}"),
+        ("\u0164", "\\v{T}"),
+        ("\u0165", "\\v{t}"),
+        ("\u0166", "{\\fontencoding{LELA}\\selectfont\\char47}"),
+        ("\u0167", "{\\fontencoding{LELA}\\selectfont\\char63}"),
+        ("\u0168", "\\~{U}"),
+        ("\u0169", "\\~{u}"),
+        ("\u016A", "\\={U}"),
+        ("\u016B", "\\={u}"),
+        ("\u016C", "\\u{U}"),
+        ("\u016D", "\\u{u}"),
+        ("\u016E", "\\r{U}"),
+        ("\u016F", "\\r{u}"),
+        ("\u0170", "\\H{U}"),
+        ("\u0171", "\\H{u}"),
+        ("\u0172", "\\k{U}"),
+        ("\u0173", "\\k{u}"),
+        ("\u0174", "\\^{W}"),
+        ("\u0175", "\\^{w}"),
+        ("\u0176", "\\^{Y}"),
+        ("\u0177", "\\^{y}"),
+        ("\u0178", "\\\"{Y}"),
+        ("\u0179", "\\'{Z}"),
+        ("\u017A", "\\'{z}"),
+        ("\u017B", "\\.{Z}"),
+        ("\u017C", "\\.{z}"),
+        ("\u017D", "\\v{Z}"),
+        ("\u017E", "\\v{z}"),
+        ("\u0195", "\\texthvlig "),
+        ("\u019E", "\\textnrleg "),
+        ("\u01AA", "\\eth "),
+        ("\u01BA", "{\\fontencoding{LELA}\\selectfont\\char195}"),
+        ("\u01C2", "\\textdoublepipe "),
+        ("\u01F5", "\\'{g}"),
+        ("\u0386", "\\'{A}"),
+        ("\u0388", "\\'{E}"),
+        ("\u0389", "\\'{H}"),
+        ("\u03CC", "\\'{o}"),
+    )
+
+    # These are dangerous
+    # should not be used on
+    # {\'E} for instance!
+    to_crappy2 = (
+        ("\u0300", "\\`"),
+        ("\u0301", "\\'"),
+        ("\u0302", "\\^"),
+        ("\u0327", "\\c"),
+    )
+
+    # list of latex conversions from
+    # https://gist.github.com/798549
+    # Corrected \`{e} -> {\`e}
+    to_latex = (
+        ("\u0020", "\\space "),
+        ("\u0023", "\\#"),
+        ("\u0024", "\\textdollar "),
+        ("\u0025", "\\%"),
+        ("\u0026", "\\&"),
+        ("\u0027", "\\textquotesingle "),
+        ("\u002A", "\\ast "),
+        ("\u005C", "\\textbackslash "),
+        ("\u005E", "\\^{}"),
+        ("\u005F", "\\_"),
+        ("\u0060", "\\textasciigrave "),
+        ("\u007B", "\\lbrace "),
+        ("\u007C", "\\vert "),
+        ("\u007D", "\\rbrace "),
+        ("\u007E", "\\textasciitilde "),
+        ("\u00A1", "\\textexclamdown "),
+        ("\u00A2", "\\textcent "),
+        ("\u00A3", "\\textsterling "),
+        ("\u00A4", "\\textcurrency "),
+        ("\u00A5", "\\textyen "),
+        ("\u00A6", "\\textbrokenbar "),
+        ("\u00A7", "\\textsection "),
+        ("\u00A8", "\\textasciidieresis "),
+        ("\u00A9", "\\textcopyright "),
+        ("\u00AA", "\\textordfeminine "),
+        ("\u00AB", "\\guillemotleft "),
+        ("\u00AC", "\\lnot "),
+        ("\u00AD", "\\-"),
+        ("\u00AE", "\\textregistered "),
+        ("\u00AF", "\\textasciimacron "),
+        ("\u00B0", "\\textdegree "),
+        ("\u00B1", "\\pm "),
+        ("\u00B2", "{^2}"),
+        ("\u00B3", "{^3}"),
+        ("\u00B4", "\\textasciiacute "),
+        ("\u00B5", "\\mathrm{\\mu}"),
+        ("\u00B6", "\\textparagraph "),
+        ("\u00B7", "\\cdot "),
+        ("\u00B8", "\\c{}"),
+        ("\u00B9", "{^1}"),
+        ("\u00BA", "\\textordmasculine "),
+        ("\u00BB", "\\guillemotright "),
+        ("\u00BC", "\\textonequarter "),
+        ("\u00BD", "\\textonehalf "),
+        ("\u00BE", "\\textthreequarters "),
+        ("\u00BF", "\\textquestiondown "),
+        ("\u00C0", "{\\`A}"),
+        ("\u00C1", "{\\'A}"),
+        ("\u00C2", "{\\^A}"),
+        ("\u00C3", "{\\~A}"),
+        ("\u00C4", "{\\\"A}"),
+        ("\u00C5", "{\\AA}"),
+        ("\u00C6", "{\\AE}"),
+        ("\u00C7", "{\\c C}"),
+        ("\u00C8", "{\\`E}"),
+        ("\u00C9", "{\\'E}"),
+        ("\u00CA", "{\\^E}"),
+        ("\u00CB", "{\\\"E}"),
+        ("\u00CC", "{\\`I}"),
+        ("\u00CD", "{\\'I}"),
+        ("\u00CE", "{\\^I}"),
+        ("\u00CF", "{\\\"I}"),
+        ("\u00D0", "{\\DH}"),
+        ("\u00D1", "{\\~N}"),
+        ("\u00D2", "{\\`O}"),
+        ("\u00D3", "{\\'O}"),
+        ("\u00D4", "{\\^O}"),
+        ("\u00D5", "{\\~O}"),
+        ("\u00D6", "{\\\"O}"),
+        ("\u00D7", "\\texttimes "),
+        ("\u00D8", "{\\O}"),
+        ("\u00D9", "{\\`U}"),
+        ("\u00DA", "{\\'U}"),
+        ("\u00DB", "{\\^U}"),
+        ("\u00DC", "{\\\"U}"),
+        ("\u00DD", "{\\'Y}"),
+        ("\u00DE", "{\\TH}"),
+        ("\u00DF", "{\\ss}"),
+        ("\u00E0", "{\\`a}"),
+        ("\u00E1", "{\\'a}"),
+        ("\u00E2", "{\\^a}"),
+        ("\u00E3", "{\\~a}"),
+        ("\u00E4", "{\\\"a}"),
+        ("\u00E5", "{\\aa}"),
+        ("\u00E6", "{\\ae}"),
+        ("\u00E7", "{\\c c}"),
+        ("\u00E8", "{\\`e}"),
+        ("\u00E9", "{\\'e}"),
+        ("\u00EA", "{\\^e}"),
+        ("\u00EB", "{\\\"e}"),
+        ("\u00EC", "{\\`\\i}"),
+        ("\u00ED", "{\\'\\i}"),
+        ("\u00EE", "{\\^\\i}"),
+        ("\u00EF", "{\\\"\\i}"),
+        ("\u00F0", "{\\dh }"),
+        ("\u00F1", "{\\~n}"),
+        ("\u00F2", "{\\`o}"),
+        ("\u00F3", "{\\'o}"),
+        ("\u00F4", "{\\^o}"),
+        ("\u00F5", "{\\~o}"),
+        ("\u00F6", "{\\\"o}"),
+        ("\u00F7", "{\\div}"),
+        ("\u00F8", "{\\o}"),
+        ("\u00F9", "{\\`u}"),
+        ("\u00FA", "{\\'u}"),
+        ("\u00FB", "{\\^u}"),
+        ("\u00FC", "{\\\"u}"),
+        ("\u00FD", "{\\'y}"),
+        ("\u00FE", "{\\th}"),
+        ("\u00FF", "{\\\"y}"),
+        ("\u0100", "{\\= A}"),
+        ("\u0101", "{\\= a}"),
+        ("\u0102", "{\\u A}"),
+        ("\u0103", "{\\u a}"),
+        ("\u0104", "{\\k A}"),
+        ("\u0105", "{\\k a}"),
+        ("\u0106", "{\\' C}"),
+        ("\u0107", "{\\' c}"),
+        ("\u0108", "{\\^ C}"),
+        ("\u0109", "{\\^ c}"),
+        ("\u010A", "{\\. C}"),
+        ("\u010B", "{\\. c}"),
+        ("\u010C", "{\\v C}"),
+        ("\u010D", "{\\v c}"),
+        ("\u010E", "{\\v D}"),
+        ("\u010F", "{\\v d}"),
+        ("\u0110", "{\\DJ}"),
+        ("\u0111", "{\\dj}"),
+        ("\u0112", "{\\= E}"),
+        ("\u0113", "{\\= e}"),
+        ("\u0114", "{\\u E}"),
+        ("\u0115", "{\\u e}"),
+        ("\u0116", "{\\.E}"),
+        ("\u0117", "{\\.e}"),
+        ("\u0118", "{\\k E}"),
+        ("\u0119", "{\\k e}"),
+        ("\u011A", "{\\v E}"),
+        ("\u011B", "{\\v e}"),
+        ("\u011C", "{\\^ G}"),
+        ("\u011D", "{\\^ g}"),
+        ("\u011E", "{\\u G}"),
+        ("\u011F", "{\\u g}"),
+        ("\u0120", "{\\. G}"),
+        ("\u0121", "{\\. g}"),
+        ("\u0122", "{\\c G}"),
+        ("\u0123", "{\\c g}"),
+        ("\u0124", "{\\^ H}"),
+        ("\u0125", "{\\^ h}"),
+        ("\u0126", "{\\fontencoding{LELA}\\selectfont\\char40}"),
+        ("\u0127", "\\Elzxh "),
+        ("\u0128", "{\\~ I}"),
+        ("\u0129", "{\\~ \\i}"),
+        ("\u012A", "{\\= I}"),
+        ("\u012B", "{\\= \\i}"),
+        ("\u012C", "{\\u I}"),
+        ("\u012D", "{\\u \\i}"),
+        ("\u012E", "{\\k I}"),
+        ("\u012F", "{\\k i}"),
+        ("\u0130", "{\\. I}"),
+        ("\u0131", "{\\i}"),
+#        (u"\u0132", "IJ"),
+#        (u"\u0133", "ij"),
+        ("\u0134", "{\\^J}"),
+        ("\u0135", "{\\^\\j}"),
+        ("\u0136", "{\\c K}"),
+        ("\u0137", "{\\c k}"),
+        ("\u0138", "{\\fontencoding{LELA}\\selectfont\\char91}"),
+        ("\u0139", "{\\'L}"),
+        ("\u013A", "{\\'l}"),
+        ("\u013B", "{\\c L}"),
+        ("\u013C", "{\\c l}"),
+        ("\u013D", "{\\v L}"),
+        ("\u013E", "{\\v l}"),
+        ("\u013F", "{\\fontencoding{LELA}\\selectfont\\char201}"),
+        ("\u0140", "{\\fontencoding{LELA}\\selectfont\\char202}"),
+        ("\u0141", "{\\L}"),
+        ("\u0142", "{\\l}"),
+        ("\u0143", "{\\'N}"),
+        ("\u0144", "{\\'n}"),
+        ("\u0145", "{\\c N}"),
+        ("\u0146", "{\\c n}"),
+        ("\u0147", "{\\v N}"),
+        ("\u0148", "{\\v n}"),
+        ("\u0149", "'n"),
+        ("\u014A", "{\\NG}"),
+        ("\u014B", "{\\ng}"),
+        ("\u014C", "{\\= O}"),
+        ("\u014D", "{\\= o}"),
+        ("\u014E", "{\\u O}"),
+        ("\u014F", "{\\u o}"),
+        ("\u0150", "{\\H O}"),
+        ("\u0151", "{\\H o}"),
+        ("\u0152", "{\\OE}"),
+        ("\u0153", "{\\oe}"),
+        ("\u0154", "{\\'R}"),
+        ("\u0155", "{\\'r}"),
+        ("\u0156", "{\\c R}"),
+        ("\u0157", "{\\c r}"),
+        ("\u0158", "{\\v R}"),
+        ("\u0159", "{\\v r}"),
+        ("\u015A", "{\\' S}"),
+        ("\u015B", "{\\' s}"),
+        ("\u015C", "{\\^ S}"),
+        ("\u015D", "{\\^ s}"),
+        ("\u015E", "{\\c S}"),
+        ("\u015F", "{\\c s}"),
+        ("\u0160", "{\\v S}"),
+        ("\u0161", "{\\v s}"),
+        ("\u0162", "{\\c T}"),
+        ("\u0163", "{\\c t}"),
+        ("\u0164", "{\\v T}"),
+        ("\u0165", "{\\v t}"),
+        ("\u0166", "{\\fontencoding{LELA}\\selectfont\\char47}"),
+        ("\u0167", "{\\fontencoding{LELA}\\selectfont\\char63}"),
+        ("\u0168", "{\\~ U}"),
+        ("\u0169", "{\\~ u}"),
+        ("\u016A", "{\\= U}"),
+        ("\u016B", "{\\= u}"),
+        ("\u016C", "{\\u U}"),
+        ("\u016D", "{\\u u}"),
+        ("\u016E", "{\\r U}"),
+        ("\u016F", "{\\r u}"),
+        ("\u0170", "{\\H U}"),
+        ("\u0171", "{\\H u}"),
+        ("\u0172", "{\\k U}"),
+        ("\u0173", "{\\k u}"),
+        ("\u0174", "{\\^ W}"),
+        ("\u0175", "{\\^ w}"),
+        ("\u0176", "{\\^ Y}"),
+        ("\u0177", "{\\^ y}"),
+        ("\u0178", "{\\\" Y}"),
+        ("\u0179", "{\\' Z}"),
+        ("\u017A", "{\\' z}"),
+        ("\u017B", "{\\. Z}"),
+        ("\u017C", "{\\. z}"),
+        ("\u017D", "{\\v Z}"),
+        ("\u017E", "{\\v z}"),
+        ("\u0195", "{\\texthvlig}"),
+        ("\u019E", "{\\textnrleg}"),
+        ("\u01AA", "{\\eth}"),
+        ("\u01BA", "{\\fontencoding{LELA}\\selectfont\\char195}"),
+        ("\u01C2", "\\textdoublepipe "),
+        ("\u01F5", "{\\' g}"),
+        ("\u0250", "\\Elztrna "),
+        ("\u0252", "\\Elztrnsa "),
+        ("\u0254", "\\Elzopeno "),
+        ("\u0256", "\\Elzrtld "),
+        ("\u0258", "{\\fontencoding{LEIP}\\selectfont\\char61}"),
+        ("\u0259", "\\Elzschwa "),
+        ("\u025B", "\\varepsilon "),
+        ("\u0263", "\\Elzpgamma "),
+        ("\u0264", "\\Elzpbgam "),
+        ("\u0265", "\\Elztrnh "),
+        ("\u026C", "\\Elzbtdl "),
+        ("\u026D", "\\Elzrtll "),
+        ("\u026F", "\\Elztrnm "),
+        ("\u0270", "\\Elztrnmlr "),
+        ("\u0271", "\\Elzltlmr "),
+        ("\u0272", "\\Elzltln "),
+        ("\u0273", "\\Elzrtln "),
+        ("\u0277", "\\Elzclomeg "),
+        ("\u0278", "\\textphi "),
+        ("\u0279", "\\Elztrnr "),
+        ("\u027A", "\\Elztrnrl "),
+        ("\u027B", "\\Elzrttrnr "),
+        ("\u027C", "\\Elzrl "),
+        ("\u027D", "\\Elzrtlr "),
+        ("\u027E", "\\Elzfhr "),
+        ("\u027F", "{\\fontencoding{LEIP}\\selectfont\\char202}"),
+        ("\u0282", "\\Elzrtls "),
+        ("\u0283", "\\Elzesh "),
+        ("\u0287", "\\Elztrnt "),
+        ("\u0288", "\\Elzrtlt "),
+        ("\u028A", "\\Elzpupsil "),
+        ("\u028B", "\\Elzpscrv "),
+        ("\u028C", "\\Elzinvv "),
+        ("\u028D", "\\Elzinvw "),
+        ("\u028E", "\\Elztrny "),
+        ("\u0290", "\\Elzrtlz "),
+        ("\u0292", "\\Elzyogh "),
+        ("\u0294", "\\Elzglst "),
+        ("\u0295", "\\Elzreglst "),
+        ("\u0296", "\\Elzinglst "),
+        ("\u029E", "\\textturnk "),
+        ("\u02A4", "\\Elzdyogh "),
+        ("\u02A7", "\\Elztesh "),
+        ("\u02C7", "\\textasciicaron "),
+        ("\u02C8", "\\Elzverts "),
+        ("\u02CC", "\\Elzverti "),
+        ("\u02D0", "\\Elzlmrk "),
+        ("\u02D1", "\\Elzhlmrk "),
+        ("\u02D2", "\\Elzsbrhr "),
+        ("\u02D3", "\\Elzsblhr "),
+        ("\u02D4", "\\Elzrais "),
+        ("\u02D5", "\\Elzlow "),
+        ("\u02D8", "\\textasciibreve "),
+        ("\u02D9", "\\textperiodcentered "),
+        ("\u02DA", "\\r{}"),
+        ("\u02DB", "\\k{}"),
+        ("\u02DC", "\\texttildelow "),
+        ("\u02DD", "\\H{}"),
+        ("\u02E5", "\\tone{55}"),
+        ("\u02E6", "\\tone{44}"),
+        ("\u02E7", "\\tone{33}"),
+        ("\u02E8", "\\tone{22}"),
+        ("\u02E9", "\\tone{11}"),
+        ("\u0303", "\\~"),
+        ("\u0304", "\\="),
+        ("\u0306", "\\u"),
+        ("\u0307", "\\."),
+        ("\u0308", "\\\""),
+        ("\u030A", "\\r"),
+        ("\u030B", "\\H"),
+        ("\u030C", "\\v"),
+        ("\u030F", "\\cyrchar\\C"),
+        ("\u0311", "{\\fontencoding{LECO}\\selectfont\\char177}"),
+        ("\u0318", "{\\fontencoding{LECO}\\selectfont\\char184}"),
+        ("\u0319", "{\\fontencoding{LECO}\\selectfont\\char185}"),
+        ("\u0321", "\\Elzpalh "),
+        ("\u0322", "\\Elzrh "),
+        ("\u0328", "\\k"),
+        ("\u032A", "\\Elzsbbrg "),
+        ("\u032B", "{\\fontencoding{LECO}\\selectfont\\char203}"),
+        ("\u032F", "{\\fontencoding{LECO}\\selectfont\\char207}"),
+        ("\u0335", "\\Elzxl "),
+        ("\u0336", "\\Elzbar "),
+        ("\u0337", "{\\fontencoding{LECO}\\selectfont\\char215}"),
+        ("\u0338", "{\\fontencoding{LECO}\\selectfont\\char216}"),
+        ("\u033A", "{\\fontencoding{LECO}\\selectfont\\char218}"),
+        ("\u033B", "{\\fontencoding{LECO}\\selectfont\\char219}"),
+        ("\u033C", "{\\fontencoding{LECO}\\selectfont\\char220}"),
+        ("\u033D", "{\\fontencoding{LECO}\\selectfont\\char221}"),
+        ("\u0361", "{\\fontencoding{LECO}\\selectfont\\char225}"),
+        ("\u0386", "{\\' A}"),
+        ("\u0388", "{\\' E}"),
+        ("\u0389", "{\\' H}"),
+        ("\u038A", "\\'{}{I}"),
+        ("\u038C", "\\'{}O"),
+        ("\u038E", "\\mathrm{'Y}"),
+        ("\u038F", "\\mathrm{'\\Omega}"),
+        ("\u0390", "\\acute{\\ddot{\\iota}}"),
+        ("\u0391", "\\Alpha "),
+        ("\u0392", "\\Beta "),
+        ("\u0393", "\\Gamma "),
+        ("\u0394", "\\Delta "),
+        ("\u0395", "\\Epsilon "),
+        ("\u0396", "\\Zeta "),
+        ("\u0397", "\\Eta "),
+        ("\u0398", "\\Theta "),
+        ("\u0399", "\\Iota "),
+        ("\u039A", "\\Kappa "),
+        ("\u039B", "\\Lambda "),
+        ("\u039E", "\\Xi "),
+        ("\u03A0", "\\Pi "),
+        ("\u03A1", "\\Rho "),
+        ("\u03A3", "\\Sigma "),
+        ("\u03A4", "\\Tau "),
+        ("\u03A5", "\\Upsilon "),
+        ("\u03A6", "\\Phi "),
+        ("\u03A7", "\\Chi "),
+        ("\u03A8", "\\Psi "),
+        ("\u03A9", "\\Omega "),
+        ("\u03AA", "\\mathrm{\\ddot{I}}"),
+        ("\u03AB", "\\mathrm{\\ddot{Y}}"),
+        ("\u03AC", "\\'{$\\alpha$}"),
+        ("\u03AD", "\\acute{\\epsilon}"),
+        ("\u03AE", "\\acute{\\eta}"),
+        ("\u03AF", "\\acute{\\iota}"),
+        ("\u03B0", "\\acute{\\ddot{\\upsilon}}"),
+        ("\u03B1", "\\alpha "),
+        ("\u03B2", "\\beta "),
+        ("\u03B3", "\\gamma "),
+        ("\u03B4", "\\delta "),
+        ("\u03B5", "\\epsilon "),
+        ("\u03B6", "\\zeta "),
+        ("\u03B7", "\\eta "),
+        ("\u03B8", "\\texttheta "),
+        ("\u03B9", "\\iota "),
+        ("\u03BA", "\\kappa "),
+        ("\u03BB", "\\lambda "),
+        ("\u03BC", "\\mu "),
+        ("\u03BD", "\\nu "),
+        ("\u03BE", "\\xi "),
+        ("\u03C0", "\\pi "),
+        ("\u03C1", "\\rho "),
+        ("\u03C2", "\\varsigma "),
+        ("\u03C3", "\\sigma "),
+        ("\u03C4", "\\tau "),
+        ("\u03C5", "\\upsilon "),
+        ("\u03C6", "\\varphi "),
+        ("\u03C7", "\\chi "),
+        ("\u03C8", "\\psi "),
+        ("\u03C9", "\\omega "),
+        ("\u03CA", "\\ddot{\\iota}"),
+        ("\u03CB", "\\ddot{\\upsilon}"),
+        ("\u03CC", "{\\' o}"),
+        ("\u03CD", "\\acute{\\upsilon}"),
+        ("\u03CE", "\\acute{\\omega}"),
+        ("\u03D0", "\\Pisymbol{ppi022}{87}"),
+        ("\u03D1", "\\textvartheta "),
+        ("\u03D2", "\\Upsilon "),
+        ("\u03D5", "\\phi "),
+        ("\u03D6", "\\varpi "),
+        ("\u03DA", "\\Stigma "),
+        ("\u03DC", "\\Digamma "),
+        ("\u03DD", "\\digamma "),
+        ("\u03DE", "\\Koppa "),
+        ("\u03E0", "\\Sampi "),
+        ("\u03F0", "\\varkappa "),
+        ("\u03F1", "\\varrho "),
+        ("\u03F4", "\\textTheta "),
+        ("\u03F6", "\\backepsilon "),
+        ("\u0401", "\\cyrchar\\CYRYO "),
+        ("\u0402", "\\cyrchar\\CYRDJE "),
+        ("\u0403", "\\cyrchar{\\'\\CYRG}"),
+        ("\u0404", "\\cyrchar\\CYRIE "),
+        ("\u0405", "\\cyrchar\\CYRDZE "),
+        ("\u0406", "\\cyrchar\\CYRII "),
+        ("\u0407", "\\cyrchar\\CYRYI "),
+        ("\u0408", "\\cyrchar\\CYRJE "),
+        ("\u0409", "\\cyrchar\\CYRLJE "),
+        ("\u040A", "\\cyrchar\\CYRNJE "),
+        ("\u040B", "\\cyrchar\\CYRTSHE "),
+        ("\u040C", "\\cyrchar{\\'\\CYRK}"),
+        ("\u040E", "\\cyrchar\\CYRUSHRT "),
+        ("\u040F", "\\cyrchar\\CYRDZHE "),
+        ("\u0410", "\\cyrchar\\CYRA "),
+        ("\u0411", "\\cyrchar\\CYRB "),
+        ("\u0412", "\\cyrchar\\CYRV "),
+        ("\u0413", "\\cyrchar\\CYRG "),
+        ("\u0414", "\\cyrchar\\CYRD "),
+        ("\u0415", "\\cyrchar\\CYRE "),
+        ("\u0416", "\\cyrchar\\CYRZH "),
+        ("\u0417", "\\cyrchar\\CYRZ "),
+        ("\u0418", "\\cyrchar\\CYRI "),
+        ("\u0419", "\\cyrchar\\CYRISHRT "),
+        ("\u041A", "\\cyrchar\\CYRK "),
+        ("\u041B", "\\cyrchar\\CYRL "),
+        ("\u041C", "\\cyrchar\\CYRM "),
+        ("\u041D", "\\cyrchar\\CYRN "),
+        ("\u041E", "\\cyrchar\\CYRO "),
+        ("\u041F", "\\cyrchar\\CYRP "),
+        ("\u0420", "\\cyrchar\\CYRR "),
+        ("\u0421", "\\cyrchar\\CYRS "),
+        ("\u0422", "\\cyrchar\\CYRT "),
+        ("\u0423", "\\cyrchar\\CYRU "),
+        ("\u0424", "\\cyrchar\\CYRF "),
+        ("\u0425", "\\cyrchar\\CYRH "),
+        ("\u0426", "\\cyrchar\\CYRC "),
+        ("\u0427", "\\cyrchar\\CYRCH "),
+        ("\u0428", "\\cyrchar\\CYRSH "),
+        ("\u0429", "\\cyrchar\\CYRSHCH "),
+        ("\u042A", "\\cyrchar\\CYRHRDSN "),
+        ("\u042B", "\\cyrchar\\CYRERY "),
+        ("\u042C", "\\cyrchar\\CYRSFTSN "),
+        ("\u042D", "\\cyrchar\\CYREREV "),
+        ("\u042E", "\\cyrchar\\CYRYU "),
+        ("\u042F", "\\cyrchar\\CYRYA "),
+        ("\u0430", "\\cyrchar\\cyra "),
+        ("\u0431", "\\cyrchar\\cyrb "),
+        ("\u0432", "\\cyrchar\\cyrv "),
+        ("\u0433", "\\cyrchar\\cyrg "),
+        ("\u0434", "\\cyrchar\\cyrd "),
+        ("\u0435", "\\cyrchar\\cyre "),
+        ("\u0436", "\\cyrchar\\cyrzh "),
+        ("\u0437", "\\cyrchar\\cyrz "),
+        ("\u0438", "\\cyrchar\\cyri "),
+        ("\u0439", "\\cyrchar\\cyrishrt "),
+        ("\u043A", "\\cyrchar\\cyrk "),
+        ("\u043B", "\\cyrchar\\cyrl "),
+        ("\u043C", "\\cyrchar\\cyrm "),
+        ("\u043D", "\\cyrchar\\cyrn "),
+        ("\u043E", "\\cyrchar\\cyro "),
+        ("\u043F", "\\cyrchar\\cyrp "),
+        ("\u0440", "\\cyrchar\\cyrr "),
+        ("\u0441", "\\cyrchar\\cyrs "),
+        ("\u0442", "\\cyrchar\\cyrt "),
+        ("\u0443", "\\cyrchar\\cyru "),
+        ("\u0444", "\\cyrchar\\cyrf "),
+        ("\u0445", "\\cyrchar\\cyrh "),
+        ("\u0446", "\\cyrchar\\cyrc "),
+        ("\u0447", "\\cyrchar\\cyrch "),
+        ("\u0448", "\\cyrchar\\cyrsh "),
+        ("\u0449", "\\cyrchar\\cyrshch "),
+        ("\u044A", "\\cyrchar\\cyrhrdsn "),
+        ("\u044B", "\\cyrchar\\cyrery "),
+        ("\u044C", "\\cyrchar\\cyrsftsn "),
+        ("\u044D", "\\cyrchar\\cyrerev "),
+        ("\u044E", "\\cyrchar\\cyryu "),
+        ("\u044F", "\\cyrchar\\cyrya "),
+        ("\u0451", "\\cyrchar\\cyryo "),
+        ("\u0452", "\\cyrchar\\cyrdje "),
+        ("\u0453", "\\cyrchar{\\'\\cyrg}"),
+        ("\u0454", "\\cyrchar\\cyrie "),
+        ("\u0455", "\\cyrchar\\cyrdze "),
+        ("\u0456", "\\cyrchar\\cyrii "),
+        ("\u0457", "\\cyrchar\\cyryi "),
+        ("\u0458", "\\cyrchar\\cyrje "),
+        ("\u0459", "\\cyrchar\\cyrlje "),
+        ("\u045A", "\\cyrchar\\cyrnje "),
+        ("\u045B", "\\cyrchar\\cyrtshe "),
+        ("\u045C", "\\cyrchar{\\'\\cyrk}"),
+        ("\u045E", "\\cyrchar\\cyrushrt "),
+        ("\u045F", "\\cyrchar\\cyrdzhe "),
+        ("\u0460", "\\cyrchar\\CYROMEGA "),
+        ("\u0461", "\\cyrchar\\cyromega "),
+        ("\u0462", "\\cyrchar\\CYRYAT "),
+        ("\u0464", "\\cyrchar\\CYRIOTE "),
+        ("\u0465", "\\cyrchar\\cyriote "),
+        ("\u0466", "\\cyrchar\\CYRLYUS "),
+        ("\u0467", "\\cyrchar\\cyrlyus "),
+        ("\u0468", "\\cyrchar\\CYRIOTLYUS "),
+        ("\u0469", "\\cyrchar\\cyriotlyus "),
+        ("\u046A", "\\cyrchar\\CYRBYUS "),
+        ("\u046C", "\\cyrchar\\CYRIOTBYUS "),
+        ("\u046D", "\\cyrchar\\cyriotbyus "),
+        ("\u046E", "\\cyrchar\\CYRKSI "),
+        ("\u046F", "\\cyrchar\\cyrksi "),
+        ("\u0470", "\\cyrchar\\CYRPSI "),
+        ("\u0471", "\\cyrchar\\cyrpsi "),
+        ("\u0472", "\\cyrchar\\CYRFITA "),
+        ("\u0474", "\\cyrchar\\CYRIZH "),
+        ("\u0478", "\\cyrchar\\CYRUK "),
+        ("\u0479", "\\cyrchar\\cyruk "),
+        ("\u047A", "\\cyrchar\\CYROMEGARND "),
+        ("\u047B", "\\cyrchar\\cyromegarnd "),
+        ("\u047C", "\\cyrchar\\CYROMEGATITLO "),
+        ("\u047D", "\\cyrchar\\cyromegatitlo "),
+        ("\u047E", "\\cyrchar\\CYROT "),
+        ("\u047F", "\\cyrchar\\cyrot "),
+        ("\u0480", "\\cyrchar\\CYRKOPPA "),
+        ("\u0481", "\\cyrchar\\cyrkoppa "),
+        ("\u0482", "\\cyrchar\\cyrthousands "),
+        ("\u0488", "\\cyrchar\\cyrhundredthousands "),
+        ("\u0489", "\\cyrchar\\cyrmillions "),
+        ("\u048C", "\\cyrchar\\CYRSEMISFTSN "),
+        ("\u048D", "\\cyrchar\\cyrsemisftsn "),
+        ("\u048E", "\\cyrchar\\CYRRTICK "),
+        ("\u048F", "\\cyrchar\\cyrrtick "),
+        ("\u0490", "\\cyrchar\\CYRGUP "),
+        ("\u0491", "\\cyrchar\\cyrgup "),
+        ("\u0492", "\\cyrchar\\CYRGHCRS "),
+        ("\u0493", "\\cyrchar\\cyrghcrs "),
+        ("\u0494", "\\cyrchar\\CYRGHK "),
+        ("\u0495", "\\cyrchar\\cyrghk "),
+        ("\u0496", "\\cyrchar\\CYRZHDSC "),
+        ("\u0497", "\\cyrchar\\cyrzhdsc "),
+        ("\u0498", "\\cyrchar\\CYRZDSC "),
+        ("\u0499", "\\cyrchar\\cyrzdsc "),
+        ("\u049A", "\\cyrchar\\CYRKDSC "),
+        ("\u049B", "\\cyrchar\\cyrkdsc "),
+        ("\u049C", "\\cyrchar\\CYRKVCRS "),
+        ("\u049D", "\\cyrchar\\cyrkvcrs "),
+        ("\u049E", "\\cyrchar\\CYRKHCRS "),
+        ("\u049F", "\\cyrchar\\cyrkhcrs "),
+        ("\u04A0", "\\cyrchar\\CYRKBEAK "),
+        ("\u04A1", "\\cyrchar\\cyrkbeak "),
+        ("\u04A2", "\\cyrchar\\CYRNDSC "),
+        ("\u04A3", "\\cyrchar\\cyrndsc "),
+        ("\u04A4", "\\cyrchar\\CYRNG "),
+        ("\u04A5", "\\cyrchar\\cyrng "),
+        ("\u04A6", "\\cyrchar\\CYRPHK "),
+        ("\u04A7", "\\cyrchar\\cyrphk "),
+        ("\u04A8", "\\cyrchar\\CYRABHHA "),
+        ("\u04A9", "\\cyrchar\\cyrabhha "),
+        ("\u04AA", "\\cyrchar\\CYRSDSC "),
+        ("\u04AB", "\\cyrchar\\cyrsdsc "),
+        ("\u04AC", "\\cyrchar\\CYRTDSC "),
+        ("\u04AD", "\\cyrchar\\cyrtdsc "),
+        ("\u04AE", "\\cyrchar\\CYRY "),
+        ("\u04AF", "\\cyrchar\\cyry "),
+        ("\u04B0", "\\cyrchar\\CYRYHCRS "),
+        ("\u04B1", "\\cyrchar\\cyryhcrs "),
+        ("\u04B2", "\\cyrchar\\CYRHDSC "),
+        ("\u04B3", "\\cyrchar\\cyrhdsc "),
+        ("\u04B4", "\\cyrchar\\CYRTETSE "),
+        ("\u04B5", "\\cyrchar\\cyrtetse "),
+        ("\u04B6", "\\cyrchar\\CYRCHRDSC "),
+        ("\u04B7", "\\cyrchar\\cyrchrdsc "),
+        ("\u04B8", "\\cyrchar\\CYRCHVCRS "),
+        ("\u04B9", "\\cyrchar\\cyrchvcrs "),
+        ("\u04BA", "\\cyrchar\\CYRSHHA "),
+        ("\u04BB", "\\cyrchar\\cyrshha "),
+        ("\u04BC", "\\cyrchar\\CYRABHCH "),
+        ("\u04BD", "\\cyrchar\\cyrabhch "),
+        ("\u04BE", "\\cyrchar\\CYRABHCHDSC "),
+        ("\u04BF", "\\cyrchar\\cyrabhchdsc "),
+        ("\u04C0", "\\cyrchar\\CYRpalochka "),
+        ("\u04C3", "\\cyrchar\\CYRKHK "),
+        ("\u04C4", "\\cyrchar\\cyrkhk "),
+        ("\u04C7", "\\cyrchar\\CYRNHK "),
+        ("\u04C8", "\\cyrchar\\cyrnhk "),
+        ("\u04CB", "\\cyrchar\\CYRCHLDSC "),
+        ("\u04CC", "\\cyrchar\\cyrchldsc "),
+        ("\u04D4", "\\cyrchar\\CYRAE "),
+        ("\u04D5", "\\cyrchar\\cyrae "),
+        ("\u04D8", "\\cyrchar\\CYRSCHWA "),
+        ("\u04D9", "\\cyrchar\\cyrschwa "),
+        ("\u04E0", "\\cyrchar\\CYRABHDZE "),
+        ("\u04E1", "\\cyrchar\\cyrabhdze "),
+        ("\u04E8", "\\cyrchar\\CYROTLD "),
+        ("\u04E9", "\\cyrchar\\cyrotld "),
+        ("\u2002", "\\hspace{0.6em}"),
+        ("\u2003", "\\hspace{1em}"),
+        ("\u2004", "\\hspace{0.33em}"),
+        ("\u2005", "\\hspace{0.25em}"),
+        ("\u2006", "\\hspace{0.166em}"),
+        ("\u2007", "\\hphantom{0}"),
+        ("\u2008", "\\hphantom{,}"),
+        ("\u2009", "\\hspace{0.167em}"),
+        ("\u2009-0200A-0200A", "\\;"),
+        ("\u200A", "\\mkern1mu "),
+        ("\u2013", "\\textendash "),
+        ("\u2014", "\\textemdash "),
+        ("\u2015", "\\rule{1em}{1pt}"),
+        ("\u2016", "\\Vert "),
+        ("\u201B", "\\Elzreapos "),
+        ("\u201C", "\\textquotedblleft "),
+        ("\u201D", "\\textquotedblright "),
+        ("\u201E", ",,"),
+        ("\u2020", "\\textdagger "),
+        ("\u2021", "\\textdaggerdbl "),
+        ("\u2022", "\\textbullet "),
+#        (u"\u2025", ".."),
+        ("\u2026", "\\ldots "),
+        ("\u2030", "\\textperthousand "),
+        ("\u2031", "\\textpertenthousand "),
+        ("\u2032", "{'}"),
+        ("\u2033", "{''}"),
+        ("\u2034", "{'''}"),
+        ("\u2035", "\\backprime "),
+        ("\u2039", "\\guilsinglleft "),
+        ("\u203A", "\\guilsinglright "),
+        ("\u2057", "''''"),
+        ("\u205F", "\\mkern4mu "),
+        ("\u2060", "\\nolinebreak "),
+        ("\u20A7", "\\ensuremath{\\Elzpes}"),
+        ("\u20AC", "\\mbox{\\texteuro} "),
+        ("\u20DB", "\\dddot "),
+        ("\u20DC", "\\ddddot "),
+        ("\u2102", "\\mathbb{C}"),
+        ("\u210A", "\\mathscr{g}"),
+        ("\u210B", "\\mathscr{H}"),
+        ("\u210C", "\\mathfrak{H}"),
+        ("\u210D", "\\mathbb{H}"),
+        ("\u210F", "\\hslash "),
+        ("\u2110", "\\mathscr{I}"),
+        ("\u2111", "\\mathfrak{I}"),
+        ("\u2112", "\\mathscr{L}"),
+        ("\u2113", "\\mathscr{l}"),
+        ("\u2115", "\\mathbb{N}"),
+        ("\u2116", "\\cyrchar\\textnumero "),
+        ("\u2118", "\\wp "),
+        ("\u2119", "\\mathbb{P}"),
+        ("\u211A", "\\mathbb{Q}"),
+        ("\u211B", "\\mathscr{R}"),
+        ("\u211C", "\\mathfrak{R}"),
+        ("\u211D", "\\mathbb{R}"),
+        ("\u211E", "\\Elzxrat "),
+        ("\u2122", "\\texttrademark "),
+        ("\u2124", "\\mathbb{Z}"),
+        ("\u2126", "\\Omega "),
+        ("\u2127", "\\mho "),
+        ("\u2128", "\\mathfrak{Z}"),
+        ("\u2129", "\\ElsevierGlyph{2129}"),
+        ("\u212B", "\\AA "),
+        ("\u212C", "\\mathscr{B}"),
+        ("\u212D", "\\mathfrak{C}"),
+        ("\u212F", "\\mathscr{e}"),
+        ("\u2130", "\\mathscr{E}"),
+        ("\u2131", "\\mathscr{F}"),
+        ("\u2133", "\\mathscr{M}"),
+        ("\u2134", "\\mathscr{o}"),
+        ("\u2135", "\\aleph "),
+        ("\u2136", "\\beth "),
+        ("\u2137", "\\gimel "),
+        ("\u2138", "\\daleth "),
+        ("\u2153", "\\textfrac{1}{3}"),
+        ("\u2154", "\\textfrac{2}{3}"),
+        ("\u2155", "\\textfrac{1}{5}"),
+        ("\u2156", "\\textfrac{2}{5}"),
+        ("\u2157", "\\textfrac{3}{5}"),
+        ("\u2158", "\\textfrac{4}{5}"),
+        ("\u2159", "\\textfrac{1}{6}"),
+        ("\u215A", "\\textfrac{5}{6}"),
+        ("\u215B", "\\textfrac{1}{8}"),
+        ("\u215C", "\\textfrac{3}{8}"),
+        ("\u215D", "\\textfrac{5}{8}"),
+        ("\u215E", "\\textfrac{7}{8}"),
+        ("\u2190", "\\leftarrow "),
+        ("\u2191", "\\uparrow "),
+        ("\u2192", "\\rightarrow "),
+        ("\u2193", "\\downarrow "),
+        ("\u2194", "\\leftrightarrow "),
+        ("\u2195", "\\updownarrow "),
+        ("\u2196", "\\nwarrow "),
+        ("\u2197", "\\nearrow "),
+        ("\u2198", "\\searrow "),
+        ("\u2199", "\\swarrow "),
+        ("\u219A", "\\nleftarrow "),
+        ("\u219B", "\\nrightarrow "),
+        ("\u219C", "\\arrowwaveright "),
+        ("\u219D", "\\arrowwaveright "),
+        ("\u219E", "\\twoheadleftarrow "),
+        ("\u21A0", "\\twoheadrightarrow "),
+        ("\u21A2", "\\leftarrowtail "),
+        ("\u21A3", "\\rightarrowtail "),
+        ("\u21A6", "\\mapsto "),
+        ("\u21A9", "\\hookleftarrow "),
+        ("\u21AA", "\\hookrightarrow "),
+        ("\u21AB", "\\looparrowleft "),
+        ("\u21AC", "\\looparrowright "),
+        ("\u21AD", "\\leftrightsquigarrow "),
+        ("\u21AE", "\\nleftrightarrow "),
+        ("\u21B0", "\\Lsh "),
+        ("\u21B1", "\\Rsh "),
+        ("\u21B3", "\\ElsevierGlyph{21B3}"),
+        ("\u21B6", "\\curvearrowleft "),
+        ("\u21B7", "\\curvearrowright "),
+        ("\u21BA", "\\circlearrowleft "),
+        ("\u21BB", "\\circlearrowright "),
+        ("\u21BC", "\\leftharpoonup "),
+        ("\u21BD", "\\leftharpoondown "),
+        ("\u21BE", "\\upharpoonright "),
+        ("\u21BF", "\\upharpoonleft "),
+        ("\u21C0", "\\rightharpoonup "),
+        ("\u21C1", "\\rightharpoondown "),
+        ("\u21C2", "\\downharpoonright "),
+        ("\u21C3", "\\downharpoonleft "),
+        ("\u21C4", "\\rightleftarrows "),
+        ("\u21C5", "\\dblarrowupdown "),
+        ("\u21C6", "\\leftrightarrows "),
+        ("\u21C7", "\\leftleftarrows "),
+        ("\u21C8", "\\upuparrows "),
+        ("\u21C9", "\\rightrightarrows "),
+        ("\u21CA", "\\downdownarrows "),
+        ("\u21CB", "\\leftrightharpoons "),
+        ("\u21CC", "\\rightleftharpoons "),
+        ("\u21CD", "\\nLeftarrow "),
+        ("\u21CE", "\\nLeftrightarrow "),
+        ("\u21CF", "\\nRightarrow "),
+        ("\u21D0", "\\Leftarrow "),
+        ("\u21D1", "\\Uparrow "),
+        ("\u21D2", "\\Rightarrow "),
+        ("\u21D3", "\\Downarrow "),
+        ("\u21D4", "\\Leftrightarrow "),
+        ("\u21D5", "\\Updownarrow "),
+        ("\u21DA", "\\Lleftarrow "),
+        ("\u21DB", "\\Rrightarrow "),
+        ("\u21DD", "\\rightsquigarrow "),
+        ("\u21F5", "\\DownArrowUpArrow "),
+        ("\u2200", "\\forall "),
+        ("\u2201", "\\complement "),
+        ("\u2202", "\\partial "),
+        ("\u2203", "\\exists "),
+        ("\u2204", "\\nexists "),
+        ("\u2205", "\\varnothing "),
+        ("\u2207", "\\nabla "),
+        ("\u2208", "\\in "),
+        ("\u2209", "\\not\\in "),
+        ("\u220B", "\\ni "),
+        ("\u220C", "\\not\\ni "),
+        ("\u220F", "\\prod "),
+        ("\u2210", "\\coprod "),
+        ("\u2211", "\\sum "),
+        ("\u2213", "\\mp "),
+        ("\u2214", "\\dotplus "),
+        ("\u2216", "\\setminus "),
+        ("\u2217", "{_\\ast}"),
+        ("\u2218", "\\circ "),
+        ("\u2219", "\\bullet "),
+        ("\u221A", "\\surd "),
+        ("\u221D", "\\propto "),
+        ("\u221E", "\\infty "),
+        ("\u221F", "\\rightangle "),
+        ("\u2220", "\\angle "),
+        ("\u2221", "\\measuredangle "),
+        ("\u2222", "\\sphericalangle "),
+        ("\u2223", "\\mid "),
+        ("\u2224", "\\nmid "),
+        ("\u2225", "\\parallel "),
+        ("\u2226", "\\nparallel "),
+        ("\u2227", "\\wedge "),
+        ("\u2228", "\\vee "),
+        ("\u2229", "\\cap "),
+        ("\u222A", "\\cup "),
+        ("\u222B", "\\int "),
+        ("\u222C", "\\int\\!\\int "),
+        ("\u222D", "\\int\\!\\int\\!\\int "),
+        ("\u222E", "\\oint "),
+        ("\u222F", "\\surfintegral "),
+        ("\u2230", "\\volintegral "),
+        ("\u2231", "\\clwintegral "),
+        ("\u2232", "\\ElsevierGlyph{2232}"),
+        ("\u2233", "\\ElsevierGlyph{2233}"),
+        ("\u2234", "\\therefore "),
+        ("\u2235", "\\because "),
+        ("\u2237", "\\Colon "),
+        ("\u2238", "\\ElsevierGlyph{2238}"),
+        ("\u223A", "\\mathbin{{:}\\!\\!{-}\\!\\!{:}}"),
+        ("\u223B", "\\homothetic "),
+        ("\u223C", "\\sim "),
+        ("\u223D", "\\backsim "),
+        ("\u223E", "\\lazysinv "),
+        ("\u2240", "\\wr "),
+        ("\u2241", "\\not\\sim "),
+        ("\u2242", "\\ElsevierGlyph{2242}"),
+        ("\u2242-00338", "\\NotEqualTilde "),
+        ("\u2243", "\\simeq "),
+        ("\u2244", "\\not\\simeq "),
+        ("\u2245", "\\cong "),
+        ("\u2246", "\\approxnotequal "),
+        ("\u2247", "\\not\\cong "),
+        ("\u2248", "\\approx "),
+        ("\u2249", "\\not\\approx "),
+        ("\u224A", "\\approxeq "),
+        ("\u224B", "\\tildetrpl "),
+        ("\u224B-00338", "\\not\\apid "),
+        ("\u224C", "\\allequal "),
+        ("\u224D", "\\asymp "),
+        ("\u224E", "\\Bumpeq "),
+        ("\u224E-00338", "\\NotHumpDownHump "),
+        ("\u224F", "\\bumpeq "),
+        ("\u224F-00338", "\\NotHumpEqual "),
+        ("\u2250", "\\doteq "),
+        ("\u2250-00338", "\\not\\doteq"),
+        ("\u2251", "\\doteqdot "),
+        ("\u2252", "\\fallingdotseq "),
+        ("\u2253", "\\risingdotseq "),
+        ("\u2254", ":="),
+        ("\u2255", "=:"),
+        ("\u2256", "\\eqcirc "),
+        ("\u2257", "\\circeq "),
+        ("\u2259", "\\estimates "),
+        ("\u225A", "\\ElsevierGlyph{225A}"),
+        ("\u225B", "\\starequal "),
+        ("\u225C", "\\triangleq "),
+        ("\u225F", "\\ElsevierGlyph{225F}"),
+        ("\u2260", "\\not ="),
+        ("\u2261", "\\equiv "),
+        ("\u2262", "\\not\\equiv "),
+        ("\u2264", "\\leq "),
+        ("\u2265", "\\geq "),
+        ("\u2266", "\\leqq "),
+        ("\u2267", "\\geqq "),
+        ("\u2268", "\\lneqq "),
+        ("\u2268-0FE00", "\\lvertneqq "),
+        ("\u2269", "\\gneqq "),
+        ("\u2269-0FE00", "\\gvertneqq "),
+        ("\u226A", "\\ll "),
+        ("\u226A-00338", "\\NotLessLess "),
+        ("\u226B", "\\gg "),
+        ("\u226B-00338", "\\NotGreaterGreater "),
+        ("\u226C", "\\between "),
+        ("\u226D", "\\not\\kern-0.3em\\times "),
+        ("\u226E", "\\not<"),
+        ("\u226F", "\\not>"),
+        ("\u2270", "\\not\\leq "),
+        ("\u2271", "\\not\\geq "),
+        ("\u2272", "\\lessequivlnt "),
+        ("\u2273", "\\greaterequivlnt "),
+        ("\u2274", "\\ElsevierGlyph{2274}"),
+        ("\u2275", "\\ElsevierGlyph{2275}"),
+        ("\u2276", "\\lessgtr "),
+        ("\u2277", "\\gtrless "),
+        ("\u2278", "\\notlessgreater "),
+        ("\u2279", "\\notgreaterless "),
+        ("\u227A", "\\prec "),
+        ("\u227B", "\\succ "),
+        ("\u227C", "\\preccurlyeq "),
+        ("\u227D", "\\succcurlyeq "),
+        ("\u227E", "\\precapprox "),
+        ("\u227E-00338", "\\NotPrecedesTilde "),
+        ("\u227F", "\\succapprox "),
+        ("\u227F-00338", "\\NotSucceedsTilde "),
+        ("\u2280", "\\not\\prec "),
+        ("\u2281", "\\not\\succ "),
+        ("\u2282", "\\subset "),
+        ("\u2283", "\\supset "),
+        ("\u2284", "\\not\\subset "),
+        ("\u2285", "\\not\\supset "),
+        ("\u2286", "\\subseteq "),
+        ("\u2287", "\\supseteq "),
+        ("\u2288", "\\not\\subseteq "),
+        ("\u2289", "\\not\\supseteq "),
+        ("\u228A", "\\subsetneq "),
+        ("\u228A-0FE00", "\\varsubsetneqq "),
+        ("\u228B", "\\supsetneq "),
+        ("\u228B-0FE00", "\\varsupsetneq "),
+        ("\u228E", "\\uplus "),
+        ("\u228F", "\\sqsubset "),
+        ("\u228F-00338", "\\NotSquareSubset "),
+        ("\u2290", "\\sqsupset "),
+        ("\u2290-00338", "\\NotSquareSuperset "),
+        ("\u2291", "\\sqsubseteq "),
+        ("\u2292", "\\sqsupseteq "),
+        ("\u2293", "\\sqcap "),
+        ("\u2294", "\\sqcup "),
+        ("\u2295", "\\oplus "),
+        ("\u2296", "\\ominus "),
+        ("\u2297", "\\otimes "),
+        ("\u2298", "\\oslash "),
+        ("\u2299", "\\odot "),
+        ("\u229A", "\\circledcirc "),
+        ("\u229B", "\\circledast "),
+        ("\u229D", "\\circleddash "),
+        ("\u229E", "\\boxplus "),
+        ("\u229F", "\\boxminus "),
+        ("\u22A0", "\\boxtimes "),
+        ("\u22A1", "\\boxdot "),
+        ("\u22A2", "\\vdash "),
+        ("\u22A3", "\\dashv "),
+        ("\u22A4", "\\top "),
+        ("\u22A5", "\\perp "),
+        ("\u22A7", "\\truestate "),
+        ("\u22A8", "\\forcesextra "),
+        ("\u22A9", "\\Vdash "),
+        ("\u22AA", "\\Vvdash "),
+        ("\u22AB", "\\VDash "),
+        ("\u22AC", "\\nvdash "),
+        ("\u22AD", "\\nvDash "),
+        ("\u22AE", "\\nVdash "),
+        ("\u22AF", "\\nVDash "),
+        ("\u22B2", "\\vartriangleleft "),
+        ("\u22B3", "\\vartriangleright "),
+        ("\u22B4", "\\trianglelefteq "),
+        ("\u22B5", "\\trianglerighteq "),
+        ("\u22B6", "\\original "),
+        ("\u22B7", "\\image "),
+        ("\u22B8", "\\multimap "),
+        ("\u22B9", "\\hermitconjmatrix "),
+        ("\u22BA", "\\intercal "),
+        ("\u22BB", "\\veebar "),
+        ("\u22BE", "\\rightanglearc "),
+        ("\u22C0", "\\ElsevierGlyph{22C0}"),
+        ("\u22C1", "\\ElsevierGlyph{22C1}"),
+        ("\u22C2", "\\bigcap "),
+        ("\u22C3", "\\bigcup "),
+        ("\u22C4", "\\diamond "),
+        ("\u22C5", "\\cdot "),
+        ("\u22C6", "\\star "),
+        ("\u22C7", "\\divideontimes "),
+        ("\u22C8", "\\bowtie "),
+        ("\u22C9", "\\ltimes "),
+        ("\u22CA", "\\rtimes "),
+        ("\u22CB", "\\leftthreetimes "),
+        ("\u22CC", "\\rightthreetimes "),
+        ("\u22CD", "\\backsimeq "),
+        ("\u22CE", "\\curlyvee "),
+        ("\u22CF", "\\curlywedge "),
+        ("\u22D0", "\\Subset "),
+        ("\u22D1", "\\Supset "),
+        ("\u22D2", "\\Cap "),
+        ("\u22D3", "\\Cup "),
+        ("\u22D4", "\\pitchfork "),
+        ("\u22D6", "\\lessdot "),
+        ("\u22D7", "\\gtrdot "),
+        ("\u22D8", "\\verymuchless "),
+        ("\u22D9", "\\verymuchgreater "),
+        ("\u22DA", "\\lesseqgtr "),
+        ("\u22DB", "\\gtreqless "),
+        ("\u22DE", "\\curlyeqprec "),
+        ("\u22DF", "\\curlyeqsucc "),
+        ("\u22E2", "\\not\\sqsubseteq "),
+        ("\u22E3", "\\not\\sqsupseteq "),
+        ("\u22E5", "\\Elzsqspne "),
+        ("\u22E6", "\\lnsim "),
+        ("\u22E7", "\\gnsim "),
+        ("\u22E8", "\\precedesnotsimilar "),
+        ("\u22E9", "\\succnsim "),
+        ("\u22EA", "\\ntriangleleft "),
+        ("\u22EB", "\\ntriangleright "),
+        ("\u22EC", "\\ntrianglelefteq "),
+        ("\u22ED", "\\ntrianglerighteq "),
+        ("\u22EE", "\\vdots "),
+        ("\u22EF", "\\cdots "),
+        ("\u22F0", "\\upslopeellipsis "),
+        ("\u22F1", "\\downslopeellipsis "),
+        ("\u2305", "\\barwedge "),
+        ("\u2306", "\\perspcorrespond "),
+        ("\u2308", "\\lceil "),
+        ("\u2309", "\\rceil "),
+        ("\u230A", "\\lfloor "),
+        ("\u230B", "\\rfloor "),
+        ("\u2315", "\\recorder "),
+        ("\u2316", "\\mathchar\"2208"),
+        ("\u231C", "\\ulcorner "),
+        ("\u231D", "\\urcorner "),
+        ("\u231E", "\\llcorner "),
+        ("\u231F", "\\lrcorner "),
+        ("\u2322", "\\frown "),
+        ("\u2323", "\\smile "),
+        ("\u2329", "\\langle "),
+        ("\u232A", "\\rangle "),
+        ("\u233D", "\\ElsevierGlyph{E838}"),
+        ("\u23A3", "\\Elzdlcorn "),
+        ("\u23B0", "\\lmoustache "),
+        ("\u23B1", "\\rmoustache "),
+        ("\u2423", "\\textvisiblespace "),
+        ("\u2460", "\\ding{172}"),
+        ("\u2461", "\\ding{173}"),
+        ("\u2462", "\\ding{174}"),
+        ("\u2463", "\\ding{175}"),
+        ("\u2464", "\\ding{176}"),
+        ("\u2465", "\\ding{177}"),
+        ("\u2466", "\\ding{178}"),
+        ("\u2467", "\\ding{179}"),
+        ("\u2468", "\\ding{180}"),
+        ("\u2469", "\\ding{181}"),
+        ("\u24C8", "\\circledS "),
+        ("\u2506", "\\Elzdshfnc "),
+        ("\u2519", "\\Elzsqfnw "),
+        ("\u2571", "\\diagup "),
+        ("\u25A0", "\\ding{110}"),
+        ("\u25A1", "\\square "),
+        ("\u25AA", "\\blacksquare "),
+        ("\u25AD", "\\fbox{~~}"),
+        ("\u25AF", "\\Elzvrecto "),
+        ("\u25B1", "\\ElsevierGlyph{E381}"),
+        ("\u25B2", "\\ding{115}"),
+        ("\u25B3", "\\bigtriangleup "),
+        ("\u25B4", "\\blacktriangle "),
+        ("\u25B5", "\\vartriangle "),
+        ("\u25B8", "\\blacktriangleright "),
+        ("\u25B9", "\\triangleright "),
+        ("\u25BC", "\\ding{116}"),
+        ("\u25BD", "\\bigtriangledown "),
+        ("\u25BE", "\\blacktriangledown "),
+        ("\u25BF", "\\triangledown "),
+        ("\u25C2", "\\blacktriangleleft "),
+        ("\u25C3", "\\triangleleft "),
+        ("\u25C6", "\\ding{117}"),
+        ("\u25CA", "\\lozenge "),
+        ("\u25CB", "\\bigcirc "),
+        ("\u25CF", "\\ding{108}"),
+        ("\u25D0", "\\Elzcirfl "),
+        ("\u25D1", "\\Elzcirfr "),
+        ("\u25D2", "\\Elzcirfb "),
+        ("\u25D7", "\\ding{119}"),
+        ("\u25D8", "\\Elzrvbull "),
+        ("\u25E7", "\\Elzsqfl "),
+        ("\u25E8", "\\Elzsqfr "),
+        ("\u25EA", "\\Elzsqfse "),
+        ("\u25EF", "\\bigcirc "),
+        ("\u2605", "\\ding{72}"),
+        ("\u2606", "\\ding{73}"),
+        ("\u260E", "\\ding{37}"),
+        ("\u261B", "\\ding{42}"),
+        ("\u261E", "\\ding{43}"),
+        ("\u263E", "\\rightmoon "),
+        ("\u263F", "\\mercury "),
+        ("\u2640", "\\venus "),
+        ("\u2642", "\\male "),
+        ("\u2643", "\\jupiter "),
+        ("\u2644", "\\saturn "),
+        ("\u2645", "\\uranus "),
+        ("\u2646", "\\neptune "),
+        ("\u2647", "\\pluto "),
+        ("\u2648", "\\aries "),
+        ("\u2649", "\\taurus "),
+        ("\u264A", "\\gemini "),
+        ("\u264B", "\\cancer "),
+        ("\u264C", "\\leo "),
+        ("\u264D", "\\virgo "),
+        ("\u264E", "\\libra "),
+        ("\u264F", "\\scorpio "),
+        ("\u2650", "\\sagittarius "),
+        ("\u2651", "\\capricornus "),
+        ("\u2652", "\\aquarius "),
+        ("\u2653", "\\pisces "),
+        ("\u2660", "\\ding{171}"),
+        ("\u2662", "\\diamond "),
+        ("\u2663", "\\ding{168}"),
+        ("\u2665", "\\ding{170}"),
+        ("\u2666", "\\ding{169}"),
+        ("\u2669", "\\quarternote "),
+        ("\u266A", "\\eighthnote "),
+        ("\u266D", "\\flat "),
+        ("\u266E", "\\natural "),
+        ("\u266F", "\\sharp "),
+        ("\u2701", "\\ding{33}"),
+        ("\u2702", "\\ding{34}"),
+        ("\u2703", "\\ding{35}"),
+        ("\u2704", "\\ding{36}"),
+        ("\u2706", "\\ding{38}"),
+        ("\u2707", "\\ding{39}"),
+        ("\u2708", "\\ding{40}"),
+        ("\u2709", "\\ding{41}"),
+        ("\u270C", "\\ding{44}"),
+        ("\u270D", "\\ding{45}"),
+        ("\u270E", "\\ding{46}"),
+        ("\u270F", "\\ding{47}"),
+        ("\u2710", "\\ding{48}"),
+        ("\u2711", "\\ding{49}"),
+        ("\u2712", "\\ding{50}"),
+        ("\u2713", "\\ding{51}"),
+        ("\u2714", "\\ding{52}"),
+        ("\u2715", "\\ding{53}"),
+        ("\u2716", "\\ding{54}"),
+        ("\u2717", "\\ding{55}"),
+        ("\u2718", "\\ding{56}"),
+        ("\u2719", "\\ding{57}"),
+        ("\u271A", "\\ding{58}"),
+        ("\u271B", "\\ding{59}"),
+        ("\u271C", "\\ding{60}"),
+        ("\u271D", "\\ding{61}"),
+        ("\u271E", "\\ding{62}"),
+        ("\u271F", "\\ding{63}"),
+        ("\u2720", "\\ding{64}"),
+        ("\u2721", "\\ding{65}"),
+        ("\u2722", "\\ding{66}"),
+        ("\u2723", "\\ding{67}"),
+        ("\u2724", "\\ding{68}"),
+        ("\u2725", "\\ding{69}"),
+        ("\u2726", "\\ding{70}"),
+        ("\u2727", "\\ding{71}"),
+        ("\u2729", "\\ding{73}"),
+        ("\u272A", "\\ding{74}"),
+        ("\u272B", "\\ding{75}"),
+        ("\u272C", "\\ding{76}"),
+        ("\u272D", "\\ding{77}"),
+        ("\u272E", "\\ding{78}"),
+        ("\u272F", "\\ding{79}"),
+        ("\u2730", "\\ding{80}"),
+        ("\u2731", "\\ding{81}"),
+        ("\u2732", "\\ding{82}"),
+        ("\u2733", "\\ding{83}"),
+        ("\u2734", "\\ding{84}"),
+        ("\u2735", "\\ding{85}"),
+        ("\u2736", "\\ding{86}"),
+        ("\u2737", "\\ding{87}"),
+        ("\u2738", "\\ding{88}"),
+        ("\u2739", "\\ding{89}"),
+        ("\u273A", "\\ding{90}"),
+        ("\u273B", "\\ding{91}"),
+        ("\u273C", "\\ding{92}"),
+        ("\u273D", "\\ding{93}"),
+        ("\u273E", "\\ding{94}"),
+        ("\u273F", "\\ding{95}"),
+        ("\u2740", "\\ding{96}"),
+        ("\u2741", "\\ding{97}"),
+        ("\u2742", "\\ding{98}"),
+        ("\u2743", "\\ding{99}"),
+        ("\u2744", "\\ding{100}"),
+        ("\u2745", "\\ding{101}"),
+        ("\u2746", "\\ding{102}"),
+        ("\u2747", "\\ding{103}"),
+        ("\u2748", "\\ding{104}"),
+        ("\u2749", "\\ding{105}"),
+        ("\u274A", "\\ding{106}"),
+        ("\u274B", "\\ding{107}"),
+        ("\u274D", "\\ding{109}"),
+        ("\u274F", "\\ding{111}"),
+        ("\u2750", "\\ding{112}"),
+        ("\u2751", "\\ding{113}"),
+        ("\u2752", "\\ding{114}"),
+        ("\u2756", "\\ding{118}"),
+        ("\u2758", "\\ding{120}"),
+        ("\u2759", "\\ding{121}"),
+        ("\u275A", "\\ding{122}"),
+        ("\u275B", "\\ding{123}"),
+        ("\u275C", "\\ding{124}"),
+        ("\u275D", "\\ding{125}"),
+        ("\u275E", "\\ding{126}"),
+        ("\u2761", "\\ding{161}"),
+        ("\u2762", "\\ding{162}"),
+        ("\u2763", "\\ding{163}"),
+        ("\u2764", "\\ding{164}"),
+        ("\u2765", "\\ding{165}"),
+        ("\u2766", "\\ding{166}"),
+        ("\u2767", "\\ding{167}"),
+        ("\u2776", "\\ding{182}"),
+        ("\u2777", "\\ding{183}"),
+        ("\u2778", "\\ding{184}"),
+        ("\u2779", "\\ding{185}"),
+        ("\u277A", "\\ding{186}"),
+        ("\u277B", "\\ding{187}"),
+        ("\u277C", "\\ding{188}"),
+        ("\u277D", "\\ding{189}"),
+        ("\u277E", "\\ding{190}"),
+        ("\u277F", "\\ding{191}"),
+        ("\u2780", "\\ding{192}"),
+        ("\u2781", "\\ding{193}"),
+        ("\u2782", "\\ding{194}"),
+        ("\u2783", "\\ding{195}"),
+        ("\u2784", "\\ding{196}"),
+        ("\u2785", "\\ding{197}"),
+        ("\u2786", "\\ding{198}"),
+        ("\u2787", "\\ding{199}"),
+        ("\u2788", "\\ding{200}"),
+        ("\u2789", "\\ding{201}"),
+        ("\u278A", "\\ding{202}"),
+        ("\u278B", "\\ding{203}"),
+        ("\u278C", "\\ding{204}"),
+        ("\u278D", "\\ding{205}"),
+        ("\u278E", "\\ding{206}"),
+        ("\u278F", "\\ding{207}"),
+        ("\u2790", "\\ding{208}"),
+        ("\u2791", "\\ding{209}"),
+        ("\u2792", "\\ding{210}"),
+        ("\u2793", "\\ding{211}"),
+        ("\u2794", "\\ding{212}"),
+        ("\u2798", "\\ding{216}"),
+        ("\u2799", "\\ding{217}"),
+        ("\u279A", "\\ding{218}"),
+        ("\u279B", "\\ding{219}"),
+        ("\u279C", "\\ding{220}"),
+        ("\u279D", "\\ding{221}"),
+        ("\u279E", "\\ding{222}"),
+        ("\u279F", "\\ding{223}"),
+        ("\u27A0", "\\ding{224}"),
+        ("\u27A1", "\\ding{225}"),
+        ("\u27A2", "\\ding{226}"),
+        ("\u27A3", "\\ding{227}"),
+        ("\u27A4", "\\ding{228}"),
+        ("\u27A5", "\\ding{229}"),
+        ("\u27A6", "\\ding{230}"),
+        ("\u27A7", "\\ding{231}"),
+        ("\u27A8", "\\ding{232}"),
+        ("\u27A9", "\\ding{233}"),
+        ("\u27AA", "\\ding{234}"),
+        ("\u27AB", "\\ding{235}"),
+        ("\u27AC", "\\ding{236}"),
+        ("\u27AD", "\\ding{237}"),
+        ("\u27AE", "\\ding{238}"),
+        ("\u27AF", "\\ding{239}"),
+        ("\u27B1", "\\ding{241}"),
+        ("\u27B2", "\\ding{242}"),
+        ("\u27B3", "\\ding{243}"),
+        ("\u27B4", "\\ding{244}"),
+        ("\u27B5", "\\ding{245}"),
+        ("\u27B6", "\\ding{246}"),
+        ("\u27B7", "\\ding{247}"),
+        ("\u27B8", "\\ding{248}"),
+        ("\u27B9", "\\ding{249}"),
+        ("\u27BA", "\\ding{250}"),
+        ("\u27BB", "\\ding{251}"),
+        ("\u27BC", "\\ding{252}"),
+        ("\u27BD", "\\ding{253}"),
+        ("\u27BE", "\\ding{254}"),
+        ("\u27F5", "\\longleftarrow "),
+        ("\u27F6", "\\longrightarrow "),
+        ("\u27F7", "\\longleftrightarrow "),
+        ("\u27F8", "\\Longleftarrow "),
+        ("\u27F9", "\\Longrightarrow "),
+        ("\u27FA", "\\Longleftrightarrow "),
+        ("\u27FC", "\\longmapsto "),
+        ("\u27FF", "\\sim\\joinrel\\leadsto"),
+        ("\u2905", "\\ElsevierGlyph{E212}"),
+        ("\u2912", "\\UpArrowBar "),
+        ("\u2913", "\\DownArrowBar "),
+        ("\u2923", "\\ElsevierGlyph{E20C}"),
+        ("\u2924", "\\ElsevierGlyph{E20D}"),
+        ("\u2925", "\\ElsevierGlyph{E20B}"),
+        ("\u2926", "\\ElsevierGlyph{E20A}"),
+        ("\u2927", "\\ElsevierGlyph{E211}"),
+        ("\u2928", "\\ElsevierGlyph{E20E}"),
+        ("\u2929", "\\ElsevierGlyph{E20F}"),
+        ("\u292A", "\\ElsevierGlyph{E210}"),
+        ("\u2933", "\\ElsevierGlyph{E21C}"),
+        ("\u2933-00338", "\\ElsevierGlyph{E21D}"),
+        ("\u2936", "\\ElsevierGlyph{E21A}"),
+        ("\u2937", "\\ElsevierGlyph{E219}"),
+        ("\u2940", "\\Elolarr "),
+        ("\u2941", "\\Elorarr "),
+        ("\u2942", "\\ElzRlarr "),
+        ("\u2944", "\\ElzrLarr "),
+        ("\u2947", "\\Elzrarrx "),
+        ("\u294E", "\\LeftRightVector "),
+        ("\u294F", "\\RightUpDownVector "),
+        ("\u2950", "\\DownLeftRightVector "),
+        ("\u2951", "\\LeftUpDownVector "),
+        ("\u2952", "\\LeftVectorBar "),
+        ("\u2953", "\\RightVectorBar "),
+        ("\u2954", "\\RightUpVectorBar "),
+        ("\u2955", "\\RightDownVectorBar "),
+        ("\u2956", "\\DownLeftVectorBar "),
+        ("\u2957", "\\DownRightVectorBar "),
+        ("\u2958", "\\LeftUpVectorBar "),
+        ("\u2959", "\\LeftDownVectorBar "),
+        ("\u295A", "\\LeftTeeVector "),
+        ("\u295B", "\\RightTeeVector "),
+        ("\u295C", "\\RightUpTeeVector "),
+        ("\u295D", "\\RightDownTeeVector "),
+        ("\u295E", "\\DownLeftTeeVector "),
+        ("\u295F", "\\DownRightTeeVector "),
+        ("\u2960", "\\LeftUpTeeVector "),
+        ("\u2961", "\\LeftDownTeeVector "),
+        ("\u296E", "\\UpEquilibrium "),
+        ("\u296F", "\\ReverseUpEquilibrium "),
+        ("\u2970", "\\RoundImplies "),
+        ("\u297C", "\\ElsevierGlyph{E214}"),
+        ("\u297D", "\\ElsevierGlyph{E215}"),
+        ("\u2980", "\\Elztfnc "),
+        ("\u2985", "\\ElsevierGlyph{3018}"),
+        ("\u2986", "\\Elroang "),
+        ("\u2993", "<\\kern-0.58em("),
+        ("\u2994", "\\ElsevierGlyph{E291}"),
+        ("\u2999", "\\Elzddfnc "),
+        ("\u299C", "\\Angle "),
+        ("\u29A0", "\\Elzlpargt "),
+        ("\u29B5", "\\ElsevierGlyph{E260}"),
+        ("\u29B6", "\\ElsevierGlyph{E61B}"),
+        ("\u29CA", "\\ElzLap "),
+        ("\u29CB", "\\Elzdefas "),
+        ("\u29CF", "\\LeftTriangleBar "),
+        ("\u29CF-00338", "\\NotLeftTriangleBar "),
+        ("\u29D0", "\\RightTriangleBar "),
+        ("\u29D0-00338", "\\NotRightTriangleBar "),
+        ("\u29DC", "\\ElsevierGlyph{E372}"),
+        ("\u29EB", "\\blacklozenge "),
+        ("\u29F4", "\\RuleDelayed "),
+        ("\u2A04", "\\Elxuplus "),
+        ("\u2A05", "\\ElzThr "),
+        ("\u2A06", "\\Elxsqcup "),
+        ("\u2A07", "\\ElzInf "),
+        ("\u2A08", "\\ElzSup "),
+        ("\u2A0D", "\\ElzCint "),
+        ("\u2A0F", "\\clockoint "),
+        ("\u2A10", "\\ElsevierGlyph{E395}"),
+        ("\u2A16", "\\sqrint "),
+        ("\u2A25", "\\ElsevierGlyph{E25A}"),
+        ("\u2A2A", "\\ElsevierGlyph{E25B}"),
+        ("\u2A2D", "\\ElsevierGlyph{E25C}"),
+        ("\u2A2E", "\\ElsevierGlyph{E25D}"),
+        ("\u2A2F", "\\ElzTimes "),
+        ("\u2A34", "\\ElsevierGlyph{E25E}"),
+        ("\u2A35", "\\ElsevierGlyph{E25E}"),
+        ("\u2A3C", "\\ElsevierGlyph{E259}"),
+        ("\u2A3F", "\\amalg "),
+        ("\u2A53", "\\ElzAnd "),
+        ("\u2A54", "\\ElzOr "),
+        ("\u2A55", "\\ElsevierGlyph{E36E}"),
+        ("\u2A56", "\\ElOr "),
+        ("\u2A5E", "\\perspcorrespond "),
+        ("\u2A5F", "\\Elzminhat "),
+        ("\u2A63", "\\ElsevierGlyph{225A}"),
+        ("\u2A6E", "\\stackrel{*}{=}"),
+        ("\u2A75", "\\Equal "),
+        ("\u2A7D", "\\leqslant "),
+        ("\u2A7D-00338", "\\nleqslant "),
+        ("\u2A7E", "\\geqslant "),
+        ("\u2A7E-00338", "\\ngeqslant "),
+        ("\u2A85", "\\lessapprox "),
+        ("\u2A86", "\\gtrapprox "),
+        ("\u2A87", "\\lneq "),
+        ("\u2A88", "\\gneq "),
+        ("\u2A89", "\\lnapprox "),
+        ("\u2A8A", "\\gnapprox "),
+        ("\u2A8B", "\\lesseqqgtr "),
+        ("\u2A8C", "\\gtreqqless "),
+        ("\u2A95", "\\eqslantless "),
+        ("\u2A96", "\\eqslantgtr "),
+        ("\u2A9D", "\\Pisymbol{ppi020}{117}"),
+        ("\u2A9E", "\\Pisymbol{ppi020}{105}"),
+        ("\u2AA1", "\\NestedLessLess "),
+        ("\u2AA1-00338", "\\NotNestedLessLess "),
+        ("\u2AA2", "\\NestedGreaterGreater "),
+        ("\u2AA2-00338", "\\NotNestedGreaterGreater "),
+        ("\u2AAF", "\\preceq "),
+        ("\u2AAF-00338", "\\not\\preceq "),
+        ("\u2AB0", "\\succeq "),
+        ("\u2AB0-00338", "\\not\\succeq "),
+        ("\u2AB5", "\\precneqq "),
+        ("\u2AB6", "\\succneqq "),
+        ("\u2AB7", "\\precapprox "),
+        ("\u2AB8", "\\succapprox "),
+        ("\u2AB9", "\\precnapprox "),
+        ("\u2ABA", "\\succnapprox "),
+        ("\u2AC5", "\\subseteqq "),
+        ("\u2AC5-00338", "\\nsubseteqq "),
+        ("\u2AC6", "\\supseteqq "),
+        ("\u2AC6-00338", "\\nsupseteqq"),
+        ("\u2ACB", "\\subsetneqq "),
+        ("\u2ACC", "\\supsetneqq "),
+        ("\u2AEB", "\\ElsevierGlyph{E30D}"),
+        ("\u2AF6", "\\Elztdcol "),
+        ("\u2AFD", "{{/}\\!\\!{/}}"),
+        ("\u2AFD-020E5", "{\\rlap{\\textbackslash}{{/}\\!\\!{/}}}"),
+        ("\u300A", "\\ElsevierGlyph{300A}"),
+        ("\u300B", "\\ElsevierGlyph{300B}"),
+        ("\u3018", "\\ElsevierGlyph{3018}"),
+        ("\u3019", "\\ElsevierGlyph{3019}"),
+        ("\u301A", "\\openbracketleft "),
+        ("\u301B", "\\openbracketright "),
+#        (u"\uFB00", "ff"),
+#        (u"\uFB01", "fi"),
+#        (u"\uFB02", "fl"),
+#        (u"\uFB03", "ffi"),
+#        (u"\uFB04", "ffl"),
+        ("\uD400", "\\mathbf{A}"),
+        ("\uD401", "\\mathbf{B}"),
+        ("\uD402", "\\mathbf{C}"),
+        ("\uD403", "\\mathbf{D}"),
+        ("\uD404", "\\mathbf{E}"),
+        ("\uD405", "\\mathbf{F}"),
+        ("\uD406", "\\mathbf{G}"),
+        ("\uD407", "\\mathbf{H}"),
+        ("\uD408", "\\mathbf{I}"),
+        ("\uD409", "\\mathbf{J}"),
+        ("\uD40A", "\\mathbf{K}"),
+        ("\uD40B", "\\mathbf{L}"),
+        ("\uD40C", "\\mathbf{M}"),
+        ("\uD40D", "\\mathbf{N}"),
+        ("\uD40E", "\\mathbf{O}"),
+        ("\uD40F", "\\mathbf{P}"),
+        ("\uD410", "\\mathbf{Q}"),
+        ("\uD411", "\\mathbf{R}"),
+        ("\uD412", "\\mathbf{S}"),
+        ("\uD413", "\\mathbf{T}"),
+        ("\uD414", "\\mathbf{U}"),
+        ("\uD415", "\\mathbf{V}"),
+        ("\uD416", "\\mathbf{W}"),
+        ("\uD417", "\\mathbf{X}"),
+        ("\uD418", "\\mathbf{Y}"),
+        ("\uD419", "\\mathbf{Z}"),
+        ("\uD41A", "\\mathbf{a}"),
+        ("\uD41B", "\\mathbf{b}"),
+        ("\uD41C", "\\mathbf{c}"),
+        ("\uD41D", "\\mathbf{d}"),
+        ("\uD41E", "\\mathbf{e}"),
+        ("\uD41F", "\\mathbf{f}"),
+        ("\uD420", "\\mathbf{g}"),
+        ("\uD421", "\\mathbf{h}"),
+        ("\uD422", "\\mathbf{i}"),
+        ("\uD423", "\\mathbf{j}"),
+        ("\uD424", "\\mathbf{k}"),
+        ("\uD425", "\\mathbf{l}"),
+        ("\uD426", "\\mathbf{m}"),
+        ("\uD427", "\\mathbf{n}"),
+        ("\uD428", "\\mathbf{o}"),
+        ("\uD429", "\\mathbf{p}"),
+        ("\uD42A", "\\mathbf{q}"),
+        ("\uD42B", "\\mathbf{r}"),
+        ("\uD42C", "\\mathbf{s}"),
+        ("\uD42D", "\\mathbf{t}"),
+        ("\uD42E", "\\mathbf{u}"),
+        ("\uD42F", "\\mathbf{v}"),
+        ("\uD430", "\\mathbf{w}"),
+        ("\uD431", "\\mathbf{x}"),
+        ("\uD432", "\\mathbf{y}"),
+        ("\uD433", "\\mathbf{z}"),
+        ("\uD434", "\\mathsl{A}"),
+        ("\uD435", "\\mathsl{B}"),
+        ("\uD436", "\\mathsl{C}"),
+        ("\uD437", "\\mathsl{D}"),
+        ("\uD438", "\\mathsl{E}"),
+        ("\uD439", "\\mathsl{F}"),
+        ("\uD43A", "\\mathsl{G}"),
+        ("\uD43B", "\\mathsl{H}"),
+        ("\uD43C", "\\mathsl{I}"),
+        ("\uD43D", "\\mathsl{J}"),
+        ("\uD43E", "\\mathsl{K}"),
+        ("\uD43F", "\\mathsl{L}"),
+        ("\uD440", "\\mathsl{M}"),
+        ("\uD441", "\\mathsl{N}"),
+        ("\uD442", "\\mathsl{O}"),
+        ("\uD443", "\\mathsl{P}"),
+        ("\uD444", "\\mathsl{Q}"),
+        ("\uD445", "\\mathsl{R}"),
+        ("\uD446", "\\mathsl{S}"),
+        ("\uD447", "\\mathsl{T}"),
+        ("\uD448", "\\mathsl{U}"),
+        ("\uD449", "\\mathsl{V}"),
+        ("\uD44A", "\\mathsl{W}"),
+        ("\uD44B", "\\mathsl{X}"),
+        ("\uD44C", "\\mathsl{Y}"),
+        ("\uD44D", "\\mathsl{Z}"),
+        ("\uD44E", "\\mathsl{a}"),
+        ("\uD44F", "\\mathsl{b}"),
+        ("\uD450", "\\mathsl{c}"),
+        ("\uD451", "\\mathsl{d}"),
+        ("\uD452", "\\mathsl{e}"),
+        ("\uD453", "\\mathsl{f}"),
+        ("\uD454", "\\mathsl{g}"),
+        ("\uD456", "\\mathsl{i}"),
+        ("\uD457", "\\mathsl{j}"),
+        ("\uD458", "\\mathsl{k}"),
+        ("\uD459", "\\mathsl{l}"),
+        ("\uD45A", "\\mathsl{m}"),
+        ("\uD45B", "\\mathsl{n}"),
+        ("\uD45C", "\\mathsl{o}"),
+        ("\uD45D", "\\mathsl{p}"),
+        ("\uD45E", "\\mathsl{q}"),
+        ("\uD45F", "\\mathsl{r}"),
+        ("\uD460", "\\mathsl{s}"),
+        ("\uD461", "\\mathsl{t}"),
+        ("\uD462", "\\mathsl{u}"),
+        ("\uD463", "\\mathsl{v}"),
+        ("\uD464", "\\mathsl{w}"),
+        ("\uD465", "\\mathsl{x}"),
+        ("\uD466", "\\mathsl{y}"),
+        ("\uD467", "\\mathsl{z}"),
+        ("\uD468", "\\mathbit{A}"),
+        ("\uD469", "\\mathbit{B}"),
+        ("\uD46A", "\\mathbit{C}"),
+        ("\uD46B", "\\mathbit{D}"),
+        ("\uD46C", "\\mathbit{E}"),
+        ("\uD46D", "\\mathbit{F}"),
+        ("\uD46E", "\\mathbit{G}"),
+        ("\uD46F", "\\mathbit{H}"),
+        ("\uD470", "\\mathbit{I}"),
+        ("\uD471", "\\mathbit{J}"),
+        ("\uD472", "\\mathbit{K}"),
+        ("\uD473", "\\mathbit{L}"),
+        ("\uD474", "\\mathbit{M}"),
+        ("\uD475", "\\mathbit{N}"),
+        ("\uD476", "\\mathbit{O}"),
+        ("\uD477", "\\mathbit{P}"),
+        ("\uD478", "\\mathbit{Q}"),
+        ("\uD479", "\\mathbit{R}"),
+        ("\uD47A", "\\mathbit{S}"),
+        ("\uD47B", "\\mathbit{T}"),
+        ("\uD47C", "\\mathbit{U}"),
+        ("\uD47D", "\\mathbit{V}"),
+        ("\uD47E", "\\mathbit{W}"),
+        ("\uD47F", "\\mathbit{X}"),
+        ("\uD480", "\\mathbit{Y}"),
+        ("\uD481", "\\mathbit{Z}"),
+        ("\uD482", "\\mathbit{a}"),
+        ("\uD483", "\\mathbit{b}"),
+        ("\uD484", "\\mathbit{c}"),
+        ("\uD485", "\\mathbit{d}"),
+        ("\uD486", "\\mathbit{e}"),
+        ("\uD487", "\\mathbit{f}"),
+        ("\uD488", "\\mathbit{g}"),
+        ("\uD489", "\\mathbit{h}"),
+        ("\uD48A", "\\mathbit{i}"),
+        ("\uD48B", "\\mathbit{j}"),
+        ("\uD48C", "\\mathbit{k}"),
+        ("\uD48D", "\\mathbit{l}"),
+        ("\uD48E", "\\mathbit{m}"),
+        ("\uD48F", "\\mathbit{n}"),
+        ("\uD490", "\\mathbit{o}"),
+        ("\uD491", "\\mathbit{p}"),
+        ("\uD492", "\\mathbit{q}"),
+        ("\uD493", "\\mathbit{r}"),
+        ("\uD494", "\\mathbit{s}"),
+        ("\uD495", "\\mathbit{t}"),
+        ("\uD496", "\\mathbit{u}"),
+        ("\uD497", "\\mathbit{v}"),
+        ("\uD498", "\\mathbit{w}"),
+        ("\uD499", "\\mathbit{x}"),
+        ("\uD49A", "\\mathbit{y}"),
+        ("\uD49B", "\\mathbit{z}"),
+        ("\uD49C", "\\mathscr{A}"),
+        ("\uD49E", "\\mathscr{C}"),
+        ("\uD49F", "\\mathscr{D}"),
+        ("\uD4A2", "\\mathscr{G}"),
+        ("\uD4A5", "\\mathscr{J}"),
+        ("\uD4A6", "\\mathscr{K}"),
+        ("\uD4A9", "\\mathscr{N}"),
+        ("\uD4AA", "\\mathscr{O}"),
+        ("\uD4AB", "\\mathscr{P}"),
+        ("\uD4AC", "\\mathscr{Q}"),
+        ("\uD4AE", "\\mathscr{S}"),
+        ("\uD4AF", "\\mathscr{T}"),
+        ("\uD4B0", "\\mathscr{U}"),
+        ("\uD4B1", "\\mathscr{V}"),
+        ("\uD4B2", "\\mathscr{W}"),
+        ("\uD4B3", "\\mathscr{X}"),
+        ("\uD4B4", "\\mathscr{Y}"),
+        ("\uD4B5", "\\mathscr{Z}"),
+        ("\uD4B6", "\\mathscr{a}"),
+        ("\uD4B7", "\\mathscr{b}"),
+        ("\uD4B8", "\\mathscr{c}"),
+        ("\uD4B9", "\\mathscr{d}"),
+        ("\uD4BB", "\\mathscr{f}"),
+        ("\uD4BD", "\\mathscr{h}"),
+        ("\uD4BE", "\\mathscr{i}"),
+        ("\uD4BF", "\\mathscr{j}"),
+        ("\uD4C0", "\\mathscr{k}"),
+        ("\uD4C1", "\\mathscr{l}"),
+        ("\uD4C2", "\\mathscr{m}"),
+        ("\uD4C3", "\\mathscr{n}"),
+        ("\uD4C5", "\\mathscr{p}"),
+        ("\uD4C6", "\\mathscr{q}"),
+        ("\uD4C7", "\\mathscr{r}"),
+        ("\uD4C8", "\\mathscr{s}"),
+        ("\uD4C9", "\\mathscr{t}"),
+        ("\uD4CA", "\\mathscr{u}"),
+        ("\uD4CB", "\\mathscr{v}"),
+        ("\uD4CC", "\\mathscr{w}"),
+        ("\uD4CD", "\\mathscr{x}"),
+        ("\uD4CE", "\\mathscr{y}"),
+        ("\uD4CF", "\\mathscr{z}"),
+        ("\uD4D0", "\\mathmit{A}"),
+        ("\uD4D1", "\\mathmit{B}"),
+        ("\uD4D2", "\\mathmit{C}"),
+        ("\uD4D3", "\\mathmit{D}"),
+        ("\uD4D4", "\\mathmit{E}"),
+        ("\uD4D5", "\\mathmit{F}"),
+        ("\uD4D6", "\\mathmit{G}"),
+        ("\uD4D7", "\\mathmit{H}"),
+        ("\uD4D8", "\\mathmit{I}"),
+        ("\uD4D9", "\\mathmit{J}"),
+        ("\uD4DA", "\\mathmit{K}"),
+        ("\uD4DB", "\\mathmit{L}"),
+        ("\uD4DC", "\\mathmit{M}"),
+        ("\uD4DD", "\\mathmit{N}"),
+        ("\uD4DE", "\\mathmit{O}"),
+        ("\uD4DF", "\\mathmit{P}"),
+        ("\uD4E0", "\\mathmit{Q}"),
+        ("\uD4E1", "\\mathmit{R}"),
+        ("\uD4E2", "\\mathmit{S}"),
+        ("\uD4E3", "\\mathmit{T}"),
+        ("\uD4E4", "\\mathmit{U}"),
+        ("\uD4E5", "\\mathmit{V}"),
+        ("\uD4E6", "\\mathmit{W}"),
+        ("\uD4E7", "\\mathmit{X}"),
+        ("\uD4E8", "\\mathmit{Y}"),
+        ("\uD4E9", "\\mathmit{Z}"),
+        ("\uD4EA", "\\mathmit{a}"),
+        ("\uD4EB", "\\mathmit{b}"),
+        ("\uD4EC", "\\mathmit{c}"),
+        ("\uD4ED", "\\mathmit{d}"),
+        ("\uD4EE", "\\mathmit{e}"),
+        ("\uD4EF", "\\mathmit{f}"),
+        ("\uD4F0", "\\mathmit{g}"),
+        ("\uD4F1", "\\mathmit{h}"),
+        ("\uD4F2", "\\mathmit{i}"),
+        ("\uD4F3", "\\mathmit{j}"),
+        ("\uD4F4", "\\mathmit{k}"),
+        ("\uD4F5", "\\mathmit{l}"),
+        ("\uD4F6", "\\mathmit{m}"),
+        ("\uD4F7", "\\mathmit{n}"),
+        ("\uD4F8", "\\mathmit{o}"),
+        ("\uD4F9", "\\mathmit{p}"),
+        ("\uD4FA", "\\mathmit{q}"),
+        ("\uD4FB", "\\mathmit{r}"),
+        ("\uD4FC", "\\mathmit{s}"),
+        ("\uD4FD", "\\mathmit{t}"),
+        ("\uD4FE", "\\mathmit{u}"),
+        ("\uD4FF", "\\mathmit{v}"),
+        ("\uD500", "\\mathmit{w}"),
+        ("\uD501", "\\mathmit{x}"),
+        ("\uD502", "\\mathmit{y}"),
+        ("\uD503", "\\mathmit{z}"),
+        ("\uD504", "\\mathfrak{A}"),
+        ("\uD505", "\\mathfrak{B}"),
+        ("\uD507", "\\mathfrak{D}"),
+        ("\uD508", "\\mathfrak{E}"),
+        ("\uD509", "\\mathfrak{F}"),
+        ("\uD50A", "\\mathfrak{G}"),
+        ("\uD50D", "\\mathfrak{J}"),
+        ("\uD50E", "\\mathfrak{K}"),
+        ("\uD50F", "\\mathfrak{L}"),
+        ("\uD510", "\\mathfrak{M}"),
+        ("\uD511", "\\mathfrak{N}"),
+        ("\uD512", "\\mathfrak{O}"),
+        ("\uD513", "\\mathfrak{P}"),
+        ("\uD514", "\\mathfrak{Q}"),
+        ("\uD516", "\\mathfrak{S}"),
+        ("\uD517", "\\mathfrak{T}"),
+        ("\uD518", "\\mathfrak{U}"),
+        ("\uD519", "\\mathfrak{V}"),
+        ("\uD51A", "\\mathfrak{W}"),
+        ("\uD51B", "\\mathfrak{X}"),
+        ("\uD51C", "\\mathfrak{Y}"),
+        ("\uD51E", "\\mathfrak{a}"),
+        ("\uD51F", "\\mathfrak{b}"),
+        ("\uD520", "\\mathfrak{c}"),
+        ("\uD521", "\\mathfrak{d}"),
+        ("\uD522", "\\mathfrak{e}"),
+        ("\uD523", "\\mathfrak{f}"),
+        ("\uD524", "\\mathfrak{g}"),
+        ("\uD525", "\\mathfrak{h}"),
+        ("\uD526", "\\mathfrak{i}"),
+        ("\uD527", "\\mathfrak{j}"),
+        ("\uD528", "\\mathfrak{k}"),
+        ("\uD529", "\\mathfrak{l}"),
+        ("\uD52A", "\\mathfrak{m}"),
+        ("\uD52B", "\\mathfrak{n}"),
+        ("\uD52C", "\\mathfrak{o}"),
+        ("\uD52D", "\\mathfrak{p}"),
+        ("\uD52E", "\\mathfrak{q}"),
+        ("\uD52F", "\\mathfrak{r}"),
+        ("\uD530", "\\mathfrak{s}"),
+        ("\uD531", "\\mathfrak{t}"),
+        ("\uD532", "\\mathfrak{u}"),
+        ("\uD533", "\\mathfrak{v}"),
+        ("\uD534", "\\mathfrak{w}"),
+        ("\uD535", "\\mathfrak{x}"),
+        ("\uD536", "\\mathfrak{y}"),
+        ("\uD537", "\\mathfrak{z}"),
+        ("\uD538", "\\mathbb{A}"),
+        ("\uD539", "\\mathbb{B}"),
+        ("\uD53B", "\\mathbb{D}"),
+        ("\uD53C", "\\mathbb{E}"),
+        ("\uD53D", "\\mathbb{F}"),
+        ("\uD53E", "\\mathbb{G}"),
+        ("\uD540", "\\mathbb{I}"),
+        ("\uD541", "\\mathbb{J}"),
+        ("\uD542", "\\mathbb{K}"),
+        ("\uD543", "\\mathbb{L}"),
+        ("\uD544", "\\mathbb{M}"),
+        ("\uD546", "\\mathbb{O}"),
+        ("\uD54A", "\\mathbb{S}"),
+        ("\uD54B", "\\mathbb{T}"),
+        ("\uD54C", "\\mathbb{U}"),
+        ("\uD54D", "\\mathbb{V}"),
+        ("\uD54E", "\\mathbb{W}"),
+        ("\uD54F", "\\mathbb{X}"),
+        ("\uD550", "\\mathbb{Y}"),
+        ("\uD552", "\\mathbb{a}"),
+        ("\uD553", "\\mathbb{b}"),
+        ("\uD554", "\\mathbb{c}"),
+        ("\uD555", "\\mathbb{d}"),
+        ("\uD556", "\\mathbb{e}"),
+        ("\uD557", "\\mathbb{f}"),
+        ("\uD558", "\\mathbb{g}"),
+        ("\uD559", "\\mathbb{h}"),
+        ("\uD55A", "\\mathbb{i}"),
+        ("\uD55B", "\\mathbb{j}"),
+        ("\uD55C", "\\mathbb{k}"),
+        ("\uD55D", "\\mathbb{l}"),
+        ("\uD55E", "\\mathbb{m}"),
+        ("\uD55F", "\\mathbb{n}"),
+        ("\uD560", "\\mathbb{o}"),
+        ("\uD561", "\\mathbb{p}"),
+        ("\uD562", "\\mathbb{q}"),
+        ("\uD563", "\\mathbb{r}"),
+        ("\uD564", "\\mathbb{s}"),
+        ("\uD565", "\\mathbb{t}"),
+        ("\uD566", "\\mathbb{u}"),
+        ("\uD567", "\\mathbb{v}"),
+        ("\uD568", "\\mathbb{w}"),
+        ("\uD569", "\\mathbb{x}"),
+        ("\uD56A", "\\mathbb{y}"),
+        ("\uD56B", "\\mathbb{z}"),
+        ("\uD56C", "\\mathslbb{A}"),
+        ("\uD56D", "\\mathslbb{B}"),
+        ("\uD56E", "\\mathslbb{C}"),
+        ("\uD56F", "\\mathslbb{D}"),
+        ("\uD570", "\\mathslbb{E}"),
+        ("\uD571", "\\mathslbb{F}"),
+        ("\uD572", "\\mathslbb{G}"),
+        ("\uD573", "\\mathslbb{H}"),
+        ("\uD574", "\\mathslbb{I}"),
+        ("\uD575", "\\mathslbb{J}"),
+        ("\uD576", "\\mathslbb{K}"),
+        ("\uD577", "\\mathslbb{L}"),
+        ("\uD578", "\\mathslbb{M}"),
+        ("\uD579", "\\mathslbb{N}"),
+        ("\uD57A", "\\mathslbb{O}"),
+        ("\uD57B", "\\mathslbb{P}"),
+        ("\uD57C", "\\mathslbb{Q}"),
+        ("\uD57D", "\\mathslbb{R}"),
+        ("\uD57E", "\\mathslbb{S}"),
+        ("\uD57F", "\\mathslbb{T}"),
+        ("\uD580", "\\mathslbb{U}"),
+        ("\uD581", "\\mathslbb{V}"),
+        ("\uD582", "\\mathslbb{W}"),
+        ("\uD583", "\\mathslbb{X}"),
+        ("\uD584", "\\mathslbb{Y}"),
+        ("\uD585", "\\mathslbb{Z}"),
+        ("\uD586", "\\mathslbb{a}"),
+        ("\uD587", "\\mathslbb{b}"),
+        ("\uD588", "\\mathslbb{c}"),
+        ("\uD589", "\\mathslbb{d}"),
+        ("\uD58A", "\\mathslbb{e}"),
+        ("\uD58B", "\\mathslbb{f}"),
+        ("\uD58C", "\\mathslbb{g}"),
+        ("\uD58D", "\\mathslbb{h}"),
+        ("\uD58E", "\\mathslbb{i}"),
+        ("\uD58F", "\\mathslbb{j}"),
+        ("\uD590", "\\mathslbb{k}"),
+        ("\uD591", "\\mathslbb{l}"),
+        ("\uD592", "\\mathslbb{m}"),
+        ("\uD593", "\\mathslbb{n}"),
+        ("\uD594", "\\mathslbb{o}"),
+        ("\uD595", "\\mathslbb{p}"),
+        ("\uD596", "\\mathslbb{q}"),
+        ("\uD597", "\\mathslbb{r}"),
+        ("\uD598", "\\mathslbb{s}"),
+        ("\uD599", "\\mathslbb{t}"),
+        ("\uD59A", "\\mathslbb{u}"),
+        ("\uD59B", "\\mathslbb{v}"),
+        ("\uD59C", "\\mathslbb{w}"),
+        ("\uD59D", "\\mathslbb{x}"),
+        ("\uD59E", "\\mathslbb{y}"),
+        ("\uD59F", "\\mathslbb{z}"),
+        ("\uD5A0", "\\mathsf{A}"),
+        ("\uD5A1", "\\mathsf{B}"),
+        ("\uD5A2", "\\mathsf{C}"),
+        ("\uD5A3", "\\mathsf{D}"),
+        ("\uD5A4", "\\mathsf{E}"),
+        ("\uD5A5", "\\mathsf{F}"),
+        ("\uD5A6", "\\mathsf{G}"),
+        ("\uD5A7", "\\mathsf{H}"),
+        ("\uD5A8", "\\mathsf{I}"),
+        ("\uD5A9", "\\mathsf{J}"),
+        ("\uD5AA", "\\mathsf{K}"),
+        ("\uD5AB", "\\mathsf{L}"),
+        ("\uD5AC", "\\mathsf{M}"),
+        ("\uD5AD", "\\mathsf{N}"),
+        ("\uD5AE", "\\mathsf{O}"),
+        ("\uD5AF", "\\mathsf{P}"),
+        ("\uD5B0", "\\mathsf{Q}"),
+        ("\uD5B1", "\\mathsf{R}"),
+        ("\uD5B2", "\\mathsf{S}"),
+        ("\uD5B3", "\\mathsf{T}"),
+        ("\uD5B4", "\\mathsf{U}"),
+        ("\uD5B5", "\\mathsf{V}"),
+        ("\uD5B6", "\\mathsf{W}"),
+        ("\uD5B7", "\\mathsf{X}"),
+        ("\uD5B8", "\\mathsf{Y}"),
+        ("\uD5B9", "\\mathsf{Z}"),
+        ("\uD5BA", "\\mathsf{a}"),
+        ("\uD5BB", "\\mathsf{b}"),
+        ("\uD5BC", "\\mathsf{c}"),
+        ("\uD5BD", "\\mathsf{d}"),
+        ("\uD5BE", "\\mathsf{e}"),
+        ("\uD5BF", "\\mathsf{f}"),
+        ("\uD5C0", "\\mathsf{g}"),
+        ("\uD5C1", "\\mathsf{h}"),
+        ("\uD5C2", "\\mathsf{i}"),
+        ("\uD5C3", "\\mathsf{j}"),
+        ("\uD5C4", "\\mathsf{k}"),
+        ("\uD5C5", "\\mathsf{l}"),
+        ("\uD5C6", "\\mathsf{m}"),
+        ("\uD5C7", "\\mathsf{n}"),
+        ("\uD5C8", "\\mathsf{o}"),
+        ("\uD5C9", "\\mathsf{p}"),
+        ("\uD5CA", "\\mathsf{q}"),
+        ("\uD5CB", "\\mathsf{r}"),
+        ("\uD5CC", "\\mathsf{s}"),
+        ("\uD5CD", "\\mathsf{t}"),
+        ("\uD5CE", "\\mathsf{u}"),
+        ("\uD5CF", "\\mathsf{v}"),
+        ("\uD5D0", "\\mathsf{w}"),
+        ("\uD5D1", "\\mathsf{x}"),
+        ("\uD5D2", "\\mathsf{y}"),
+        ("\uD5D3", "\\mathsf{z}"),
+        ("\uD5D4", "\\mathsfbf{A}"),
+        ("\uD5D5", "\\mathsfbf{B}"),
+        ("\uD5D6", "\\mathsfbf{C}"),
+        ("\uD5D7", "\\mathsfbf{D}"),
+        ("\uD5D8", "\\mathsfbf{E}"),
+        ("\uD5D9", "\\mathsfbf{F}"),
+        ("\uD5DA", "\\mathsfbf{G}"),
+        ("\uD5DB", "\\mathsfbf{H}"),
+        ("\uD5DC", "\\mathsfbf{I}"),
+        ("\uD5DD", "\\mathsfbf{J}"),
+        ("\uD5DE", "\\mathsfbf{K}"),
+        ("\uD5DF", "\\mathsfbf{L}"),
+        ("\uD5E0", "\\mathsfbf{M}"),
+        ("\uD5E1", "\\mathsfbf{N}"),
+        ("\uD5E2", "\\mathsfbf{O}"),
+        ("\uD5E3", "\\mathsfbf{P}"),
+        ("\uD5E4", "\\mathsfbf{Q}"),
+        ("\uD5E5", "\\mathsfbf{R}"),
+        ("\uD5E6", "\\mathsfbf{S}"),
+        ("\uD5E7", "\\mathsfbf{T}"),
+        ("\uD5E8", "\\mathsfbf{U}"),
+        ("\uD5E9", "\\mathsfbf{V}"),
+        ("\uD5EA", "\\mathsfbf{W}"),
+        ("\uD5EB", "\\mathsfbf{X}"),
+        ("\uD5EC", "\\mathsfbf{Y}"),
+        ("\uD5ED", "\\mathsfbf{Z}"),
+        ("\uD5EE", "\\mathsfbf{a}"),
+        ("\uD5EF", "\\mathsfbf{b}"),
+        ("\uD5F0", "\\mathsfbf{c}"),
+        ("\uD5F1", "\\mathsfbf{d}"),
+        ("\uD5F2", "\\mathsfbf{e}"),
+        ("\uD5F3", "\\mathsfbf{f}"),
+        ("\uD5F4", "\\mathsfbf{g}"),
+        ("\uD5F5", "\\mathsfbf{h}"),
+        ("\uD5F6", "\\mathsfbf{i}"),
+        ("\uD5F7", "\\mathsfbf{j}"),
+        ("\uD5F8", "\\mathsfbf{k}"),
+        ("\uD5F9", "\\mathsfbf{l}"),
+        ("\uD5FA", "\\mathsfbf{m}"),
+        ("\uD5FB", "\\mathsfbf{n}"),
+        ("\uD5FC", "\\mathsfbf{o}"),
+        ("\uD5FD", "\\mathsfbf{p}"),
+        ("\uD5FE", "\\mathsfbf{q}"),
+        ("\uD5FF", "\\mathsfbf{r}"),
+        ("\uD600", "\\mathsfbf{s}"),
+        ("\uD601", "\\mathsfbf{t}"),
+        ("\uD602", "\\mathsfbf{u}"),
+        ("\uD603", "\\mathsfbf{v}"),
+        ("\uD604", "\\mathsfbf{w}"),
+        ("\uD605", "\\mathsfbf{x}"),
+        ("\uD606", "\\mathsfbf{y}"),
+        ("\uD607", "\\mathsfbf{z}"),
+        ("\uD608", "\\mathsfsl{A}"),
+        ("\uD609", "\\mathsfsl{B}"),
+        ("\uD60A", "\\mathsfsl{C}"),
+        ("\uD60B", "\\mathsfsl{D}"),
+        ("\uD60C", "\\mathsfsl{E}"),
+        ("\uD60D", "\\mathsfsl{F}"),
+        ("\uD60E", "\\mathsfsl{G}"),
+        ("\uD60F", "\\mathsfsl{H}"),
+        ("\uD610", "\\mathsfsl{I}"),
+        ("\uD611", "\\mathsfsl{J}"),
+        ("\uD612", "\\mathsfsl{K}"),
+        ("\uD613", "\\mathsfsl{L}"),
+        ("\uD614", "\\mathsfsl{M}"),
+        ("\uD615", "\\mathsfsl{N}"),
+        ("\uD616", "\\mathsfsl{O}"),
+        ("\uD617", "\\mathsfsl{P}"),
+        ("\uD618", "\\mathsfsl{Q}"),
+        ("\uD619", "\\mathsfsl{R}"),
+        ("\uD61A", "\\mathsfsl{S}"),
+        ("\uD61B", "\\mathsfsl{T}"),
+        ("\uD61C", "\\mathsfsl{U}"),
+        ("\uD61D", "\\mathsfsl{V}"),
+        ("\uD61E", "\\mathsfsl{W}"),
+        ("\uD61F", "\\mathsfsl{X}"),
+        ("\uD620", "\\mathsfsl{Y}"),
+        ("\uD621", "\\mathsfsl{Z}"),
+        ("\uD622", "\\mathsfsl{a}"),
+        ("\uD623", "\\mathsfsl{b}"),
+        ("\uD624", "\\mathsfsl{c}"),
+        ("\uD625", "\\mathsfsl{d}"),
+        ("\uD626", "\\mathsfsl{e}"),
+        ("\uD627", "\\mathsfsl{f}"),
+        ("\uD628", "\\mathsfsl{g}"),
+        ("\uD629", "\\mathsfsl{h}"),
+        ("\uD62A", "\\mathsfsl{i}"),
+        ("\uD62B", "\\mathsfsl{j}"),
+        ("\uD62C", "\\mathsfsl{k}"),
+        ("\uD62D", "\\mathsfsl{l}"),
+        ("\uD62E", "\\mathsfsl{m}"),
+        ("\uD62F", "\\mathsfsl{n}"),
+        ("\uD630", "\\mathsfsl{o}"),
+        ("\uD631", "\\mathsfsl{p}"),
+        ("\uD632", "\\mathsfsl{q}"),
+        ("\uD633", "\\mathsfsl{r}"),
+        ("\uD634", "\\mathsfsl{s}"),
+        ("\uD635", "\\mathsfsl{t}"),
+        ("\uD636", "\\mathsfsl{u}"),
+        ("\uD637", "\\mathsfsl{v}"),
+        ("\uD638", "\\mathsfsl{w}"),
+        ("\uD639", "\\mathsfsl{x}"),
+        ("\uD63A", "\\mathsfsl{y}"),
+        ("\uD63B", "\\mathsfsl{z}"),
+        ("\uD63C", "\\mathsfbfsl{A}"),
+        ("\uD63D", "\\mathsfbfsl{B}"),
+        ("\uD63E", "\\mathsfbfsl{C}"),
+        ("\uD63F", "\\mathsfbfsl{D}"),
+        ("\uD640", "\\mathsfbfsl{E}"),
+        ("\uD641", "\\mathsfbfsl{F}"),
+        ("\uD642", "\\mathsfbfsl{G}"),
+        ("\uD643", "\\mathsfbfsl{H}"),
+        ("\uD644", "\\mathsfbfsl{I}"),
+        ("\uD645", "\\mathsfbfsl{J}"),
+        ("\uD646", "\\mathsfbfsl{K}"),
+        ("\uD647", "\\mathsfbfsl{L}"),
+        ("\uD648", "\\mathsfbfsl{M}"),
+        ("\uD649", "\\mathsfbfsl{N}"),
+        ("\uD64A", "\\mathsfbfsl{O}"),
+        ("\uD64B", "\\mathsfbfsl{P}"),
+        ("\uD64C", "\\mathsfbfsl{Q}"),
+        ("\uD64D", "\\mathsfbfsl{R}"),
+        ("\uD64E", "\\mathsfbfsl{S}"),
+        ("\uD64F", "\\mathsfbfsl{T}"),
+        ("\uD650", "\\mathsfbfsl{U}"),
+        ("\uD651", "\\mathsfbfsl{V}"),
+        ("\uD652", "\\mathsfbfsl{W}"),
+        ("\uD653", "\\mathsfbfsl{X}"),
+        ("\uD654", "\\mathsfbfsl{Y}"),
+        ("\uD655", "\\mathsfbfsl{Z}"),
+        ("\uD656", "\\mathsfbfsl{a}"),
+        ("\uD657", "\\mathsfbfsl{b}"),
+        ("\uD658", "\\mathsfbfsl{c}"),
+        ("\uD659", "\\mathsfbfsl{d}"),
+        ("\uD65A", "\\mathsfbfsl{e}"),
+        ("\uD65B", "\\mathsfbfsl{f}"),
+        ("\uD65C", "\\mathsfbfsl{g}"),
+        ("\uD65D", "\\mathsfbfsl{h}"),
+        ("\uD65E", "\\mathsfbfsl{i}"),
+        ("\uD65F", "\\mathsfbfsl{j}"),
+        ("\uD660", "\\mathsfbfsl{k}"),
+        ("\uD661", "\\mathsfbfsl{l}"),
+        ("\uD662", "\\mathsfbfsl{m}"),
+        ("\uD663", "\\mathsfbfsl{n}"),
+        ("\uD664", "\\mathsfbfsl{o}"),
+        ("\uD665", "\\mathsfbfsl{p}"),
+        ("\uD666", "\\mathsfbfsl{q}"),
+        ("\uD667", "\\mathsfbfsl{r}"),
+        ("\uD668", "\\mathsfbfsl{s}"),
+        ("\uD669", "\\mathsfbfsl{t}"),
+        ("\uD66A", "\\mathsfbfsl{u}"),
+        ("\uD66B", "\\mathsfbfsl{v}"),
+        ("\uD66C", "\\mathsfbfsl{w}"),
+        ("\uD66D", "\\mathsfbfsl{x}"),
+        ("\uD66E", "\\mathsfbfsl{y}"),
+        ("\uD66F", "\\mathsfbfsl{z}"),
+        ("\uD670", "\\mathtt{A}"),
+        ("\uD671", "\\mathtt{B}"),
+        ("\uD672", "\\mathtt{C}"),
+        ("\uD673", "\\mathtt{D}"),
+        ("\uD674", "\\mathtt{E}"),
+        ("\uD675", "\\mathtt{F}"),
+        ("\uD676", "\\mathtt{G}"),
+        ("\uD677", "\\mathtt{H}"),
+        ("\uD678", "\\mathtt{I}"),
+        ("\uD679", "\\mathtt{J}"),
+        ("\uD67A", "\\mathtt{K}"),
+        ("\uD67B", "\\mathtt{L}"),
+        ("\uD67C", "\\mathtt{M}"),
+        ("\uD67D", "\\mathtt{N}"),
+        ("\uD67E", "\\mathtt{O}"),
+        ("\uD67F", "\\mathtt{P}"),
+        ("\uD680", "\\mathtt{Q}"),
+        ("\uD681", "\\mathtt{R}"),
+        ("\uD682", "\\mathtt{S}"),
+        ("\uD683", "\\mathtt{T}"),
+        ("\uD684", "\\mathtt{U}"),
+        ("\uD685", "\\mathtt{V}"),
+        ("\uD686", "\\mathtt{W}"),
+        ("\uD687", "\\mathtt{X}"),
+        ("\uD688", "\\mathtt{Y}"),
+        ("\uD689", "\\mathtt{Z}"),
+        ("\uD68A", "\\mathtt{a}"),
+        ("\uD68B", "\\mathtt{b}"),
+        ("\uD68C", "\\mathtt{c}"),
+        ("\uD68D", "\\mathtt{d}"),
+        ("\uD68E", "\\mathtt{e}"),
+        ("\uD68F", "\\mathtt{f}"),
+        ("\uD690", "\\mathtt{g}"),
+        ("\uD691", "\\mathtt{h}"),
+        ("\uD692", "\\mathtt{i}"),
+        ("\uD693", "\\mathtt{j}"),
+        ("\uD694", "\\mathtt{k}"),
+        ("\uD695", "\\mathtt{l}"),
+        ("\uD696", "\\mathtt{m}"),
+        ("\uD697", "\\mathtt{n}"),
+        ("\uD698", "\\mathtt{o}"),
+        ("\uD699", "\\mathtt{p}"),
+        ("\uD69A", "\\mathtt{q}"),
+        ("\uD69B", "\\mathtt{r}"),
+        ("\uD69C", "\\mathtt{s}"),
+        ("\uD69D", "\\mathtt{t}"),
+        ("\uD69E", "\\mathtt{u}"),
+        ("\uD69F", "\\mathtt{v}"),
+        ("\uD6A0", "\\mathtt{w}"),
+        ("\uD6A1", "\\mathtt{x}"),
+        ("\uD6A2", "\\mathtt{y}"),
+        ("\uD6A3", "\\mathtt{z}"),
+        ("\uD6A8", "\\mathbf{\\Alpha}"),
+        ("\uD6A9", "\\mathbf{\\Beta}"),
+        ("\uD6AA", "\\mathbf{\\Gamma}"),
+        ("\uD6AB", "\\mathbf{\\Delta}"),
+        ("\uD6AC", "\\mathbf{\\Epsilon}"),
+        ("\uD6AD", "\\mathbf{\\Zeta}"),
+        ("\uD6AE", "\\mathbf{\\Eta}"),
+        ("\uD6AF", "\\mathbf{\\Theta}"),
+        ("\uD6B0", "\\mathbf{\\Iota}"),
+        ("\uD6B1", "\\mathbf{\\Kappa}"),
+        ("\uD6B2", "\\mathbf{\\Lambda}"),
+        ("\uD6B5", "\\mathbf{\\Xi}"),
+        ("\uD6B7", "\\mathbf{\\Pi}"),
+        ("\uD6B8", "\\mathbf{\\Rho}"),
+        ("\uD6B9", "\\mathbf{\\vartheta}"),
+        ("\uD6BA", "\\mathbf{\\Sigma}"),
+        ("\uD6BB", "\\mathbf{\\Tau}"),
+        ("\uD6BC", "\\mathbf{\\Upsilon}"),
+        ("\uD6BD", "\\mathbf{\\Phi}"),
+        ("\uD6BE", "\\mathbf{\\Chi}"),
+        ("\uD6BF", "\\mathbf{\\Psi}"),
+        ("\uD6C0", "\\mathbf{\\Omega}"),
+        ("\uD6C1", "\\mathbf{\\nabla}"),
+        ("\uD6C2", "\\mathbf{\\Alpha}"),
+        ("\uD6C3", "\\mathbf{\\Beta}"),
+        ("\uD6C4", "\\mathbf{\\Gamma}"),
+        ("\uD6C5", "\\mathbf{\\Delta}"),
+        ("\uD6C6", "\\mathbf{\\Epsilon}"),
+        ("\uD6C7", "\\mathbf{\\Zeta}"),
+        ("\uD6C8", "\\mathbf{\\Eta}"),
+        ("\uD6C9", "\\mathbf{\\theta}"),
+        ("\uD6CA", "\\mathbf{\\Iota}"),
+        ("\uD6CB", "\\mathbf{\\Kappa}"),
+        ("\uD6CC", "\\mathbf{\\Lambda}"),
+        ("\uD6CF", "\\mathbf{\\Xi}"),
+        ("\uD6D1", "\\mathbf{\\Pi}"),
+        ("\uD6D2", "\\mathbf{\\Rho}"),
+        ("\uD6D3", "\\mathbf{\\varsigma}"),
+        ("\uD6D4", "\\mathbf{\\Sigma}"),
+        ("\uD6D5", "\\mathbf{\\Tau}"),
+        ("\uD6D6", "\\mathbf{\\Upsilon}"),
+        ("\uD6D7", "\\mathbf{\\Phi}"),
+        ("\uD6D8", "\\mathbf{\\Chi}"),
+        ("\uD6D9", "\\mathbf{\\Psi}"),
+        ("\uD6DA", "\\mathbf{\\Omega}"),
+        ("\uD6DB", "\\partial "),
+        ("\uD6DC", "\\in"),
+        ("\uD6DD", "\\mathbf{\\vartheta}"),
+        ("\uD6DE", "\\mathbf{\\varkappa}"),
+        ("\uD6DF", "\\mathbf{\\phi}"),
+        ("\uD6E0", "\\mathbf{\\varrho}"),
+        ("\uD6E1", "\\mathbf{\\varpi}"),
+        ("\uD6E2", "\\mathsl{\\Alpha}"),
+        ("\uD6E3", "\\mathsl{\\Beta}"),
+        ("\uD6E4", "\\mathsl{\\Gamma}"),
+        ("\uD6E5", "\\mathsl{\\Delta}"),
+        ("\uD6E6", "\\mathsl{\\Epsilon}"),
+        ("\uD6E7", "\\mathsl{\\Zeta}"),
+        ("\uD6E8", "\\mathsl{\\Eta}"),
+        ("\uD6E9", "\\mathsl{\\Theta}"),
+        ("\uD6EA", "\\mathsl{\\Iota}"),
+        ("\uD6EB", "\\mathsl{\\Kappa}"),
+        ("\uD6EC", "\\mathsl{\\Lambda}"),
+        ("\uD6EF", "\\mathsl{\\Xi}"),
+        ("\uD6F1", "\\mathsl{\\Pi}"),
+        ("\uD6F2", "\\mathsl{\\Rho}"),
+        ("\uD6F3", "\\mathsl{\\vartheta}"),
+        ("\uD6F4", "\\mathsl{\\Sigma}"),
+        ("\uD6F5", "\\mathsl{\\Tau}"),
+        ("\uD6F6", "\\mathsl{\\Upsilon}"),
+        ("\uD6F7", "\\mathsl{\\Phi}"),
+        ("\uD6F8", "\\mathsl{\\Chi}"),
+        ("\uD6F9", "\\mathsl{\\Psi}"),
+        ("\uD6FA", "\\mathsl{\\Omega}"),
+        ("\uD6FB", "\\mathsl{\\nabla}"),
+        ("\uD6FC", "\\mathsl{\\Alpha}"),
+        ("\uD6FD", "\\mathsl{\\Beta}"),
+        ("\uD6FE", "\\mathsl{\\Gamma}"),
+        ("\uD6FF", "\\mathsl{\\Delta}"),
+        ("\uD700", "\\mathsl{\\Epsilon}"),
+        ("\uD701", "\\mathsl{\\Zeta}"),
+        ("\uD702", "\\mathsl{\\Eta}"),
+        ("\uD703", "\\mathsl{\\Theta}"),
+        ("\uD704", "\\mathsl{\\Iota}"),
+        ("\uD705", "\\mathsl{\\Kappa}"),
+        ("\uD706", "\\mathsl{\\Lambda}"),
+        ("\uD709", "\\mathsl{\\Xi}"),
+        ("\uD70B", "\\mathsl{\\Pi}"),
+        ("\uD70C", "\\mathsl{\\Rho}"),
+        ("\uD70D", "\\mathsl{\\varsigma}"),
+        ("\uD70E", "\\mathsl{\\Sigma}"),
+        ("\uD70F", "\\mathsl{\\Tau}"),
+        ("\uD710", "\\mathsl{\\Upsilon}"),
+        ("\uD711", "\\mathsl{\\Phi}"),
+        ("\uD712", "\\mathsl{\\Chi}"),
+        ("\uD713", "\\mathsl{\\Psi}"),
+        ("\uD714", "\\mathsl{\\Omega}"),
+        ("\uD715", "\\partial "),
+        ("\uD716", "\\in"),
+        ("\uD717", "\\mathsl{\\vartheta}"),
+        ("\uD718", "\\mathsl{\\varkappa}"),
+        ("\uD719", "\\mathsl{\\phi}"),
+        ("\uD71A", "\\mathsl{\\varrho}"),
+        ("\uD71B", "\\mathsl{\\varpi}"),
+        ("\uD71C", "\\mathbit{\\Alpha}"),
+        ("\uD71D", "\\mathbit{\\Beta}"),
+        ("\uD71E", "\\mathbit{\\Gamma}"),
+        ("\uD71F", "\\mathbit{\\Delta}"),
+        ("\uD720", "\\mathbit{\\Epsilon}"),
+        ("\uD721", "\\mathbit{\\Zeta}"),
+        ("\uD722", "\\mathbit{\\Eta}"),
+        ("\uD723", "\\mathbit{\\Theta}"),
+        ("\uD724", "\\mathbit{\\Iota}"),
+        ("\uD725", "\\mathbit{\\Kappa}"),
+        ("\uD726", "\\mathbit{\\Lambda}"),
+        ("\uD729", "\\mathbit{\\Xi}"),
+        ("\uD72B", "\\mathbit{\\Pi}"),
+        ("\uD72C", "\\mathbit{\\Rho}"),
+        ("\uD72D", "\\mathbit{O}"),
+        ("\uD72E", "\\mathbit{\\Sigma}"),
+        ("\uD72F", "\\mathbit{\\Tau}"),
+        ("\uD730", "\\mathbit{\\Upsilon}"),
+        ("\uD731", "\\mathbit{\\Phi}"),
+        ("\uD732", "\\mathbit{\\Chi}"),
+        ("\uD733", "\\mathbit{\\Psi}"),
+        ("\uD734", "\\mathbit{\\Omega}"),
+        ("\uD735", "\\mathbit{\\nabla}"),
+        ("\uD736", "\\mathbit{\\Alpha}"),
+        ("\uD737", "\\mathbit{\\Beta}"),
+        ("\uD738", "\\mathbit{\\Gamma}"),
+        ("\uD739", "\\mathbit{\\Delta}"),
+        ("\uD73A", "\\mathbit{\\Epsilon}"),
+        ("\uD73B", "\\mathbit{\\Zeta}"),
+        ("\uD73C", "\\mathbit{\\Eta}"),
+        ("\uD73D", "\\mathbit{\\Theta}"),
+        ("\uD73E", "\\mathbit{\\Iota}"),
+        ("\uD73F", "\\mathbit{\\Kappa}"),
+        ("\uD740", "\\mathbit{\\Lambda}"),
+        ("\uD743", "\\mathbit{\\Xi}"),
+        ("\uD745", "\\mathbit{\\Pi}"),
+        ("\uD746", "\\mathbit{\\Rho}"),
+        ("\uD747", "\\mathbit{\\varsigma}"),
+        ("\uD748", "\\mathbit{\\Sigma}"),
+        ("\uD749", "\\mathbit{\\Tau}"),
+        ("\uD74A", "\\mathbit{\\Upsilon}"),
+        ("\uD74B", "\\mathbit{\\Phi}"),
+        ("\uD74C", "\\mathbit{\\Chi}"),
+        ("\uD74D", "\\mathbit{\\Psi}"),
+        ("\uD74E", "\\mathbit{\\Omega}"),
+        ("\uD74F", "\\partial "),
+        ("\uD750", "\\in"),
+        ("\uD751", "\\mathbit{\\vartheta}"),
+        ("\uD752", "\\mathbit{\\varkappa}"),
+        ("\uD753", "\\mathbit{\\phi}"),
+        ("\uD754", "\\mathbit{\\varrho}"),
+        ("\uD755", "\\mathbit{\\varpi}"),
+        ("\uD756", "\\mathsfbf{\\Alpha}"),
+        ("\uD757", "\\mathsfbf{\\Beta}"),
+        ("\uD758", "\\mathsfbf{\\Gamma}"),
+        ("\uD759", "\\mathsfbf{\\Delta}"),
+        ("\uD75A", "\\mathsfbf{\\Epsilon}"),
+        ("\uD75B", "\\mathsfbf{\\Zeta}"),
+        ("\uD75C", "\\mathsfbf{\\Eta}"),
+        ("\uD75D", "\\mathsfbf{\\Theta}"),
+        ("\uD75E", "\\mathsfbf{\\Iota}"),
+        ("\uD75F", "\\mathsfbf{\\Kappa}"),
+        ("\uD760", "\\mathsfbf{\\Lambda}"),
+        ("\uD763", "\\mathsfbf{\\Xi}"),
+        ("\uD765", "\\mathsfbf{\\Pi}"),
+        ("\uD766", "\\mathsfbf{\\Rho}"),
+        ("\uD767", "\\mathsfbf{\\vartheta}"),
+        ("\uD768", "\\mathsfbf{\\Sigma}"),
+        ("\uD769", "\\mathsfbf{\\Tau}"),
+        ("\uD76A", "\\mathsfbf{\\Upsilon}"),
+        ("\uD76B", "\\mathsfbf{\\Phi}"),
+        ("\uD76C", "\\mathsfbf{\\Chi}"),
+        ("\uD76D", "\\mathsfbf{\\Psi}"),
+        ("\uD76E", "\\mathsfbf{\\Omega}"),
+        ("\uD76F", "\\mathsfbf{\\nabla}"),
+        ("\uD770", "\\mathsfbf{\\Alpha}"),
+        ("\uD771", "\\mathsfbf{\\Beta}"),
+        ("\uD772", "\\mathsfbf{\\Gamma}"),
+        ("\uD773", "\\mathsfbf{\\Delta}"),
+        ("\uD774", "\\mathsfbf{\\Epsilon}"),
+        ("\uD775", "\\mathsfbf{\\Zeta}"),
+        ("\uD776", "\\mathsfbf{\\Eta}"),
+        ("\uD777", "\\mathsfbf{\\Theta}"),
+        ("\uD778", "\\mathsfbf{\\Iota}"),
+        ("\uD779", "\\mathsfbf{\\Kappa}"),
+        ("\uD77A", "\\mathsfbf{\\Lambda}"),
+        ("\uD77D", "\\mathsfbf{\\Xi}"),
+        ("\uD77F", "\\mathsfbf{\\Pi}"),
+        ("\uD780", "\\mathsfbf{\\Rho}"),
+        ("\uD781", "\\mathsfbf{\\varsigma}"),
+        ("\uD782", "\\mathsfbf{\\Sigma}"),
+        ("\uD783", "\\mathsfbf{\\Tau}"),
+        ("\uD784", "\\mathsfbf{\\Upsilon}"),
+        ("\uD785", "\\mathsfbf{\\Phi}"),
+        ("\uD786", "\\mathsfbf{\\Chi}"),
+        ("\uD787", "\\mathsfbf{\\Psi}"),
+        ("\uD788", "\\mathsfbf{\\Omega}"),
+        ("\uD789", "\\partial "),
+        ("\uD78A", "\\in"),
+        ("\uD78B", "\\mathsfbf{\\vartheta}"),
+        ("\uD78C", "\\mathsfbf{\\varkappa}"),
+        ("\uD78D", "\\mathsfbf{\\phi}"),
+        ("\uD78E", "\\mathsfbf{\\varrho}"),
+        ("\uD78F", "\\mathsfbf{\\varpi}"),
+        ("\uD790", "\\mathsfbfsl{\\Alpha}"),
+        ("\uD791", "\\mathsfbfsl{\\Beta}"),
+        ("\uD792", "\\mathsfbfsl{\\Gamma}"),
+        ("\uD793", "\\mathsfbfsl{\\Delta}"),
+        ("\uD794", "\\mathsfbfsl{\\Epsilon}"),
+        ("\uD795", "\\mathsfbfsl{\\Zeta}"),
+        ("\uD796", "\\mathsfbfsl{\\Eta}"),
+        ("\uD797", "\\mathsfbfsl{\\vartheta}"),
+        ("\uD798", "\\mathsfbfsl{\\Iota}"),
+        ("\uD799", "\\mathsfbfsl{\\Kappa}"),
+        ("\uD79A", "\\mathsfbfsl{\\Lambda}"),
+        ("\uD79D", "\\mathsfbfsl{\\Xi}"),
+        ("\uD79F", "\\mathsfbfsl{\\Pi}"),
+        ("\uD7A0", "\\mathsfbfsl{\\Rho}"),
+        ("\uD7A1", "\\mathsfbfsl{\\vartheta}"),
+        ("\uD7A2", "\\mathsfbfsl{\\Sigma}"),
+        ("\uD7A3", "\\mathsfbfsl{\\Tau}"),
+        ("\uD7A4", "\\mathsfbfsl{\\Upsilon}"),
+        ("\uD7A5", "\\mathsfbfsl{\\Phi}"),
+        ("\uD7A6", "\\mathsfbfsl{\\Chi}"),
+        ("\uD7A7", "\\mathsfbfsl{\\Psi}"),
+        ("\uD7A8", "\\mathsfbfsl{\\Omega}"),
+        ("\uD7A9", "\\mathsfbfsl{\\nabla}"),
+        ("\uD7AA", "\\mathsfbfsl{\\Alpha}"),
+        ("\uD7AB", "\\mathsfbfsl{\\Beta}"),
+        ("\uD7AC", "\\mathsfbfsl{\\Gamma}"),
+        ("\uD7AD", "\\mathsfbfsl{\\Delta}"),
+        ("\uD7AE", "\\mathsfbfsl{\\Epsilon}"),
+        ("\uD7AF", "\\mathsfbfsl{\\Zeta}"),
+        ("\uD7B0", "\\mathsfbfsl{\\Eta}"),
+        ("\uD7B1", "\\mathsfbfsl{\\vartheta}"),
+        ("\uD7B2", "\\mathsfbfsl{\\Iota}"),
+        ("\uD7B3", "\\mathsfbfsl{\\Kappa}"),
+        ("\uD7B4", "\\mathsfbfsl{\\Lambda}"),
+        ("\uD7B7", "\\mathsfbfsl{\\Xi}"),
+        ("\uD7B9", "\\mathsfbfsl{\\Pi}"),
+        ("\uD7BA", "\\mathsfbfsl{\\Rho}"),
+        ("\uD7BB", "\\mathsfbfsl{\\varsigma}"),
+        ("\uD7BC", "\\mathsfbfsl{\\Sigma}"),
+        ("\uD7BD", "\\mathsfbfsl{\\Tau}"),
+        ("\uD7BE", "\\mathsfbfsl{\\Upsilon}"),
+        ("\uD7BF", "\\mathsfbfsl{\\Phi}"),
+        ("\uD7C0", "\\mathsfbfsl{\\Chi}"),
+        ("\uD7C1", "\\mathsfbfsl{\\Psi}"),
+        ("\uD7C2", "\\mathsfbfsl{\\Omega}"),
+        ("\uD7C3", "\\partial "),
+        ("\uD7C4", "\\in"),
+        ("\uD7C5", "\\mathsfbfsl{\\vartheta}"),
+        ("\uD7C6", "\\mathsfbfsl{\\varkappa}"),
+        ("\uD7C7", "\\mathsfbfsl{\\phi}"),
+        ("\uD7C8", "\\mathsfbfsl{\\varrho}"),
+        ("\uD7C9", "\\mathsfbfsl{\\varpi}"),
+        ("\uD7CE", "\\mathbf{0}"),
+        ("\uD7CF", "\\mathbf{1}"),
+        ("\uD7D0", "\\mathbf{2}"),
+        ("\uD7D1", "\\mathbf{3}"),
+        ("\uD7D2", "\\mathbf{4}"),
+        ("\uD7D3", "\\mathbf{5}"),
+        ("\uD7D4", "\\mathbf{6}"),
+        ("\uD7D5", "\\mathbf{7}"),
+        ("\uD7D6", "\\mathbf{8}"),
+        ("\uD7D7", "\\mathbf{9}"),
+        ("\uD7D8", "\\mathbb{0}"),
+        ("\uD7D9", "\\mathbb{1}"),
+        ("\uD7DA", "\\mathbb{2}"),
+        ("\uD7DB", "\\mathbb{3}"),
+        ("\uD7DC", "\\mathbb{4}"),
+        ("\uD7DD", "\\mathbb{5}"),
+        ("\uD7DE", "\\mathbb{6}"),
+        ("\uD7DF", "\\mathbb{7}"),
+        ("\uD7E0", "\\mathbb{8}"),
+        ("\uD7E1", "\\mathbb{9}"),
+        ("\uD7E2", "\\mathsf{0}"),
+        ("\uD7E3", "\\mathsf{1}"),
+        ("\uD7E4", "\\mathsf{2}"),
+        ("\uD7E5", "\\mathsf{3}"),
+        ("\uD7E6", "\\mathsf{4}"),
+        ("\uD7E7", "\\mathsf{5}"),
+        ("\uD7E8", "\\mathsf{6}"),
+        ("\uD7E9", "\\mathsf{7}"),
+        ("\uD7EA", "\\mathsf{8}"),
+        ("\uD7EB", "\\mathsf{9}"),
+        ("\uD7EC", "\\mathsfbf{0}"),
+        ("\uD7ED", "\\mathsfbf{1}"),
+        ("\uD7EE", "\\mathsfbf{2}"),
+        ("\uD7EF", "\\mathsfbf{3}"),
+        ("\uD7F0", "\\mathsfbf{4}"),
+        ("\uD7F1", "\\mathsfbf{5}"),
+        ("\uD7F2", "\\mathsfbf{6}"),
+        ("\uD7F3", "\\mathsfbf{7}"),
+        ("\uD7F4", "\\mathsfbf{8}"),
+        ("\uD7F5", "\\mathsfbf{9}"),
+        ("\uD7F6", "\\mathtt{0}"),
+        ("\uD7F7", "\\mathtt{1}"),
+        ("\uD7F8", "\\mathtt{2}"),
+        ("\uD7F9", "\\mathtt{3}"),
+        ("\uD7FA", "\\mathtt{4}"),
+        ("\uD7FB", "\\mathtt{5}"),
+        ("\uD7FC", "\\mathtt{6}"),
+        ("\uD7FD", "\\mathtt{7}"),
+        ("\uD7FE", "\\mathtt{8}"),
+        ("\uD7FF", "\\mathtt{9}"),
+    )
+
+    if sys.version_info >= (3, 0):
+        unicode_to_latex = to_latex
+        unicode_to_crappy_latex1 = to_crappy1
+        unicode_to_crappy_latex2 = to_crappy2
+        unicode_to_latex_map = dict(unicode_to_latex)
+    else:
+        unicode_to_latex = tuple((k.decode('unicode-escape'), v) for k, v in to_latex)
+        unicode_to_crappy_latex1 = tuple((k.decode('unicode-escape'), v) for k, v in to_crappy1)
+        unicode_to_crappy_latex2 = tuple((k.decode('unicode-escape'), v) for k, v in to_crappy2)
+        unicode_to_latex_map = dict(unicode_to_latex)
+
+prepare_unicode_to_latex()
diff --git a/uberwriter/plugins/bibtex/fuzzywuzzy/StringMatcher.py b/uberwriter/plugins/bibtex/fuzzywuzzy/StringMatcher.py
new file mode 100644
index 0000000..f27f1ff
--- /dev/null
+++ b/uberwriter/plugins/bibtex/fuzzywuzzy/StringMatcher.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+StringMatcher.py
+
+ported from python-Levenshtein
+[https://github.com/miohtama/python-Levenshtein]
+"""
+
+from Levenshtein import *
+from warnings import warn
+
+
+class StringMatcher:
+    """A SequenceMatcher-like class built on the top of Levenshtein"""
+
+    def _reset_cache(self):
+        self._ratio = self._distance = None
+        self._opcodes = self._editops = self._matching_blocks = None
+
+    def __init__(self, isjunk=None, seq1='', seq2=''):
+        if isjunk:
+            warn("isjunk not NOT implemented, it will be ignored")
+        self._str1, self._str2 = seq1, seq2
+        self._reset_cache()
+
+    def set_seqs(self, seq1, seq2):
+        self._str1, self._str2 = seq1, seq2
+        self._reset_cache()
+
+    def set_seq1(self, seq1):
+        self._str1 = seq1
+        self._reset_cache()
+
+    def set_seq2(self, seq2):
+        self._str2 = seq2
+        self._reset_cache()
+
+    def get_opcodes(self):
+        if not self._opcodes:
+            if self._editops:
+                self._opcodes = opcodes(self._editops, self._str1, self._str2)
+            else:
+                self._opcodes = opcodes(self._str1, self._str2)
+        return self._opcodes
+
+    def get_editops(self):
+        if not self._editops:
+            if self._opcodes:
+                self._editops = editops(self._opcodes, self._str1, self._str2)
+            else:
+                self._editops = editops(self._str1, self._str2)
+        return self._editops
+
+    def get_matching_blocks(self):
+        if not self._matching_blocks:
+            self._matching_blocks = matching_blocks(self.get_opcodes(),
+                                                    self._str1, self._str2)
+        return self._matching_blocks
+
+    def ratio(self):
+        if not self._ratio:
+            self._ratio = ratio(self._str1, self._str2)
+        return self._ratio
+
+    def quick_ratio(self):
+        # This is usually quick enough :o)
+        if not self._ratio:
+            self._ratio = ratio(self._str1, self._str2)
+        return self._ratio
+
+    def real_quick_ratio(self):
+        len1, len2 = len(self._str1), len(self._str2)
+        return 2.0 * min(len1, len2) / (len1 + len2)
+
+    def distance(self):
+        if not self._distance:
+            self._distance = distance(self._str1, self._str2)
+        return self._distance
diff --git a/uberwriter/plugins/bibtex/fuzzywuzzy/__init__.py b/uberwriter/plugins/bibtex/fuzzywuzzy/__init__.py
new file mode 100644
index 0000000..dceb6e4
--- /dev/null
+++ b/uberwriter/plugins/bibtex/fuzzywuzzy/__init__.py
@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+__version__ = '0.8.1'
diff --git a/uberwriter/plugins/bibtex/fuzzywuzzy/fuzz.py b/uberwriter/plugins/bibtex/fuzzywuzzy/fuzz.py
new file mode 100644
index 0000000..46ace22
--- /dev/null
+++ b/uberwriter/plugins/bibtex/fuzzywuzzy/fuzz.py
@@ -0,0 +1,263 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+fuzz.py
+
+Copyright (c) 2011 Adam Cohen
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"""
+from __future__ import unicode_literals
+import warnings
+
+try:
+    from .StringMatcher import StringMatcher as SequenceMatcher
+except ImportError:
+    warnings.warn('Using slow pure-python SequenceMatcher. Install python-Levenshtein to remove this warning')
+    from difflib import SequenceMatcher
+
+from . import utils
+
+
+###########################
+# Basic Scoring Functions #
+###########################
+
+@utils.check_for_none
+@utils.check_empty_string
+def ratio(s1, s2):
+    s1, s2 = utils.make_type_consistent(s1, s2)
+
+    m = SequenceMatcher(None, s1, s2)
+    return utils.intr(100 * m.ratio())
+
+
+@utils.check_for_none
+@utils.check_empty_string
+def partial_ratio(s1, s2):
+    """"Return the ratio of the most similar substring
+    as a number between 0 and 100."""
+    s1, s2 = utils.make_type_consistent(s1, s2)
+
+    if len(s1) <= len(s2):
+        shorter = s1
+        longer = s2
+    else:
+        shorter = s2
+        longer = s1
+
+    m = SequenceMatcher(None, shorter, longer)
+    blocks = m.get_matching_blocks()
+
+    # each block represents a sequence of matching characters in a string
+    # of the form (idx_1, idx_2, len)
+    # the best partial match will block align with at least one of those blocks
+    #   e.g. shorter = "abcd", longer = XXXbcdeEEE
+    #   block = (1,3,3)
+    #   best score === ratio("abcd", "Xbcd")
+    scores = []
+    for block in blocks:
+        long_start = block[1] - block[0] if (block[1] - block[0]) > 0 else 0
+        long_end = long_start + len(shorter)
+        long_substr = longer[long_start:long_end]
+
+        m2 = SequenceMatcher(None, shorter, long_substr)
+        r = m2.ratio()
+        if r > .995:
+            return 100
+        else:
+            scores.append(r)
+
+    return utils.intr(100 * max(scores))
+
+
+##############################
+# Advanced Scoring Functions #
+##############################
+
+def _process_and_sort(s, force_ascii):
+    """Return a cleaned string with token sorted."""
+    # pull tokens
+    tokens = utils.full_process(s, force_ascii=force_ascii).split()
+
+    # sort tokens and join
+    sorted_string = u" ".join(sorted(tokens))
+    return sorted_string.strip()
+
+
+# Sorted Token
+#   find all alphanumeric tokens in the string
+#   sort those tokens and take ratio of resulting joined strings
+#   controls for unordered string elements
+@utils.check_for_none
+def _token_sort(s1, s2, partial=True, force_ascii=True):
+    sorted1 = _process_and_sort(s1, force_ascii)
+    sorted2 = _process_and_sort(s2, force_ascii)
+
+    if partial:
+        return partial_ratio(sorted1, sorted2)
+    else:
+        return ratio(sorted1, sorted2)
+
+
+def token_sort_ratio(s1, s2, force_ascii=True):
+    """Return a measure of the sequences' similarity between 0 and 100
+    but sorting the token before comparing.
+    """
+    return _token_sort(s1, s2, partial=False, force_ascii=force_ascii)
+
+
+def partial_token_sort_ratio(s1, s2, force_ascii=True):
+    """Return the ratio of the most similar substring as a number between
+    0 and 100 but sorting the token before comparing.
+    """
+    return _token_sort(s1, s2, partial=True, force_ascii=force_ascii)
+
+
+@utils.check_for_none
+def _token_set(s1, s2, partial=True, force_ascii=True):
+    """Find all alphanumeric tokens in each string...
+        - treat them as a set
+        - construct two strings of the form:
+            
+        - take ratios of those two strings
+        - controls for unordered partial matches"""
+
+    p1 = utils.full_process(s1, force_ascii=force_ascii)
+    p2 = utils.full_process(s2, force_ascii=force_ascii)
+
+    if not utils.validate_string(p1):
+        return 0
+    if not utils.validate_string(p2):
+        return 0
+
+    # pull tokens
+    tokens1 = set(utils.full_process(p1).split())
+    tokens2 = set(utils.full_process(p2).split())
+
+    intersection = tokens1.intersection(tokens2)
+    diff1to2 = tokens1.difference(tokens2)
+    diff2to1 = tokens2.difference(tokens1)
+
+    sorted_sect = " ".join(sorted(intersection))
+    sorted_1to2 = " ".join(sorted(diff1to2))
+    sorted_2to1 = " ".join(sorted(diff2to1))
+
+    combined_1to2 = sorted_sect + " " + sorted_1to2
+    combined_2to1 = sorted_sect + " " + sorted_2to1
+
+    # strip
+    sorted_sect = sorted_sect.strip()
+    combined_1to2 = combined_1to2.strip()
+    combined_2to1 = combined_2to1.strip()
+
+    if partial:
+        ratio_func = partial_ratio
+    else:
+        ratio_func = ratio
+
+    pairwise = [
+        ratio_func(sorted_sect, combined_1to2),
+        ratio_func(sorted_sect, combined_2to1),
+        ratio_func(combined_1to2, combined_2to1)
+    ]
+    return max(pairwise)
+
+
+def token_set_ratio(s1, s2, force_ascii=True):
+    return _token_set(s1, s2, partial=False, force_ascii=force_ascii)
+
+
+def partial_token_set_ratio(s1, s2, force_ascii=True):
+    return _token_set(s1, s2, partial=True, force_ascii=force_ascii)
+
+
+###################
+# Combination API #
+###################
+
+# q is for quick
+def QRatio(s1, s2, force_ascii=True):
+
+    p1 = utils.full_process(s1, force_ascii=force_ascii)
+    p2 = utils.full_process(s2, force_ascii=force_ascii)
+
+    if not utils.validate_string(p1):
+        return 0
+    if not utils.validate_string(p2):
+        return 0
+
+    return ratio(p1, p2)
+
+
+def UQRatio(s1, s2):
+    return QRatio(s1, s2, force_ascii=False)
+
+
+# w is for weighted
+def WRatio(s1, s2, force_ascii=True):
+    """Return a measure of the sequences' similarity between 0 and 100,
+    using different algorithms.
+    """
+
+    p1 = utils.full_process(s1, force_ascii=force_ascii)
+    p2 = utils.full_process(s2, force_ascii=force_ascii)
+
+    if not utils.validate_string(p1):
+        return 0
+    if not utils.validate_string(p2):
+        return 0
+
+    # should we look at partials?
+    try_partial = True
+    unbase_scale = .95
+    partial_scale = .90
+
+    base = ratio(p1, p2)
+    len_ratio = float(max(len(p1), len(p2))) / min(len(p1), len(p2))
+
+    # if strings are similar length, don't use partials
+    if len_ratio < 1.5:
+        try_partial = False
+
+    # if one string is much much shorter than the other
+    if len_ratio > 8:
+        partial_scale = .6
+
+    if try_partial:
+        partial = partial_ratio(p1, p2) * partial_scale
+        ptsor = partial_token_sort_ratio(p1, p2, force_ascii=force_ascii) \
+            * unbase_scale * partial_scale
+        ptser = partial_token_set_ratio(p1, p2, force_ascii=force_ascii) \
+            * unbase_scale * partial_scale
+
+        return utils.intr(max(base, partial, ptsor, ptser))
+    else:
+        tsor = token_sort_ratio(p1, p2, force_ascii=force_ascii) * unbase_scale
+        tser = token_set_ratio(p1, p2, force_ascii=force_ascii) * unbase_scale
+
+        return utils.intr(max(base, tsor, tser))
+
+
+def UWRatio(s1, s2):
+    """Return a measure of the sequences' similarity between 0 and 100,
+    using different algorithms. Same as WRatio but preserving unicode.
+    """
+    return WRatio(s1, s2, force_ascii=False)
diff --git a/uberwriter/plugins/bibtex/fuzzywuzzy/process.py b/uberwriter/plugins/bibtex/fuzzywuzzy/process.py
new file mode 100644
index 0000000..88eaa83
--- /dev/null
+++ b/uberwriter/plugins/bibtex/fuzzywuzzy/process.py
@@ -0,0 +1,227 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+process.py
+
+Copyright (c) 2011 Adam Cohen
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"""
+import itertools
+
+from . import fuzz
+from . import utils
+
+
+def extract(query, choices, processor=None, scorer=None, limit=5):
+    """Select the best match in a list or dictionary of choices.
+
+    Find best matches in a list or dictionary of choices, return a
+    list of tuples containing the match and it's score. If a dictionary
+    is used, also returns the key for each match.
+
+    Arguments:
+        query: An object representing the thing we want to find.
+        choices: An iterable or dictionary-like object containing choices
+            to be matched against the query. Dictionary arguments of
+            {key: value} pairs will attempt to match the query against
+            each value.
+        processor: Optional function of the form f(a) -> b, where a is an
+            individual choice and b is the choice to be used in matching.
+
+            This can be used to match against, say, the first element of
+            a list:
+
+            lambda x: x[0]
+
+            Defaults to fuzzywuzzy.utils.full_process().
+        scorer: Optional function for scoring matches between the query and
+            an individual processed choice. This should be a function
+            of the form f(query, choice) -> int.
+
+            By default, fuzz.WRatio() is used and expects both query and
+            choice to be strings.
+        limit: Optional maximum for the number of elements returned. Defaults
+            to 5.
+
+    Returns:
+        List of tuples containing the match and its score.
+
+        If a list is used for choices, then the result will be 2-tuples.
+        If a dictionary is used, then the result will be 3-tuples containing
+        he key for each match.
+
+        For example, searching for 'bird' in the dictionary
+
+        {'bard': 'train', 'dog': 'man'}
+
+        may return
+
+        [('train', 22, 'bard'), ('man', 0, 'dog')]
+    """
+
+    if choices is None:
+        return []
+
+    # Catch generators without lengths
+    try:
+        if len(choices) == 0:
+            return []
+    except TypeError:
+        pass
+
+    # default, turn whatever the choice is into a workable string
+    if not processor:
+        processor = utils.full_process
+
+    # default: wratio
+    if not scorer:
+        scorer = fuzz.WRatio
+
+    sl = []
+
+    try:
+        # See if choices is a dictionary-like object.
+        for key, choice in choices.items():
+            processed = processor(choice)
+            score = scorer(query, processed)
+            sl.append((choice, score, key))
+    except AttributeError:
+        # It's a list; just iterate over it.
+        for choice in choices:
+            processed = processor(choice)
+            score = scorer(query, processed)
+            sl.append((choice, score))
+
+    sl.sort(key=lambda i: i[1], reverse=True)
+    return sl[:limit]
+
+
+def extractBests(query, choices, processor=None, scorer=None, score_cutoff=0, limit=5):
+    """Get a list of the best matches to a collection of choices.
+
+    Convenience function for getting the choices with best scores.
+
+    Args:
+        query: A string to match against
+        choices: A list or dictionary of choices, suitable for use with
+            extract().
+        processor: Optional function for transforming choices before matching.
+            See extract().
+        scorer: Scoring function for extract().
+        score_cutoff: Optional argument for score threshold. No matches with
+            a score less than this number will be returned. Defaults to 0.
+        limit: Optional maximum for the number of elements returned. Defaults
+            to 5.
+
+    Returns: A a list of (match, score) tuples.
+    """
+    best_list = extract(query, choices, processor, scorer, limit)
+    return list(itertools.takewhile(lambda x: x[1] >= score_cutoff, best_list))
+
+
+def extractOne(query, choices, processor=None, scorer=None, score_cutoff=0):
+    """Find the single best match above a score in a list of choices.
+
+    This is a convenience method which returns the single best choice.
+    See extract() for the full arguments list.
+
+    Args:
+        query: A string to match against
+        choices: A list or dictionary of choices, suitable for use with
+            extract().
+        processor: Optional function for transforming choices before matching.
+            See extract().
+        scorer: Scoring function for extract().
+        score_cutoff: Optional argument for score threshold. If the best
+            match is found, but it is not greater than this number, then
+            return None anyway ("not a good enough match").  Defaults to 0.
+
+    Returns:
+        A tuple containing a single match and its score, if a match
+        was found that was above score_cutoff. Otherwise, returns None.
+    """
+    best_list = extract(query, choices, processor, scorer, limit=1)
+    if len(best_list) > 0 and best_list[0][1] >= score_cutoff:
+        return best_list[0]
+    return None
+
+
+def dedupe(contains_dupes, threshold=70, scorer=fuzz.token_set_ratio):
+    """This convenience function takes a list of strings containing duplicates and uses fuzzy matching to identify
+    and remove duplicates. Specifically, it uses the process.extract to identify duplicates that
+    score greater than a user defined threshold. Then, it looks for the longest item in the duplicate list
+    since we assume this item contains the most entity information and returns that. It breaks string
+    length ties on an alphabetical sort.
+
+    Note: as the threshold DECREASES the number of duplicates that are found INCREASES. This means that the
+        returned deduplicated list will likely be shorter. Raise the threshold for fuzzy_dedupe to be less
+        sensitive.
+
+    Args:
+        contains_dupes: A list of strings that we would like to dedupe.
+        threshold: the numerical value (0,100) point at which we expect to find duplicates.
+            Defaults to 70 out of 100
+        scorer: Optional function for scoring matches between the query and
+            an individual processed choice. This should be a function
+            of the form f(query, choice) -> int.
+            By default, fuzz.token_set_ratio() is used and expects both query and
+            choice to be strings.
+
+    Returns:
+        A deduplicated list. For example:
+
+            In: contains_dupes = ['Frodo Baggin', 'Frodo Baggins', 'F. Baggins', 'Samwise G.', 'Gandalf', 'Bilbo Baggins']
+            In: fuzzy_dedupe(contains_dupes)
+            Out: ['Frodo Baggins', 'Samwise G.', 'Bilbo Baggins', 'Gandalf']
+        """
+
+    extractor = []
+
+    # iterate over items in *contains_dupes*
+    for item in contains_dupes:
+        # return all duplicate matches found
+        matches = extract(item, contains_dupes, limit=None, scorer=scorer)
+        # filter matches based on the threshold
+        filtered = [x for x in matches if x[1] > threshold]
+        # if there is only 1 item in *filtered*, no duplicates were found so append to *extracted*
+        if len(filtered) == 1:
+            extractor.append(filtered[0][0])
+
+        else:
+            # alpha sort
+            filtered = sorted(filtered, key=lambda x: x[0])
+            # length sort
+            filter_sort = sorted(filtered, key=lambda x: len(x[0]), reverse=True)
+            # take first item as our 'canonical example'
+            extractor.append(filter_sort[0][0])
+
+    # uniquify *extractor* list
+    keys = {}
+    for e in extractor:
+        keys[e] = 1
+    extractor = keys.keys()
+
+    # check that extractor differs from contain_dupes (e.g. duplicates were found)
+    # if not, then return the original list
+    if len(extractor) == len(contains_dupes):
+        return contains_dupes
+    else:
+        return extractor
diff --git a/uberwriter/plugins/bibtex/fuzzywuzzy/string_processing.py b/uberwriter/plugins/bibtex/fuzzywuzzy/string_processing.py
new file mode 100644
index 0000000..0fee736
--- /dev/null
+++ b/uberwriter/plugins/bibtex/fuzzywuzzy/string_processing.py
@@ -0,0 +1,34 @@
+from __future__ import unicode_literals
+import re
+import string
+import sys
+
+
+PY3 = sys.version_info[0] == 3
+
+
+class StringProcessor(object):
+    """
+    This class defines method to process strings in the most
+    efficient way. Ideally all the methods below use unicode strings
+    for both input and output.
+    """
+
+    regex = re.compile(r"(?ui)\W")
+
+    @classmethod
+    def replace_non_letters_non_numbers_with_whitespace(cls, a_string):
+        """
+        This function replaces any sequence of non letters and non
+        numbers with a single white space.
+        """
+        return cls.regex.sub(u" ", a_string)
+
+    if PY3:
+        strip = staticmethod(str.strip)
+        to_lower_case = staticmethod(str.lower)
+        to_upper_case = staticmethod(str.upper)
+    else:
+        strip = staticmethod(string.strip)
+        to_lower_case = staticmethod(string.lower)
+        to_upper_case = staticmethod(string.upper)
diff --git a/uberwriter/plugins/bibtex/fuzzywuzzy/utils.py b/uberwriter/plugins/bibtex/fuzzywuzzy/utils.py
new file mode 100644
index 0000000..bb0426d
--- /dev/null
+++ b/uberwriter/plugins/bibtex/fuzzywuzzy/utils.py
@@ -0,0 +1,94 @@
+from __future__ import unicode_literals
+import sys
+import functools
+
+from fuzzywuzzy.string_processing import StringProcessor
+
+
+PY3 = sys.version_info[0] == 3
+
+
+def validate_string(s):
+    try:
+        return len(s) > 0
+    except TypeError:
+        return False
+
+
+def check_for_none(func):
+    @functools.wraps(func)
+    def decorator(*args, **kwargs):
+        if args[0] is None:
+            raise TypeError("s1 is None")
+        if args[1] is None:
+            raise TypeError("s2 is None")
+        return func(*args, **kwargs)
+    return decorator
+
+
+def check_empty_string(func):
+    @functools.wraps(func)
+    def decorator(*args, **kwargs):
+        if len(args[0]) == 0 or len(args[1]) == 0:
+            return 0
+        return func(*args, **kwargs)
+    return decorator
+
+bad_chars = str("").join([chr(i) for i in range(128, 256)])  # ascii dammit!
+if PY3:
+    translation_table = dict((ord(c), None) for c in bad_chars)
+    unicode = str
+
+
+def asciionly(s):
+    if PY3:
+        return s.translate(translation_table)
+    else:
+        return s.translate(None, bad_chars)
+
+
+def asciidammit(s):
+    if type(s) is str:
+        return asciionly(s)
+    elif type(s) is unicode:
+        return asciionly(s.encode('ascii', 'ignore'))
+    else:
+        return asciidammit(unicode(s))
+
+
+def make_type_consistent(s1, s2):
+    """If both objects aren't either both string or unicode instances force them to unicode"""
+    if isinstance(s1, str) and isinstance(s2, str):
+        return s1, s2
+
+    elif isinstance(s1, unicode) and isinstance(s2, unicode):
+        return s1, s2
+
+    else:
+        return unicode(s1), unicode(s2)
+
+
+def full_process(s, force_ascii=False):
+    """Process string by
+        -- removing all but letters and numbers
+        -- trim whitespace
+        -- force to lower case
+        if force_ascii == True, force convert to ascii"""
+
+    if s is None:
+        return ""
+
+    if force_ascii:
+        s = asciidammit(s)
+    # Keep only Letters and Numbers (see Unicode docs).
+    string_out = StringProcessor.replace_non_letters_non_numbers_with_whitespace(s)
+    # Force into lowercase.
+    string_out = StringProcessor.to_lower_case(string_out)
+    # Remove leading and trailing whitespaces.
+    string_out = StringProcessor.strip(string_out)
+    return string_out
+
+
+def intr(n):
+    '''Returns a correctly rounded integer'''
+    return int(round(n))
diff --git a/uberwriter/plugins/bibtex/gi_composites.py b/uberwriter/plugins/bibtex/gi_composites.py
new file mode 100644
index 0000000..e29f2e1
--- /dev/null
+++ b/uberwriter/plugins/bibtex/gi_composites.py
@@ -0,0 +1,276 @@
+#
+# Copyright (C) 2015 Dustin Spicuzza 
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+# USA
+
+from os.path import abspath, join
+
+import inspect
+import warnings
+
+from gi.repository import Gio
+from gi.repository import GLib
+from gi.repository import GObject
+from gi.repository import Gtk
+
+__all__ = ['GtkTemplate']
+
+class GtkTemplateWarning(UserWarning):
+    pass
+
+def _connect_func(builder, obj, signal_name, handler_name,
+                  connect_object, flags, cls):
+    '''Handles GtkBuilder signal connect events'''
+    
+    if connect_object is None:
+        extra = ()
+    else:
+        extra = (connect_object,)
+    
+    # The handler name refers to an attribute on the template instance,
+    # so ask GtkBuilder for the template instance
+    template_inst = builder.get_object(cls.__gtype_name__)
+    
+    if template_inst is None: # This should never happen
+        errmsg = "Internal error: cannot find template instance! obj: %s; " \
+                 "signal: %s; handler: %s; connect_obj: %s; class: %s" % \
+                 (obj, signal_name, handler_name, connect_object, cls)
+        warnings.warn(errmsg, GtkTemplateWarning)
+        return
+    
+    handler = getattr(template_inst, handler_name)
+
+    if flags == GObject.ConnectFlags.AFTER:
+        obj.connect_after(signal_name, handler, *extra)
+    else:
+        obj.connect(signal_name, handler, *extra)
+    
+    template_inst.__connected_template_signals__.add(handler_name)
+
+
+def _register_template(cls, template_bytes):
+    '''Registers the template for the widget and hooks init_template'''
+
+    # This implementation won't work if there are nested templates, but
+    # we can't do that anyways due to PyGObject limitations so it's ok
+    
+    if not hasattr(cls, 'set_template'):
+        raise TypeError("Requires PyGObject 3.13.2 or greater")
+
+    cls.set_template(template_bytes)
+    
+    bound_methods = set()
+    bound_widgets = set()
+    
+    # Walk the class, find marked callbacks and child attributes
+    for name in dir(cls):
+        
+        o = getattr(cls, name, None)
+        
+        if inspect.ismethod(o):
+            if hasattr(o, '_gtk_callback'):
+                bound_methods.add(name)
+                # Don't need to call this, as connect_func always gets called
+                #cls.bind_template_callback_full(name, o)
+        elif isinstance(o, _Child):
+            cls.bind_template_child_full(name, True, 0)
+            bound_widgets.add(name)
+    
+    # Have to setup a special connect function to connect at template init
+    # because the methods are not bound yet
+    cls.set_connect_func(_connect_func, cls)
+    
+    cls.__gtemplate_methods__ = bound_methods
+    cls.__gtemplate_widgets__ = bound_widgets
+    
+    base_init_template = cls.init_template
+    cls.init_template = lambda s: _init_template(s, cls, base_init_template)
+
+
+def _init_template(self, cls, base_init_template):
+    '''This would be better as an override for Gtk.Widget'''
+    
+    # TODO: could disallow using a metaclass.. but this is good enough
+    # .. if you disagree, feel free to fix it and issue a PR :)
+    if self.__class__ is not cls:
+        raise TypeError("Inheritance from classes with @GtkTemplate decorators "
+                        "is not allowed at this time")
+    
+    connected_signals = set()
+    self.__connected_template_signals__ = connected_signals
+    
+    base_init_template(self)
+    print('initing template')
+    print(self.__gtemplate_widgets__)
+
+    for name in self.__gtemplate_widgets__:
+        widget = self.get_template_child(cls, name)
+        self.__dict__[name] = widget
+        print(name)
+        
+        if widget is None:
+            # Bug: if you bind a template child, and one of them was
+            #      not present, then the whole template is broken (and
+            #      it's not currently possible for us to know which 
+            #      one is broken either -- but the stderr should show
+            #      something useful with a Gtk-CRITICAL message)
+            raise AttributeError("A missing child widget was set using "
+                                 "GtkTemplate.Child and the entire "
+                                 "template is now broken (widgets: %s)" %
+                                 ', '.join(self.__gtemplate_widgets__))
+    
+    for name in self.__gtemplate_methods__.difference(connected_signals):
+        errmsg = ("Signal '%s' was declared with @GtkTemplate.Callback " +
+                  "but was not present in template") % name
+        warnings.warn(errmsg, GtkTemplateWarning)
+
+
+# TODO: Make it easier for IDE to introspect this
+class _Child(object):
+    '''
+        Assign this to an attribute in your class definition and it will
+        be replaced with a widget defined in the UI file when init_template
+        is called
+    '''
+    
+    __slots__ = []
+    
+    @staticmethod
+    def widgets(count):
+        '''
+            Allows declaring multiple widgets with less typing::
+            
+                button    \
+                label1    \
+                label2    = GtkTemplate.Child.widgets(3)
+        '''
+        return [_Child() for _ in range(count)]
+
+
+class _GtkTemplate(object):
+    '''
+        Use this class decorator to signify that a class is a composite
+        widget which will receive widgets and connect to signals as
+        defined in a UI template. You must call init_template to
+        cause the widgets/signals to be initialized from the template::
+        
+            @GtkTemplate(ui='foo.ui')
+            class Foo(Gtk.Box):
+                
+                def __init__(self):
+                    super(Foo, self).__init__()
+                    self.init_template()
+
+        The 'ui' parameter can either be a file path or a GResource resource
+        path::
+
+            @GtkTemplate(ui='/org/example/foo.ui')
+            class Foo(Gtk.Box):
+                pass
+                
+        To connect a signal to a method on your instance, do::
+            
+            @GtkTemplate.Callback
+            def on_thing_happened(self, widget):
+                pass
+        
+        To create a child attribute that is retrieved from your template,
+        add this to your class definition::
+        
+            @GtkTemplate(ui='foo.ui')
+            class Foo(Gtk.Box):
+            
+                widget = GtkTemplate.Child()
+        
+    
+        Note: This is implemented as a class decorator, but if it were
+        included with PyGI I suspect it might be better to do this
+        in the GObject metaclass (or similar) so that init_template
+        can be called automatically instead of forcing the user to do it.
+        
+        .. note:: Due to limitations in PyGObject, you may not inherit from
+                  python objects that use the GtkTemplate decorator.
+    '''
+    
+    __ui_path__ = None
+    
+    @staticmethod
+    def Callback(f):
+        '''
+            Decorator that designates a method to be attached to a signal from
+            the template
+        '''
+        f._gtk_callback = True
+        return f
+
+    
+    Child = _Child
+    
+    @staticmethod
+    def set_ui_path(*path):
+        '''
+            If using file paths instead of resources, call this *before*
+            loading anything that uses GtkTemplate, or it will fail to load
+            your template file
+            
+            :param path: one or more path elements, will be joined together
+                         to create the final path
+            
+            TODO: Alternatively, could wait until first class instantiation
+                  before registering templates? Would need a metaclass...
+        '''
+        _GtkTemplate.__ui_path__ = abspath(join(*path))
+    
+    
+    def __init__(self, ui):
+        self.ui = ui
+    
+    def __call__(self, cls):
+        
+        if not issubclass(cls, Gtk.Widget):
+            raise TypeError("Can only use @GtkTemplate on Widgets")
+
+        # Nested templates don't work
+        if hasattr(cls, '__gtemplate_methods__'):
+            raise TypeError("Cannot nest template classes")
+        
+        # Load the template either from a resource path or a file
+        # - Prefer the resource path first
+
+        try:
+            template_bytes = Gio.resources_lookup_data(self.ui, Gio.ResourceLookupFlags.NONE)
+        except GLib.GError:
+            ui = self.ui
+            if isinstance(ui, (list, tuple)):
+                ui = join(ui)
+
+            if _GtkTemplate.__ui_path__ is not None:
+                ui = join(_GtkTemplate.__ui_path__, ui)
+
+            with open(ui, 'rb') as fp:
+                template_bytes = GLib.Bytes.new(fp.read())
+
+        _register_template(cls, template_bytes)
+        return cls
+
+
+   
+# Future shim support if this makes it into PyGI?
+#if hasattr(Gtk, 'GtkTemplate'):
+#    GtkTemplate = lambda c: c
+#else:
+GtkTemplate = _GtkTemplate
+    
diff --git a/uberwriter/plugins/ubercsv/csvtomd b/uberwriter/plugins/ubercsv/csvtomd
new file mode 160000
index 0000000..264ee48
--- /dev/null
+++ b/uberwriter/plugins/ubercsv/csvtomd
@@ -0,0 +1 @@
+Subproject commit 264ee48c1fe05ef2198697e88f34bae581654caa
diff --git a/uberwriter/plugins/uberquation/equation_widget.glade~ b/uberwriter/plugins/uberquation/equation_widget.glade~
new file mode 100644
index 0000000..63bd82b
--- /dev/null
+++ b/uberwriter/plugins/uberquation/equation_widget.glade~
@@ -0,0 +1,109 @@
+
+
+
+  
+  
+    True
+    False
+  
+  
+    
+  
+  
+    False
+    
+    
+      
+        True
+        False
+        5
+        5
+        5
+        5
+        
+          
+            True
+            False
+            True
+            True
+            gtk-justify-center
+          
+          
+            0
+            1
+            3
+          
+        
+        
+          
+            True
+            True
+            textbuffer1
+            
+            
+          
+          
+            0
+            2
+            3
+          
+        
+        
+          
+            True
+            False
+            vertical
+            
+              
+                True
+                True
+                5
+                edit-find-symbolic
+                False
+                False
+                
+              
+              
+                False
+                True
+                0
+              
+            
+            
+              
+                True
+                True
+                in
+                
+                  
+                    True
+                    False
+                    
+                      
+                        listbox
+                        True
+                        False
+                        True
+                        False
+                      
+                    
+                  
+                
+              
+              
+                False
+                True
+                1
+              
+            
+          
+          
+            0
+            0
+            3
+          
+        
+      
+    
+  
+
diff --git a/uberwriter/plugins/uberquation/icons/Rightarrow b/uberwriter/plugins/uberquation/icons/Rightarrow
new file mode 100644
index 0000000..7247e64
--- /dev/null
+++ b/uberwriter/plugins/uberquation/icons/Rightarrow
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/uberwriter/plugins/uberquation/icons/^{0} b/uberwriter/plugins/uberquation/icons/^{0}
new file mode 100644
index 0000000..ddee9c3
--- /dev/null
+++ b/uberwriter/plugins/uberquation/icons/^{0}
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uberwriter/plugins/uberquation/icons/_{0} b/uberwriter/plugins/uberquation/icons/_{0}
new file mode 100644
index 0000000..3c951f0
--- /dev/null
+++ b/uberwriter/plugins/uberquation/icons/_{0}
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uberwriter/plugins/uberquation/icons/alpha b/uberwriter/plugins/uberquation/icons/alpha
new file mode 100644
index 0000000..7141860
--- /dev/null
+++ b/uberwriter/plugins/uberquation/icons/alpha
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/uberwriter/plugins/uberquation/icons/beta b/uberwriter/plugins/uberquation/icons/beta
new file mode 100644
index 0000000..f6878fc
--- /dev/null
+++ b/uberwriter/plugins/uberquation/icons/beta
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/uberwriter/plugins/uberquation/icons/int_{0}^{1}{2} b/uberwriter/plugins/uberquation/icons/int_{0}^{1}{2}
new file mode 100644
index 0000000..586b7f0
--- /dev/null
+++ b/uberwriter/plugins/uberquation/icons/int_{0}^{1}{2}
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uberwriter/plugins/uberquation/icons/rarrow b/uberwriter/plugins/uberquation/icons/rarrow
new file mode 100644
index 0000000..e434596
--- /dev/null
+++ b/uberwriter/plugins/uberquation/icons/rarrow
@@ -0,0 +1,5 @@
+
+
+
+
+