diff --git a/resources/recipes/alternet.recipe b/resources/recipes/alternet.recipe
new file mode 100644
index 0000000000..d9498c7a0c
--- /dev/null
+++ b/resources/recipes/alternet.recipe
@@ -0,0 +1,38 @@
+from calibre.ptempfile import PersistentTemporaryFile
+from calibre.web.feeds.news import BasicNewsRecipe
+
+class Alternet(BasicNewsRecipe):
+ title = u'Alternet'
+ __author__= 'rty'
+ oldest_article = 7
+ max_articles_per_feed = 100
+ publisher = 'alternet.org'
+ category = 'News, Magazine'
+ description = 'News magazine and online community'
+ feeds = [
+ (u'Front Page', u'http://feeds.feedblitz.com/alternet'),
+ (u'Breaking News', u'http://feeds.feedblitz.com/alternet_breaking_news'),
+ (u'Top Ten Campaigns', u'http://feeds.feedblitz.com/alternet_top_10_campaigns'),
+ (u'Special Coverage Areas', u'http://feeds.feedblitz.com/alternet_coverage')
+ ]
+
+ remove_javascript = True
+ use_embedded_content = False
+ no_stylesheets = True
+ language = 'en'
+ encoding = 'UTF-8'
+ temp_files = []
+ articles_are_obfuscated = True
+
+ def get_article_url(self, article):
+ return article.get('link', None)
+
+ def get_obfuscated_article(self, url):
+ br = self.get_browser()
+ br.open(url)
+ response = br.follow_link(url_regex = r'/printversion/[0-9]+', nr = 0)
+ html = response.read()
+ self.temp_files.append(PersistentTemporaryFile('_fa.html'))
+ self.temp_files[-1].write(html)
+ self.temp_files[-1].close()
+ return self.temp_files[-1].name
diff --git a/resources/templates/rtf.xsl b/resources/templates/rtf.xsl
index 74696f0857..c3162b0c15 100644
--- a/resources/templates/rtf.xsl
+++ b/resources/templates/rtf.xsl
@@ -265,9 +265,20 @@
pt;
+
+ text-align: justify;
+
+
+ text-align: center;
+
+
+ text-align: left;
+
+
+ text-align: right;
+
-
diff --git a/src/calibre/__init__.py b/src/calibre/__init__.py
index 92ee2ca6d2..15bd54c80c 100644
--- a/src/calibre/__init__.py
+++ b/src/calibre/__init__.py
@@ -361,6 +361,8 @@ def strftime(fmt, t=None):
before 1900 '''
if t is None:
t = time.localtime()
+ if hasattr(t, 'timetuple'):
+ t = t.timetuple()
early_year = t[0] < 1900
if early_year:
replacement = 1900 if t[0]%4 == 0 else 1901
diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py
index 9d876b42d1..35cb0ad3d2 100644
--- a/src/calibre/customize/builtins.py
+++ b/src/calibre/customize/builtins.py
@@ -446,7 +446,7 @@ from calibre.devices.eb600.driver import EB600, COOL_ER, SHINEBOOK, \
BOOQ, ELONEX, POCKETBOOK301, MENTOR
from calibre.devices.iliad.driver import ILIAD
from calibre.devices.irexdr.driver import IREXDR1000, IREXDR800
-from calibre.devices.jetbook.driver import JETBOOK
+from calibre.devices.jetbook.driver import JETBOOK, MIBUK
from calibre.devices.kindle.driver import KINDLE, KINDLE2, KINDLE_DX
from calibre.devices.nook.driver import NOOK
from calibre.devices.prs505.driver import PRS505
@@ -467,12 +467,12 @@ from calibre.devices.kobo.driver import KOBO
from calibre.ebooks.metadata.fetch import GoogleBooks, ISBNDB, Amazon, \
LibraryThing
from calibre.ebooks.metadata.douban import DoubanBooks
-from calibre.library.catalog import CSV_XML, EPUB_MOBI
+from calibre.library.catalog import CSV_XML, EPUB_MOBI, BIBTEX
from calibre.ebooks.epub.fix.unmanifested import Unmanifested
from calibre.ebooks.epub.fix.epubcheck import Epubcheck
plugins = [HTML2ZIP, PML2PMLZ, ArchiveExtract, GoogleBooks, ISBNDB, Amazon,
- LibraryThing, DoubanBooks, CSV_XML, EPUB_MOBI, Unmanifested, Epubcheck]
+ LibraryThing, DoubanBooks, CSV_XML, EPUB_MOBI, BIBTEX, Unmanifested, Epubcheck]
plugins += [
ComicInput,
EPUBInput,
@@ -517,6 +517,7 @@ plugins += [
IREXDR1000,
IREXDR800,
JETBOOK,
+ MIBUK,
SHINEBOOK,
POCKETBOOK360,
POCKETBOOK301,
diff --git a/src/calibre/devices/jetbook/driver.py b/src/calibre/devices/jetbook/driver.py
index 671fea5d75..6a3bc635ff 100644
--- a/src/calibre/devices/jetbook/driver.py
+++ b/src/calibre/devices/jetbook/driver.py
@@ -80,3 +80,21 @@ class JETBOOK(USBMS):
return mi
+class MIBUK(USBMS):
+
+ name = 'MiBuk Wolder Device Interface'
+ description = _('Communicate with the MiBuk Wolder reader.')
+ author = 'Kovid Goyal'
+ supported_platforms = ['windows', 'osx', 'linux']
+
+ FORMATS = ['epub', 'mobi', 'prc', 'fb2', 'txt', 'rtf', 'pdf']
+
+ VENDOR_ID = [0x0525]
+ PRODUCT_ID = [0xa4a5]
+ BCD = [0x314]
+ SUPPORTS_SUB_DIRS = True
+
+ VENDOR_NAME = 'LINUX'
+ WINDOWS_MAIN_MEM = 'WOLDERMIBUK'
+
+
diff --git a/src/calibre/ebooks/rtf/input.py b/src/calibre/ebooks/rtf/input.py
index d5e1a95157..50f5571d58 100644
--- a/src/calibre/ebooks/rtf/input.py
+++ b/src/calibre/ebooks/rtf/input.py
@@ -192,12 +192,18 @@ class RTFInput(InputFormatPlugin):
from calibre.ebooks.rtf2xml.ParseRtf import RtfInvalidCodeException
self.log = log
self.log('Converting RTF to XML...')
+ #Name of the preprocesssed RTF file
fname = self.preprocess(stream.name)
try:
xml = self.generate_xml(fname)
except RtfInvalidCodeException, e:
raise ValueError(_('This RTF file has a feature calibre does not '
'support. Convert it to HTML first and then try it.\n%s')%e)
+
+ '''dataxml = open('dataxml.xml', 'w')
+ dataxml.write(xml)
+ dataxml.close'''
+
d = glob.glob(os.path.join('*_rtf_pict_dir', 'picts.rtf'))
if d:
imap = {}
@@ -205,6 +211,7 @@ class RTFInput(InputFormatPlugin):
imap = self.extract_images(d[0])
except:
self.log.exception('Failed to extract images...')
+
self.log('Parsing XML...')
parser = etree.XMLParser(recover=True, no_network=True)
doc = etree.fromstring(xml, parser=parser)
@@ -214,10 +221,10 @@ class RTFInput(InputFormatPlugin):
name = imap.get(num, None)
if name is not None:
pict.set('num', name)
+
self.log('Converting XML to HTML...')
inline_class = InlineClass(self.log)
styledoc = etree.fromstring(P('templates/rtf.xsl', data=True))
-
extensions = { ('calibre', 'inline-class') : inline_class }
transform = etree.XSLT(styledoc, extensions=extensions)
result = transform(doc)
diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py
index d922af0914..41d72d17f1 100644
--- a/src/calibre/gui2/__init__.py
+++ b/src/calibre/gui2/__init__.py
@@ -4,7 +4,7 @@ __copyright__ = '2008, Kovid Goyal '
import os, sys
from threading import RLock
-from PyQt4.Qt import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, QSize, \
+from PyQt4.Qt import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, \
QByteArray, QTranslator, QCoreApplication, QThread, \
QEvent, QTimer, pyqtSignal, QDate, QDesktopServices, \
QFileDialog, QMessageBox, QPixmap, QFileIconProvider, \
@@ -33,10 +33,6 @@ def _config():
help=_('Send file to storage card instead of main memory by default'))
c.add_opt('confirm_delete', default=False,
help=_('Confirm before deleting'))
- c.add_opt('toolbar_icon_size', default=QSize(48, 48),
- help=_('Toolbar icon size')) # value QVariant.toSize
- c.add_opt('show_text_in_toolbar', default=True,
- help=_('Show button labels in the toolbar'))
c.add_opt('main_window_geometry', default=None,
help=_('Main window geometry')) # value QVariant.toByteArray
c.add_opt('new_version_notification', default=True,
diff --git a/src/calibre/gui2/catalog/catalog_bibtex.py b/src/calibre/gui2/catalog/catalog_bibtex.py
new file mode 100644
index 0000000000..ea222603b7
--- /dev/null
+++ b/src/calibre/gui2/catalog/catalog_bibtex.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
+from __future__ import with_statement
+
+__license__ = 'GPL v3'
+__copyright__ = '2009, Kovid Goyal '
+__docformat__ = 'restructuredtext en'
+
+
+from calibre.gui2 import gprefs
+from calibre.gui2.catalog.catalog_bibtex_ui import Ui_Form
+from PyQt4.Qt import QWidget, QListWidgetItem
+
+class PluginWidget(QWidget, Ui_Form):
+
+ TITLE = _('BibTeX Options')
+ HELP = _('Options specific to')+' BibTeX '+_('output')
+ OPTION_FIELDS = [('bib_cit','{authors}{id}'),
+ ('bib_entry', 0), #mixed
+ ('bibfile_enc', 0), #utf-8
+ ('bibfile_enctag', 0), #strict
+ ('impcit', True) ]
+
+ sync_enabled = False
+ formats = set(['bib'])
+
+ def __init__(self, parent=None):
+ QWidget.__init__(self, parent)
+ self.setupUi(self)
+ from calibre.library.catalog import FIELDS
+ self.all_fields = []
+ for x in FIELDS :
+ if x != 'all':
+ self.all_fields.append(x)
+ QListWidgetItem(x, self.db_fields)
+
+ def initialize(self, name): #not working properly to update
+ self.name = name
+ fields = gprefs.get(name+'_db_fields', self.all_fields)
+ # Restore the activated db_fields from last use
+ for x in xrange(self.db_fields.count()):
+ item = self.db_fields.item(x)
+ item.setSelected(unicode(item.text()) in fields)
+ # Update dialog fields from stored options
+ for opt in self.OPTION_FIELDS:
+ opt_value = gprefs.get(self.name + '_' + opt[0], opt[1])
+ if opt[0] in ['bibfile_enc', 'bibfile_enctag', 'bib_entry']:
+ getattr(self, opt[0]).setCurrentIndex(opt_value)
+ elif opt[0] == 'impcit' :
+ getattr(self, opt[0]).setChecked(opt_value)
+ else:
+ getattr(self, opt[0]).setText(opt_value)
+
+ def options(self):
+
+ # Save the currently activated fields
+ fields = []
+ for x in xrange(self.db_fields.count()):
+ item = self.db_fields.item(x)
+ if item.isSelected():
+ fields.append(unicode(item.text()))
+ gprefs.set(self.name+'_db_fields', fields)
+
+ # Dictionary currently activated fields
+ if len(self.db_fields.selectedItems()):
+ opts_dict = {'fields':[unicode(item.text()) for item in self.db_fields.selectedItems()]}
+ else:
+ opts_dict = {'fields':['all']}
+
+ # Save/return the current options
+ # bib_cit stores as text
+ # 'bibfile_enc','bibfile_enctag' stores as int (Indexes)
+ for opt in self.OPTION_FIELDS:
+ if opt[0] in ['bibfile_enc', 'bibfile_enctag', 'bib_entry']:
+ opt_value = getattr(self,opt[0]).currentIndex()
+ elif opt[0] == 'impcit' :
+ opt_value = getattr(self, opt[0]).isChecked()
+ else :
+ opt_value = unicode(getattr(self, opt[0]).text())
+ gprefs.set(self.name + '_' + opt[0], opt_value)
+
+ opts_dict[opt[0]] = opt_value
+
+ return opts_dict
diff --git a/src/calibre/gui2/catalog/catalog_bibtex.ui b/src/calibre/gui2/catalog/catalog_bibtex.ui
new file mode 100644
index 0000000000..7f4920655d
--- /dev/null
+++ b/src/calibre/gui2/catalog/catalog_bibtex.ui
@@ -0,0 +1,173 @@
+
+
+ Form
+
+
+
+ 0
+ 0
+ 579
+ 411
+
+
+
+ Form
+
+
+ -
+
+
+ Bib file encoding:
+
+
+
+ -
+
+
+ Fields to include in output:
+
+
+
+ -
+
+
-
+
+ utf-8
+
+
+ -
+
+ cp1252
+
+
+ -
+
+ ascii/LaTeX
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ QAbstractItemView::MultiSelection
+
+
+
+ -
+
+
+ Encoding configuration (change if you have errors) :
+
+
+
+ -
+
+
-
+
+ strict
+
+
+ -
+
+ replace
+
+
+ -
+
+ ignore
+
+
+ -
+
+ backslashreplace
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 60
+
+
+
+
+ -
+
+
+ BibTeX entry type:
+
+
+
+ -
+
+
-
+
+ mixed
+
+
+ -
+
+ misc
+
+
+ -
+
+ book
+
+
+
+
+ -
+
+
+ Create a citation tag?
+
+
+
+ -
+
+
+ Expression to form the BibTeX citation tag:
+
+
+
+ -
+
+
+ -
+
+
+ Some explanation about this template:
+ -The fields availables are 'author_sort', 'authors', 'id',
+ 'isbn', 'pubdate', 'publisher', 'series_index', 'series',
+ 'tags', 'timestamp', 'title', 'uuid'
+ -For list types ie authors and tags, only the first element
+ wil be selected.
+ -For time field, only the date will be used.
+
+
+ false
+
+
+
+
+
+
+
+
diff --git a/src/calibre/gui2/convert/metadata.ui b/src/calibre/gui2/convert/metadata.ui
index ec5a913f18..7bc45e234e 100644
--- a/src/calibre/gui2/convert/metadata.ui
+++ b/src/calibre/gui2/convert/metadata.ui
@@ -20,6 +20,30 @@
Book Cover
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ -
+
+
+ Use cover from &source file
+
+
+ true
+
+
+
-
@@ -71,30 +95,6 @@
- -
-
-
- Use cover from &source file
-
-
- true
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
opt_prefer_metadata_cover
@@ -232,9 +232,6 @@
QComboBox::InsertAlphabetically
-
- QComboBox::AdjustToContents
-
-
diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py
index bc8ba7c381..c919547956 100644
--- a/src/calibre/gui2/device.py
+++ b/src/calibre/gui2/device.py
@@ -638,7 +638,6 @@ class DeviceMixin(object): # {{{
self.device_error_dialog = error_dialog(self, _('Error'),
_('Error communicating with device'), ' ')
self.device_error_dialog.setModal(Qt.NonModal)
- self.device_connected = None
self.emailer = Emailer()
self.emailer.start()
self.device_manager = DeviceManager(Dispatcher(self.device_detected),
@@ -755,17 +754,14 @@ class DeviceMixin(object): # {{{
self.device_manager.device.__class__.get_gui_name()+\
_(' detected.'), 3000)
self.device_connected = device_kind
- self.location_view.model().device_connected(self.device_manager.device)
self.refresh_ondevice_info (device_connected = True, reset_only = True)
else:
self.device_connected = None
self.status_bar.device_disconnected()
- self.location_view.model().update_devices()
if self.current_view() != self.library_view:
self.book_details.reset_info()
- self.location_view.setCurrentIndex(self.location_view.model().index(0))
- self.refresh_ondevice_info (device_connected = False)
- self.tool_bar.device_status_changed(bool(connected))
+ self.location_manager.update_devices()
+ self.refresh_ondevice_info(device_connected=False)
def info_read(self, job):
'''
@@ -774,7 +770,8 @@ class DeviceMixin(object): # {{{
if job.failed:
return self.device_job_exception(job)
info, cp, fs = job.result
- self.location_view.model().update_devices(cp, fs)
+ self.location_manager.update_devices(cp, fs,
+ self.device_manager.device.icon)
self.status_bar.device_connected(info[0])
self.device_manager.books(Dispatcher(self.metadata_downloaded))
@@ -1076,9 +1073,9 @@ class DeviceMixin(object): # {{{
dynamic.set('catalogs_to_be_synced', set([]))
if files:
remove = []
- space = { self.location_view.model().free[0] : None,
- self.location_view.model().free[1] : 'carda',
- self.location_view.model().free[2] : 'cardb' }
+ space = { self.location_manager.free[0] : None,
+ self.location_manager.free[1] : 'carda',
+ self.location_manager.free[2] : 'cardb' }
on_card = space.get(sorted(space.keys(), reverse=True)[0], None)
self.upload_books(files, names, metadata,
on_card=on_card,
@@ -1140,9 +1137,9 @@ class DeviceMixin(object): # {{{
dynamic.set('news_to_be_synced', set([]))
if config['upload_news_to_device'] and files:
remove = ids if del_on_upload else []
- space = { self.location_view.model().free[0] : None,
- self.location_view.model().free[1] : 'carda',
- self.location_view.model().free[2] : 'cardb' }
+ space = { self.location_manager.free[0] : None,
+ self.location_manager.free[1] : 'carda',
+ self.location_manager.free[2] : 'cardb' }
on_card = space.get(sorted(space.keys(), reverse=True)[0], None)
self.upload_books(files, names, metadata,
on_card=on_card,
@@ -1263,7 +1260,8 @@ class DeviceMixin(object): # {{{
self.device_job_exception(job)
return
cp, fs = job.result
- self.location_view.model().update_devices(cp, fs)
+ self.location_manager.update_devices(cp, fs,
+ self.device_manager.device.icon)
# reset the views so that up-to-date info is shown. These need to be
# here because the sony driver updates collections in sync_booklists
self.memory_view.reset()
diff --git a/src/calibre/gui2/dialogs/choose_library.py b/src/calibre/gui2/dialogs/choose_library.py
new file mode 100644
index 0000000000..d656a93b6d
--- /dev/null
+++ b/src/calibre/gui2/dialogs/choose_library.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
+
+__license__ = 'GPL v3'
+__copyright__ = '2010, Kovid Goyal '
+__docformat__ = 'restructuredtext en'
+
+import os
+
+from PyQt4.Qt import QDialog
+
+from calibre.gui2.dialogs.choose_library_ui import Ui_Dialog
+from calibre.gui2 import error_dialog, choose_dir
+from calibre.constants import filesystem_encoding
+from calibre import isbytestring, patheq
+from calibre.utils.config import prefs
+from calibre.gui2.wizard import move_library
+
+class ChooseLibrary(QDialog, Ui_Dialog):
+
+ def __init__(self, db, callback, parent):
+ QDialog.__init__(self, parent)
+ self.setupUi(self)
+ self.db = db
+ self.new_db = None
+ self.callback = callback
+
+ lp = db.library_path
+ if isbytestring(lp):
+ lp = lp.decode(filesystem_encoding)
+ loc = unicode(self.old_location.text()).format(lp)
+ self.old_location.setText(loc)
+ self.browse_button.clicked.connect(self.choose_loc)
+
+ def choose_loc(self, *args):
+ loc = choose_dir(self, 'choose library location',
+ _('Choose location for calibre library'))
+ if loc is not None:
+ self.location.setText(loc)
+
+ def check_action(self, ac, loc):
+ exists = self.db.exists_at(loc)
+ if patheq(loc, self.db.library_path):
+ error_dialog(self, _('Same as current'),
+ _('The location %s contains the current calibre'
+ ' library')%loc, show=True)
+ return False
+ empty = not os.listdir(loc)
+ if ac == 'existing' and not exists:
+ error_dialog(self, _('No existing library found'),
+ _('There is no existing calibre library at %s')%loc,
+ show=True)
+ return False
+ if ac in ('new', 'move') and not empty:
+ error_dialog(self, _('Not empty'),
+ _('The folder %s is not empty. Please choose an empty'
+ ' folder')%loc,
+ show=True)
+ return False
+
+ return True
+
+ def perform_action(self, ac, loc):
+ if ac in ('new', 'existing'):
+ prefs['library_path'] = loc
+ self.callback(loc)
+ else:
+ move_library(self.db.library_path, loc, self.parent(),
+ self.callback)
+
+ def accept(self):
+ action = 'move'
+ if self.existing_library.isChecked():
+ action = 'existing'
+ elif self.empty_library.isChecked():
+ action = 'new'
+ loc = os.path.abspath(unicode(self.location.text()).strip())
+ if not loc or not os.path.exists(loc) or not self.check_action(action,
+ loc):
+ return
+ QDialog.accept(self)
+ self.perform_action(action, loc)
diff --git a/src/calibre/gui2/dialogs/choose_library.ui b/src/calibre/gui2/dialogs/choose_library.ui
new file mode 100644
index 0000000000..793c805eda
--- /dev/null
+++ b/src/calibre/gui2/dialogs/choose_library.ui
@@ -0,0 +1,171 @@
+
+
+ Dialog
+
+
+
+ 0
+ 0
+ 602
+ 245
+
+
+
+ Choose your calibre library
+
+
+
+ :/images/lt.png:/images/lt.png
+
+
+
-
+
+
+ Your calibre library is currently located at {0}
+
+
+ true
+
+
+
+ -
+
+
+ New &Location:
+
+
+ location
+
+
+
+ -
+
+
+ true
+
+
+
+ -
+
+
+ Use &existing library at the new location
+
+
+ true
+
+
+
+ -
+
+
+ &Create an empty library at the new location
+
+
+
+ -
+
+
+ &Move current library to new location
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/images/document_open.svg:/images/document_open.svg
+
+
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ Dialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ Dialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/src/calibre/gui2/dialogs/config/__init__.py b/src/calibre/gui2/dialogs/config/__init__.py
index b064dc53c2..84d55c8fb6 100644
--- a/src/calibre/gui2/dialogs/config/__init__.py
+++ b/src/calibre/gui2/dialogs/config/__init__.py
@@ -14,7 +14,7 @@ from PyQt4.Qt import QDialog, QListWidgetItem, QIcon, \
from calibre.constants import iswindows, isosx
from calibre.gui2.dialogs.config.config_ui import Ui_Dialog
from calibre.gui2.dialogs.config.create_custom_column import CreateCustomColumn
-from calibre.gui2 import choose_dir, error_dialog, config, gprefs, \
+from calibre.gui2 import error_dialog, config, gprefs, \
open_url, open_local_file, \
ALL_COLUMNS, NONE, info_dialog, choose_files, \
warning_dialog, ResizableDialog, question_dialog
@@ -343,9 +343,6 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
self.model = library_view.model()
self.db = self.model.db
self.server = server
- path = prefs['library_path']
- self.location.setText(path if path else '')
- self.connect(self.browse_button, SIGNAL('clicked(bool)'), self.browse)
self.connect(self.compact_button, SIGNAL('clicked(bool)'), self.compact)
input_map = prefs['input_format_order']
@@ -808,12 +805,6 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
d = CheckIntegrity(self.db, self)
d.exec_()
- def browse(self):
- dir = choose_dir(self, 'database location dialog',
- _('Select location for books'))
- if dir:
- self.location.setText(dir)
-
def accept(self):
mcs = unicode(self.max_cover_size.text()).strip()
if not re.match(r'\d+x\d+', mcs):
@@ -834,7 +825,6 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
config['use_roman_numerals_for_series_number'] = bool(self.roman_numerals.isChecked())
config['new_version_notification'] = bool(self.new_version_notification.isChecked())
prefs['network_timeout'] = int(self.timeout.value())
- path = unicode(self.location.text())
input_cols = [unicode(self.input_order.item(i).data(Qt.UserRole).toString()) for i in range(self.input_order.count())]
prefs['input_format_order'] = input_cols
@@ -875,24 +865,13 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
val = self.opt_gui_layout.itemData(self.opt_gui_layout.currentIndex()).toString()
config['gui_layout'] = unicode(val)
- if not path or not os.path.exists(path) or not os.path.isdir(path):
- d = error_dialog(self, _('Invalid database location'),
- _('Invalid database location ')+path+
- _('
Must be a directory.'))
- d.exec_()
- elif not os.access(path, os.W_OK):
- d = error_dialog(self, _('Invalid database location'),
- _('Invalid database location.
Cannot write to ')+path)
- d.exec_()
- else:
- self.database_location = os.path.abspath(path)
- if must_restart:
- warning_dialog(self, _('Must restart'),
- _('The changes you made require that Calibre be '
- 'restarted. Please restart as soon as practical.'),
- show=True, show_copy_button=False)
- self.parent.must_restart_before_config = True
- QDialog.accept(self)
+ if must_restart:
+ warning_dialog(self, _('Must restart'),
+ _('The changes you made require that Calibre be '
+ 'restarted. Please restart as soon as practical.'),
+ show=True, show_copy_button=False)
+ self.parent.must_restart_before_config = True
+ QDialog.accept(self)
class VacThread(QThread):
diff --git a/src/calibre/gui2/dialogs/config/config.ui b/src/calibre/gui2/dialogs/config/config.ui
index 5f890631b2..5d6bff2467 100644
--- a/src/calibre/gui2/dialogs/config/config.ui
+++ b/src/calibre/gui2/dialogs/config/config.ui
@@ -113,50 +113,6 @@
- -
-
-
-
-
-
-
- 16777215
- 70
-
-
-
- &Location of ebooks (The ebooks are stored in folders sorted by author and metadata is stored in the file metadata.db)
-
-
- true
-
-
- location
-
-
-
- -
-
-
-
-
-
- -
-
-
- Browse for the new database location
-
-
- ...
-
-
-
- :/images/mimetypes/dir.svg:/images/mimetypes/dir.svg
-
-
-
-
-
-
-
-
diff --git a/src/calibre/gui2/dialogs/metadata_single.ui b/src/calibre/gui2/dialogs/metadata_single.ui
index 4efb48d870..5da9d37d04 100644
--- a/src/calibre/gui2/dialogs/metadata_single.ui
+++ b/src/calibre/gui2/dialogs/metadata_single.ui
@@ -277,12 +277,6 @@
-
-
-
- 0
- 0
-
-
List of known series. You can add new series.
@@ -295,9 +289,6 @@
QComboBox::InsertAlphabetically
-
- QComboBox::AdjustToContents
-
-
diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py
index 2474685522..254d2c3d00 100644
--- a/src/calibre/gui2/init.py
+++ b/src/calibre/gui2/init.py
@@ -7,14 +7,13 @@ __docformat__ = 'restructuredtext en'
import functools, sys, os
-from PyQt4.Qt import QMenu, Qt, pyqtSignal, QIcon, QStackedWidget, \
- QSize, QSizePolicy, QStatusBar, QUrl, QLabel, QFont
+from PyQt4.Qt import QMenu, Qt, QStackedWidget, \
+ QSize, QSizePolicy, QStatusBar, QLabel, QFont
from calibre.utils.config import prefs
-from calibre.ebooks import BOOK_EXTENSIONS
from calibre.constants import isosx, __appname__, preferred_encoding, \
__version__
-from calibre.gui2 import config, is_widescreen, open_url
+from calibre.gui2 import config, is_widescreen
from calibre.gui2.library.views import BooksView, DeviceBooksView
from calibre.gui2.widgets import Splitter
from calibre.gui2.tag_view import TagBrowserWidget
@@ -28,157 +27,6 @@ def partial(*args, **kwargs):
_keep_refs.append(ans)
return ans
-class SaveMenu(QMenu): # {{{
-
- save_fmt = pyqtSignal(object)
-
- def __init__(self, parent):
- QMenu.__init__(self, _('Save single format to disk...'), parent)
- for ext in sorted(BOOK_EXTENSIONS):
- action = self.addAction(ext.upper())
- setattr(self, 'do_'+ext, partial(self.do, ext))
- action.triggered.connect(
- getattr(self, 'do_'+ext))
-
- def do(self, ext, *args):
- self.save_fmt.emit(ext)
-
-# }}}
-
-class ToolbarMixin(object): # {{{
-
- def __init__(self):
- self.action_help.triggered.connect(self.show_help)
- md = QMenu()
- md.addAction(_('Edit metadata individually'),
- partial(self.edit_metadata, False, bulk=False))
- md.addSeparator()
- md.addAction(_('Edit metadata in bulk'),
- partial(self.edit_metadata, False, bulk=True))
- md.addSeparator()
- md.addAction(_('Download metadata and covers'),
- partial(self.download_metadata, False, covers=True),
- Qt.ControlModifier+Qt.Key_D)
- md.addAction(_('Download only metadata'),
- partial(self.download_metadata, False, covers=False))
- md.addAction(_('Download only covers'),
- partial(self.download_metadata, False, covers=True,
- set_metadata=False, set_social_metadata=False))
- md.addAction(_('Download only social metadata'),
- partial(self.download_metadata, False, covers=False,
- set_metadata=False, set_social_metadata=True))
- self.metadata_menu = md
-
- mb = QMenu()
- mb.addAction(_('Merge into first selected book - delete others'),
- self.merge_books)
- mb.addSeparator()
- mb.addAction(_('Merge into first selected book - keep others'),
- partial(self.merge_books, safe_merge=True))
- self.merge_menu = mb
- self.action_merge.setMenu(mb)
- md.addSeparator()
- md.addAction(self.action_merge)
-
- self.add_menu = QMenu()
- self.add_menu.addAction(_('Add books from a single directory'),
- self.add_books)
- self.add_menu.addAction(_('Add books from directories, including '
- 'sub-directories (One book per directory, assumes every ebook '
- 'file is the same book in a different format)'),
- self.add_recursive_single)
- self.add_menu.addAction(_('Add books from directories, including '
- 'sub directories (Multiple books per directory, assumes every '
- 'ebook file is a different book)'), self.add_recursive_multiple)
- self.add_menu.addAction(_('Add Empty book. (Book entry with no '
- 'formats)'), self.add_empty)
- self.action_add.setMenu(self.add_menu)
- self.action_add.triggered.connect(self.add_books)
- self.action_del.triggered.connect(self.delete_books)
- self.action_edit.triggered.connect(self.edit_metadata)
- self.action_merge.triggered.connect(self.merge_books)
-
- self.action_save.triggered.connect(self.save_to_disk)
- self.save_menu = QMenu()
- self.save_menu.addAction(_('Save to disk'), partial(self.save_to_disk,
- False))
- self.save_menu.addAction(_('Save to disk in a single directory'),
- partial(self.save_to_single_dir, False))
- self.save_menu.addAction(_('Save only %s format to disk')%
- prefs['output_format'].upper(),
- partial(self.save_single_format_to_disk, False))
- self.save_menu.addAction(
- _('Save only %s format to disk in a single directory')%
- prefs['output_format'].upper(),
- partial(self.save_single_fmt_to_single_dir, False))
- self.save_sub_menu = SaveMenu(self)
- self.save_menu.addMenu(self.save_sub_menu)
- self.save_sub_menu.save_fmt.connect(self.save_specific_format_disk)
-
- self.action_view.triggered.connect(self.view_book)
- self.view_menu = QMenu()
- self.view_menu.addAction(_('View'), partial(self.view_book, False))
- ac = self.view_menu.addAction(_('View specific format'))
- ac.setShortcut((Qt.ControlModifier if isosx else Qt.AltModifier)+Qt.Key_V)
- self.action_view.setMenu(self.view_menu)
- ac.triggered.connect(self.view_specific_format, type=Qt.QueuedConnection)
-
- self.delete_menu = QMenu()
- self.delete_menu.addAction(_('Remove selected books'), self.delete_books)
- self.delete_menu.addAction(
- _('Remove files of a specific format from selected books..'),
- self.delete_selected_formats)
- self.delete_menu.addAction(
- _('Remove all formats from selected books, except...'),
- self.delete_all_but_selected_formats)
- self.delete_menu.addAction(
- _('Remove covers from selected books'), self.delete_covers)
- self.delete_menu.addSeparator()
- self.delete_menu.addAction(
- _('Remove matching books from device'),
- self.remove_matching_books_from_device)
- self.action_del.setMenu(self.delete_menu)
-
- self.action_open_containing_folder.setShortcut(Qt.Key_O)
- self.addAction(self.action_open_containing_folder)
- self.action_open_containing_folder.triggered.connect(self.view_folder)
- self.action_sync.setShortcut(Qt.Key_D)
- self.action_sync.setEnabled(True)
- self.create_device_menu()
- self.action_sync.triggered.connect(
- self._sync_action_triggered)
-
- self.action_edit.setMenu(md)
- self.action_save.setMenu(self.save_menu)
-
- cm = QMenu()
- cm.addAction(_('Convert individually'), partial(self.convert_ebook,
- False, bulk=False))
- cm.addAction(_('Bulk convert'),
- partial(self.convert_ebook, False, bulk=True))
- cm.addSeparator()
- ac = cm.addAction(
- _('Create catalog of books in your calibre library'))
- ac.triggered.connect(self.generate_catalog)
- self.action_convert.setMenu(cm)
- self.action_convert.triggered.connect(self.convert_ebook)
- self.convert_menu = cm
-
- pm = QMenu()
- pm.addAction(QIcon(I('config.svg')), _('Preferences'), self.do_config)
- pm.addAction(QIcon(I('wizard.svg')), _('Run welcome wizard'),
- self.run_wizard)
- self.action_preferences.setMenu(pm)
- self.preferences_menu = pm
- for x in (self.preferences_action, self.action_preferences):
- x.triggered.connect(self.do_config)
-
- def show_help(self, *args):
- open_url(QUrl('http://calibre-ebook.com/user_manual'))
-
-
-# }}}
-
class LibraryViewMixin(object): # {{{
def __init__(self, db):
diff --git a/src/calibre/gui2/layout.py b/src/calibre/gui2/layout.py
index c1ff3ab505..3116037685 100644
--- a/src/calibre/gui2/layout.py
+++ b/src/calibre/gui2/layout.py
@@ -6,108 +6,105 @@ __copyright__ = '2010, Kovid Goyal '
__docformat__ = 'restructuredtext en'
from operator import attrgetter
+from functools import partial
-from PyQt4.Qt import QIcon, Qt, QWidget, QAction, QToolBar, QSize, QVariant, \
- QAbstractListModel, QFont, QApplication, QPalette, pyqtSignal, QToolButton, \
- QModelIndex, QListView, QAbstractButton, QPainter, QPixmap, QColor, \
- QVBoxLayout, QSizePolicy, QLabel, QHBoxLayout
+from PyQt4.Qt import QIcon, Qt, QWidget, QAction, QToolBar, QSize, \
+ pyqtSignal, QToolButton, \
+ QObject, QVBoxLayout, QSizePolicy, QLabel, QHBoxLayout, QActionGroup, \
+ QMenu, QUrl
-from calibre.constants import __appname__, filesystem_encoding
+from calibre.constants import __appname__, isosx
from calibre.gui2.search_box import SearchBox2, SavedSearchBox
from calibre.gui2.throbber import ThrobbingButton
-from calibre.gui2 import NONE, config
+from calibre.gui2 import config, open_url
from calibre.gui2.widgets import ComboBoxWithHelp
from calibre import human_readable
+from calibre.utils.config import prefs
+from calibre.ebooks import BOOK_EXTENSIONS
ICON_SIZE = 48
-# Location View {{{
+class SaveMenu(QMenu): # {{{
-class LocationModel(QAbstractListModel): # {{{
-
- devicesChanged = pyqtSignal()
+ save_fmt = pyqtSignal(object)
def __init__(self, parent):
- QAbstractListModel.__init__(self, parent)
- self.icons = [QVariant(QIcon(I('library.png'))),
- QVariant(QIcon(I('reader.svg'))),
- QVariant(QIcon(I('sd.svg'))),
- QVariant(QIcon(I('sd.svg')))]
- self.text = [_('Library\n%d books'),
- _('Reader\n%s'),
- _('Card A\n%s'),
- _('Card B\n%s')]
+ QMenu.__init__(self, _('Save single format to disk...'), parent)
+ for ext in sorted(BOOK_EXTENSIONS):
+ action = self.addAction(ext.upper())
+ setattr(self, 'do_'+ext, partial(self.do, ext))
+ action.triggered.connect(
+ getattr(self, 'do_'+ext))
+
+ def do(self, ext, *args):
+ self.save_fmt.emit(ext)
+
+# }}}
+
+class LocationManager(QObject): # {{{
+
+ locations_changed = pyqtSignal()
+ unmount_device = pyqtSignal()
+ location_selected = pyqtSignal(object)
+
+ def __init__(self, parent=None):
+ QObject.__init__(self, parent)
self.free = [-1, -1, -1]
self.count = 0
- self.highlight_row = 0
- self.library_tooltip = _('Click to see the books available on your computer')
- self.tooltips = [
- self.library_tooltip,
- _('Click to see the books in the main memory of your reader'),
- _('Click to see the books on storage card A in your reader'),
- _('Click to see the books on storage card B in your reader')
- ]
+ self.location_actions = QActionGroup(self)
+ self.location_actions.setExclusive(True)
+ self.current_location = 'library'
+ self._mem = []
+ self.tooltips = {}
- def database_changed(self, db):
- lp = db.library_path
- if not isinstance(lp, unicode):
- lp = lp.decode(filesystem_encoding, 'replace')
- self.tooltips[0] = self.library_tooltip + '\n\n' + \
- _('Books located at') + ' ' + lp
- self.dataChanged.emit(self.index(0), self.index(0))
+ def ac(name, text, icon, tooltip):
+ icon = QIcon(I(icon))
+ ac = self.location_actions.addAction(icon, text)
+ setattr(self, 'location_'+name, ac)
+ ac.setAutoRepeat(False)
+ ac.setCheckable(True)
+ receiver = partial(self._location_selected, name)
+ ac.triggered.connect(receiver)
+ self.tooltips[name] = tooltip
+ if name != 'library':
+ m = QMenu(parent)
+ self._mem.append(m)
+ a = m.addAction(icon, tooltip)
+ a.triggered.connect(receiver)
+ self._mem.append(a)
+ a = m.addAction(QIcon(I('eject.svg')), _('Eject this device'))
+ a.triggered.connect(self._eject_requested)
+ ac.setMenu(m)
+ self._mem.append(a)
+ else:
+ ac.setToolTip(tooltip)
- def rowCount(self, *args):
- return 1 + len([i for i in self.free if i >= 0])
+ return ac
- def get_device_row(self, row):
- if row == 2 and self.free[1] == -1 and self.free[2] > -1:
- row = 3
- return row
+ ac('library', _('Library'), 'lt.png',
+ _('Show books in calibre library'))
+ ac('main', _('Main'), 'reader.svg',
+ _('Show books in the main memory of the device'))
+ ac('carda', _('Card A'), 'sd.svg',
+ _('Show books in storage card A'))
+ ac('cardb', _('Card B'), 'sd.svg',
+ _('Show books in storage card B'))
- def get_tooltip(self, row, drow):
- ans = self.tooltips[row]
- if row > 0:
- fs = self.free[drow-1]
- if fs > -1:
- ans += '\n\n%s '%(human_readable(fs)) + _('free')
- return ans
+ def _location_selected(self, location, *args):
+ if location != self.current_location and hasattr(self,
+ 'location_'+location):
+ self.current_location = location
+ self.location_selected.emit(location)
+ getattr(self, 'location_'+location).setChecked(True)
- def data(self, index, role):
- row = index.row()
- drow = self.get_device_row(row)
- data = NONE
- if role == Qt.DisplayRole:
- text = self.text[drow]%(human_readable(self.free[drow-1])) if row > 0 \
- else self.text[drow]%self.count
- data = QVariant(text)
- elif role == Qt.DecorationRole:
- data = self.icons[drow]
- elif role in (Qt.ToolTipRole, Qt.StatusTipRole):
- ans = self.get_tooltip(row, drow)
- data = QVariant(ans)
- elif role == Qt.SizeHintRole:
- data = QVariant(QSize(155, 90))
- elif role == Qt.FontRole:
- font = QFont('monospace')
- font.setBold(row == self.highlight_row)
- data = QVariant(font)
- elif role == Qt.ForegroundRole and row == self.highlight_row:
- return QVariant(QApplication.palette().brush(
- QPalette.HighlightedText))
- elif role == Qt.BackgroundRole and row == self.highlight_row:
- return QVariant(QApplication.palette().brush(
- QPalette.Highlight))
+ def _eject_requested(self, *args):
+ self.unmount_device.emit()
- return data
-
- def device_connected(self, dev):
- self.icons[1] = QIcon(dev.icon)
- self.dataChanged.emit(self.index(1), self.index(1))
-
- def headerData(self, section, orientation, role):
- return NONE
-
- def update_devices(self, cp=(None, None), fs=[-1, -1, -1]):
+ def update_devices(self, cp=(None, None), fs=[-1, -1, -1], icon=None):
+ if icon is None:
+ icon = I('reader.svg')
+ self.location_main.setIcon(QIcon(icon))
+ had_device = self.has_device
if cp is None:
cp = (None, None)
if isinstance(cp, (str, unicode)):
@@ -120,137 +117,34 @@ class LocationModel(QAbstractListModel): # {{{
cpa, cpb = cp
self.free[1] = fs[1] if fs[1] is not None and cpa is not None else -1
self.free[2] = fs[2] if fs[2] is not None and cpb is not None else -1
- self.reset()
- self.devicesChanged.emit()
+ self.update_tooltips()
+ if self.has_device != had_device:
+ self.locations_changed.emit()
+ if not self.has_device:
+ self.location_library.trigger()
- def location_changed(self, row):
- self.highlight_row = row
- self.dataChanged.emit(
- self.index(0), self.index(self.rowCount(QModelIndex())-1))
+ def update_tooltips(self):
+ for i, loc in enumerate(('main', 'carda', 'cardb')):
+ t = self.tooltips[loc]
+ if self.free[i] > -1:
+ t += u'\n\n%s '%human_readable(self.free[i]) + _('available')
+ ac = getattr(self, 'location_'+loc)
+ ac.setToolTip(t)
+ ac.setWhatsThis(t)
+ ac.setStatusTip(t)
- def location_for_row(self, row):
- if row == 0: return 'library'
- if row == 1: return 'main'
- if row == 3: return 'cardb'
- return 'carda' if self.free[1] > -1 else 'cardb'
-
-# }}}
-
-class LocationView(QListView):
-
- umount_device = pyqtSignal()
- location_selected = pyqtSignal(object)
-
- def __init__(self, parent):
- QListView.__init__(self, parent)
- self.setModel(LocationModel(self))
- self.reset()
- self.currentChanged = self.current_changed
-
- self.eject_button = EjectButton(self)
- self.eject_button.hide()
-
- self.entered.connect(self.item_entered)
- self.viewportEntered.connect(self.viewport_entered)
- self.eject_button.clicked.connect(self.eject_clicked)
- self.model().devicesChanged.connect(self.eject_button.hide)
- self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,
- QSizePolicy.Expanding))
- self.setMouseTracking(True)
- self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
- self.setEditTriggers(self.NoEditTriggers)
- self.setTabKeyNavigation(True)
- self.setProperty("showDropIndicator", True)
- self.setSelectionMode(self.SingleSelection)
- self.setIconSize(QSize(ICON_SIZE, ICON_SIZE))
- self.setMovement(self.Static)
- self.setFlow(self.LeftToRight)
- self.setGridSize(QSize(175, ICON_SIZE))
- self.setViewMode(self.ListMode)
- self.setWordWrap(True)
- self.setObjectName("location_view")
- self.setMaximumSize(QSize(600, ICON_SIZE+16))
- self.setMinimumWidth(400)
-
- def eject_clicked(self, *args):
- self.umount_device.emit()
-
- def count_changed(self, new_count):
- self.model().count = new_count
- self.model().reset()
@property
- def book_count(self):
- return self.model().count
-
- def current_changed(self, current, previous):
- if current.isValid():
- i = current.row()
- location = self.model().location_for_row(i)
- self.location_selected.emit(location)
- self.model().location_changed(i)
-
- def location_changed(self, row):
- if 0 <= row and row <= 3:
- self.model().location_changed(row)
-
- def leaveEvent(self, event):
- self.unsetCursor()
- self.eject_button.hide()
-
- def item_entered(self, location):
- self.setCursor(Qt.PointingHandCursor)
- self.eject_button.hide()
-
- if location.row() == 1:
- rect = self.visualRect(location)
-
- self.eject_button.resize(rect.height()/2, rect.height()/2)
-
- x, y = rect.left(), rect.top()
- x = x + (rect.width() - self.eject_button.width() - 2)
- y += 6
-
- self.eject_button.move(x, y)
- self.eject_button.show()
-
- def viewport_entered(self):
- self.unsetCursor()
- self.eject_button.hide()
-
-
-class EjectButton(QAbstractButton):
-
- def __init__(self, parent):
- QAbstractButton.__init__(self, parent)
- self.mouse_over = False
- self.setMouseTracking(True)
-
- def enterEvent(self, event):
- self.mouse_over = True
- QAbstractButton.enterEvent(self, event)
-
- def leaveEvent(self, event):
- self.mouse_over = False
- QAbstractButton.leaveEvent(self, event)
-
- def paintEvent(self, event):
- painter = QPainter(self)
- painter.setClipRect(event.rect())
- image = QPixmap(I('eject')).scaledToHeight(event.rect().height(),
- Qt.SmoothTransformation)
-
- if not self.mouse_over:
- alpha_mask = QPixmap(image.width(), image.height())
- color = QColor(128, 128, 128)
- alpha_mask.fill(color)
- image.setAlphaChannel(alpha_mask)
-
- painter.drawPixmap(0, 0, image)
-
-
+ def has_device(self):
+ return max(self.free) > -1
+ @property
+ def available_actions(self):
+ ans = [self.location_library]
+ for i, loc in enumerate(('main', 'carda', 'cardb')):
+ if self.free[i] > -1:
+ ans.append(getattr(self, 'location_'+loc))
+ return ans
# }}}
@@ -326,7 +220,7 @@ class SearchBar(QWidget): # {{{
class ToolBar(QToolBar): # {{{
- def __init__(self, actions, donate, location_view, parent=None):
+ def __init__(self, actions, donate, location_manager, parent=None):
QToolBar.__init__(self, parent)
self.setContextMenuPolicy(Qt.PreventContextMenu)
self.setMovable(False)
@@ -335,11 +229,12 @@ class ToolBar(QToolBar): # {{{
self.setAllowedAreas(Qt.TopToolBarArea|Qt.BottomToolBarArea)
self.setIconSize(QSize(ICON_SIZE, ICON_SIZE))
self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
+ self.setStyleSheet('QToolButton:checked { font-weight: bold }')
- self.showing_device = False
self.all_actions = actions
self.donate = donate
- self.location_view = location_view
+ self.location_manager = location_manager
+ self.location_manager.locations_changed.connect(self.build_bar)
self.d_widget = QWidget()
self.d_widget.setLayout(QVBoxLayout())
self.d_widget.layout().addWidget(donate)
@@ -350,40 +245,45 @@ class ToolBar(QToolBar): # {{{
def contextMenuEvent(self, *args):
pass
- def device_status_changed(self, connected):
- self.showing_device = connected
- self.build_bar()
-
def build_bar(self):
- order_field = 'device' if self.showing_device else 'normal'
+ showing_device = self.location_manager.has_device
+ order_field = 'device' if showing_device else 'normal'
o = attrgetter(order_field+'_order')
- sepvals = [2] if self.showing_device else [1]
+ sepvals = [2] if showing_device else [1]
sepvals += [3]
actions = [x for x in self.all_actions if o(x) > -1]
actions.sort(cmp=lambda x,y : cmp(o(x), o(y)))
self.clear()
- for x in actions:
- self.addAction(x)
- ch = self.widgetForAction(x)
+
+
+ def setup_tool_button(ac):
+ ch = self.widgetForAction(ac)
ch.setCursor(Qt.PointingHandCursor)
ch.setAutoRaise(True)
-
- if x.action_name == 'choose_library':
- self.location_action = self.addWidget(self.location_view)
- self.choose_action = x
- if config['show_donate_button']:
- self.addWidget(self.d_widget)
- if x.action_name not in ('choose_library', 'help'):
+ if ac.menu() is not None:
ch.setPopupMode(ch.MenuButtonPopup)
+ for x in actions:
+ self.addAction(x)
+ setup_tool_button(x)
+
+ if x.action_name == 'choose_library':
+ self.choose_action = x
+ if showing_device:
+ self.addSeparator()
+ for ac in self.location_manager.available_actions:
+ self.addAction(ac)
+ setup_tool_button(ac)
+ self.addSeparator()
+ self.location_manager.location_library.trigger()
+ elif config['show_donate_button']:
+ self.addWidget(self.d_widget)
for x in actions:
if x.separator_before in sepvals:
self.insertSeparator(x)
-
- self.location_action.setVisible(self.showing_device)
- self.choose_action.setVisible(not self.showing_device)
+ self.choose_action.setVisible(not showing_device)
def count_changed(self, new_count):
text = _('%d books')%new_count
@@ -397,6 +297,9 @@ class ToolBar(QToolBar): # {{{
self.setToolButtonStyle(style)
QToolBar.resizeEvent(self, ev)
+ def database_changed(self, db):
+ pass
+
# }}}
class Action(QAction):
@@ -405,6 +308,7 @@ class Action(QAction):
class MainWindowMixin(object):
def __init__(self):
+ self.device_connected = None
self.setObjectName('MainWindow')
self.setWindowIcon(QIcon(I('library.png')))
self.setWindowTitle(__appname__)
@@ -417,9 +321,30 @@ class MainWindowMixin(object):
self.resize(1012, 740)
self.donate_button = ThrobbingButton(self.centralwidget)
self.donate_button.set_normal_icon_size(ICON_SIZE, ICON_SIZE)
+ self.location_manager = LocationManager(self)
- # Actions {{{
+ all_actions = self.setup_actions()
+ self.search_bar = SearchBar(self)
+ self.tool_bar = ToolBar(all_actions, self.donate_button,
+ self.location_manager, self)
+ self.addToolBar(Qt.TopToolBarArea, self.tool_bar)
+ self.tool_bar.choose_action.triggered.connect(self.choose_library)
+
+ l = self.centralwidget.layout()
+ l.addWidget(self.search_bar)
+
+
+ def read_toolbar_settings(self):
+ pass
+
+ def choose_library(self, *args):
+ from calibre.gui2.dialogs.choose_library import ChooseLibrary
+ db = self.library_view.model().db
+ c = ChooseLibrary(db, self.library_moved, self)
+ c.exec_()
+
+ def setup_actions(self): # {{{
all_actions = []
def ac(normal_order, device_order, separator_before,
@@ -467,17 +392,135 @@ class MainWindowMixin(object):
ac(-1, -1, 0, 'books_with_the_same_tags', _('Books with the same tags'),
'tags.svg')
- # }}}
+ self.action_help.triggered.connect(self.show_help)
+ md = QMenu()
+ md.addAction(_('Edit metadata individually'),
+ partial(self.edit_metadata, False, bulk=False))
+ md.addSeparator()
+ md.addAction(_('Edit metadata in bulk'),
+ partial(self.edit_metadata, False, bulk=True))
+ md.addSeparator()
+ md.addAction(_('Download metadata and covers'),
+ partial(self.download_metadata, False, covers=True),
+ Qt.ControlModifier+Qt.Key_D)
+ md.addAction(_('Download only metadata'),
+ partial(self.download_metadata, False, covers=False))
+ md.addAction(_('Download only covers'),
+ partial(self.download_metadata, False, covers=True,
+ set_metadata=False, set_social_metadata=False))
+ md.addAction(_('Download only social metadata'),
+ partial(self.download_metadata, False, covers=False,
+ set_metadata=False, set_social_metadata=True))
+ self.metadata_menu = md
- self.location_view = LocationView(self.centralwidget)
- self.search_bar = SearchBar(self)
- self.tool_bar = ToolBar(all_actions, self.donate_button, self.location_view, self)
- self.addToolBar(Qt.TopToolBarArea, self.tool_bar)
+ mb = QMenu()
+ mb.addAction(_('Merge into first selected book - delete others'),
+ self.merge_books)
+ mb.addSeparator()
+ mb.addAction(_('Merge into first selected book - keep others'),
+ partial(self.merge_books, safe_merge=True))
+ self.merge_menu = mb
+ self.action_merge.setMenu(mb)
+ md.addSeparator()
+ md.addAction(self.action_merge)
- l = self.centralwidget.layout()
- l.addWidget(self.search_bar)
+ self.add_menu = QMenu()
+ self.add_menu.addAction(_('Add books from a single directory'),
+ self.add_books)
+ self.add_menu.addAction(_('Add books from directories, including '
+ 'sub-directories (One book per directory, assumes every ebook '
+ 'file is the same book in a different format)'),
+ self.add_recursive_single)
+ self.add_menu.addAction(_('Add books from directories, including '
+ 'sub directories (Multiple books per directory, assumes every '
+ 'ebook file is a different book)'), self.add_recursive_multiple)
+ self.add_menu.addAction(_('Add Empty book. (Book entry with no '
+ 'formats)'), self.add_empty)
+ self.action_add.setMenu(self.add_menu)
+ self.action_add.triggered.connect(self.add_books)
+ self.action_del.triggered.connect(self.delete_books)
+ self.action_edit.triggered.connect(self.edit_metadata)
+ self.action_merge.triggered.connect(self.merge_books)
+
+ self.action_save.triggered.connect(self.save_to_disk)
+ self.save_menu = QMenu()
+ self.save_menu.addAction(_('Save to disk'), partial(self.save_to_disk,
+ False))
+ self.save_menu.addAction(_('Save to disk in a single directory'),
+ partial(self.save_to_single_dir, False))
+ self.save_menu.addAction(_('Save only %s format to disk')%
+ prefs['output_format'].upper(),
+ partial(self.save_single_format_to_disk, False))
+ self.save_menu.addAction(
+ _('Save only %s format to disk in a single directory')%
+ prefs['output_format'].upper(),
+ partial(self.save_single_fmt_to_single_dir, False))
+ self.save_sub_menu = SaveMenu(self)
+ self.save_menu.addMenu(self.save_sub_menu)
+ self.save_sub_menu.save_fmt.connect(self.save_specific_format_disk)
+
+ self.action_view.triggered.connect(self.view_book)
+ self.view_menu = QMenu()
+ self.view_menu.addAction(_('View'), partial(self.view_book, False))
+ ac = self.view_menu.addAction(_('View specific format'))
+ ac.setShortcut((Qt.ControlModifier if isosx else Qt.AltModifier)+Qt.Key_V)
+ self.action_view.setMenu(self.view_menu)
+ ac.triggered.connect(self.view_specific_format, type=Qt.QueuedConnection)
+
+ self.delete_menu = QMenu()
+ self.delete_menu.addAction(_('Remove selected books'), self.delete_books)
+ self.delete_menu.addAction(
+ _('Remove files of a specific format from selected books..'),
+ self.delete_selected_formats)
+ self.delete_menu.addAction(
+ _('Remove all formats from selected books, except...'),
+ self.delete_all_but_selected_formats)
+ self.delete_menu.addAction(
+ _('Remove covers from selected books'), self.delete_covers)
+ self.delete_menu.addSeparator()
+ self.delete_menu.addAction(
+ _('Remove matching books from device'),
+ self.remove_matching_books_from_device)
+ self.action_del.setMenu(self.delete_menu)
+
+ self.action_open_containing_folder.setShortcut(Qt.Key_O)
+ self.addAction(self.action_open_containing_folder)
+ self.action_open_containing_folder.triggered.connect(self.view_folder)
+ self.action_sync.setShortcut(Qt.Key_D)
+ self.action_sync.setEnabled(True)
+ self.create_device_menu()
+ self.action_sync.triggered.connect(
+ self._sync_action_triggered)
+
+ self.action_edit.setMenu(md)
+ self.action_save.setMenu(self.save_menu)
+
+ cm = QMenu()
+ cm.addAction(_('Convert individually'), partial(self.convert_ebook,
+ False, bulk=False))
+ cm.addAction(_('Bulk convert'),
+ partial(self.convert_ebook, False, bulk=True))
+ cm.addSeparator()
+ ac = cm.addAction(
+ _('Create catalog of books in your calibre library'))
+ ac.triggered.connect(self.generate_catalog)
+ self.action_convert.setMenu(cm)
+ self.action_convert.triggered.connect(self.convert_ebook)
+ self.convert_menu = cm
+
+ pm = QMenu()
+ pm.addAction(QIcon(I('config.svg')), _('Preferences'), self.do_config)
+ pm.addAction(QIcon(I('wizard.svg')), _('Run welcome wizard'),
+ self.run_wizard)
+ self.action_preferences.setMenu(pm)
+ self.preferences_menu = pm
+ for x in (self.preferences_action, self.action_preferences):
+ x.triggered.connect(self.do_config)
+
+ return all_actions
+ # }}}
+
+ def show_help(self, *args):
+ open_url(QUrl('http://calibre-ebook.com/user_manual'))
- def read_toolbar_settings(self):
- pass
-
diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py
index ba4c637932..eec03876e9 100644
--- a/src/calibre/gui2/ui.py
+++ b/src/calibre/gui2/ui.py
@@ -12,13 +12,13 @@ __docformat__ = 'restructuredtext en'
import collections, os, sys, textwrap, time
from Queue import Queue, Empty
from threading import Thread
-from PyQt4.Qt import Qt, SIGNAL, QObject, QTimer, \
+from PyQt4.Qt import Qt, SIGNAL, QTimer, \
QPixmap, QMenu, QIcon, pyqtSignal, \
QDialog, \
QSystemTrayIcon, QApplication, QKeySequence, QAction, \
QMessageBox, QHelpEvent
-from calibre import prints, patheq
+from calibre import prints
from calibre.constants import __appname__, isosx
from calibre.ptempfile import PersistentTemporaryFile
from calibre.utils.config import prefs, dynamic
@@ -27,7 +27,6 @@ from calibre.gui2 import error_dialog, GetMetadata, open_local_file, \
gprefs, max_available_height, config, info_dialog
from calibre.gui2.cover_flow import CoverFlowMixin
from calibre.gui2.widgets import ProgressIndicator
-from calibre.gui2.wizard import move_library
from calibre.gui2.dialogs.scheduler import Scheduler
from calibre.gui2.update import UpdateMixin
from calibre.gui2.main_window import MainWindow
@@ -38,7 +37,7 @@ from calibre.gui2.dialogs.config import ConfigDialog
from calibre.gui2.dialogs.book_info import BookInfo
from calibre.library.database2 import LibraryDatabase2
-from calibre.gui2.init import ToolbarMixin, LibraryViewMixin, LayoutMixin
+from calibre.gui2.init import LibraryViewMixin, LayoutMixin
from calibre.gui2.search_box import SearchBoxMixin, SavedSearchBoxMixin
from calibre.gui2.search_restriction_mixin import SearchRestrictionMixin
from calibre.gui2.tag_view import TagBrowserMixin
@@ -91,7 +90,7 @@ class SystemTrayIcon(QSystemTrayIcon): # {{{
# }}}
-class Main(MainWindow, MainWindowMixin, DeviceMixin, ToolbarMixin, # {{{
+class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
TagBrowserMixin, CoverFlowMixin, LibraryViewMixin, SearchBoxMixin,
SavedSearchBoxMixin, SearchRestrictionMixin, LayoutMixin, UpdateMixin,
AnnotationsAction, AddAction, DeleteAction,
@@ -192,21 +191,14 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, ToolbarMixin, # {{{
####################### Start spare job server ########################
QTimer.singleShot(1000, self.add_spare_server)
- ####################### Location View ########################
- QObject.connect(self.location_view,
- SIGNAL('location_selected(PyQt_PyObject)'),
- self.location_selected)
- QObject.connect(self.location_view,
- SIGNAL('umount_device()'),
- self.device_manager.umount_device)
+ ####################### Location Manager ########################
+ self.location_manager.location_selected.connect(self.location_selected)
+ self.location_manager.unmount_device.connect(self.device_manager.umount_device)
self.eject_action.triggered.connect(self.device_manager.umount_device)
#################### Update notification ###################
UpdateMixin.__init__(self, opts)
- ####################### Setup Toolbar #####################
- ToolbarMixin.__init__(self)
-
####################### Search boxes ########################
SavedSearchBoxMixin.__init__(self)
SearchBoxMixin.__init__(self)
@@ -218,7 +210,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, ToolbarMixin, # {{{
if self.system_tray_icon.isVisible() and opts.start_in_tray:
self.hide_windows()
- for t in (self.location_view, self.tool_bar):
+ for t in (self.tool_bar, ):
self.library_view.model().count_changed_signal.connect \
(t.count_changed)
if not gprefs.get('quick_start_guide_added', False):
@@ -235,8 +227,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, ToolbarMixin, # {{{
self.db_images.reset()
self.library_view.model().count_changed()
- self.location_view.model().database_changed(self.library_view.model().db)
- self.library_view.model().database_changed.connect(self.location_view.model().database_changed,
+ self.tool_bar.database_changed(self.library_view.model().db)
+ self.library_view.model().database_changed.connect(self.tool_bar.database_changed,
type=Qt.QueuedConnection)
########################### Tags Browser ##############################
@@ -396,10 +388,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, ToolbarMixin, # {{{
self.tags_view.recount()
self.create_device_menu()
self.set_device_menu_items_state(bool(self.device_connected))
- if not patheq(self.library_path, d.database_location):
- newloc = d.database_location
- move_library(self.library_path, newloc, self,
- self.library_moved)
def library_moved(self, newloc):
if newloc is None: return
diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py
index 97758482fc..994fa4575f 100644
--- a/src/calibre/gui2/widgets.py
+++ b/src/calibre/gui2/widgets.py
@@ -490,6 +490,7 @@ class EnComboBox(QComboBox):
QComboBox.__init__(self, *args)
self.setLineEdit(EnLineEdit(self))
self.setAutoCompletionCaseSensitivity(Qt.CaseSensitive)
+ self.setMinimumContentsLength(20)
def text(self):
return unicode(self.currentText())
diff --git a/src/calibre/library/catalog.py b/src/calibre/library/catalog.py
index 21aa863031..a540a8a660 100644
--- a/src/calibre/library/catalog.py
+++ b/src/calibre/library/catalog.py
@@ -1,7 +1,9 @@
+# -*- coding: utf-8 -*-
+
__license__ = 'GPL v3'
__copyright__ = '2010, Greg Riker '
-import datetime, htmlentitydefs, os, re, shutil
+import datetime, htmlentitydefs, os, re, shutil, codecs
from collections import namedtuple
from copy import deepcopy
@@ -9,6 +11,7 @@ from copy import deepcopy
from xml.sax.saxutils import escape
from calibre import filesystem_encoding, prints, prepare_string_for_xml, strftime
+from calibre.constants import preferred_encoding
from calibre.customize import CatalogPlugin
from calibre.customize.conversion import OptionRecommendation, DummyReporter
from calibre.ebooks.BeautifulSoup import BeautifulSoup, BeautifulStoneSoup, Tag, NavigableString
@@ -21,6 +24,10 @@ FIELDS = ['all', 'author_sort', 'authors', 'comments',
'series_index', 'series', 'size', 'tags', 'timestamp', 'title',
'uuid']
+#Allowed fields for template
+TEMPLATE_ALLOWED_FIELDS = [ 'author_sort', 'authors', 'id', 'isbn', 'pubdate',
+ 'publisher', 'series_index', 'series', 'tags', 'timestamp', 'title', 'uuid' ]
+
class CSV_XML(CatalogPlugin):
'CSV/XML catalog generator'
@@ -89,17 +96,20 @@ class CSV_XML(CatalogPlugin):
fields = self.get_output_fields(opts)
if self.fmt == 'csv':
- outfile = open(path_to_output, 'w')
+ outfile = codecs.open(path_to_output, 'w', 'utf8')
# Output the field headers
outfile.write(u'%s\n' % u','.join(fields))
# Output the entry fields
for entry in data:
- outstr = ''
- for (x, field) in enumerate(fields):
+ outstr = []
+ for field in fields:
item = entry[field]
- if field == 'formats':
+ if item is None:
+ outstr.append('""')
+ continue
+ elif field == 'formats':
fmt_list = []
for format in item:
fmt_list.append(format.rpartition('.')[2].lower())
@@ -111,18 +121,13 @@ class CSV_XML(CatalogPlugin):
item = u'%s' % re.sub(r'[\D]', '', item)
elif field in ['pubdate', 'timestamp']:
item = isoformat(item)
+ elif field == 'comments':
+ item = item.replace(u'\r\n',u' ')
+ item = item.replace(u'\n',u' ')
- if x < len(fields) - 1:
- if item is not None:
- outstr += u'"%s",' % unicode(item).replace('"','""')
- else:
- outstr += '"",'
- else:
- if item is not None:
- outstr += u'"%s"\n' % unicode(item).replace('"','""')
- else:
- outstr += '""\n'
- outfile.write(outstr.encode('utf-8'))
+ outstr.append(u'"%s"' % unicode(item).replace('"','""'))
+
+ outfile.write(u','.join(outstr) + u'\n')
outfile.close()
elif self.fmt == 'xml':
@@ -181,6 +186,329 @@ class CSV_XML(CatalogPlugin):
f.write(etree.tostring(root, encoding='utf-8',
xml_declaration=True, pretty_print=True))
+class BIBTEX(CatalogPlugin):
+ 'BIBTEX catalog generator'
+
+ Option = namedtuple('Option', 'option, default, dest, action, help')
+
+ name = 'Catalog_BIBTEX'
+ description = 'BIBTEX catalog generator'
+ supported_platforms = ['windows', 'osx', 'linux']
+ author = 'Sengian'
+ version = (1, 0, 0)
+ file_types = set(['bib'])
+
+ cli_options = [
+ Option('--fields',
+ default = 'all',
+ dest = 'fields',
+ action = None,
+ help = _('The fields to output when cataloging books in the '
+ 'database. Should be a comma-separated list of fields.\n'
+ 'Available fields: %s.\n'
+ "Default: '%%default'\n"
+ "Applies to: BIBTEX output format")%', '.join(FIELDS)),
+
+ Option('--sort-by',
+ default = 'id',
+ dest = 'sort_by',
+ action = None,
+ help = _('Output field to sort on.\n'
+ 'Available fields: author_sort, id, rating, size, timestamp, title.\n'
+ "Default: '%default'\n"
+ "Applies to: BIBTEX output format")),
+
+ Option('--create-citation',
+ default = 'True',
+ dest = 'impcit',
+ action = None,
+ help = _('Create a citation for BibTeX entries.\n'
+ 'Boolean value: True, False\n'
+ "Default: '%default'\n"
+ "Applies to: BIBTEX output format")),
+
+ Option('--citation-template',
+ default = '{authors}{id}',
+ dest = 'bib_cit',
+ action = None,
+ help = _('The template for citation creation from database fields.\n'
+ ' Should be a template with {} enclosed fields.\n'
+ 'Available fields: %s.\n'
+ "Default: '%%default'\n"
+ "Applies to: BIBTEX output format")%', '.join(TEMPLATE_ALLOWED_FIELDS)),
+
+ Option('--choose-encoding',
+ default = 'utf8',
+ dest = 'bibfile_enc',
+ action = None,
+ help = _('BibTeX file encoding output.\n'
+ 'Available types: utf8, cp1252, ascii.\n'
+ "Default: '%default'\n"
+ "Applies to: BIBTEX output format")),
+
+ Option('--choose-encoding-configuration',
+ default = 'strict',
+ dest = 'bibfile_enctag',
+ action = None,
+ help = _('BibTeX file encoding flag.\n'
+ 'Available types: strict, replace, ignore, backslashreplace.\n'
+ "Default: '%default'\n"
+ "Applies to: BIBTEX output format")),
+
+ Option('--entry-type',
+ default = 'book',
+ dest = 'bib_entry',
+ action = None,
+ help = _('Entry type for BibTeX catalog.\n'
+ 'Available types: book, misc, mixed.\n'
+ "Default: '%default'\n"
+ "Applies to: BIBTEX output format"))]
+
+ def run(self, path_to_output, opts, db, notification=DummyReporter()):
+
+ from types import StringType, UnicodeType
+
+ from calibre.library.save_to_disk import preprocess_template
+ #Bibtex functions
+ from calibre.utils.bibtex import bibtex_author_format, utf8ToBibtex, ValidateCitationKey
+
+ def create_bibtex_entry(entry, fields, mode, template_citation,
+ asccii_bibtex = True, citation_bibtex = True):
+
+ #Bibtex doesn't like UTF-8 but keep unicode until writing
+ #Define starting chain or if book valid strict and not book return a Fail string
+
+ bibtex_entry = []
+ if mode != "misc" and check_entry_book_valid(entry) :
+ bibtex_entry.append(u'@book{')
+ elif mode != "book" :
+ bibtex_entry.append(u'@misc{')
+ else :
+ #case strict book
+ return ''
+
+ if citation_bibtex :
+ # Citation tag
+ bibtex_entry.append(make_bibtex_citation(entry, template_citation, asccii_bibtex))
+ bibtex_entry = [u' '.join(bibtex_entry)]
+
+ for field in fields:
+ item = entry[field]
+ #check if the field should be included (none or empty)
+ if item is None:
+ continue
+ try:
+ if len(item) == 0 :
+ continue
+ except TypeError:
+ pass
+
+ if field == 'authors' :
+ bibtex_entry.append(u'author = "%s"' % bibtex_author_format(item))
+
+ elif field in ['title', 'publisher', 'cover', 'uuid',
+ 'author_sort', 'series'] :
+ bibtex_entry.append(u'%s = "%s"' % (field, utf8ToBibtex(item, asccii_bibtex)))
+
+ elif field == 'id' :
+ bibtex_entry.append(u'calibreid = "%s"' % int(item))
+
+ elif field == 'rating' :
+ bibtex_entry.append(u'rating = "%s"' % int(item))
+
+ elif field == 'size' :
+ bibtex_entry.append(u'%s = "%s octets"' % (field, int(item)))
+
+ elif field == 'tags' :
+ #A list to flatten
+ bibtex_entry.append(u'tags = "%s"' % utf8ToBibtex(u', '.join(item), asccii_bibtex))
+
+ elif field == 'comments' :
+ #\n removal
+ item = item.replace(u'\r\n',u' ')
+ item = item.replace(u'\n',u' ')
+ bibtex_entry.append(u'note = "%s"' % utf8ToBibtex(item, asccii_bibtex))
+
+ elif field == 'isbn' :
+ # Could be 9, 10 or 13 digits
+ bibtex_entry.append(u'isbn = "%s"' % re.sub(u'[\D]', u'', item))
+
+ elif field == 'formats' :
+ item = u', '.join([format.rpartition('.')[2].lower() for format in item])
+ bibtex_entry.append(u'formats = "%s"' % item)
+
+ elif field == 'series_index' :
+ bibtex_entry.append(u'volume = "%s"' % int(item))
+
+ elif field == 'timestamp' :
+ bibtex_entry.append(u'timestamp = "%s"' % isoformat(item).partition('T')[0])
+
+ elif field == 'pubdate' :
+ bibtex_entry.append(u'year = "%s"' % item.year)
+ bibtex_entry.append(u'month = "%s"' % utf8ToBibtex(strftime("%b", item),
+ asccii_bibtex))
+
+ bibtex_entry = u',\n '.join(bibtex_entry)
+ bibtex_entry += u' }\n\n'
+
+ return bibtex_entry
+
+ def check_entry_book_valid(entry):
+ #Check that the required fields are ok for a book entry
+ for field in ['title', 'authors', 'publisher'] :
+ if entry[field] is None or len(entry[field]) == 0 :
+ return False
+ if entry['pubdate'] is None :
+ return False
+ else :
+ return True
+
+ def make_bibtex_citation(entry, template_citation, asccii_bibtex):
+
+ #define a function to replace the template entry by its value
+ def tpl_replace(objtplname) :
+
+ tpl_field = re.sub(u'[\{\}]', u'', objtplname.group())
+
+ if tpl_field in TEMPLATE_ALLOWED_FIELDS :
+ if tpl_field in ['pubdate', 'timestamp'] :
+ tpl_field = isoformat(entry[tpl_field]).partition('T')[0]
+ elif tpl_field in ['tags', 'authors'] :
+ tpl_field =entry[tpl_field][0]
+ elif tpl_field in ['id', 'series_index'] :
+ tpl_field = str(entry[tpl_field])
+ else :
+ tpl_field = entry[tpl_field]
+ return tpl_field
+ else:
+ return u''
+
+ if len(template_citation) >0 :
+ tpl_citation = utf8ToBibtex(ValidateCitationKey(re.sub(u'\{[^{}]*\}',
+ tpl_replace, template_citation)), asccii_bibtex)
+
+ if len(tpl_citation) >0 :
+ return tpl_citation
+
+ if len(entry["isbn"]) > 0 :
+ template_citation = u'%s' % re.sub(u'[\D]',u'', entry["isbn"])
+
+ else :
+ template_citation = u'%s' % str(entry["id"])
+
+ if asccii_bibtex :
+ return ValidateCitationKey(template_citation.encode('ascii', 'replace'))
+ else :
+ return ValidateCitationKey(template_citation)
+
+ self.fmt = path_to_output.rpartition('.')[2]
+ self.notification = notification
+
+ # Combobox options
+ bibfile_enc = ['utf8', 'cp1252', 'ascii']
+ bibfile_enctag = ['strict', 'replace', 'ignore', 'backslashreplace']
+ bib_entry = ['mixed', 'misc', 'book']
+
+ # Needed beacause CLI return str vs int by widget
+ try:
+ bibfile_enc = bibfile_enc[opts.bibfile_enc]
+ bibfile_enctag = bibfile_enctag[opts.bibfile_enctag]
+ bib_entry = bib_entry[opts.bib_entry]
+ except:
+ if opts.bibfile_enc in bibfile_enc :
+ bibfile_enc = opts.bibfile_enc
+ else :
+ log(" WARNING: incorrect --choose-encoding flag, revert to default")
+ bibfile_enc = bibfile_enc[0]
+ if opts.bibfile_enctag in bibfile_enctag :
+ bibfile_enctag = opts.bibfile_enctag
+ else :
+ log(" WARNING: incorrect --choose-encoding-configuration flag, revert to default")
+ bibfile_enctag = bibfile_enctag[0]
+ if opts.bib_entry in bib_entry :
+ bib_entry = opts.bib_entry
+ else :
+ log(" WARNING: incorrect --entry-type flag, revert to default")
+ bib_entry = bib_entry[0]
+
+ if opts.verbose:
+ opts_dict = vars(opts)
+ log("%s(): Generating %s" % (self.name,self.fmt))
+ if opts_dict['search_text']:
+ log(" --search='%s'" % opts_dict['search_text'])
+
+ if opts_dict['ids']:
+ log(" Book count: %d" % len(opts_dict['ids']))
+ if opts_dict['search_text']:
+ log(" (--search ignored when a subset of the database is specified)")
+
+ if opts_dict['fields']:
+ if opts_dict['fields'] == 'all':
+ log(" Fields: %s" % ', '.join(FIELDS[1:]))
+ else:
+ log(" Fields: %s" % opts_dict['fields'])
+
+ log(" Output file will be encoded in %s with %s flag" % (bibfile_enc, bibfile_enctag))
+
+ log(" BibTeX entry type is %s with a citation like '%s' flag" % (bib_entry, opts_dict['bib_cit']))
+
+ # If a list of ids are provided, don't use search_text
+ if opts.ids:
+ opts.search_text = None
+
+ data = self.search_sort_db(db, opts)
+
+ if not len(data):
+ log.error("\nNo matching database entries for search criteria '%s'" % opts.search_text)
+
+ # Get the requested output fields as a list
+ fields = self.get_output_fields(opts)
+
+ if not len(data):
+ log.error("\nNo matching database entries for search criteria '%s'" % opts.search_text)
+
+ #Entries writing after Bibtex formating (or not)
+ if bibfile_enc != 'ascii' :
+ asccii_bibtex = False
+ else :
+ asccii_bibtex = True
+
+ #Check and go to default in case of bad CLI
+ if isinstance(opts.impcit, (StringType, UnicodeType)) :
+ if opts.impcit == 'False' :
+ citation_bibtex= False
+ elif opts.impcit == 'True' :
+ citation_bibtex= True
+ else :
+ log(" WARNING: incorrect --create-citation, revert to default")
+ citation_bibtex= True
+ else :
+ citation_bibtex= opts.impcit
+
+ template_citation = preprocess_template(opts.bib_cit)
+
+ #Open output and write entries
+ outfile = codecs.open(path_to_output, 'w', bibfile_enc, bibfile_enctag)
+
+ #File header
+ nb_entries = len(data)
+
+ #check in book strict if all is ok else throw a warning into log
+ if bib_entry == 'book' :
+ nb_books = len(filter(check_entry_book_valid, data))
+ if nb_books < nb_entries :
+ log(" WARNING: only %d entries in %d are book compatible" % (nb_books, nb_entries))
+ nb_entries = nb_books
+
+ outfile.write(u'%%%Calibre catalog\n%%%{0} entries in catalog\n\n'.format(nb_entries))
+ outfile.write(u'@preamble{"This catalog of %d entries was generated by calibre on %s"}\n\n'
+ % (nb_entries, nowf().strftime("%A, %d. %B %Y %H:%M").decode(preferred_encoding)))
+
+ for entry in data:
+ outfile.write(create_bibtex_entry(entry, fields, bib_entry, template_citation,
+ asccii_bibtex, citation_bibtex))
+
+ outfile.close()
class EPUB_MOBI(CatalogPlugin):
'ePub catalog generator'
diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py
index 1534d3ffbf..85e951d4b0 100644
--- a/src/calibre/library/database2.py
+++ b/src/calibre/library/database2.py
@@ -116,6 +116,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
# missing functions
self.books_list_filter = self.conn.create_dynamic_filter('books_list_filter')
+ @classmethod
+ def exists_at(cls, path):
+ return path and os.path.exists(os.path.join(path, 'metadata.db'))
+
def __init__(self, library_path, row_factory=False):
self.field_metadata = FieldMetadata()
if not os.path.exists(library_path):
diff --git a/src/calibre/utils/bibtex.py b/src/calibre/utils/bibtex.py
new file mode 100644
index 0000000000..7809781f7c
--- /dev/null
+++ b/src/calibre/utils/bibtex.py
@@ -0,0 +1,2539 @@
+# -*- coding: utf-8 -*-
+
+""" Collection of python utility-methodes commonly used by other
+ bibliograph packages.
+ From http://pypi.python.org/pypi/bibliograph.core/
+ from Tom Gross
+
+ Adapted for calibre use
+
+ Zope Public License (ZPL) Version 2.1
+
+ A copyright notice accompanies this license document that
+ identifies the copyright holders.
+
+ This license has been certified as open source. It has also
+ been designated as GPL compatible by the Free Software
+ Foundation (FSF).
+
+ Redistribution and use in source and binary forms, with or
+ without modification, are permitted provided that the
+ following conditions are met:
+
+ 1. Redistributions in source code must retain the
+ accompanying copyright notice, this list of conditions,
+ and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the accompanying
+ copyright notice, this list of conditions, and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. Names of the copyright holders must not be used to
+ endorse or promote products derived from this software
+ without prior written permission from the copyright
+ holders.
+
+ 4. The right to distribute this software or to use it for
+ any purpose does not give you the right to use
+ Servicemarks (sm) or Trademarks (tm) of the copyright
+ holders. Use of them is covered by separate agreement
+ with the copyright holders.
+
+ 5. If any files are modified, you must cause the modified
+ files to carry prominent notices stating that you changed
+ the files and the date of any change.
+
+ Disclaimer
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS''
+ AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ NO EVENT SHALL THE COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+ """
+
+__docformat__ = 'reStructuredText'
+__author__ = 'sengian '
+
+import re, string
+
+utf8enc2latex_mapping = {
+ # This is a mapping of Unicode characters to LaTeX equivalents.
+ # The information has been extracted from
+ # , written by
+ # David Carlisle and Sebastian Rahtz.
+ #
+ # The extraction has been done by the "create_unimap.py" script
+ # located at .
+
+ #Fix some encoding problem between cp1252 and latin1
+ # from http://www.microsoft.com/typography/unicode/1252.htm
+ u'\x80': '{\\mbox{\\texteuro}}', # EURO SIGN
+ u'\x82': '{,}', # SINGLE LOW-9 QUOTATION MARK
+ u'\x83': '$f$', # LATIN SMALL LETTER F WITH HOOK
+ u'\x84': '{,,}', # DOUBLE LOW-9 QUOTATION MARK
+ u'\x85': '{\\ldots}', # HORIZONTAL ELLIPSIS
+ u'\x86': '{\\textdagger}', # DAGGER
+ u'\x87': '{\\textdaggerdbl}', # DOUBLE DAGGER
+ u'\x88': '{\textasciicircum}', # MODIFIER LETTER CIRCUMFLEX ACCENT
+ u'\x89': '{\\textperthousand}', # PER MILLE SIGN
+ u'\x8A': '{\\v{S}}', # LATIN CAPITAL LETTER S WITH CARON
+ u'\x8B': '{\\guilsinglleft}', # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ u'\x8C': '{\\OE}', # LATIN CAPITAL LIGATURE OE
+ u'\x8E': '{\\v{Z}}', # LATIN CAPITAL LETTER Z WITH CARON
+ u'\x91': '{`}', # LEFT SINGLE QUOTATION MARK
+ u'\x92': "{'}", # RIGHT SINGLE QUOTATION MARK
+ u'\x93': '{\\textquotedblleft}', # LEFT DOUBLE QUOTATION MARK
+ u'\x94': '{\\textquotedblright}', # RIGHT DOUBLE QUOTATION MARK
+ u'\x95': '{\\textbullet}', # BULLET
+ u'\x96': '{\\textendash}', # EN DASH
+ u'\x97': '{\\textemdash}', # EM DASH
+ u'\x98': '{\\texttildelow}', # SMALL TILDE
+ u'\x99': '{\\texttrademark}', # TRADE MARK SIGN
+ u'\x9A': '{\\v{s}}', # LATIN SMALL LETTER S WITH CARON
+ u'\x9B': '{\\guilsinglright}', # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ u'\x9C': '{\\oe}', # LATIN SMALL LIGATURE OE
+ u'\x9E': '{\\v{z}}', # LATIN SMALL LETTER Z WITH CARON
+ u'\x9F': '{\\"{Y}}', # LATIN CAPITAL LETTER Y WITH DIAERESIS
+
+ u'\xa0': '$~$',
+ u'\xa1': '{\\textexclamdown}',
+ u'\xa2': '{\\textcent}',
+ u'\xa3': '{\\textsterling}',
+ u'\xa4': '{\\textcurrency}',
+ u'\xa5': '{\\textyen}',
+ u'\xa6': '{\\textbrokenbar}',
+ u'\xa7': '{\\textsection}',
+ u'\xa8': '{\\textasciidieresis}',
+ u'\xa9': '{\\textcopyright}',
+ u'\xaa': '{\\textordfeminine}',
+ u'\xab': '{\\guillemotleft}',
+ u'\xac': '$\\lnot$',
+ u'\xad': '$\\-$',
+ u'\xae': '{\\textregistered}',
+ u'\xaf': '{\\textasciimacron}',
+ u'\xb0': '{\\textdegree}',
+ u'\xb1': '$\\pm$',
+ u'\xb2': '${^2}$',
+ u'\xb3': '${^3}$',
+ u'\xb4': '{\\textasciiacute}',
+ u'\xb5': '$\\mathrm{\\mu}$',
+ u'\xb6': '{\\textparagraph}',
+ u'\xb7': '$\\cdot$',
+ u'\xb8': '{\\c{}}',
+ u'\xb9': '${^1}$',
+ u'\xba': '{\\textordmasculine}',
+ u'\xbb': '{\\guillemotright}',
+ u'\xbc': '{\\textonequarter}',
+ u'\xbd': '{\\textonehalf}',
+ u'\xbe': '{\\textthreequarters}',
+ u'\xbf': '{\\textquestiondown}',
+ u'\xc0': '{\\`{A}}',
+ u'\xc1': "{\\'{A}}",
+ u'\xc2': '{\\^{A}}',
+ u'\xc3': '{\\~{A}}',
+ u'\xc4': '{\\"{A}}',
+ u'\xc5': '{\\AA}',
+ u'\xc6': '{\\AE}',
+ u'\xc7': '{\\c{C}}',
+ u'\xc8': '{\\`{E}}',
+ u'\xc9': "{\\'{E}}",
+ u'\xca': '{\\^{E}}',
+ u'\xcb': '{\\"{E}}',
+ u'\xcc': '{\\`{I}}',
+ u'\xcd': "{\\'{I}}",
+ u'\xce': '{\\^{I}}',
+ u'\xcf': '{\\"{I}}',
+ u'\xd0': '{\\DH}',
+ u'\xd1': '{\\~{N}}',
+ u'\xd2': '{\\`{O}}',
+ u'\xd3': "{\\'{O}}",
+ u'\xd4': '{\\^{O}}',
+ u'\xd5': '{\\~{O}}',
+ u'\xd6': '{\\"{O}}',
+ u'\xd7': '{\\texttimes}',
+ u'\xd8': '{\\O}',
+ u'\xd9': '{\\`{U}}',
+ u'\xda': "{\\'{U}}",
+ u'\xdb': '{\\^{U}}',
+ u'\xdc': '{\\"{U}}',
+ u'\xdd': "{\\'{Y}}",
+ u'\xde': '{\\TH}',
+ u'\xdf': '{\\ss}',
+ u'\xe0': '{\\`{a}}',
+ u'\xe1': "{\\'{a}}",
+ u'\xe2': '{\\^{a}}',
+ u'\xe3': '{\\~{a}}',
+ u'\xe4': '{\\"{a}}',
+ u'\xe5': '{\\aa}',
+ u'\xe6': '{\\ae}',
+ u'\xe7': '{\\c{c}}',
+ u'\xe8': '{\\`{e}}',
+ u'\xe9': "{\\'{e}}",
+ u'\xea': '{\\^{e}}',
+ u'\xeb': '{\\"{e}}',
+ u'\xec': '{\\`{\\i}}',
+ u'\xed': "{\\'{\\i}}",
+ u'\xee': '{\\^{\\i}}',
+ u'\xef': '{\\"{\\i}}',
+ u'\xf0': '{\\dh}',
+ u'\xf1': '{\\~{n}}',
+ u'\xf2': '{\\`{o}}',
+ u'\xf3': "{\\'{o}}",
+ u'\xf4': '{\\^{o}}',
+ u'\xf5': '{\\~{o}}',
+ u'\xf6': '{\\"{o}}',
+ u'\xf7': '$\\div$',
+ u'\xf8': '{\\o}',
+ u'\xf9': '{\\`{u}}',
+ u'\xfa': "{\\'{u}}",
+ u'\xfb': '{\\^{u}}',
+ u'\xfc': '{\\"{u}}',
+ u'\xfd': "{\\'{y}}",
+ u'\xfe': '{\\th}',
+ u'\xff': '{\\"{y}}',
+ u'\u0100': '{\\={A}}',
+ u'\u0101': '{\\={a}}',
+ u'\u0102': '{\\u{A}}',
+ u'\u0103': '{\\u{a}}',
+ u'\u0104': '{\\k{A}}',
+ u'\u0105': '{\\k{a}}',
+ u'\u0106': "{\\'{C}}",
+ u'\u0107': "{\\'{c}}",
+ u'\u0108': '{\\^{C}}',
+ u'\u0109': '{\\^{c}}',
+ u'\u010a': '{\\.{C}}',
+ u'\u010b': '{\\.{c}}',
+ u'\u010c': '{\\v{C}}',
+ u'\u010d': '{\\v{c}}',
+ u'\u010e': '{\\v{D}}',
+ u'\u010f': '{\\v{d}}',
+ u'\u0110': '{\\DJ}',
+ u'\u0111': '{\\dj}',
+ u'\u0112': '{\\={E}}',
+ u'\u0113': '{\\={e}}',
+ u'\u0114': '{\\u{E}}',
+ u'\u0115': '{\\u{e}}',
+ u'\u0116': '{\\.{E}}',
+ u'\u0117': '{\\.{e}}',
+ u'\u0118': '{\\k{E}}',
+ u'\u0119': '{\\k{e}}',
+ u'\u011a': '{\\v{E}}',
+ u'\u011b': '{\\v{e}}',
+ u'\u011c': '{\\^{G}}',
+ u'\u011d': '{\\^{g}}',
+ u'\u011e': '{\\u{G}}',
+ u'\u011f': '{\\u{g}}',
+ u'\u0120': '{\\.{G}}',
+ u'\u0121': '{\\.{g}}',
+ u'\u0122': '{\\c{G}}',
+ u'\u0123': '{\\c{g}}',
+ u'\u0124': '{\\^{H}}',
+ u'\u0125': '{\\^{h}}',
+ u'\u0126': '{{\\fontencoding{LELA}\\selectfont\\char40}}',
+ u'\u0127': '$\\Elzxh$',
+ u'\u0128': '{\\~{I}}',
+ u'\u0129': '{\\~{\\i}}',
+ u'\u012a': '{\\={I}}',
+ u'\u012b': '{\\={\\i}}',
+ u'\u012c': '{\\u{I}}',
+ u'\u012d': '{\\u{\\i}}',
+ u'\u012e': '{\\k{I}}',
+ u'\u012f': '{\\k{i}}',
+ u'\u0130': '{\\.{I}}',
+ u'\u0131': '{\\i}',
+ u'\u0132': '{IJ}',
+ u'\u0133': '{ij}',
+ u'\u0134': '{\\^{J}}',
+ u'\u0135': '{\\^{\\j}}',
+ u'\u0136': '{\\c{K}}',
+ u'\u0137': '{\\c{k}}',
+ u'\u0138': '{{\\fontencoding{LELA}\\selectfont\\char91}}',
+ u'\u0139': "{\\'{L}}",
+ u'\u013a': "{\\'{l}}",
+ u'\u013b': '{\\c{L}}',
+ u'\u013c': '{\\c{l}}',
+ u'\u013d': '{\\v{L}}',
+ u'\u013e': '{\\v{l}}',
+ u'\u013f': '{{\\fontencoding{LELA}\\selectfont\\char201}}',
+ u'\u0140': '{{\\fontencoding{LELA}\\selectfont\\char202}}',
+ u'\u0141': '{\\L}',
+ u'\u0142': '{\\l}',
+ u'\u0143': "{\\'{N}}",
+ u'\u0144': "{\\'{n}}",
+ u'\u0145': '{\\c{N}}',
+ u'\u0146': '{\\c{n}}',
+ u'\u0147': '{\\v{N}}',
+ u'\u0148': '{\\v{n}}',
+ u'\u0149': "{'n}",
+ u'\u014a': '{\\NG}',
+ u'\u014b': '{\\ng}',
+ u'\u014c': '{\\={O}}',
+ u'\u014d': '{\\={o}}',
+ u'\u014e': '{\\u{O}}',
+ u'\u014f': '{\\u{o}}',
+ u'\u0150': '{\\H{O}}',
+ u'\u0151': '{\\H{o}}',
+ u'\u0152': '{\\OE}',
+ u'\u0153': '{\\oe}',
+ u'\u0154': "{\\'{R}}",
+ u'\u0155': "{\\'{r}}",
+ u'\u0156': '{\\c{R}}',
+ u'\u0157': '{\\c{r}}',
+ u'\u0158': '{\\v{R}}',
+ u'\u0159': '{\\v{r}}',
+ u'\u015a': "{\\'{S}}",
+ u'\u015b': "{\\'{s}}",
+ u'\u015c': '{\\^{S}}',
+ u'\u015d': '{\\^{s}}',
+ u'\u015e': '{\\c{S}}',
+ u'\u015f': '{\\c{s}}',
+ u'\u0160': '{\\v{S}}',
+ u'\u0161': '{\\v{s}}',
+ u'\u0162': '{\\c{T}}',
+ u'\u0163': '{\\c{t}}',
+ u'\u0164': '{\\v{T}}',
+ u'\u0165': '{\\v{t}}',
+ u'\u0166': '{{\\fontencoding{LELA}\\selectfont\\char47}}',
+ u'\u0167': '{{\\fontencoding{LELA}\\selectfont\\char63}}',
+ u'\u0168': '{\\~{U}}',
+ u'\u0169': '{\\~{u}}',
+ u'\u016a': '{\\={U}}',
+ u'\u016b': '{\\={u}}',
+ u'\u016c': '{\\u{U}}',
+ u'\u016d': '{\\u{u}}',
+ u'\u016e': '{\\r{U}}',
+ u'\u016f': '{\\r{u}}',
+ u'\u0170': '{\\H{U}}',
+ u'\u0171': '{\\H{u}}',
+ u'\u0172': '{\\k{U}}',
+ u'\u0173': '{\\k{u}}',
+ u'\u0174': '{\\^{W}}',
+ u'\u0175': '{\\^{w}}',
+ u'\u0176': '{\\^{Y}}',
+ u'\u0177': '{\\^{y}}',
+ u'\u0178': '{\\"{Y}}',
+ u'\u0179': "{\\'{Z}}",
+ u'\u017a': "{\\'{z}}",
+ u'\u017b': '{\\.{Z}}',
+ u'\u017c': '{\\.{z}}',
+ u'\u017d': '{\\v{Z}}',
+ u'\u017e': '{\\v{z}}',
+ u'\u0192': '$f$',
+ u'\u0195': '{\\texthvlig}',
+ u'\u019e': '{\\textnrleg}',
+ u'\u01aa': '$\\eth$',
+ u'\u01ba': '{{\\fontencoding{LELA}\\selectfont\\char195}}',
+ u'\u01c2': '{\\textdoublepipe}',
+ u'\u01f5': "{\\'{g}}",
+ u'\u0250': '$\\Elztrna$',
+ u'\u0252': '$\\Elztrnsa$',
+ u'\u0254': '$\\Elzopeno$',
+ u'\u0256': '$\\Elzrtld$',
+ u'\u0258': '{{\\fontencoding{LEIP}\\selectfont\\char61}}',
+ u'\u0259': '$\\Elzschwa$',
+ u'\u025b': '$\\varepsilon$',
+ u'\u0261': '{g}',
+ u'\u0263': '$\\Elzpgamma$',
+ u'\u0264': '$\\Elzpbgam$',
+ u'\u0265': '$\\Elztrnh$',
+ u'\u026c': '$\\Elzbtdl$',
+ u'\u026d': '$\\Elzrtll$',
+ u'\u026f': '$\\Elztrnm$',
+ u'\u0270': '$\\Elztrnmlr$',
+ u'\u0271': '$\\Elzltlmr$',
+ u'\u0272': '{\\Elzltln}',
+ u'\u0273': '$\\Elzrtln$',
+ u'\u0277': '$\\Elzclomeg$',
+ u'\u0278': '{\\textphi}',
+ u'\u0279': '$\\Elztrnr$',
+ u'\u027a': '$\\Elztrnrl$',
+ u'\u027b': '$\\Elzrttrnr$',
+ u'\u027c': '$\\Elzrl$',
+ u'\u027d': '$\\Elzrtlr$',
+ u'\u027e': '$\\Elzfhr$',
+ u'\u027f': '{{\\fontencoding{LEIP}\\selectfont\\char202}}',
+ u'\u0282': '$\\Elzrtls$',
+ u'\u0283': '$\\Elzesh$',
+ u'\u0287': '$\\Elztrnt$',
+ u'\u0288': '$\\Elzrtlt$',
+ u'\u028a': '$\\Elzpupsil$',
+ u'\u028b': '$\\Elzpscrv$',
+ u'\u028c': '$\\Elzinvv$',
+ u'\u028d': '$\\Elzinvw$',
+ u'\u028e': '$\\Elztrny$',
+ u'\u0290': '$\\Elzrtlz$',
+ u'\u0292': '$\\Elzyogh$',
+ u'\u0294': '$\\Elzglst$',
+ u'\u0295': '$\\Elzreglst$',
+ u'\u0296': '$\\Elzinglst$',
+ u'\u029e': '{\\textturnk}',
+ u'\u02a4': '$\\Elzdyogh$',
+ u'\u02a7': '$\\Elztesh$',
+ u'\u02bc': "{'}",
+ u'\u02c7': '{\\textasciicaron}',
+ u'\u02c8': '$\\Elzverts$',
+ u'\u02cc': '$\\Elzverti$',
+ u'\u02d0': '$\\Elzlmrk$',
+ u'\u02d1': '$\\Elzhlmrk$',
+ u'\u02d2': '$\\Elzsbrhr$',
+ u'\u02d3': '$\\Elzsblhr$',
+ u'\u02d4': '$\\Elzrais$',
+ u'\u02d5': '$\\Elzlow$',
+ u'\u02d8': '{\\textasciibreve}',
+ u'\u02d9': '{\\textperiodcentered}',
+ u'\u02da': '{\\r{}}',
+ u'\u02db': '{\\k{}}',
+ u'\u02dc': '{\\texttildelow}',
+ u'\u02dd': '{\\H{}}',
+ u'\u02e5': '{\\tone{55}}',
+ u'\u02e6': '{\\tone{44}}',
+ u'\u02e7': '{\\tone{33}}',
+ u'\u02e8': '{\\tone{22}}',
+ u'\u02e9': '{\\tone{11}}',
+ u'\u0300': '{\\`}',
+ u'\u0301': "{\\'}",
+ u'\u0302': '{\\^}',
+ u'\u0303': '{\\~}',
+ u'\u0304': '{\\=}',
+ u'\u0306': '{\\u}',
+ u'\u0307': '{\\.}',
+ u'\u0308': '{\\"}',
+ u'\u030a': '{\\r}',
+ u'\u030b': '{\\H}',
+ u'\u030c': '{\\v}',
+ u'\u030f': '{\\cyrchar\\C}',
+ u'\u0311': '{{\\fontencoding{LECO}\\selectfont\\char177}}',
+ u'\u0318': '{{\\fontencoding{LECO}\\selectfont\\char184}}',
+ u'\u0319': '{{\\fontencoding{LECO}\\selectfont\\char185}}',
+ u'\u0321': '$\\Elzpalh$',
+ u'\u0322': '{\\Elzrh}',
+ u'\u0327': '{\\c}',
+ u'\u0328': '{\\k}',
+ u'\u032a': '$\\Elzsbbrg$',
+ u'\u032b': '{{\\fontencoding{LECO}\\selectfont\\char203}}',
+ u'\u032f': '{{\\fontencoding{LECO}\\selectfont\\char207}}',
+ u'\u0335': '{\\Elzxl}',
+ u'\u0336': '{\\Elzbar}',
+ u'\u0337': '{{\\fontencoding{LECO}\\selectfont\\char215}}',
+ u'\u0338': '{{\\fontencoding{LECO}\\selectfont\\char216}}',
+ u'\u033a': '{{\\fontencoding{LECO}\\selectfont\\char218}}',
+ u'\u033b': '{{\\fontencoding{LECO}\\selectfont\\char219}}',
+ u'\u033c': '{{\\fontencoding{LECO}\\selectfont\\char220}}',
+ u'\u033d': '{{\\fontencoding{LECO}\\selectfont\\char221}}',
+ u'\u0361': '{{\\fontencoding{LECO}\\selectfont\\char225}}',
+ u'\u0386': "{\\'{A}}",
+ u'\u0388': "{\\'{E}}",
+ u'\u0389': "{\\'{H}}",
+ u'\u038a': "{\\'{}{I}}",
+ u'\u038c': "{\\'{}O}",
+ u'\u038e': "$\\mathrm{'Y}$",
+ u'\u038f': "$\\mathrm{'\\Omega}$",
+ u'\u0390': '$\\acute{\\ddot{\\iota}}$',
+ u'\u0391': '$\\Alpha$',
+ u'\u0392': '$\\Beta$',
+ u'\u0393': '$\\Gamma$',
+ u'\u0394': '$\\Delta$',
+ u'\u0395': '$\\Epsilon$',
+ u'\u0396': '$\\Zeta$',
+ u'\u0397': '$\\Eta$',
+ u'\u0398': '$\\Theta$',
+ u'\u0399': '$\\Iota$',
+ u'\u039a': '$\\Kappa$',
+ u'\u039b': '$\\Lambda$',
+ u'\u039c': '$M$',
+ u'\u039d': '$N$',
+ u'\u039e': '$\\Xi$',
+ u'\u039f': '$O$',
+ u'\u03a0': '$\\Pi$',
+ u'\u03a1': '$\\Rho$',
+ u'\u03a3': '$\\Sigma$',
+ u'\u03a4': '$\\Tau$',
+ u'\u03a5': '$\\Upsilon$',
+ u'\u03a6': '$\\Phi$',
+ u'\u03a7': '$\\Chi$',
+ u'\u03a8': '$\\Psi$',
+ u'\u03a9': '$\\Omega$',
+ u'\u03aa': '$\\mathrm{\\ddot{I}}$',
+ u'\u03ab': '$\\mathrm{\\ddot{Y}}$',
+ u'\u03ac': "{\\'{$\\alpha$}}",
+ u'\u03ad': '$\\acute{\\epsilon}$',
+ u'\u03ae': '$\\acute{\\eta}$',
+ u'\u03af': '$\\acute{\\iota}$',
+ u'\u03b0': '$\\acute{\\ddot{\\upsilon}}$',
+ u'\u03b1': '$\\alpha$',
+ u'\u03b2': '$\\beta$',
+ u'\u03b3': '$\\gamma$',
+ u'\u03b4': '$\\delta$',
+ u'\u03b5': '$\\epsilon$',
+ u'\u03b6': '$\\zeta$',
+ u'\u03b7': '$\\eta$',
+ u'\u03b8': '{\\texttheta}',
+ u'\u03b9': '$\\iota$',
+ u'\u03ba': '$\\kappa$',
+ u'\u03bb': '$\\lambda$',
+ u'\u03bc': '$\\mu$',
+ u'\u03bd': '$\\nu$',
+ u'\u03be': '$\\xi$',
+ u'\u03bf': '$o$',
+ u'\u03c0': '$\\pi$',
+ u'\u03c1': '$\\rho$',
+ u'\u03c2': '$\\varsigma$',
+ u'\u03c3': '$\\sigma$',
+ u'\u03c4': '$\\tau$',
+ u'\u03c5': '$\\upsilon$',
+ u'\u03c6': '$\\varphi$',
+ u'\u03c7': '$\\chi$',
+ u'\u03c8': '$\\psi$',
+ u'\u03c9': '$\\omega$',
+ u'\u03ca': '$\\ddot{\\iota}$',
+ u'\u03cb': '$\\ddot{\\upsilon}$',
+ u'\u03cc': "{\\'{o}}",
+ u'\u03cd': '$\\acute{\\upsilon}$',
+ u'\u03ce': '$\\acute{\\omega}$',
+ u'\u03d0': '{\\Pisymbol{ppi022}{87}}',
+ u'\u03d1': '{\\textvartheta}',
+ u'\u03d2': '$\\Upsilon$',
+ u'\u03d5': '$\\phi$',
+ u'\u03d6': '$\\varpi$',
+ u'\u03da': '$\\Stigma$',
+ u'\u03dc': '$\\Digamma$',
+ u'\u03dd': '$\\digamma$',
+ u'\u03de': '$\\Koppa$',
+ u'\u03e0': '$\\Sampi$',
+ u'\u03f0': '$\\varkappa$',
+ u'\u03f1': '$\\varrho$',
+ u'\u03f4': '{\\textTheta}',
+ u'\u03f6': '$\\backepsilon$',
+ u'\u0401': '{\\cyrchar\\CYRYO}',
+ u'\u0402': '{\\cyrchar\\CYRDJE}',
+ u'\u0403': "{\\cyrchar{\\'\\CYRG}}",
+ u'\u0404': '{\\cyrchar\\CYRIE}',
+ u'\u0405': '{\\cyrchar\\CYRDZE}',
+ u'\u0406': '{\\cyrchar\\CYRII}',
+ u'\u0407': '{\\cyrchar\\CYRYI}',
+ u'\u0408': '{\\cyrchar\\CYRJE}',
+ u'\u0409': '{\\cyrchar\\CYRLJE}',
+ u'\u040a': '{\\cyrchar\\CYRNJE}',
+ u'\u040b': '{\\cyrchar\\CYRTSHE}',
+ u'\u040c': "{\\cyrchar{\\'\\CYRK}}",
+ u'\u040e': '{\\cyrchar\\CYRUSHRT}',
+ u'\u040f': '{\\cyrchar\\CYRDZHE}',
+ u'\u0410': '{\\cyrchar\\CYRA}',
+ u'\u0411': '{\\cyrchar\\CYRB}',
+ u'\u0412': '{\\cyrchar\\CYRV}',
+ u'\u0413': '{\\cyrchar\\CYRG}',
+ u'\u0414': '{\\cyrchar\\CYRD}',
+ u'\u0415': '{\\cyrchar\\CYRE}',
+ u'\u0416': '{\\cyrchar\\CYRZH}',
+ u'\u0417': '{\\cyrchar\\CYRZ}',
+ u'\u0418': '{\\cyrchar\\CYRI}',
+ u'\u0419': '{\\cyrchar\\CYRISHRT}',
+ u'\u041a': '{\\cyrchar\\CYRK}',
+ u'\u041b': '{\\cyrchar\\CYRL}',
+ u'\u041c': '{\\cyrchar\\CYRM}',
+ u'\u041d': '{\\cyrchar\\CYRN}',
+ u'\u041e': '{\\cyrchar\\CYRO}',
+ u'\u041f': '{\\cyrchar\\CYRP}',
+ u'\u0420': '{\\cyrchar\\CYRR}',
+ u'\u0421': '{\\cyrchar\\CYRS}',
+ u'\u0422': '{\\cyrchar\\CYRT}',
+ u'\u0423': '{\\cyrchar\\CYRU}',
+ u'\u0424': '{\\cyrchar\\CYRF}',
+ u'\u0425': '{\\cyrchar\\CYRH}',
+ u'\u0426': '{\\cyrchar\\CYRC}',
+ u'\u0427': '{\\cyrchar\\CYRCH}',
+ u'\u0428': '{\\cyrchar\\CYRSH}',
+ u'\u0429': '{\\cyrchar\\CYRSHCH}',
+ u'\u042a': '{\\cyrchar\\CYRHRDSN}',
+ u'\u042b': '{\\cyrchar\\CYRERY}',
+ u'\u042c': '{\\cyrchar\\CYRSFTSN}',
+ u'\u042d': '{\\cyrchar\\CYREREV}',
+ u'\u042e': '{\\cyrchar\\CYRYU}',
+ u'\u042f': '{\\cyrchar\\CYRYA}',
+ u'\u0430': '{\\cyrchar\\cyra}',
+ u'\u0431': '{\\cyrchar\\cyrb}',
+ u'\u0432': '{\\cyrchar\\cyrv}',
+ u'\u0433': '{\\cyrchar\\cyrg}',
+ u'\u0434': '{\\cyrchar\\cyrd}',
+ u'\u0435': '{\\cyrchar\\cyre}',
+ u'\u0436': '{\\cyrchar\\cyrzh}',
+ u'\u0437': '{\\cyrchar\\cyrz}',
+ u'\u0438': '{\\cyrchar\\cyri}',
+ u'\u0439': '{\\cyrchar\\cyrishrt}',
+ u'\u043a': '{\\cyrchar\\cyrk}',
+ u'\u043b': '{\\cyrchar\\cyrl}',
+ u'\u043c': '{\\cyrchar\\cyrm}',
+ u'\u043d': '{\\cyrchar\\cyrn}',
+ u'\u043e': '{\\cyrchar\\cyro}',
+ u'\u043f': '{\\cyrchar\\cyrp}',
+ u'\u0440': '{\\cyrchar\\cyrr}',
+ u'\u0441': '{\\cyrchar\\cyrs}',
+ u'\u0442': '{\\cyrchar\\cyrt}',
+ u'\u0443': '{\\cyrchar\\cyru}',
+ u'\u0444': '{\\cyrchar\\cyrf}',
+ u'\u0445': '{\\cyrchar\\cyrh}',
+ u'\u0446': '{\\cyrchar\\cyrc}',
+ u'\u0447': '{\\cyrchar\\cyrch}',
+ u'\u0448': '{\\cyrchar\\cyrsh}',
+ u'\u0449': '{\\cyrchar\\cyrshch}',
+ u'\u044a': '{\\cyrchar\\cyrhrdsn}',
+ u'\u044b': '{\\cyrchar\\cyrery}',
+ u'\u044c': '{\\cyrchar\\cyrsftsn}',
+ u'\u044d': '{\\cyrchar\\cyrerev}',
+ u'\u044e': '{\\cyrchar\\cyryu}',
+ u'\u044f': '{\\cyrchar\\cyrya}',
+ u'\u0451': '{\\cyrchar\\cyryo}',
+ u'\u0452': '{\\cyrchar\\cyrdje}',
+ u'\u0453': "{\\cyrchar{\\'\\cyrg}}",
+ u'\u0454': '{\\cyrchar\\cyrie}',
+ u'\u0455': '{\\cyrchar\\cyrdze}',
+ u'\u0456': '{\\cyrchar\\cyrii}',
+ u'\u0457': '{\\cyrchar\\cyryi}',
+ u'\u0458': '{\\cyrchar\\cyrje}',
+ u'\u0459': '{\\cyrchar\\cyrlje}',
+ u'\u045a': '{\\cyrchar\\cyrnje}',
+ u'\u045b': '{\\cyrchar\\cyrtshe}',
+ u'\u045c': "{\\cyrchar{\\'\\cyrk}}",
+ u'\u045e': '{\\cyrchar\\cyrushrt}',
+ u'\u045f': '{\\cyrchar\\cyrdzhe}',
+ u'\u0460': '{\\cyrchar\\CYROMEGA}',
+ u'\u0461': '{\\cyrchar\\cyromega}',
+ u'\u0462': '{\\cyrchar\\CYRYAT}',
+ u'\u0464': '{\\cyrchar\\CYRIOTE}',
+ u'\u0465': '{\\cyrchar\\cyriote}',
+ u'\u0466': '{\\cyrchar\\CYRLYUS}',
+ u'\u0467': '{\\cyrchar\\cyrlyus}',
+ u'\u0468': '{\\cyrchar\\CYRIOTLYUS}',
+ u'\u0469': '{\\cyrchar\\cyriotlyus}',
+ u'\u046a': '{\\cyrchar\\CYRBYUS}',
+ u'\u046c': '{\\cyrchar\\CYRIOTBYUS}',
+ u'\u046d': '{\\cyrchar\\cyriotbyus}',
+ u'\u046e': '{\\cyrchar\\CYRKSI}',
+ u'\u046f': '{\\cyrchar\\cyrksi}',
+ u'\u0470': '{\\cyrchar\\CYRPSI}',
+ u'\u0471': '{\\cyrchar\\cyrpsi}',
+ u'\u0472': '{\\cyrchar\\CYRFITA}',
+ u'\u0474': '{\\cyrchar\\CYRIZH}',
+ u'\u0478': '{\\cyrchar\\CYRUK}',
+ u'\u0479': '{\\cyrchar\\cyruk}',
+ u'\u047a': '{\\cyrchar\\CYROMEGARND}',
+ u'\u047b': '{\\cyrchar\\cyromegarnd}',
+ u'\u047c': '{\\cyrchar\\CYROMEGATITLO}',
+ u'\u047d': '{\\cyrchar\\cyromegatitlo}',
+ u'\u047e': '{\\cyrchar\\CYROT}',
+ u'\u047f': '{\\cyrchar\\cyrot}',
+ u'\u0480': '{\\cyrchar\\CYRKOPPA}',
+ u'\u0481': '{\\cyrchar\\cyrkoppa}',
+ u'\u0482': '{\\cyrchar\\cyrthousands}',
+ u'\u0488': '{\\cyrchar\\cyrhundredthousands}',
+ u'\u0489': '{\\cyrchar\\cyrmillions}',
+ u'\u048c': '{\\cyrchar\\CYRSEMISFTSN}',
+ u'\u048d': '{\\cyrchar\\cyrsemisftsn}',
+ u'\u048e': '{\\cyrchar\\CYRRTICK}',
+ u'\u048f': '{\\cyrchar\\cyrrtick}',
+ u'\u0490': '{\\cyrchar\\CYRGUP}',
+ u'\u0491': '{\\cyrchar\\cyrgup}',
+ u'\u0492': '{\\cyrchar\\CYRGHCRS}',
+ u'\u0493': '{\\cyrchar\\cyrghcrs}',
+ u'\u0494': '{\\cyrchar\\CYRGHK}',
+ u'\u0495': '{\\cyrchar\\cyrghk}',
+ u'\u0496': '{\\cyrchar\\CYRZHDSC}',
+ u'\u0497': '{\\cyrchar\\cyrzhdsc}',
+ u'\u0498': '{\\cyrchar\\CYRZDSC}',
+ u'\u0499': '{\\cyrchar\\cyrzdsc}',
+ u'\u049a': '{\\cyrchar\\CYRKDSC}',
+ u'\u049b': '{\\cyrchar\\cyrkdsc}',
+ u'\u049c': '{\\cyrchar\\CYRKVCRS}',
+ u'\u049d': '{\\cyrchar\\cyrkvcrs}',
+ u'\u049e': '{\\cyrchar\\CYRKHCRS}',
+ u'\u049f': '{\\cyrchar\\cyrkhcrs}',
+ u'\u04a0': '{\\cyrchar\\CYRKBEAK}',
+ u'\u04a1': '{\\cyrchar\\cyrkbeak}',
+ u'\u04a2': '{\\cyrchar\\CYRNDSC}',
+ u'\u04a3': '{\\cyrchar\\cyrndsc}',
+ u'\u04a4': '{\\cyrchar\\CYRNG}',
+ u'\u04a5': '{\\cyrchar\\cyrng}',
+ u'\u04a6': '{\\cyrchar\\CYRPHK}',
+ u'\u04a7': '{\\cyrchar\\cyrphk}',
+ u'\u04a8': '{\\cyrchar\\CYRABHHA}',
+ u'\u04a9': '{\\cyrchar\\cyrabhha}',
+ u'\u04aa': '{\\cyrchar\\CYRSDSC}',
+ u'\u04ab': '{\\cyrchar\\cyrsdsc}',
+ u'\u04ac': '{\\cyrchar\\CYRTDSC}',
+ u'\u04ad': '{\\cyrchar\\cyrtdsc}',
+ u'\u04ae': '{\\cyrchar\\CYRY}',
+ u'\u04af': '{\\cyrchar\\cyry}',
+ u'\u04b0': '{\\cyrchar\\CYRYHCRS}',
+ u'\u04b1': '{\\cyrchar\\cyryhcrs}',
+ u'\u04b2': '{\\cyrchar\\CYRHDSC}',
+ u'\u04b3': '{\\cyrchar\\cyrhdsc}',
+ u'\u04b4': '{\\cyrchar\\CYRTETSE}',
+ u'\u04b5': '{\\cyrchar\\cyrtetse}',
+ u'\u04b6': '{\\cyrchar\\CYRCHRDSC}',
+ u'\u04b7': '{\\cyrchar\\cyrchrdsc}',
+ u'\u04b8': '{\\cyrchar\\CYRCHVCRS}',
+ u'\u04b9': '{\\cyrchar\\cyrchvcrs}',
+ u'\u04ba': '{\\cyrchar\\CYRSHHA}',
+ u'\u04bb': '{\\cyrchar\\cyrshha}',
+ u'\u04bc': '{\\cyrchar\\CYRABHCH}',
+ u'\u04bd': '{\\cyrchar\\cyrabhch}',
+ u'\u04be': '{\\cyrchar\\CYRABHCHDSC}',
+ u'\u04bf': '{\\cyrchar\\cyrabhchdsc}',
+ u'\u04c0': '{\\cyrchar\\CYRpalochka}',
+ u'\u04c3': '{\\cyrchar\\CYRKHK}',
+ u'\u04c4': '{\\cyrchar\\cyrkhk}',
+ u'\u04c7': '{\\cyrchar\\CYRNHK}',
+ u'\u04c8': '{\\cyrchar\\cyrnhk}',
+ u'\u04cb': '{\\cyrchar\\CYRCHLDSC}',
+ u'\u04cc': '{\\cyrchar\\cyrchldsc}',
+ u'\u04d4': '{\\cyrchar\\CYRAE}',
+ u'\u04d5': '{\\cyrchar\\cyrae}',
+ u'\u04d8': '{\\cyrchar\\CYRSCHWA}',
+ u'\u04d9': '{\\cyrchar\\cyrschwa}',
+ u'\u04e0': '{\\cyrchar\\CYRABHDZE}',
+ u'\u04e1': '{\\cyrchar\\cyrabhdze}',
+ u'\u04e8': '{\\cyrchar\\CYROTLD}',
+ u'\u04e9': '{\\cyrchar\\cyrotld}',
+ u'\u2002': '{\\hspace{0.6em}}',
+ u'\u2003': '{\\hspace{1em}}',
+ u'\u2004': '{\\hspace{0.33em}}',
+ u'\u2005': '{\\hspace{0.25em}}',
+ u'\u2006': '{\\hspace{0.166em}}',
+ u'\u2007': '{\\hphantom{0}}',
+ u'\u2008': '{\\hphantom{,}}',
+ u'\u2009': '{\\hspace{0.167em}}',
+ u'\u200a': '$\\mkern1mu$',
+ u'\u2010': '{-}',
+ u'\u2013': '{\\textendash}',
+ u'\u2014': '{\\textemdash}',
+ u'\u2015': '{\\rule{1em}{1pt}}',
+ u'\u2016': '$\\Vert$',
+ u'\u2018': '{`}',
+ u'\u2019': "{'}",
+ u'\u201a': '{,}',
+ u'\u201b': '$\\Elzreapos$',
+ u'\u201c': '{\\textquotedblleft}',
+ u'\u201d': '{\\textquotedblright}',
+ u'\u201e': '{,,}',
+ u'\u2020': '{\\textdagger}',
+ u'\u2021': '{\\textdaggerdbl}',
+ u'\u2022': '{\\textbullet}',
+ u'\u2024': '{.}',
+ u'\u2025': '{..}',
+ u'\u2026': '{\\ldots}',
+ u'\u2030': '{\\textperthousand}',
+ u'\u2031': '{\\textpertenthousand}',
+ u'\u2032': "${'}$",
+ u'\u2033': "${''}$",
+ u'\u2034': "${'''}$",
+ u'\u2035': '$\\backprime$',
+ u'\u2039': '{\\guilsinglleft}',
+ u'\u203a': '{\\guilsinglright}',
+ u'\u2057': "$''''$",
+ u'\u205f': '{\\mkern4mu}',
+ u'\u2060': '{\\nolinebreak}',
+ u'\u20a7': '{\\ensuremath{\\Elzpes}}',
+ u'\u20ac': '{\\mbox{\\texteuro}}',
+ u'\u20db': '$\\dddot$',
+ u'\u20dc': '$\\ddddot$',
+ u'\u2102': '$\\mathbb{C}$',
+ u'\u210a': '{\\mathscr{g}}',
+ u'\u210b': '$\\mathscr{H}$',
+ u'\u210c': '$\\mathfrak{H}$',
+ u'\u210d': '$\\mathbb{H}$',
+ u'\u210f': '$\\hslash$',
+ u'\u2110': '$\\mathscr{I}$',
+ u'\u2111': '$\\mathfrak{I}$',
+ u'\u2112': '$\\mathscr{L}$',
+ u'\u2113': '$\\mathscr{l}$',
+ u'\u2115': '$\\mathbb{N}$',
+ u'\u2116': '{\\cyrchar\\textnumero}',
+ u'\u2118': '$\\wp$',
+ u'\u2119': '$\\mathbb{P}$',
+ u'\u211a': '$\\mathbb{Q}$',
+ u'\u211b': '$\\mathscr{R}$',
+ u'\u211c': '$\\mathfrak{R}$',
+ u'\u211d': '$\\mathbb{R}$',
+ u'\u211e': '$\\Elzxrat$',
+ u'\u2122': '{\\texttrademark}',
+ u'\u2124': '$\\mathbb{Z}$',
+ u'\u2126': '$\\Omega$',
+ u'\u2127': '$\\mho$',
+ u'\u2128': '$\\mathfrak{Z}$',
+ u'\u2129': '$\\ElsevierGlyph{2129}$',
+ u'\u212b': '{\\AA}',
+ u'\u212c': '$\\mathscr{B}$',
+ u'\u212d': '$\\mathfrak{C}$',
+ u'\u212f': '$\\mathscr{e}$',
+ u'\u2130': '$\\mathscr{E}$',
+ u'\u2131': '$\\mathscr{F}$',
+ u'\u2133': '$\\mathscr{M}$',
+ u'\u2134': '$\\mathscr{o}$',
+ u'\u2135': '$\\aleph$',
+ u'\u2136': '$\\beth$',
+ u'\u2137': '$\\gimel$',
+ u'\u2138': '$\\daleth$',
+ u'\u2153': '$\\textfrac{1}{3}$',
+ u'\u2154': '$\\textfrac{2}{3}$',
+ u'\u2155': '$\\textfrac{1}{5}$',
+ u'\u2156': '$\\textfrac{2}{5}$',
+ u'\u2157': '$\\textfrac{3}{5}$',
+ u'\u2158': '$\\textfrac{4}{5}$',
+ u'\u2159': '$\\textfrac{1}{6}$',
+ u'\u215a': '$\\textfrac{5}{6}$',
+ u'\u215b': '$\\textfrac{1}{8}$',
+ u'\u215c': '$\\textfrac{3}{8}$',
+ u'\u215d': '$\\textfrac{5}{8}$',
+ u'\u215e': '$\\textfrac{7}{8}$',
+ u'\u2190': '$\\leftarrow$',
+ u'\u2191': '$\\uparrow$',
+ u'\u2192': '$\\rightarrow$',
+ u'\u2193': '$\\downarrow$',
+ u'\u2194': '$\\leftrightarrow$',
+ u'\u2195': '$\\updownarrow$',
+ u'\u2196': '$\\nwarrow$',
+ u'\u2197': '$\\nearrow$',
+ u'\u2198': '$\\searrow$',
+ u'\u2199': '$\\swarrow$',
+ u'\u219a': '$\\nleftarrow$',
+ u'\u219b': '$\\nrightarrow$',
+ u'\u219c': '$\\arrowwaveright$',
+ u'\u219d': '$\\arrowwaveright$',
+ u'\u219e': '$\\twoheadleftarrow$',
+ u'\u21a0': '$\\twoheadrightarrow$',
+ u'\u21a2': '$\\leftarrowtail$',
+ u'\u21a3': '$\\rightarrowtail$',
+ u'\u21a6': '$\\mapsto$',
+ u'\u21a9': '$\\hookleftarrow$',
+ u'\u21aa': '$\\hookrightarrow$',
+ u'\u21ab': '$\\looparrowleft$',
+ u'\u21ac': '$\\looparrowright$',
+ u'\u21ad': '$\\leftrightsquigarrow$',
+ u'\u21ae': '$\\nleftrightarrow$',
+ u'\u21b0': '$\\Lsh$',
+ u'\u21b1': '$\\Rsh$',
+ u'\u21b3': '$\\ElsevierGlyph{21B3}$',
+ u'\u21b6': '$\\curvearrowleft$',
+ u'\u21b7': '$\\curvearrowright$',
+ u'\u21ba': '$\\circlearrowleft$',
+ u'\u21bb': '$\\circlearrowright$',
+ u'\u21bc': '$\\leftharpoonup$',
+ u'\u21bd': '$\\leftharpoondown$',
+ u'\u21be': '$\\upharpoonright$',
+ u'\u21bf': '$\\upharpoonleft$',
+ u'\u21c0': '$\\rightharpoonup$',
+ u'\u21c1': '$\\rightharpoondown$',
+ u'\u21c2': '$\\downharpoonright$',
+ u'\u21c3': '$\\downharpoonleft$',
+ u'\u21c4': '$\\rightleftarrows$',
+ u'\u21c5': '$\\dblarrowupdown$',
+ u'\u21c6': '$\\leftrightarrows$',
+ u'\u21c7': '$\\leftleftarrows$',
+ u'\u21c8': '$\\upuparrows$',
+ u'\u21c9': '$\\rightrightarrows$',
+ u'\u21ca': '$\\downdownarrows$',
+ u'\u21cb': '$\\leftrightharpoons$',
+ u'\u21cc': '$\\rightleftharpoons$',
+ u'\u21cd': '$\\nLeftarrow$',
+ u'\u21ce': '$\\nLeftrightarrow$',
+ u'\u21cf': '$\\nRightarrow$',
+ u'\u21d0': '$\\Leftarrow$',
+ u'\u21d1': '$\\Uparrow$',
+ u'\u21d2': '$\\Rightarrow$',
+ u'\u21d3': '$\\Downarrow$',
+ u'\u21d4': '$\\Leftrightarrow$',
+ u'\u21d5': '$\\Updownarrow$',
+ u'\u21da': '$\\Lleftarrow$',
+ u'\u21db': '$\\Rrightarrow$',
+ u'\u21dd': '$\\rightsquigarrow$',
+ u'\u21f5': '$\\DownArrowUpArrow$',
+ u'\u2200': '$\\forall$',
+ u'\u2201': '$\\complement$',
+ u'\u2202': '$\\partial$',
+ u'\u2203': '$\\exists$',
+ u'\u2204': '$\\nexists$',
+ u'\u2205': '$\\varnothing$',
+ u'\u2207': '$\\nabla$',
+ u'\u2208': '$\\in$',
+ u'\u2209': '$\\not\\in$',
+ u'\u220b': '$\\ni$',
+ u'\u220c': '$\\not\\ni$',
+ u'\u220f': '$\\prod$',
+ u'\u2210': '$\\coprod$',
+ u'\u2211': '$\\sum$',
+ u'\u2212': '{-}',
+ u'\u2213': '$\\mp$',
+ u'\u2214': '$\\dotplus$',
+ u'\u2216': '$\\setminus$',
+ u'\u2217': '${_\\ast}$',
+ u'\u2218': '$\\circ$',
+ u'\u2219': '$\\bullet$',
+ u'\u221a': '$\\surd$',
+ u'\u221d': '$\\propto$',
+ u'\u221e': '$\\infty$',
+ u'\u221f': '$\\rightangle$',
+ u'\u2220': '$\\angle$',
+ u'\u2221': '$\\measuredangle$',
+ u'\u2222': '$\\sphericalangle$',
+ u'\u2223': '$\\mid$',
+ u'\u2224': '$\\nmid$',
+ u'\u2225': '$\\parallel$',
+ u'\u2226': '$\\nparallel$',
+ u'\u2227': '$\\wedge$',
+ u'\u2228': '$\\vee$',
+ u'\u2229': '$\\cap$',
+ u'\u222a': '$\\cup$',
+ u'\u222b': '$\\int$',
+ u'\u222c': '$\\int\\!\\int$',
+ u'\u222d': '$\\int\\!\\int\\!\\int$',
+ u'\u222e': '$\\oint$',
+ u'\u222f': '$\\surfintegral$',
+ u'\u2230': '$\\volintegral$',
+ u'\u2231': '$\\clwintegral$',
+ u'\u2232': '$\\ElsevierGlyph{2232}$',
+ u'\u2233': '$\\ElsevierGlyph{2233}$',
+ u'\u2234': '$\\therefore$',
+ u'\u2235': '$\\because$',
+ u'\u2237': '$\\Colon$',
+ u'\u2238': '$\\ElsevierGlyph{2238}$',
+ u'\u223a': '$\\mathbin{{:}\\!\\!{-}\\!\\!{:}}$',
+ u'\u223b': '$\\homothetic$',
+ u'\u223c': '$\\sim$',
+ u'\u223d': '$\\backsim$',
+ u'\u223e': '$\\lazysinv$',
+ u'\u2240': '$\\wr$',
+ u'\u2241': '$\\not\\sim$',
+ u'\u2242': '$\\ElsevierGlyph{2242}$',
+ u'\u2243': '$\\simeq$',
+ u'\u2244': '$\\not\\simeq$',
+ u'\u2245': '$\\cong$',
+ u'\u2246': '$\\approxnotequal$',
+ u'\u2247': '$\\not\\cong$',
+ u'\u2248': '$\\approx$',
+ u'\u2249': '$\\not\\approx$',
+ u'\u224a': '$\\approxeq$',
+ u'\u224b': '$\\tildetrpl$',
+ u'\u224c': '$\\allequal$',
+ u'\u224d': '$\\asymp$',
+ u'\u224e': '$\\Bumpeq$',
+ u'\u224f': '$\\bumpeq$',
+ u'\u2250': '$\\doteq$',
+ u'\u2251': '$\\doteqdot$',
+ u'\u2252': '$\\fallingdotseq$',
+ u'\u2253': '$\\risingdotseq$',
+ u'\u2254': '{:=}',
+ u'\u2255': '$=:$',
+ u'\u2256': '$\\eqcirc$',
+ u'\u2257': '$\\circeq$',
+ u'\u2259': '$\\estimates$',
+ u'\u225a': '$\\ElsevierGlyph{225A}$',
+ u'\u225b': '$\\starequal$',
+ u'\u225c': '$\\triangleq$',
+ u'\u225f': '$\\ElsevierGlyph{225F}$',
+ u'\u2260': '$\\not =$',
+ u'\u2261': '$\\equiv$',
+ u'\u2262': '$\\not\\equiv$',
+ u'\u2264': '$\\leq$',
+ u'\u2265': '$\\geq$',
+ u'\u2266': '$\\leqq$',
+ u'\u2267': '$\\geqq$',
+ u'\u2268': '$\\lneqq$',
+ u'\u2269': '$\\gneqq$',
+ u'\u226a': '$\\ll$',
+ u'\u226b': '$\\gg$',
+ u'\u226c': '$\\between$',
+ u'\u226d': '$\\not\\kern-0.3em\\times$',
+ u'\u226e': '$\\not<$',
+ u'\u226f': '$\\not>$',
+ u'\u2270': '$\\not\\leq$',
+ u'\u2271': '$\\not\\geq$',
+ u'\u2272': '$\\lessequivlnt$',
+ u'\u2273': '$\\greaterequivlnt$',
+ u'\u2274': '$\\ElsevierGlyph{2274}$',
+ u'\u2275': '$\\ElsevierGlyph{2275}$',
+ u'\u2276': '$\\lessgtr$',
+ u'\u2277': '$\\gtrless$',
+ u'\u2278': '$\\notlessgreater$',
+ u'\u2279': '$\\notgreaterless$',
+ u'\u227a': '$\\prec$',
+ u'\u227b': '$\\succ$',
+ u'\u227c': '$\\preccurlyeq$',
+ u'\u227d': '$\\succcurlyeq$',
+ u'\u227e': '$\\precapprox$',
+ u'\u227f': '$\\succapprox$',
+ u'\u2280': '$\\not\\prec$',
+ u'\u2281': '$\\not\\succ$',
+ u'\u2282': '$\\subset$',
+ u'\u2283': '$\\supset$',
+ u'\u2284': '$\\not\\subset$',
+ u'\u2285': '$\\not\\supset$',
+ u'\u2286': '$\\subseteq$',
+ u'\u2287': '$\\supseteq$',
+ u'\u2288': '$\\not\\subseteq$',
+ u'\u2289': '$\\not\\supseteq$',
+ u'\u228a': '$\\subsetneq$',
+ u'\u228b': '$\\supsetneq$',
+ u'\u228e': '$\\uplus$',
+ u'\u228f': '$\\sqsubset$',
+ u'\u2290': '$\\sqsupset$',
+ u'\u2291': '$\\sqsubseteq$',
+ u'\u2292': '$\\sqsupseteq$',
+ u'\u2293': '$\\sqcap$',
+ u'\u2294': '$\\sqcup$',
+ u'\u2295': '$\\oplus$',
+ u'\u2296': '$\\ominus$',
+ u'\u2297': '$\\otimes$',
+ u'\u2298': '$\\oslash$',
+ u'\u2299': '$\\odot$',
+ u'\u229a': '$\\circledcirc$',
+ u'\u229b': '$\\circledast$',
+ u'\u229d': '$\\circleddash$',
+ u'\u229e': '$\\boxplus$',
+ u'\u229f': '$\\boxminus$',
+ u'\u22a0': '$\\boxtimes$',
+ u'\u22a1': '$\\boxdot$',
+ u'\u22a2': '$\\vdash$',
+ u'\u22a3': '$\\dashv$',
+ u'\u22a4': '$\\top$',
+ u'\u22a5': '$\\perp$',
+ u'\u22a7': '$\\truestate$',
+ u'\u22a8': '$\\forcesextra$',
+ u'\u22a9': '$\\Vdash$',
+ u'\u22aa': '$\\Vvdash$',
+ u'\u22ab': '$\\VDash$',
+ u'\u22ac': '$\\nvdash$',
+ u'\u22ad': '$\\nvDash$',
+ u'\u22ae': '$\\nVdash$',
+ u'\u22af': '$\\nVDash$',
+ u'\u22b2': '$\\vartriangleleft$',
+ u'\u22b3': '$\\vartriangleright$',
+ u'\u22b4': '$\\trianglelefteq$',
+ u'\u22b5': '$\\trianglerighteq$',
+ u'\u22b6': '$\\original$',
+ u'\u22b7': '$\\image$',
+ u'\u22b8': '$\\multimap$',
+ u'\u22b9': '$\\hermitconjmatrix$',
+ u'\u22ba': '$\\intercal$',
+ u'\u22bb': '$\\veebar$',
+ u'\u22be': '$\\rightanglearc$',
+ u'\u22c0': '$\\ElsevierGlyph{22C0}$',
+ u'\u22c1': '$\\ElsevierGlyph{22C1}$',
+ u'\u22c2': '$\\bigcap$',
+ u'\u22c3': '$\\bigcup$',
+ u'\u22c4': '$\\diamond$',
+ u'\u22c5': '$\\cdot$',
+ u'\u22c6': '$\\star$',
+ u'\u22c7': '$\\divideontimes$',
+ u'\u22c8': '$\\bowtie$',
+ u'\u22c9': '$\\ltimes$',
+ u'\u22ca': '$\\rtimes$',
+ u'\u22cb': '$\\leftthreetimes$',
+ u'\u22cc': '$\\rightthreetimes$',
+ u'\u22cd': '$\\backsimeq$',
+ u'\u22ce': '$\\curlyvee$',
+ u'\u22cf': '$\\curlywedge$',
+ u'\u22d0': '$\\Subset$',
+ u'\u22d1': '$\\Supset$',
+ u'\u22d2': '$\\Cap$',
+ u'\u22d3': '$\\Cup$',
+ u'\u22d4': '$\\pitchfork$',
+ u'\u22d6': '$\\lessdot$',
+ u'\u22d7': '$\\gtrdot$',
+ u'\u22d8': '$\\verymuchless$',
+ u'\u22d9': '$\\verymuchgreater$',
+ u'\u22da': '$\\lesseqgtr$',
+ u'\u22db': '$\\gtreqless$',
+ u'\u22de': '$\\curlyeqprec$',
+ u'\u22df': '$\\curlyeqsucc$',
+ u'\u22e2': '$\\not\\sqsubseteq$',
+ u'\u22e3': '$\\not\\sqsupseteq$',
+ u'\u22e5': '$\\Elzsqspne$',
+ u'\u22e6': '$\\lnsim$',
+ u'\u22e7': '$\\gnsim$',
+ u'\u22e8': '$\\precedesnotsimilar$',
+ u'\u22e9': '$\\succnsim$',
+ u'\u22ea': '$\\ntriangleleft$',
+ u'\u22eb': '$\\ntriangleright$',
+ u'\u22ec': '$\\ntrianglelefteq$',
+ u'\u22ed': '$\\ntrianglerighteq$',
+ u'\u22ee': '$\\vdots$',
+ u'\u22ef': '$\\cdots$',
+ u'\u22f0': '$\\upslopeellipsis$',
+ u'\u22f1': '$\\downslopeellipsis$',
+ u'\u2305': '{\\barwedge}',
+ u'\u2306': '$\\perspcorrespond$',
+ u'\u2308': '$\\lceil$',
+ u'\u2309': '$\\rceil$',
+ u'\u230a': '$\\lfloor$',
+ u'\u230b': '$\\rfloor$',
+ u'\u2315': '$\\recorder$',
+ u'\u2316': '$\\mathchar"2208$',
+ u'\u231c': '$\\ulcorner$',
+ u'\u231d': '$\\urcorner$',
+ u'\u231e': '$\\llcorner$',
+ u'\u231f': '$\\lrcorner$',
+ u'\u2322': '$\\frown$',
+ u'\u2323': '$\\smile$',
+ u'\u2329': '$\\langle$',
+ u'\u232a': '$\\rangle$',
+ u'\u233d': '$\\ElsevierGlyph{E838}$',
+ u'\u23a3': '$\\Elzdlcorn$',
+ u'\u23b0': '$\\lmoustache$',
+ u'\u23b1': '$\\rmoustache$',
+ u'\u2423': '{\\textvisiblespace}',
+ u'\u2460': '{\\ding{172}}',
+ u'\u2461': '{\\ding{173}}',
+ u'\u2462': '{\\ding{174}}',
+ u'\u2463': '{\\ding{175}}',
+ u'\u2464': '{\\ding{176}}',
+ u'\u2465': '{\\ding{177}}',
+ u'\u2466': '{\\ding{178}}',
+ u'\u2467': '{\\ding{179}}',
+ u'\u2468': '{\\ding{180}}',
+ u'\u2469': '{\\ding{181}}',
+ u'\u24c8': '$\\circledS$',
+ u'\u2506': '$\\Elzdshfnc$',
+ u'\u2519': '$\\Elzsqfnw$',
+ u'\u2571': '$\\diagup$',
+ u'\u25a0': '{\\ding{110}}',
+ u'\u25a1': '$\\square$',
+ u'\u25aa': '$\\blacksquare$',
+ u'\u25ad': '$\\fbox{~~}$',
+ u'\u25af': '$\\Elzvrecto$',
+ u'\u25b1': '$\\ElsevierGlyph{E381}$',
+ u'\u25b2': '{\\ding{115}}',
+ u'\u25b3': '$\\bigtriangleup$',
+ u'\u25b4': '$\\blacktriangle$',
+ u'\u25b5': '$\\vartriangle$',
+ u'\u25b8': '$\\blacktriangleright$',
+ u'\u25b9': '$\\triangleright$',
+ u'\u25bc': '{\\ding{116}}',
+ u'\u25bd': '$\\bigtriangledown$',
+ u'\u25be': '$\\blacktriangledown$',
+ u'\u25bf': '$\\triangledown$',
+ u'\u25c2': '$\\blacktriangleleft$',
+ u'\u25c3': '$\\triangleleft$',
+ u'\u25c6': '{\\ding{117}}',
+ u'\u25ca': '$\\lozenge$',
+ u'\u25cb': '$\\bigcirc$',
+ u'\u25cf': '{\\ding{108}}',
+ u'\u25d0': '$\\Elzcirfl$',
+ u'\u25d1': '$\\Elzcirfr$',
+ u'\u25d2': '$\\Elzcirfb$',
+ u'\u25d7': '{\\ding{119}}',
+ u'\u25d8': '$\\Elzrvbull$',
+ u'\u25e7': '$\\Elzsqfl$',
+ u'\u25e8': '$\\Elzsqfr$',
+ u'\u25ea': '$\\Elzsqfse$',
+ u'\u25ef': '$\\bigcirc$',
+ u'\u2605': '{\\ding{72}}',
+ u'\u2606': '{\\ding{73}}',
+ u'\u260e': '{\\ding{37}}',
+ u'\u261b': '{\\ding{42}}',
+ u'\u261e': '{\\ding{43}}',
+ u'\u263e': '{\\rightmoon}',
+ u'\u263f': '{\\mercury}',
+ u'\u2640': '{\\venus}',
+ u'\u2642': '{\\male}',
+ u'\u2643': '{\\jupiter}',
+ u'\u2644': '{\\saturn}',
+ u'\u2645': '{\\uranus}',
+ u'\u2646': '{\\neptune}',
+ u'\u2647': '{\\pluto}',
+ u'\u2648': '{\\aries}',
+ u'\u2649': '{\\taurus}',
+ u'\u264a': '{\\gemini}',
+ u'\u264b': '{\\cancer}',
+ u'\u264c': '{\\leo}',
+ u'\u264d': '{\\virgo}',
+ u'\u264e': '{\\libra}',
+ u'\u264f': '{\\scorpio}',
+ u'\u2650': '{\\sagittarius}',
+ u'\u2651': '{\\capricornus}',
+ u'\u2652': '{\\aquarius}',
+ u'\u2653': '{\\pisces}',
+ u'\u2660': '{\\ding{171}}',
+ u'\u2662': '$\\diamond$',
+ u'\u2663': '{\\ding{168}}',
+ u'\u2665': '{\\ding{170}}',
+ u'\u2666': '{\\ding{169}}',
+ u'\u2669': '{\\quarternote}',
+ u'\u266a': '{\\eighthnote}',
+ u'\u266d': '$\\flat$',
+ u'\u266e': '$\\natural$',
+ u'\u266f': '$\\sharp$',
+ u'\u2701': '{\\ding{33}}',
+ u'\u2702': '{\\ding{34}}',
+ u'\u2703': '{\\ding{35}}',
+ u'\u2704': '{\\ding{36}}',
+ u'\u2706': '{\\ding{38}}',
+ u'\u2707': '{\\ding{39}}',
+ u'\u2708': '{\\ding{40}}',
+ u'\u2709': '{\\ding{41}}',
+ u'\u270c': '{\\ding{44}}',
+ u'\u270d': '{\\ding{45}}',
+ u'\u270e': '{\\ding{46}}',
+ u'\u270f': '{\\ding{47}}',
+ u'\u2710': '{\\ding{48}}',
+ u'\u2711': '{\\ding{49}}',
+ u'\u2712': '{\\ding{50}}',
+ u'\u2713': '{\\ding{51}}',
+ u'\u2714': '{\\ding{52}}',
+ u'\u2715': '{\\ding{53}}',
+ u'\u2716': '{\\ding{54}}',
+ u'\u2717': '{\\ding{55}}',
+ u'\u2718': '{\\ding{56}}',
+ u'\u2719': '{\\ding{57}}',
+ u'\u271a': '{\\ding{58}}',
+ u'\u271b': '{\\ding{59}}',
+ u'\u271c': '{\\ding{60}}',
+ u'\u271d': '{\\ding{61}}',
+ u'\u271e': '{\\ding{62}}',
+ u'\u271f': '{\\ding{63}}',
+ u'\u2720': '{\\ding{64}}',
+ u'\u2721': '{\\ding{65}}',
+ u'\u2722': '{\\ding{66}}',
+ u'\u2723': '{\\ding{67}}',
+ u'\u2724': '{\\ding{68}}',
+ u'\u2725': '{\\ding{69}}',
+ u'\u2726': '{\\ding{70}}',
+ u'\u2727': '{\\ding{71}}',
+ u'\u2729': '{\\ding{73}}',
+ u'\u272a': '{\\ding{74}}',
+ u'\u272b': '{\\ding{75}}',
+ u'\u272c': '{\\ding{76}}',
+ u'\u272d': '{\\ding{77}}',
+ u'\u272e': '{\\ding{78}}',
+ u'\u272f': '{\\ding{79}}',
+ u'\u2730': '{\\ding{80}}',
+ u'\u2731': '{\\ding{81}}',
+ u'\u2732': '{\\ding{82}}',
+ u'\u2733': '{\\ding{83}}',
+ u'\u2734': '{\\ding{84}}',
+ u'\u2735': '{\\ding{85}}',
+ u'\u2736': '{\\ding{86}}',
+ u'\u2737': '{\\ding{87}}',
+ u'\u2738': '{\\ding{88}}',
+ u'\u2739': '{\\ding{89}}',
+ u'\u273a': '{\\ding{90}}',
+ u'\u273b': '{\\ding{91}}',
+ u'\u273c': '{\\ding{92}}',
+ u'\u273d': '{\\ding{93}}',
+ u'\u273e': '{\\ding{94}}',
+ u'\u273f': '{\\ding{95}}',
+ u'\u2740': '{\\ding{96}}',
+ u'\u2741': '{\\ding{97}}',
+ u'\u2742': '{\\ding{98}}',
+ u'\u2743': '{\\ding{99}}',
+ u'\u2744': '{\\ding{100}}',
+ u'\u2745': '{\\ding{101}}',
+ u'\u2746': '{\\ding{102}}',
+ u'\u2747': '{\\ding{103}}',
+ u'\u2748': '{\\ding{104}}',
+ u'\u2749': '{\\ding{105}}',
+ u'\u274a': '{\\ding{106}}',
+ u'\u274b': '{\\ding{107}}',
+ u'\u274d': '{\\ding{109}}',
+ u'\u274f': '{\\ding{111}}',
+ u'\u2750': '{\\ding{112}}',
+ u'\u2751': '{\\ding{113}}',
+ u'\u2752': '{\\ding{114}}',
+ u'\u2756': '{\\ding{118}}',
+ u'\u2758': '{\\ding{120}}',
+ u'\u2759': '{\\ding{121}}',
+ u'\u275a': '{\\ding{122}}',
+ u'\u275b': '{\\ding{123}}',
+ u'\u275c': '{\\ding{124}}',
+ u'\u275d': '{\\ding{125}}',
+ u'\u275e': '{\\ding{126}}',
+ u'\u2761': '{\\ding{161}}',
+ u'\u2762': '{\\ding{162}}',
+ u'\u2763': '{\\ding{163}}',
+ u'\u2764': '{\\ding{164}}',
+ u'\u2765': '{\\ding{165}}',
+ u'\u2766': '{\\ding{166}}',
+ u'\u2767': '{\\ding{167}}',
+ u'\u2776': '{\\ding{182}}',
+ u'\u2777': '{\\ding{183}}',
+ u'\u2778': '{\\ding{184}}',
+ u'\u2779': '{\\ding{185}}',
+ u'\u277a': '{\\ding{186}}',
+ u'\u277b': '{\\ding{187}}',
+ u'\u277c': '{\\ding{188}}',
+ u'\u277d': '{\\ding{189}}',
+ u'\u277e': '{\\ding{190}}',
+ u'\u277f': '{\\ding{191}}',
+ u'\u2780': '{\\ding{192}}',
+ u'\u2781': '{\\ding{193}}',
+ u'\u2782': '{\\ding{194}}',
+ u'\u2783': '{\\ding{195}}',
+ u'\u2784': '{\\ding{196}}',
+ u'\u2785': '{\\ding{197}}',
+ u'\u2786': '{\\ding{198}}',
+ u'\u2787': '{\\ding{199}}',
+ u'\u2788': '{\\ding{200}}',
+ u'\u2789': '{\\ding{201}}',
+ u'\u278a': '{\\ding{202}}',
+ u'\u278b': '{\\ding{203}}',
+ u'\u278c': '{\\ding{204}}',
+ u'\u278d': '{\\ding{205}}',
+ u'\u278e': '{\\ding{206}}',
+ u'\u278f': '{\\ding{207}}',
+ u'\u2790': '{\\ding{208}}',
+ u'\u2791': '{\\ding{209}}',
+ u'\u2792': '{\\ding{210}}',
+ u'\u2793': '{\\ding{211}}',
+ u'\u2794': '{\\ding{212}}',
+ u'\u2798': '{\\ding{216}}',
+ u'\u2799': '{\\ding{217}}',
+ u'\u279a': '{\\ding{218}}',
+ u'\u279b': '{\\ding{219}}',
+ u'\u279c': '{\\ding{220}}',
+ u'\u279d': '{\\ding{221}}',
+ u'\u279e': '{\\ding{222}}',
+ u'\u279f': '{\\ding{223}}',
+ u'\u27a0': '{\\ding{224}}',
+ u'\u27a1': '{\\ding{225}}',
+ u'\u27a2': '{\\ding{226}}',
+ u'\u27a3': '{\\ding{227}}',
+ u'\u27a4': '{\\ding{228}}',
+ u'\u27a5': '{\\ding{229}}',
+ u'\u27a6': '{\\ding{230}}',
+ u'\u27a7': '{\\ding{231}}',
+ u'\u27a8': '{\\ding{232}}',
+ u'\u27a9': '{\\ding{233}}',
+ u'\u27aa': '{\\ding{234}}',
+ u'\u27ab': '{\\ding{235}}',
+ u'\u27ac': '{\\ding{236}}',
+ u'\u27ad': '{\\ding{237}}',
+ u'\u27ae': '{\\ding{238}}',
+ u'\u27af': '{\\ding{239}}',
+ u'\u27b1': '{\\ding{241}}',
+ u'\u27b2': '{\\ding{242}}',
+ u'\u27b3': '{\\ding{243}}',
+ u'\u27b4': '{\\ding{244}}',
+ u'\u27b5': '{\\ding{245}}',
+ u'\u27b6': '{\\ding{246}}',
+ u'\u27b7': '{\\ding{247}}',
+ u'\u27b8': '{\\ding{248}}',
+ u'\u27b9': '{\\ding{249}}',
+ u'\u27ba': '{\\ding{250}}',
+ u'\u27bb': '{\\ding{251}}',
+ u'\u27bc': '{\\ding{252}}',
+ u'\u27bd': '{\\ding{253}}',
+ u'\u27be': '{\\ding{254}}',
+ u'\u27f5': '$\\longleftarrow$',
+ u'\u27f6': '$\\longrightarrow$',
+ u'\u27f7': '$\\longleftrightarrow$',
+ u'\u27f8': '$\\Longleftarrow$',
+ u'\u27f9': '$\\Longrightarrow$',
+ u'\u27fa': '$\\Longleftrightarrow$',
+ u'\u27fc': '$\\longmapsto$',
+ u'\u27ff': '$\\sim\\joinrel\\leadsto$',
+ u'\u2905': '$\\ElsevierGlyph{E212}$',
+ u'\u2912': '$\\UpArrowBar$',
+ u'\u2913': '$\\DownArrowBar$',
+ u'\u2923': '$\\ElsevierGlyph{E20C}$',
+ u'\u2924': '$\\ElsevierGlyph{E20D}$',
+ u'\u2925': '$\\ElsevierGlyph{E20B}$',
+ u'\u2926': '$\\ElsevierGlyph{E20A}$',
+ u'\u2927': '$\\ElsevierGlyph{E211}$',
+ u'\u2928': '$\\ElsevierGlyph{E20E}$',
+ u'\u2929': '$\\ElsevierGlyph{E20F}$',
+ u'\u292a': '$\\ElsevierGlyph{E210}$',
+ u'\u2933': '$\\ElsevierGlyph{E21C}$',
+ u'\u2936': '$\\ElsevierGlyph{E21A}$',
+ u'\u2937': '$\\ElsevierGlyph{E219}$',
+ u'\u2940': '$\\Elolarr$',
+ u'\u2941': '$\\Elorarr$',
+ u'\u2942': '$\\ElzRlarr$',
+ u'\u2944': '$\\ElzrLarr$',
+ u'\u2947': '$\\Elzrarrx$',
+ u'\u294e': '$\\LeftRightVector$',
+ u'\u294f': '$\\RightUpDownVector$',
+ u'\u2950': '$\\DownLeftRightVector$',
+ u'\u2951': '$\\LeftUpDownVector$',
+ u'\u2952': '$\\LeftVectorBar$',
+ u'\u2953': '$\\RightVectorBar$',
+ u'\u2954': '$\\RightUpVectorBar$',
+ u'\u2955': '$\\RightDownVectorBar$',
+ u'\u2956': '$\\DownLeftVectorBar$',
+ u'\u2957': '$\\DownRightVectorBar$',
+ u'\u2958': '$\\LeftUpVectorBar$',
+ u'\u2959': '$\\LeftDownVectorBar$',
+ u'\u295a': '$\\LeftTeeVector$',
+ u'\u295b': '$\\RightTeeVector$',
+ u'\u295c': '$\\RightUpTeeVector$',
+ u'\u295d': '$\\RightDownTeeVector$',
+ u'\u295e': '$\\DownLeftTeeVector$',
+ u'\u295f': '$\\DownRightTeeVector$',
+ u'\u2960': '$\\LeftUpTeeVector$',
+ u'\u2961': '$\\LeftDownTeeVector$',
+ u'\u296e': '$\\UpEquilibrium$',
+ u'\u296f': '$\\ReverseUpEquilibrium$',
+ u'\u2970': '$\\RoundImplies$',
+ u'\u297c': '$\\ElsevierGlyph{E214}$',
+ u'\u297d': '$\\ElsevierGlyph{E215}$',
+ u'\u2980': '$\\Elztfnc$',
+ u'\u2985': '$\\ElsevierGlyph{3018}$',
+ u'\u2986': '$\\Elroang$',
+ u'\u2993': '$<\\kern-0.58em($',
+ u'\u2994': '$\\ElsevierGlyph{E291}$',
+ u'\u2999': '$\\Elzddfnc$',
+ u'\u299c': '$\\Angle$',
+ u'\u29a0': '$\\Elzlpargt$',
+ u'\u29b5': '$\\ElsevierGlyph{E260}$',
+ u'\u29b6': '$\\ElsevierGlyph{E61B}$',
+ u'\u29ca': '$\\ElzLap$',
+ u'\u29cb': '$\\Elzdefas$',
+ u'\u29cf': '$\\LeftTriangleBar$',
+ u'\u29d0': '$\\RightTriangleBar$',
+ u'\u29dc': '$\\ElsevierGlyph{E372}$',
+ u'\u29eb': '$\\blacklozenge$',
+ u'\u29f4': '$\\RuleDelayed$',
+ u'\u2a04': '$\\Elxuplus$',
+ u'\u2a05': '$\\ElzThr$',
+ u'\u2a06': '$\\Elxsqcup$',
+ u'\u2a07': '$\\ElzInf$',
+ u'\u2a08': '$\\ElzSup$',
+ u'\u2a0d': '$\\ElzCint$',
+ u'\u2a0f': '$\\clockoint$',
+ u'\u2a10': '$\\ElsevierGlyph{E395}$',
+ u'\u2a16': '$\\sqrint$',
+ u'\u2a25': '$\\ElsevierGlyph{E25A}$',
+ u'\u2a2a': '$\\ElsevierGlyph{E25B}$',
+ u'\u2a2d': '$\\ElsevierGlyph{E25C}$',
+ u'\u2a2e': '$\\ElsevierGlyph{E25D}$',
+ u'\u2a2f': '$\\ElzTimes$',
+ u'\u2a34': '$\\ElsevierGlyph{E25E}$',
+ u'\u2a35': '$\\ElsevierGlyph{E25E}$',
+ u'\u2a3c': '$\\ElsevierGlyph{E259}$',
+ u'\u2a3f': '$\\amalg$',
+ u'\u2a53': '$\\ElzAnd$',
+ u'\u2a54': '$\\ElzOr$',
+ u'\u2a55': '$\\ElsevierGlyph{E36E}$',
+ u'\u2a56': '$\\ElOr$',
+ u'\u2a5e': '$\\perspcorrespond$',
+ u'\u2a5f': '$\\Elzminhat$',
+ u'\u2a63': '$\\ElsevierGlyph{225A}$',
+ u'\u2a6e': '$\\stackrel{*}{=}$',
+ u'\u2a75': '$\\Equal$',
+ u'\u2a7d': '$\\leqslant$',
+ u'\u2a7e': '$\\geqslant$',
+ u'\u2a85': '$\\lessapprox$',
+ u'\u2a86': '$\\gtrapprox$',
+ u'\u2a87': '$\\lneq$',
+ u'\u2a88': '$\\gneq$',
+ u'\u2a89': '$\\lnapprox$',
+ u'\u2a8a': '$\\gnapprox$',
+ u'\u2a8b': '$\\lesseqqgtr$',
+ u'\u2a8c': '$\\gtreqqless$',
+ u'\u2a95': '$\\eqslantless$',
+ u'\u2a96': '$\\eqslantgtr$',
+ u'\u2a9d': '$\\Pisymbol{ppi020}{117}$',
+ u'\u2a9e': '$\\Pisymbol{ppi020}{105}$',
+ u'\u2aa1': '$\\NestedLessLess$',
+ u'\u2aa2': '$\\NestedGreaterGreater$',
+ u'\u2aaf': '$\\preceq$',
+ u'\u2ab0': '$\\succeq$',
+ u'\u2ab5': '$\\precneqq$',
+ u'\u2ab6': '$\\succneqq$',
+ u'\u2ab7': '$\\precapprox$',
+ u'\u2ab8': '$\\succapprox$',
+ u'\u2ab9': '$\\precnapprox$',
+ u'\u2aba': '$\\succnapprox$',
+ u'\u2ac5': '$\\subseteqq$',
+ u'\u2ac6': '$\\supseteqq$',
+ u'\u2acb': '$\\subsetneqq$',
+ u'\u2acc': '$\\supsetneqq$',
+ u'\u2aeb': '$\\ElsevierGlyph{E30D}$',
+ u'\u2af6': '$\\Elztdcol$',
+ u'\u2afd': '${{/}\\!\\!{/}}$',
+ u'\u300a': '$\\ElsevierGlyph{300A}$',
+ u'\u300b': '$\\ElsevierGlyph{300B}$',
+ u'\u3018': '$\\ElsevierGlyph{3018}$',
+ u'\u3019': '$\\ElsevierGlyph{3019}$',
+ u'\u301a': '$\\openbracketleft$',
+ u'\u301b': '$\\openbracketright$',
+ u'\ufb00': '{ff}',
+ u'\ufb01': '{fi}',
+ u'\ufb02': '{fl}',
+ u'\ufb03': '{ffi}',
+ u'\ufb04': '{ffl}',
+ u'\U0001d400': '$\\mathbf{A}$',
+ u'\U0001d401': '$\\mathbf{B}$',
+ u'\U0001d402': '$\\mathbf{C}$',
+ u'\U0001d403': '$\\mathbf{D}$',
+ u'\U0001d404': '$\\mathbf{E}$',
+ u'\U0001d405': '$\\mathbf{F}$',
+ u'\U0001d406': '$\\mathbf{G}$',
+ u'\U0001d407': '$\\mathbf{H}$',
+ u'\U0001d408': '$\\mathbf{I}$',
+ u'\U0001d409': '$\\mathbf{J}$',
+ u'\U0001d40a': '$\\mathbf{K}$',
+ u'\U0001d40b': '$\\mathbf{L}$',
+ u'\U0001d40c': '$\\mathbf{M}$',
+ u'\U0001d40d': '$\\mathbf{N}$',
+ u'\U0001d40e': '$\\mathbf{O}$',
+ u'\U0001d40f': '$\\mathbf{P}$',
+ u'\U0001d410': '$\\mathbf{Q}$',
+ u'\U0001d411': '$\\mathbf{R}$',
+ u'\U0001d412': '$\\mathbf{S}$',
+ u'\U0001d413': '$\\mathbf{T}$',
+ u'\U0001d414': '$\\mathbf{U}$',
+ u'\U0001d415': '$\\mathbf{V}$',
+ u'\U0001d416': '$\\mathbf{W}$',
+ u'\U0001d417': '$\\mathbf{X}$',
+ u'\U0001d418': '$\\mathbf{Y}$',
+ u'\U0001d419': '$\\mathbf{Z}$',
+ u'\U0001d41a': '$\\mathbf{a}$',
+ u'\U0001d41b': '$\\mathbf{b}$',
+ u'\U0001d41c': '$\\mathbf{c}$',
+ u'\U0001d41d': '$\\mathbf{d}$',
+ u'\U0001d41e': '$\\mathbf{e}$',
+ u'\U0001d41f': '$\\mathbf{f}$',
+ u'\U0001d420': '$\\mathbf{g}$',
+ u'\U0001d421': '$\\mathbf{h}$',
+ u'\U0001d422': '$\\mathbf{i}$',
+ u'\U0001d423': '$\\mathbf{j}$',
+ u'\U0001d424': '$\\mathbf{k}$',
+ u'\U0001d425': '$\\mathbf{l}$',
+ u'\U0001d426': '$\\mathbf{m}$',
+ u'\U0001d427': '$\\mathbf{n}$',
+ u'\U0001d428': '$\\mathbf{o}$',
+ u'\U0001d429': '$\\mathbf{p}$',
+ u'\U0001d42a': '$\\mathbf{q}$',
+ u'\U0001d42b': '$\\mathbf{r}$',
+ u'\U0001d42c': '$\\mathbf{s}$',
+ u'\U0001d42d': '$\\mathbf{t}$',
+ u'\U0001d42e': '$\\mathbf{u}$',
+ u'\U0001d42f': '$\\mathbf{v}$',
+ u'\U0001d430': '$\\mathbf{w}$',
+ u'\U0001d431': '$\\mathbf{x}$',
+ u'\U0001d432': '$\\mathbf{y}$',
+ u'\U0001d433': '$\\mathbf{z}$',
+ u'\U0001d434': '$\\mathsl{A}$',
+ u'\U0001d435': '$\\mathsl{B}$',
+ u'\U0001d436': '$\\mathsl{C}$',
+ u'\U0001d437': '$\\mathsl{D}$',
+ u'\U0001d438': '$\\mathsl{E}$',
+ u'\U0001d439': '$\\mathsl{F}$',
+ u'\U0001d43a': '$\\mathsl{G}$',
+ u'\U0001d43b': '$\\mathsl{H}$',
+ u'\U0001d43c': '$\\mathsl{I}$',
+ u'\U0001d43d': '$\\mathsl{J}$',
+ u'\U0001d43e': '$\\mathsl{K}$',
+ u'\U0001d43f': '$\\mathsl{L}$',
+ u'\U0001d440': '$\\mathsl{M}$',
+ u'\U0001d441': '$\\mathsl{N}$',
+ u'\U0001d442': '$\\mathsl{O}$',
+ u'\U0001d443': '$\\mathsl{P}$',
+ u'\U0001d444': '$\\mathsl{Q}$',
+ u'\U0001d445': '$\\mathsl{R}$',
+ u'\U0001d446': '$\\mathsl{S}$',
+ u'\U0001d447': '$\\mathsl{T}$',
+ u'\U0001d448': '$\\mathsl{U}$',
+ u'\U0001d449': '$\\mathsl{V}$',
+ u'\U0001d44a': '$\\mathsl{W}$',
+ u'\U0001d44b': '$\\mathsl{X}$',
+ u'\U0001d44c': '$\\mathsl{Y}$',
+ u'\U0001d44d': '$\\mathsl{Z}$',
+ u'\U0001d44e': '$\\mathsl{a}$',
+ u'\U0001d44f': '$\\mathsl{b}$',
+ u'\U0001d450': '$\\mathsl{c}$',
+ u'\U0001d451': '$\\mathsl{d}$',
+ u'\U0001d452': '$\\mathsl{e}$',
+ u'\U0001d453': '$\\mathsl{f}$',
+ u'\U0001d454': '$\\mathsl{g}$',
+ u'\U0001d456': '$\\mathsl{i}$',
+ u'\U0001d457': '$\\mathsl{j}$',
+ u'\U0001d458': '$\\mathsl{k}$',
+ u'\U0001d459': '$\\mathsl{l}$',
+ u'\U0001d45a': '$\\mathsl{m}$',
+ u'\U0001d45b': '$\\mathsl{n}$',
+ u'\U0001d45c': '$\\mathsl{o}$',
+ u'\U0001d45d': '$\\mathsl{p}$',
+ u'\U0001d45e': '$\\mathsl{q}$',
+ u'\U0001d45f': '$\\mathsl{r}$',
+ u'\U0001d460': '$\\mathsl{s}$',
+ u'\U0001d461': '$\\mathsl{t}$',
+ u'\U0001d462': '$\\mathsl{u}$',
+ u'\U0001d463': '$\\mathsl{v}$',
+ u'\U0001d464': '$\\mathsl{w}$',
+ u'\U0001d465': '$\\mathsl{x}$',
+ u'\U0001d466': '$\\mathsl{y}$',
+ u'\U0001d467': '$\\mathsl{z}$',
+ u'\U0001d468': '$\\mathbit{A}$',
+ u'\U0001d469': '$\\mathbit{B}$',
+ u'\U0001d46a': '$\\mathbit{C}$',
+ u'\U0001d46b': '$\\mathbit{D}$',
+ u'\U0001d46c': '$\\mathbit{E}$',
+ u'\U0001d46d': '$\\mathbit{F}$',
+ u'\U0001d46e': '$\\mathbit{G}$',
+ u'\U0001d46f': '$\\mathbit{H}$',
+ u'\U0001d470': '$\\mathbit{I}$',
+ u'\U0001d471': '$\\mathbit{J}$',
+ u'\U0001d472': '$\\mathbit{K}$',
+ u'\U0001d473': '$\\mathbit{L}$',
+ u'\U0001d474': '$\\mathbit{M}$',
+ u'\U0001d475': '$\\mathbit{N}$',
+ u'\U0001d476': '$\\mathbit{O}$',
+ u'\U0001d477': '$\\mathbit{P}$',
+ u'\U0001d478': '$\\mathbit{Q}$',
+ u'\U0001d479': '$\\mathbit{R}$',
+ u'\U0001d47a': '$\\mathbit{S}$',
+ u'\U0001d47b': '$\\mathbit{T}$',
+ u'\U0001d47c': '$\\mathbit{U}$',
+ u'\U0001d47d': '$\\mathbit{V}$',
+ u'\U0001d47e': '$\\mathbit{W}$',
+ u'\U0001d47f': '$\\mathbit{X}$',
+ u'\U0001d480': '$\\mathbit{Y}$',
+ u'\U0001d481': '$\\mathbit{Z}$',
+ u'\U0001d482': '$\\mathbit{a}$',
+ u'\U0001d483': '$\\mathbit{b}$',
+ u'\U0001d484': '$\\mathbit{c}$',
+ u'\U0001d485': '$\\mathbit{d}$',
+ u'\U0001d486': '$\\mathbit{e}$',
+ u'\U0001d487': '$\\mathbit{f}$',
+ u'\U0001d488': '$\\mathbit{g}$',
+ u'\U0001d489': '$\\mathbit{h}$',
+ u'\U0001d48a': '$\\mathbit{i}$',
+ u'\U0001d48b': '$\\mathbit{j}$',
+ u'\U0001d48c': '$\\mathbit{k}$',
+ u'\U0001d48d': '$\\mathbit{l}$',
+ u'\U0001d48e': '$\\mathbit{m}$',
+ u'\U0001d48f': '$\\mathbit{n}$',
+ u'\U0001d490': '$\\mathbit{o}$',
+ u'\U0001d491': '$\\mathbit{p}$',
+ u'\U0001d492': '$\\mathbit{q}$',
+ u'\U0001d493': '$\\mathbit{r}$',
+ u'\U0001d494': '$\\mathbit{s}$',
+ u'\U0001d495': '$\\mathbit{t}$',
+ u'\U0001d496': '$\\mathbit{u}$',
+ u'\U0001d497': '$\\mathbit{v}$',
+ u'\U0001d498': '$\\mathbit{w}$',
+ u'\U0001d499': '$\\mathbit{x}$',
+ u'\U0001d49a': '$\\mathbit{y}$',
+ u'\U0001d49b': '$\\mathbit{z}$',
+ u'\U0001d49c': '$\\mathscr{A}$',
+ u'\U0001d49e': '$\\mathscr{C}$',
+ u'\U0001d49f': '$\\mathscr{D}$',
+ u'\U0001d4a2': '$\\mathscr{G}$',
+ u'\U0001d4a5': '$\\mathscr{J}$',
+ u'\U0001d4a6': '$\\mathscr{K}$',
+ u'\U0001d4a9': '$\\mathscr{N}$',
+ u'\U0001d4aa': '$\\mathscr{O}$',
+ u'\U0001d4ab': '$\\mathscr{P}$',
+ u'\U0001d4ac': '$\\mathscr{Q}$',
+ u'\U0001d4ae': '$\\mathscr{S}$',
+ u'\U0001d4af': '$\\mathscr{T}$',
+ u'\U0001d4b0': '$\\mathscr{U}$',
+ u'\U0001d4b1': '$\\mathscr{V}$',
+ u'\U0001d4b2': '$\\mathscr{W}$',
+ u'\U0001d4b3': '$\\mathscr{X}$',
+ u'\U0001d4b4': '$\\mathscr{Y}$',
+ u'\U0001d4b5': '$\\mathscr{Z}$',
+ u'\U0001d4b6': '$\\mathscr{a}$',
+ u'\U0001d4b7': '$\\mathscr{b}$',
+ u'\U0001d4b8': '$\\mathscr{c}$',
+ u'\U0001d4b9': '$\\mathscr{d}$',
+ u'\U0001d4bb': '$\\mathscr{f}$',
+ u'\U0001d4bd': '$\\mathscr{h}$',
+ u'\U0001d4be': '$\\mathscr{i}$',
+ u'\U0001d4bf': '$\\mathscr{j}$',
+ u'\U0001d4c0': '$\\mathscr{k}$',
+ u'\U0001d4c1': '$\\mathscr{l}$',
+ u'\U0001d4c2': '$\\mathscr{m}$',
+ u'\U0001d4c3': '$\\mathscr{n}$',
+ u'\U0001d4c5': '$\\mathscr{p}$',
+ u'\U0001d4c6': '$\\mathscr{q}$',
+ u'\U0001d4c7': '$\\mathscr{r}$',
+ u'\U0001d4c8': '$\\mathscr{s}$',
+ u'\U0001d4c9': '$\\mathscr{t}$',
+ u'\U0001d4ca': '$\\mathscr{u}$',
+ u'\U0001d4cb': '$\\mathscr{v}$',
+ u'\U0001d4cc': '$\\mathscr{w}$',
+ u'\U0001d4cd': '$\\mathscr{x}$',
+ u'\U0001d4ce': '$\\mathscr{y}$',
+ u'\U0001d4cf': '$\\mathscr{z}$',
+ u'\U0001d4d0': '$\\mathmit{A}$',
+ u'\U0001d4d1': '$\\mathmit{B}$',
+ u'\U0001d4d2': '$\\mathmit{C}$',
+ u'\U0001d4d3': '$\\mathmit{D}$',
+ u'\U0001d4d4': '$\\mathmit{E}$',
+ u'\U0001d4d5': '$\\mathmit{F}$',
+ u'\U0001d4d6': '$\\mathmit{G}$',
+ u'\U0001d4d7': '$\\mathmit{H}$',
+ u'\U0001d4d8': '$\\mathmit{I}$',
+ u'\U0001d4d9': '$\\mathmit{J}$',
+ u'\U0001d4da': '$\\mathmit{K}$',
+ u'\U0001d4db': '$\\mathmit{L}$',
+ u'\U0001d4dc': '$\\mathmit{M}$',
+ u'\U0001d4dd': '$\\mathmit{N}$',
+ u'\U0001d4de': '$\\mathmit{O}$',
+ u'\U0001d4df': '$\\mathmit{P}$',
+ u'\U0001d4e0': '$\\mathmit{Q}$',
+ u'\U0001d4e1': '$\\mathmit{R}$',
+ u'\U0001d4e2': '$\\mathmit{S}$',
+ u'\U0001d4e3': '$\\mathmit{T}$',
+ u'\U0001d4e4': '$\\mathmit{U}$',
+ u'\U0001d4e5': '$\\mathmit{V}$',
+ u'\U0001d4e6': '$\\mathmit{W}$',
+ u'\U0001d4e7': '$\\mathmit{X}$',
+ u'\U0001d4e8': '$\\mathmit{Y}$',
+ u'\U0001d4e9': '$\\mathmit{Z}$',
+ u'\U0001d4ea': '$\\mathmit{a}$',
+ u'\U0001d4eb': '$\\mathmit{b}$',
+ u'\U0001d4ec': '$\\mathmit{c}$',
+ u'\U0001d4ed': '$\\mathmit{d}$',
+ u'\U0001d4ee': '$\\mathmit{e}$',
+ u'\U0001d4ef': '$\\mathmit{f}$',
+ u'\U0001d4f0': '$\\mathmit{g}$',
+ u'\U0001d4f1': '$\\mathmit{h}$',
+ u'\U0001d4f2': '$\\mathmit{i}$',
+ u'\U0001d4f3': '$\\mathmit{j}$',
+ u'\U0001d4f4': '$\\mathmit{k}$',
+ u'\U0001d4f5': '$\\mathmit{l}$',
+ u'\U0001d4f6': '$\\mathmit{m}$',
+ u'\U0001d4f7': '$\\mathmit{n}$',
+ u'\U0001d4f8': '$\\mathmit{o}$',
+ u'\U0001d4f9': '$\\mathmit{p}$',
+ u'\U0001d4fa': '$\\mathmit{q}$',
+ u'\U0001d4fb': '$\\mathmit{r}$',
+ u'\U0001d4fc': '$\\mathmit{s}$',
+ u'\U0001d4fd': '$\\mathmit{t}$',
+ u'\U0001d4fe': '$\\mathmit{u}$',
+ u'\U0001d4ff': '$\\mathmit{v}$',
+ u'\U0001d500': '$\\mathmit{w}$',
+ u'\U0001d501': '$\\mathmit{x}$',
+ u'\U0001d502': '$\\mathmit{y}$',
+ u'\U0001d503': '$\\mathmit{z}$',
+ u'\U0001d504': '$\\mathfrak{A}$',
+ u'\U0001d505': '$\\mathfrak{B}$',
+ u'\U0001d507': '$\\mathfrak{D}$',
+ u'\U0001d508': '$\\mathfrak{E}$',
+ u'\U0001d509': '$\\mathfrak{F}$',
+ u'\U0001d50a': '$\\mathfrak{G}$',
+ u'\U0001d50d': '$\\mathfrak{J}$',
+ u'\U0001d50e': '$\\mathfrak{K}$',
+ u'\U0001d50f': '$\\mathfrak{L}$',
+ u'\U0001d510': '$\\mathfrak{M}$',
+ u'\U0001d511': '$\\mathfrak{N}$',
+ u'\U0001d512': '$\\mathfrak{O}$',
+ u'\U0001d513': '$\\mathfrak{P}$',
+ u'\U0001d514': '$\\mathfrak{Q}$',
+ u'\U0001d516': '$\\mathfrak{S}$',
+ u'\U0001d517': '$\\mathfrak{T}$',
+ u'\U0001d518': '$\\mathfrak{U}$',
+ u'\U0001d519': '$\\mathfrak{V}$',
+ u'\U0001d51a': '$\\mathfrak{W}$',
+ u'\U0001d51b': '$\\mathfrak{X}$',
+ u'\U0001d51c': '$\\mathfrak{Y}$',
+ u'\U0001d51e': '$\\mathfrak{a}$',
+ u'\U0001d51f': '$\\mathfrak{b}$',
+ u'\U0001d520': '$\\mathfrak{c}$',
+ u'\U0001d521': '$\\mathfrak{d}$',
+ u'\U0001d522': '$\\mathfrak{e}$',
+ u'\U0001d523': '$\\mathfrak{f}$',
+ u'\U0001d524': '$\\mathfrak{g}$',
+ u'\U0001d525': '$\\mathfrak{h}$',
+ u'\U0001d526': '$\\mathfrak{i}$',
+ u'\U0001d527': '$\\mathfrak{j}$',
+ u'\U0001d528': '$\\mathfrak{k}$',
+ u'\U0001d529': '$\\mathfrak{l}$',
+ u'\U0001d52a': '$\\mathfrak{m}$',
+ u'\U0001d52b': '$\\mathfrak{n}$',
+ u'\U0001d52c': '$\\mathfrak{o}$',
+ u'\U0001d52d': '$\\mathfrak{p}$',
+ u'\U0001d52e': '$\\mathfrak{q}$',
+ u'\U0001d52f': '$\\mathfrak{r}$',
+ u'\U0001d530': '$\\mathfrak{s}$',
+ u'\U0001d531': '$\\mathfrak{t}$',
+ u'\U0001d532': '$\\mathfrak{u}$',
+ u'\U0001d533': '$\\mathfrak{v}$',
+ u'\U0001d534': '$\\mathfrak{w}$',
+ u'\U0001d535': '$\\mathfrak{x}$',
+ u'\U0001d536': '$\\mathfrak{y}$',
+ u'\U0001d537': '$\\mathfrak{z}$',
+ u'\U0001d538': '$\\mathbb{A}$',
+ u'\U0001d539': '$\\mathbb{B}$',
+ u'\U0001d53b': '$\\mathbb{D}$',
+ u'\U0001d53c': '$\\mathbb{E}$',
+ u'\U0001d53d': '$\\mathbb{F}$',
+ u'\U0001d53e': '$\\mathbb{G}$',
+ u'\U0001d540': '$\\mathbb{I}$',
+ u'\U0001d541': '$\\mathbb{J}$',
+ u'\U0001d542': '$\\mathbb{K}$',
+ u'\U0001d543': '$\\mathbb{L}$',
+ u'\U0001d544': '$\\mathbb{M}$',
+ u'\U0001d546': '$\\mathbb{O}$',
+ u'\U0001d54a': '$\\mathbb{S}$',
+ u'\U0001d54b': '$\\mathbb{T}$',
+ u'\U0001d54c': '$\\mathbb{U}$',
+ u'\U0001d54d': '$\\mathbb{V}$',
+ u'\U0001d54e': '$\\mathbb{W}$',
+ u'\U0001d54f': '$\\mathbb{X}$',
+ u'\U0001d550': '$\\mathbb{Y}$',
+ u'\U0001d552': '$\\mathbb{a}$',
+ u'\U0001d553': '$\\mathbb{b}$',
+ u'\U0001d554': '$\\mathbb{c}$',
+ u'\U0001d555': '$\\mathbb{d}$',
+ u'\U0001d556': '$\\mathbb{e}$',
+ u'\U0001d557': '$\\mathbb{f}$',
+ u'\U0001d558': '$\\mathbb{g}$',
+ u'\U0001d559': '$\\mathbb{h}$',
+ u'\U0001d55a': '$\\mathbb{i}$',
+ u'\U0001d55b': '$\\mathbb{j}$',
+ u'\U0001d55c': '$\\mathbb{k}$',
+ u'\U0001d55d': '$\\mathbb{l}$',
+ u'\U0001d55e': '$\\mathbb{m}$',
+ u'\U0001d55f': '$\\mathbb{n}$',
+ u'\U0001d560': '$\\mathbb{o}$',
+ u'\U0001d561': '$\\mathbb{p}$',
+ u'\U0001d562': '$\\mathbb{q}$',
+ u'\U0001d563': '$\\mathbb{r}$',
+ u'\U0001d564': '$\\mathbb{s}$',
+ u'\U0001d565': '$\\mathbb{t}$',
+ u'\U0001d566': '$\\mathbb{u}$',
+ u'\U0001d567': '$\\mathbb{v}$',
+ u'\U0001d568': '$\\mathbb{w}$',
+ u'\U0001d569': '$\\mathbb{x}$',
+ u'\U0001d56a': '$\\mathbb{y}$',
+ u'\U0001d56b': '$\\mathbb{z}$',
+ u'\U0001d56c': '$\\mathslbb{A}$',
+ u'\U0001d56d': '$\\mathslbb{B}$',
+ u'\U0001d56e': '$\\mathslbb{C}$',
+ u'\U0001d56f': '$\\mathslbb{D}$',
+ u'\U0001d570': '$\\mathslbb{E}$',
+ u'\U0001d571': '$\\mathslbb{F}$',
+ u'\U0001d572': '$\\mathslbb{G}$',
+ u'\U0001d573': '$\\mathslbb{H}$',
+ u'\U0001d574': '$\\mathslbb{I}$',
+ u'\U0001d575': '$\\mathslbb{J}$',
+ u'\U0001d576': '$\\mathslbb{K}$',
+ u'\U0001d577': '$\\mathslbb{L}$',
+ u'\U0001d578': '$\\mathslbb{M}$',
+ u'\U0001d579': '$\\mathslbb{N}$',
+ u'\U0001d57a': '$\\mathslbb{O}$',
+ u'\U0001d57b': '$\\mathslbb{P}$',
+ u'\U0001d57c': '$\\mathslbb{Q}$',
+ u'\U0001d57d': '$\\mathslbb{R}$',
+ u'\U0001d57e': '$\\mathslbb{S}$',
+ u'\U0001d57f': '$\\mathslbb{T}$',
+ u'\U0001d580': '$\\mathslbb{U}$',
+ u'\U0001d581': '$\\mathslbb{V}$',
+ u'\U0001d582': '$\\mathslbb{W}$',
+ u'\U0001d583': '$\\mathslbb{X}$',
+ u'\U0001d584': '$\\mathslbb{Y}$',
+ u'\U0001d585': '$\\mathslbb{Z}$',
+ u'\U0001d586': '$\\mathslbb{a}$',
+ u'\U0001d587': '$\\mathslbb{b}$',
+ u'\U0001d588': '$\\mathslbb{c}$',
+ u'\U0001d589': '$\\mathslbb{d}$',
+ u'\U0001d58a': '$\\mathslbb{e}$',
+ u'\U0001d58b': '$\\mathslbb{f}$',
+ u'\U0001d58c': '$\\mathslbb{g}$',
+ u'\U0001d58d': '$\\mathslbb{h}$',
+ u'\U0001d58e': '$\\mathslbb{i}$',
+ u'\U0001d58f': '$\\mathslbb{j}$',
+ u'\U0001d590': '$\\mathslbb{k}$',
+ u'\U0001d591': '$\\mathslbb{l}$',
+ u'\U0001d592': '$\\mathslbb{m}$',
+ u'\U0001d593': '$\\mathslbb{n}$',
+ u'\U0001d594': '$\\mathslbb{o}$',
+ u'\U0001d595': '$\\mathslbb{p}$',
+ u'\U0001d596': '$\\mathslbb{q}$',
+ u'\U0001d597': '$\\mathslbb{r}$',
+ u'\U0001d598': '$\\mathslbb{s}$',
+ u'\U0001d599': '$\\mathslbb{t}$',
+ u'\U0001d59a': '$\\mathslbb{u}$',
+ u'\U0001d59b': '$\\mathslbb{v}$',
+ u'\U0001d59c': '$\\mathslbb{w}$',
+ u'\U0001d59d': '$\\mathslbb{x}$',
+ u'\U0001d59e': '$\\mathslbb{y}$',
+ u'\U0001d59f': '$\\mathslbb{z}$',
+ u'\U0001d5a0': '$\\mathsf{A}$',
+ u'\U0001d5a1': '$\\mathsf{B}$',
+ u'\U0001d5a2': '$\\mathsf{C}$',
+ u'\U0001d5a3': '$\\mathsf{D}$',
+ u'\U0001d5a4': '$\\mathsf{E}$',
+ u'\U0001d5a5': '$\\mathsf{F}$',
+ u'\U0001d5a6': '$\\mathsf{G}$',
+ u'\U0001d5a7': '$\\mathsf{H}$',
+ u'\U0001d5a8': '$\\mathsf{I}$',
+ u'\U0001d5a9': '$\\mathsf{J}$',
+ u'\U0001d5aa': '$\\mathsf{K}$',
+ u'\U0001d5ab': '$\\mathsf{L}$',
+ u'\U0001d5ac': '$\\mathsf{M}$',
+ u'\U0001d5ad': '$\\mathsf{N}$',
+ u'\U0001d5ae': '$\\mathsf{O}$',
+ u'\U0001d5af': '$\\mathsf{P}$',
+ u'\U0001d5b0': '$\\mathsf{Q}$',
+ u'\U0001d5b1': '$\\mathsf{R}$',
+ u'\U0001d5b2': '$\\mathsf{S}$',
+ u'\U0001d5b3': '$\\mathsf{T}$',
+ u'\U0001d5b4': '$\\mathsf{U}$',
+ u'\U0001d5b5': '$\\mathsf{V}$',
+ u'\U0001d5b6': '$\\mathsf{W}$',
+ u'\U0001d5b7': '$\\mathsf{X}$',
+ u'\U0001d5b8': '$\\mathsf{Y}$',
+ u'\U0001d5b9': '$\\mathsf{Z}$',
+ u'\U0001d5ba': '$\\mathsf{a}$',
+ u'\U0001d5bb': '$\\mathsf{b}$',
+ u'\U0001d5bc': '$\\mathsf{c}$',
+ u'\U0001d5bd': '$\\mathsf{d}$',
+ u'\U0001d5be': '$\\mathsf{e}$',
+ u'\U0001d5bf': '$\\mathsf{f}$',
+ u'\U0001d5c0': '$\\mathsf{g}$',
+ u'\U0001d5c1': '$\\mathsf{h}$',
+ u'\U0001d5c2': '$\\mathsf{i}$',
+ u'\U0001d5c3': '$\\mathsf{j}$',
+ u'\U0001d5c4': '$\\mathsf{k}$',
+ u'\U0001d5c5': '$\\mathsf{l}$',
+ u'\U0001d5c6': '$\\mathsf{m}$',
+ u'\U0001d5c7': '$\\mathsf{n}$',
+ u'\U0001d5c8': '$\\mathsf{o}$',
+ u'\U0001d5c9': '$\\mathsf{p}$',
+ u'\U0001d5ca': '$\\mathsf{q}$',
+ u'\U0001d5cb': '$\\mathsf{r}$',
+ u'\U0001d5cc': '$\\mathsf{s}$',
+ u'\U0001d5cd': '$\\mathsf{t}$',
+ u'\U0001d5ce': '$\\mathsf{u}$',
+ u'\U0001d5cf': '$\\mathsf{v}$',
+ u'\U0001d5d0': '$\\mathsf{w}$',
+ u'\U0001d5d1': '$\\mathsf{x}$',
+ u'\U0001d5d2': '$\\mathsf{y}$',
+ u'\U0001d5d3': '$\\mathsf{z}$',
+ u'\U0001d5d4': '$\\mathsfbf{A}$',
+ u'\U0001d5d5': '$\\mathsfbf{B}$',
+ u'\U0001d5d6': '$\\mathsfbf{C}$',
+ u'\U0001d5d7': '$\\mathsfbf{D}$',
+ u'\U0001d5d8': '$\\mathsfbf{E}$',
+ u'\U0001d5d9': '$\\mathsfbf{F}$',
+ u'\U0001d5da': '$\\mathsfbf{G}$',
+ u'\U0001d5db': '$\\mathsfbf{H}$',
+ u'\U0001d5dc': '$\\mathsfbf{I}$',
+ u'\U0001d5dd': '$\\mathsfbf{J}$',
+ u'\U0001d5de': '$\\mathsfbf{K}$',
+ u'\U0001d5df': '$\\mathsfbf{L}$',
+ u'\U0001d5e0': '$\\mathsfbf{M}$',
+ u'\U0001d5e1': '$\\mathsfbf{N}$',
+ u'\U0001d5e2': '$\\mathsfbf{O}$',
+ u'\U0001d5e3': '$\\mathsfbf{P}$',
+ u'\U0001d5e4': '$\\mathsfbf{Q}$',
+ u'\U0001d5e5': '$\\mathsfbf{R}$',
+ u'\U0001d5e6': '$\\mathsfbf{S}$',
+ u'\U0001d5e7': '$\\mathsfbf{T}$',
+ u'\U0001d5e8': '$\\mathsfbf{U}$',
+ u'\U0001d5e9': '$\\mathsfbf{V}$',
+ u'\U0001d5ea': '$\\mathsfbf{W}$',
+ u'\U0001d5eb': '$\\mathsfbf{X}$',
+ u'\U0001d5ec': '$\\mathsfbf{Y}$',
+ u'\U0001d5ed': '$\\mathsfbf{Z}$',
+ u'\U0001d5ee': '$\\mathsfbf{a}$',
+ u'\U0001d5ef': '$\\mathsfbf{b}$',
+ u'\U0001d5f0': '$\\mathsfbf{c}$',
+ u'\U0001d5f1': '$\\mathsfbf{d}$',
+ u'\U0001d5f2': '$\\mathsfbf{e}$',
+ u'\U0001d5f3': '$\\mathsfbf{f}$',
+ u'\U0001d5f4': '$\\mathsfbf{g}$',
+ u'\U0001d5f5': '$\\mathsfbf{h}$',
+ u'\U0001d5f6': '$\\mathsfbf{i}$',
+ u'\U0001d5f7': '$\\mathsfbf{j}$',
+ u'\U0001d5f8': '$\\mathsfbf{k}$',
+ u'\U0001d5f9': '$\\mathsfbf{l}$',
+ u'\U0001d5fa': '$\\mathsfbf{m}$',
+ u'\U0001d5fb': '$\\mathsfbf{n}$',
+ u'\U0001d5fc': '$\\mathsfbf{o}$',
+ u'\U0001d5fd': '$\\mathsfbf{p}$',
+ u'\U0001d5fe': '$\\mathsfbf{q}$',
+ u'\U0001d5ff': '$\\mathsfbf{r}$',
+ u'\U0001d600': '$\\mathsfbf{s}$',
+ u'\U0001d601': '$\\mathsfbf{t}$',
+ u'\U0001d602': '$\\mathsfbf{u}$',
+ u'\U0001d603': '$\\mathsfbf{v}$',
+ u'\U0001d604': '$\\mathsfbf{w}$',
+ u'\U0001d605': '$\\mathsfbf{x}$',
+ u'\U0001d606': '$\\mathsfbf{y}$',
+ u'\U0001d607': '$\\mathsfbf{z}$',
+ u'\U0001d608': '$\\mathsfsl{A}$',
+ u'\U0001d609': '$\\mathsfsl{B}$',
+ u'\U0001d60a': '$\\mathsfsl{C}$',
+ u'\U0001d60b': '$\\mathsfsl{D}$',
+ u'\U0001d60c': '$\\mathsfsl{E}$',
+ u'\U0001d60d': '$\\mathsfsl{F}$',
+ u'\U0001d60e': '$\\mathsfsl{G}$',
+ u'\U0001d60f': '$\\mathsfsl{H}$',
+ u'\U0001d610': '$\\mathsfsl{I}$',
+ u'\U0001d611': '$\\mathsfsl{J}$',
+ u'\U0001d612': '$\\mathsfsl{K}$',
+ u'\U0001d613': '$\\mathsfsl{L}$',
+ u'\U0001d614': '$\\mathsfsl{M}$',
+ u'\U0001d615': '$\\mathsfsl{N}$',
+ u'\U0001d616': '$\\mathsfsl{O}$',
+ u'\U0001d617': '$\\mathsfsl{P}$',
+ u'\U0001d618': '$\\mathsfsl{Q}$',
+ u'\U0001d619': '$\\mathsfsl{R}$',
+ u'\U0001d61a': '$\\mathsfsl{S}$',
+ u'\U0001d61b': '$\\mathsfsl{T}$',
+ u'\U0001d61c': '$\\mathsfsl{U}$',
+ u'\U0001d61d': '$\\mathsfsl{V}$',
+ u'\U0001d61e': '$\\mathsfsl{W}$',
+ u'\U0001d61f': '$\\mathsfsl{X}$',
+ u'\U0001d620': '$\\mathsfsl{Y}$',
+ u'\U0001d621': '$\\mathsfsl{Z}$',
+ u'\U0001d622': '$\\mathsfsl{a}$',
+ u'\U0001d623': '$\\mathsfsl{b}$',
+ u'\U0001d624': '$\\mathsfsl{c}$',
+ u'\U0001d625': '$\\mathsfsl{d}$',
+ u'\U0001d626': '$\\mathsfsl{e}$',
+ u'\U0001d627': '$\\mathsfsl{f}$',
+ u'\U0001d628': '$\\mathsfsl{g}$',
+ u'\U0001d629': '$\\mathsfsl{h}$',
+ u'\U0001d62a': '$\\mathsfsl{i}$',
+ u'\U0001d62b': '$\\mathsfsl{j}$',
+ u'\U0001d62c': '$\\mathsfsl{k}$',
+ u'\U0001d62d': '$\\mathsfsl{l}$',
+ u'\U0001d62e': '$\\mathsfsl{m}$',
+ u'\U0001d62f': '$\\mathsfsl{n}$',
+ u'\U0001d630': '$\\mathsfsl{o}$',
+ u'\U0001d631': '$\\mathsfsl{p}$',
+ u'\U0001d632': '$\\mathsfsl{q}$',
+ u'\U0001d633': '$\\mathsfsl{r}$',
+ u'\U0001d634': '$\\mathsfsl{s}$',
+ u'\U0001d635': '$\\mathsfsl{t}$',
+ u'\U0001d636': '$\\mathsfsl{u}$',
+ u'\U0001d637': '$\\mathsfsl{v}$',
+ u'\U0001d638': '$\\mathsfsl{w}$',
+ u'\U0001d639': '$\\mathsfsl{x}$',
+ u'\U0001d63a': '$\\mathsfsl{y}$',
+ u'\U0001d63b': '$\\mathsfsl{z}$',
+ u'\U0001d63c': '$\\mathsfbfsl{A}$',
+ u'\U0001d63d': '$\\mathsfbfsl{B}$',
+ u'\U0001d63e': '$\\mathsfbfsl{C}$',
+ u'\U0001d63f': '$\\mathsfbfsl{D}$',
+ u'\U0001d640': '$\\mathsfbfsl{E}$',
+ u'\U0001d641': '$\\mathsfbfsl{F}$',
+ u'\U0001d642': '$\\mathsfbfsl{G}$',
+ u'\U0001d643': '$\\mathsfbfsl{H}$',
+ u'\U0001d644': '$\\mathsfbfsl{I}$',
+ u'\U0001d645': '$\\mathsfbfsl{J}$',
+ u'\U0001d646': '$\\mathsfbfsl{K}$',
+ u'\U0001d647': '$\\mathsfbfsl{L}$',
+ u'\U0001d648': '$\\mathsfbfsl{M}$',
+ u'\U0001d649': '$\\mathsfbfsl{N}$',
+ u'\U0001d64a': '$\\mathsfbfsl{O}$',
+ u'\U0001d64b': '$\\mathsfbfsl{P}$',
+ u'\U0001d64c': '$\\mathsfbfsl{Q}$',
+ u'\U0001d64d': '$\\mathsfbfsl{R}$',
+ u'\U0001d64e': '$\\mathsfbfsl{S}$',
+ u'\U0001d64f': '$\\mathsfbfsl{T}$',
+ u'\U0001d650': '$\\mathsfbfsl{U}$',
+ u'\U0001d651': '$\\mathsfbfsl{V}$',
+ u'\U0001d652': '$\\mathsfbfsl{W}$',
+ u'\U0001d653': '$\\mathsfbfsl{X}$',
+ u'\U0001d654': '$\\mathsfbfsl{Y}$',
+ u'\U0001d655': '$\\mathsfbfsl{Z}$',
+ u'\U0001d656': '$\\mathsfbfsl{a}$',
+ u'\U0001d657': '$\\mathsfbfsl{b}$',
+ u'\U0001d658': '$\\mathsfbfsl{c}$',
+ u'\U0001d659': '$\\mathsfbfsl{d}$',
+ u'\U0001d65a': '$\\mathsfbfsl{e}$',
+ u'\U0001d65b': '$\\mathsfbfsl{f}$',
+ u'\U0001d65c': '$\\mathsfbfsl{g}$',
+ u'\U0001d65d': '$\\mathsfbfsl{h}$',
+ u'\U0001d65e': '$\\mathsfbfsl{i}$',
+ u'\U0001d65f': '$\\mathsfbfsl{j}$',
+ u'\U0001d660': '$\\mathsfbfsl{k}$',
+ u'\U0001d661': '$\\mathsfbfsl{l}$',
+ u'\U0001d662': '$\\mathsfbfsl{m}$',
+ u'\U0001d663': '$\\mathsfbfsl{n}$',
+ u'\U0001d664': '$\\mathsfbfsl{o}$',
+ u'\U0001d665': '$\\mathsfbfsl{p}$',
+ u'\U0001d666': '$\\mathsfbfsl{q}$',
+ u'\U0001d667': '$\\mathsfbfsl{r}$',
+ u'\U0001d668': '$\\mathsfbfsl{s}$',
+ u'\U0001d669': '$\\mathsfbfsl{t}$',
+ u'\U0001d66a': '$\\mathsfbfsl{u}$',
+ u'\U0001d66b': '$\\mathsfbfsl{v}$',
+ u'\U0001d66c': '$\\mathsfbfsl{w}$',
+ u'\U0001d66d': '$\\mathsfbfsl{x}$',
+ u'\U0001d66e': '$\\mathsfbfsl{y}$',
+ u'\U0001d66f': '$\\mathsfbfsl{z}$',
+ u'\U0001d670': '$\\mathtt{A}$',
+ u'\U0001d671': '$\\mathtt{B}$',
+ u'\U0001d672': '$\\mathtt{C}$',
+ u'\U0001d673': '$\\mathtt{D}$',
+ u'\U0001d674': '$\\mathtt{E}$',
+ u'\U0001d675': '$\\mathtt{F}$',
+ u'\U0001d676': '$\\mathtt{G}$',
+ u'\U0001d677': '$\\mathtt{H}$',
+ u'\U0001d678': '$\\mathtt{I}$',
+ u'\U0001d679': '$\\mathtt{J}$',
+ u'\U0001d67a': '$\\mathtt{K}$',
+ u'\U0001d67b': '$\\mathtt{L}$',
+ u'\U0001d67c': '$\\mathtt{M}$',
+ u'\U0001d67d': '$\\mathtt{N}$',
+ u'\U0001d67e': '$\\mathtt{O}$',
+ u'\U0001d67f': '$\\mathtt{P}$',
+ u'\U0001d680': '$\\mathtt{Q}$',
+ u'\U0001d681': '$\\mathtt{R}$',
+ u'\U0001d682': '$\\mathtt{S}$',
+ u'\U0001d683': '$\\mathtt{T}$',
+ u'\U0001d684': '$\\mathtt{U}$',
+ u'\U0001d685': '$\\mathtt{V}$',
+ u'\U0001d686': '$\\mathtt{W}$',
+ u'\U0001d687': '$\\mathtt{X}$',
+ u'\U0001d688': '$\\mathtt{Y}$',
+ u'\U0001d689': '$\\mathtt{Z}$',
+ u'\U0001d68a': '$\\mathtt{a}$',
+ u'\U0001d68b': '$\\mathtt{b}$',
+ u'\U0001d68c': '$\\mathtt{c}$',
+ u'\U0001d68d': '$\\mathtt{d}$',
+ u'\U0001d68e': '$\\mathtt{e}$',
+ u'\U0001d68f': '$\\mathtt{f}$',
+ u'\U0001d690': '$\\mathtt{g}$',
+ u'\U0001d691': '$\\mathtt{h}$',
+ u'\U0001d692': '$\\mathtt{i}$',
+ u'\U0001d693': '$\\mathtt{j}$',
+ u'\U0001d694': '$\\mathtt{k}$',
+ u'\U0001d695': '$\\mathtt{l}$',
+ u'\U0001d696': '$\\mathtt{m}$',
+ u'\U0001d697': '$\\mathtt{n}$',
+ u'\U0001d698': '$\\mathtt{o}$',
+ u'\U0001d699': '$\\mathtt{p}$',
+ u'\U0001d69a': '$\\mathtt{q}$',
+ u'\U0001d69b': '$\\mathtt{r}$',
+ u'\U0001d69c': '$\\mathtt{s}$',
+ u'\U0001d69d': '$\\mathtt{t}$',
+ u'\U0001d69e': '$\\mathtt{u}$',
+ u'\U0001d69f': '$\\mathtt{v}$',
+ u'\U0001d6a0': '$\\mathtt{w}$',
+ u'\U0001d6a1': '$\\mathtt{x}$',
+ u'\U0001d6a2': '$\\mathtt{y}$',
+ u'\U0001d6a3': '$\\mathtt{z}$',
+ u'\U0001d6a8': '$\\mathbf{\\Alpha}$',
+ u'\U0001d6a9': '$\\mathbf{\\Beta}$',
+ u'\U0001d6aa': '$\\mathbf{\\Gamma}$',
+ u'\U0001d6ab': '$\\mathbf{\\Delta}$',
+ u'\U0001d6ac': '$\\mathbf{\\Epsilon}$',
+ u'\U0001d6ad': '$\\mathbf{\\Zeta}$',
+ u'\U0001d6ae': '$\\mathbf{\\Eta}$',
+ u'\U0001d6af': '$\\mathbf{\\Theta}$',
+ u'\U0001d6b0': '$\\mathbf{\\Iota}$',
+ u'\U0001d6b1': '$\\mathbf{\\Kappa}$',
+ u'\U0001d6b2': '$\\mathbf{\\Lambda}$',
+ u'\U0001d6b3': '$M$',
+ u'\U0001d6b4': '$N$',
+ u'\U0001d6b5': '$\\mathbf{\\Xi}$',
+ u'\U0001d6b6': '$O$',
+ u'\U0001d6b7': '$\\mathbf{\\Pi}$',
+ u'\U0001d6b8': '$\\mathbf{\\Rho}$',
+ u'\U0001d6b9': '{\\mathbf{\\vartheta}}',
+ u'\U0001d6ba': '$\\mathbf{\\Sigma}$',
+ u'\U0001d6bb': '$\\mathbf{\\Tau}$',
+ u'\U0001d6bc': '$\\mathbf{\\Upsilon}$',
+ u'\U0001d6bd': '$\\mathbf{\\Phi}$',
+ u'\U0001d6be': '$\\mathbf{\\Chi}$',
+ u'\U0001d6bf': '$\\mathbf{\\Psi}$',
+ u'\U0001d6c0': '$\\mathbf{\\Omega}$',
+ u'\U0001d6c1': '$\\mathbf{\\nabla}$',
+ u'\U0001d6c2': '$\\mathbf{\\Alpha}$',
+ u'\U0001d6c3': '$\\mathbf{\\Beta}$',
+ u'\U0001d6c4': '$\\mathbf{\\Gamma}$',
+ u'\U0001d6c5': '$\\mathbf{\\Delta}$',
+ u'\U0001d6c6': '$\\mathbf{\\Epsilon}$',
+ u'\U0001d6c7': '$\\mathbf{\\Zeta}$',
+ u'\U0001d6c8': '$\\mathbf{\\Eta}$',
+ u'\U0001d6c9': '$\\mathbf{\\theta}$',
+ u'\U0001d6ca': '$\\mathbf{\\Iota}$',
+ u'\U0001d6cb': '$\\mathbf{\\Kappa}$',
+ u'\U0001d6cc': '$\\mathbf{\\Lambda}$',
+ u'\U0001d6cd': '$M$',
+ u'\U0001d6ce': '$N$',
+ u'\U0001d6cf': '$\\mathbf{\\Xi}$',
+ u'\U0001d6d0': '$O$',
+ u'\U0001d6d1': '$\\mathbf{\\Pi}$',
+ u'\U0001d6d2': '$\\mathbf{\\Rho}$',
+ u'\U0001d6d3': '$\\mathbf{\\varsigma}$',
+ u'\U0001d6d4': '$\\mathbf{\\Sigma}$',
+ u'\U0001d6d5': '$\\mathbf{\\Tau}$',
+ u'\U0001d6d6': '$\\mathbf{\\Upsilon}$',
+ u'\U0001d6d7': '$\\mathbf{\\Phi}$',
+ u'\U0001d6d8': '$\\mathbf{\\Chi}$',
+ u'\U0001d6d9': '$\\mathbf{\\Psi}$',
+ u'\U0001d6da': '$\\mathbf{\\Omega}$',
+ u'\U0001d6db': '$\\partial$',
+ u'\U0001d6dc': '$\\in$',
+ u'\U0001d6dd': '{\\mathbf{\\vartheta}}',
+ u'\U0001d6de': '{\\mathbf{\\varkappa}}',
+ u'\U0001d6df': '{\\mathbf{\\phi}}',
+ u'\U0001d6e0': '{\\mathbf{\\varrho}}',
+ u'\U0001d6e1': '{\\mathbf{\\varpi}}',
+ u'\U0001d6e2': '$\\mathsl{\\Alpha}$',
+ u'\U0001d6e3': '$\\mathsl{\\Beta}$',
+ u'\U0001d6e4': '$\\mathsl{\\Gamma}$',
+ u'\U0001d6e5': '$\\mathsl{\\Delta}$',
+ u'\U0001d6e6': '$\\mathsl{\\Epsilon}$',
+ u'\U0001d6e7': '$\\mathsl{\\Zeta}$',
+ u'\U0001d6e8': '$\\mathsl{\\Eta}$',
+ u'\U0001d6e9': '$\\mathsl{\\Theta}$',
+ u'\U0001d6ea': '$\\mathsl{\\Iota}$',
+ u'\U0001d6eb': '$\\mathsl{\\Kappa}$',
+ u'\U0001d6ec': '$\\mathsl{\\Lambda}$',
+ u'\U0001d6ed': '$M$',
+ u'\U0001d6ee': '$N$',
+ u'\U0001d6ef': '$\\mathsl{\\Xi}$',
+ u'\U0001d6f0': '$O$',
+ u'\U0001d6f1': '$\\mathsl{\\Pi}$',
+ u'\U0001d6f2': '$\\mathsl{\\Rho}$',
+ u'\U0001d6f3': '{\\mathsl{\\vartheta}}',
+ u'\U0001d6f4': '$\\mathsl{\\Sigma}$',
+ u'\U0001d6f5': '$\\mathsl{\\Tau}$',
+ u'\U0001d6f6': '$\\mathsl{\\Upsilon}$',
+ u'\U0001d6f7': '$\\mathsl{\\Phi}$',
+ u'\U0001d6f8': '$\\mathsl{\\Chi}$',
+ u'\U0001d6f9': '$\\mathsl{\\Psi}$',
+ u'\U0001d6fa': '$\\mathsl{\\Omega}$',
+ u'\U0001d6fb': '$\\mathsl{\\nabla}$',
+ u'\U0001d6fc': '$\\mathsl{\\Alpha}$',
+ u'\U0001d6fd': '$\\mathsl{\\Beta}$',
+ u'\U0001d6fe': '$\\mathsl{\\Gamma}$',
+ u'\U0001d6ff': '$\\mathsl{\\Delta}$',
+ u'\U0001d700': '$\\mathsl{\\Epsilon}$',
+ u'\U0001d701': '$\\mathsl{\\Zeta}$',
+ u'\U0001d702': '$\\mathsl{\\Eta}$',
+ u'\U0001d703': '$\\mathsl{\\Theta}$',
+ u'\U0001d704': '$\\mathsl{\\Iota}$',
+ u'\U0001d705': '$\\mathsl{\\Kappa}$',
+ u'\U0001d706': '$\\mathsl{\\Lambda}$',
+ u'\U0001d707': '$M$',
+ u'\U0001d708': '$N$',
+ u'\U0001d709': '$\\mathsl{\\Xi}$',
+ u'\U0001d70a': '$O$',
+ u'\U0001d70b': '$\\mathsl{\\Pi}$',
+ u'\U0001d70c': '$\\mathsl{\\Rho}$',
+ u'\U0001d70d': '$\\mathsl{\\varsigma}$',
+ u'\U0001d70e': '$\\mathsl{\\Sigma}$',
+ u'\U0001d70f': '$\\mathsl{\\Tau}$',
+ u'\U0001d710': '$\\mathsl{\\Upsilon}$',
+ u'\U0001d711': '$\\mathsl{\\Phi}$',
+ u'\U0001d712': '$\\mathsl{\\Chi}$',
+ u'\U0001d713': '$\\mathsl{\\Psi}$',
+ u'\U0001d714': '$\\mathsl{\\Omega}$',
+ u'\U0001d715': '$\\partial$',
+ u'\U0001d716': '$\\in$',
+ u'\U0001d717': '{\\mathsl{\\vartheta}}',
+ u'\U0001d718': '{\\mathsl{\\varkappa}}',
+ u'\U0001d719': '{\\mathsl{\\phi}}',
+ u'\U0001d71a': '{\\mathsl{\\varrho}}',
+ u'\U0001d71b': '{\\mathsl{\\varpi}}',
+ u'\U0001d71c': '$\\mathbit{\\Alpha}$',
+ u'\U0001d71d': '$\\mathbit{\\Beta}$',
+ u'\U0001d71e': '$\\mathbit{\\Gamma}$',
+ u'\U0001d71f': '$\\mathbit{\\Delta}$',
+ u'\U0001d720': '$\\mathbit{\\Epsilon}$',
+ u'\U0001d721': '$\\mathbit{\\Zeta}$',
+ u'\U0001d722': '$\\mathbit{\\Eta}$',
+ u'\U0001d723': '$\\mathbit{\\Theta}$',
+ u'\U0001d724': '$\\mathbit{\\Iota}$',
+ u'\U0001d725': '$\\mathbit{\\Kappa}$',
+ u'\U0001d726': '$\\mathbit{\\Lambda}$',
+ u'\U0001d727': '$M$',
+ u'\U0001d728': '$N$',
+ u'\U0001d729': '$\\mathbit{\\Xi}$',
+ u'\U0001d72a': '$O$',
+ u'\U0001d72b': '$\\mathbit{\\Pi}$',
+ u'\U0001d72c': '$\\mathbit{\\Rho}$',
+ u'\U0001d72d': '{\\mathbit{O}}',
+ u'\U0001d72e': '$\\mathbit{\\Sigma}$',
+ u'\U0001d72f': '$\\mathbit{\\Tau}$',
+ u'\U0001d730': '$\\mathbit{\\Upsilon}$',
+ u'\U0001d731': '$\\mathbit{\\Phi}$',
+ u'\U0001d732': '$\\mathbit{\\Chi}$',
+ u'\U0001d733': '$\\mathbit{\\Psi}$',
+ u'\U0001d734': '$\\mathbit{\\Omega}$',
+ u'\U0001d735': '$\\mathbit{\\nabla}$',
+ u'\U0001d736': '$\\mathbit{\\Alpha}$',
+ u'\U0001d737': '$\\mathbit{\\Beta}$',
+ u'\U0001d738': '$\\mathbit{\\Gamma}$',
+ u'\U0001d739': '$\\mathbit{\\Delta}$',
+ u'\U0001d73a': '$\\mathbit{\\Epsilon}$',
+ u'\U0001d73b': '$\\mathbit{\\Zeta}$',
+ u'\U0001d73c': '$\\mathbit{\\Eta}$',
+ u'\U0001d73d': '$\\mathbit{\\Theta}$',
+ u'\U0001d73e': '$\\mathbit{\\Iota}$',
+ u'\U0001d73f': '$\\mathbit{\\Kappa}$',
+ u'\U0001d740': '$\\mathbit{\\Lambda}$',
+ u'\U0001d741': '$M$',
+ u'\U0001d742': '$N$',
+ u'\U0001d743': '$\\mathbit{\\Xi}$',
+ u'\U0001d744': '$O$',
+ u'\U0001d745': '$\\mathbit{\\Pi}$',
+ u'\U0001d746': '$\\mathbit{\\Rho}$',
+ u'\U0001d747': '$\\mathbit{\\varsigma}$',
+ u'\U0001d748': '$\\mathbit{\\Sigma}$',
+ u'\U0001d749': '$\\mathbit{\\Tau}$',
+ u'\U0001d74a': '$\\mathbit{\\Upsilon}$',
+ u'\U0001d74b': '$\\mathbit{\\Phi}$',
+ u'\U0001d74c': '$\\mathbit{\\Chi}$',
+ u'\U0001d74d': '$\\mathbit{\\Psi}$',
+ u'\U0001d74e': '$\\mathbit{\\Omega}$',
+ u'\U0001d74f': '$\\partial$',
+ u'\U0001d750': '$\\in$',
+ u'\U0001d751': '{\\mathbit{\\vartheta}}',
+ u'\U0001d752': '{\\mathbit{\\varkappa}}',
+ u'\U0001d753': '{\\mathbit{\\phi}}',
+ u'\U0001d754': '{\\mathbit{\\varrho}}',
+ u'\U0001d755': '{\\mathbit{\\varpi}}',
+ u'\U0001d756': '$\\mathsfbf{\\Alpha}$',
+ u'\U0001d757': '$\\mathsfbf{\\Beta}$',
+ u'\U0001d758': '$\\mathsfbf{\\Gamma}$',
+ u'\U0001d759': '$\\mathsfbf{\\Delta}$',
+ u'\U0001d75a': '$\\mathsfbf{\\Epsilon}$',
+ u'\U0001d75b': '$\\mathsfbf{\\Zeta}$',
+ u'\U0001d75c': '$\\mathsfbf{\\Eta}$',
+ u'\U0001d75d': '$\\mathsfbf{\\Theta}$',
+ u'\U0001d75e': '$\\mathsfbf{\\Iota}$',
+ u'\U0001d75f': '$\\mathsfbf{\\Kappa}$',
+ u'\U0001d760': '$\\mathsfbf{\\Lambda}$',
+ u'\U0001d761': '$M$',
+ u'\U0001d762': '$N$',
+ u'\U0001d763': '$\\mathsfbf{\\Xi}$',
+ u'\U0001d764': '$O$',
+ u'\U0001d765': '$\\mathsfbf{\\Pi}$',
+ u'\U0001d766': '$\\mathsfbf{\\Rho}$',
+ u'\U0001d767': '{\\mathsfbf{\\vartheta}}',
+ u'\U0001d768': '$\\mathsfbf{\\Sigma}$',
+ u'\U0001d769': '$\\mathsfbf{\\Tau}$',
+ u'\U0001d76a': '$\\mathsfbf{\\Upsilon}$',
+ u'\U0001d76b': '$\\mathsfbf{\\Phi}$',
+ u'\U0001d76c': '$\\mathsfbf{\\Chi}$',
+ u'\U0001d76d': '$\\mathsfbf{\\Psi}$',
+ u'\U0001d76e': '$\\mathsfbf{\\Omega}$',
+ u'\U0001d76f': '$\\mathsfbf{\\nabla}$',
+ u'\U0001d770': '$\\mathsfbf{\\Alpha}$',
+ u'\U0001d771': '$\\mathsfbf{\\Beta}$',
+ u'\U0001d772': '$\\mathsfbf{\\Gamma}$',
+ u'\U0001d773': '$\\mathsfbf{\\Delta}$',
+ u'\U0001d774': '$\\mathsfbf{\\Epsilon}$',
+ u'\U0001d775': '$\\mathsfbf{\\Zeta}$',
+ u'\U0001d776': '$\\mathsfbf{\\Eta}$',
+ u'\U0001d777': '$\\mathsfbf{\\Theta}$',
+ u'\U0001d778': '$\\mathsfbf{\\Iota}$',
+ u'\U0001d779': '$\\mathsfbf{\\Kappa}$',
+ u'\U0001d77a': '$\\mathsfbf{\\Lambda}$',
+ u'\U0001d77b': '$M$',
+ u'\U0001d77c': '$N$',
+ u'\U0001d77d': '$\\mathsfbf{\\Xi}$',
+ u'\U0001d77e': '$O$',
+ u'\U0001d77f': '$\\mathsfbf{\\Pi}$',
+ u'\U0001d780': '$\\mathsfbf{\\Rho}$',
+ u'\U0001d781': '$\\mathsfbf{\\varsigma}$',
+ u'\U0001d782': '$\\mathsfbf{\\Sigma}$',
+ u'\U0001d783': '$\\mathsfbf{\\Tau}$',
+ u'\U0001d784': '$\\mathsfbf{\\Upsilon}$',
+ u'\U0001d785': '$\\mathsfbf{\\Phi}$',
+ u'\U0001d786': '$\\mathsfbf{\\Chi}$',
+ u'\U0001d787': '$\\mathsfbf{\\Psi}$',
+ u'\U0001d788': '$\\mathsfbf{\\Omega}$',
+ u'\U0001d789': '$\\partial$',
+ u'\U0001d78a': '$\\in$',
+ u'\U0001d78b': '{\\mathsfbf{\\vartheta}}',
+ u'\U0001d78c': '{\\mathsfbf{\\varkappa}}',
+ u'\U0001d78d': '{\\mathsfbf{\\phi}}',
+ u'\U0001d78e': '{\\mathsfbf{\\varrho}}',
+ u'\U0001d78f': '{\\mathsfbf{\\varpi}}',
+ u'\U0001d790': '$\\mathsfbfsl{\\Alpha}$',
+ u'\U0001d791': '$\\mathsfbfsl{\\Beta}$',
+ u'\U0001d792': '$\\mathsfbfsl{\\Gamma}$',
+ u'\U0001d793': '$\\mathsfbfsl{\\Delta}$',
+ u'\U0001d794': '$\\mathsfbfsl{\\Epsilon}$',
+ u'\U0001d795': '$\\mathsfbfsl{\\Zeta}$',
+ u'\U0001d796': '$\\mathsfbfsl{\\Eta}$',
+ u'\U0001d797': '$\\mathsfbfsl{\\vartheta}$',
+ u'\U0001d798': '$\\mathsfbfsl{\\Iota}$',
+ u'\U0001d799': '$\\mathsfbfsl{\\Kappa}$',
+ u'\U0001d79a': '$\\mathsfbfsl{\\Lambda}$',
+ u'\U0001d79b': '$M$',
+ u'\U0001d79c': '$N$',
+ u'\U0001d79d': '$\\mathsfbfsl{\\Xi}$',
+ u'\U0001d79e': '$O$',
+ u'\U0001d79f': '$\\mathsfbfsl{\\Pi}$',
+ u'\U0001d7a0': '$\\mathsfbfsl{\\Rho}$',
+ u'\U0001d7a1': '{\\mathsfbfsl{\\vartheta}}',
+ u'\U0001d7a2': '$\\mathsfbfsl{\\Sigma}$',
+ u'\U0001d7a3': '$\\mathsfbfsl{\\Tau}$',
+ u'\U0001d7a4': '$\\mathsfbfsl{\\Upsilon}$',
+ u'\U0001d7a5': '$\\mathsfbfsl{\\Phi}$',
+ u'\U0001d7a6': '$\\mathsfbfsl{\\Chi}$',
+ u'\U0001d7a7': '$\\mathsfbfsl{\\Psi}$',
+ u'\U0001d7a8': '$\\mathsfbfsl{\\Omega}$',
+ u'\U0001d7a9': '$\\mathsfbfsl{\\nabla}$',
+ u'\U0001d7aa': '$\\mathsfbfsl{\\Alpha}$',
+ u'\U0001d7ab': '$\\mathsfbfsl{\\Beta}$',
+ u'\U0001d7ac': '$\\mathsfbfsl{\\Gamma}$',
+ u'\U0001d7ad': '$\\mathsfbfsl{\\Delta}$',
+ u'\U0001d7ae': '$\\mathsfbfsl{\\Epsilon}$',
+ u'\U0001d7af': '$\\mathsfbfsl{\\Zeta}$',
+ u'\U0001d7b0': '$\\mathsfbfsl{\\Eta}$',
+ u'\U0001d7b1': '$\\mathsfbfsl{\\vartheta}$',
+ u'\U0001d7b2': '$\\mathsfbfsl{\\Iota}$',
+ u'\U0001d7b3': '$\\mathsfbfsl{\\Kappa}$',
+ u'\U0001d7b4': '$\\mathsfbfsl{\\Lambda}$',
+ u'\U0001d7b5': '$M$',
+ u'\U0001d7b6': '$N$',
+ u'\U0001d7b7': '$\\mathsfbfsl{\\Xi}$',
+ u'\U0001d7b8': '$O$',
+ u'\U0001d7b9': '$\\mathsfbfsl{\\Pi}$',
+ u'\U0001d7ba': '$\\mathsfbfsl{\\Rho}$',
+ u'\U0001d7bb': '$\\mathsfbfsl{\\varsigma}$',
+ u'\U0001d7bc': '$\\mathsfbfsl{\\Sigma}$',
+ u'\U0001d7bd': '$\\mathsfbfsl{\\Tau}$',
+ u'\U0001d7be': '$\\mathsfbfsl{\\Upsilon}$',
+ u'\U0001d7bf': '$\\mathsfbfsl{\\Phi}$',
+ u'\U0001d7c0': '$\\mathsfbfsl{\\Chi}$',
+ u'\U0001d7c1': '$\\mathsfbfsl{\\Psi}$',
+ u'\U0001d7c2': '$\\mathsfbfsl{\\Omega}$',
+ u'\U0001d7c3': '$\\partial$',
+ u'\U0001d7c4': '$\\in$',
+ u'\U0001d7c5': '{\\mathsfbfsl{\\vartheta}}',
+ u'\U0001d7c6': '{\\mathsfbfsl{\\varkappa}}',
+ u'\U0001d7c7': '{\\mathsfbfsl{\\phi}}',
+ u'\U0001d7c8': '{\\mathsfbfsl{\\varrho}}',
+ u'\U0001d7c9': '{\\mathsfbfsl{\\varpi}}',
+ u'\U0001d7ce': '$\\mathbf{0}$',
+ u'\U0001d7cf': '$\\mathbf{1}$',
+ u'\U0001d7d0': '$\\mathbf{2}$',
+ u'\U0001d7d1': '$\\mathbf{3}$',
+ u'\U0001d7d2': '$\\mathbf{4}$',
+ u'\U0001d7d3': '$\\mathbf{5}$',
+ u'\U0001d7d4': '$\\mathbf{6}$',
+ u'\U0001d7d5': '$\\mathbf{7}$',
+ u'\U0001d7d6': '$\\mathbf{8}$',
+ u'\U0001d7d7': '$\\mathbf{9}$',
+ u'\U0001d7d8': '$\\mathbb{0}$',
+ u'\U0001d7d9': '$\\mathbb{1}$',
+ u'\U0001d7da': '$\\mathbb{2}$',
+ u'\U0001d7db': '$\\mathbb{3}$',
+ u'\U0001d7dc': '$\\mathbb{4}$',
+ u'\U0001d7dd': '$\\mathbb{5}$',
+ u'\U0001d7de': '$\\mathbb{6}$',
+ u'\U0001d7df': '$\\mathbb{7}$',
+ u'\U0001d7e0': '$\\mathbb{8}$',
+ u'\U0001d7e1': '$\\mathbb{9}$',
+ u'\U0001d7e2': '$\\mathsf{0}$',
+ u'\U0001d7e3': '$\\mathsf{1}$',
+ u'\U0001d7e4': '$\\mathsf{2}$',
+ u'\U0001d7e5': '$\\mathsf{3}$',
+ u'\U0001d7e6': '$\\mathsf{4}$',
+ u'\U0001d7e7': '$\\mathsf{5}$',
+ u'\U0001d7e8': '$\\mathsf{6}$',
+ u'\U0001d7e9': '$\\mathsf{7}$',
+ u'\U0001d7ea': '$\\mathsf{8}$',
+ u'\U0001d7eb': '$\\mathsf{9}$',
+ u'\U0001d7ec': '$\\mathsfbf{0}$',
+ u'\U0001d7ed': '$\\mathsfbf{1}$',
+ u'\U0001d7ee': '$\\mathsfbf{2}$',
+ u'\U0001d7ef': '$\\mathsfbf{3}$',
+ u'\U0001d7f0': '$\\mathsfbf{4}$',
+ u'\U0001d7f1': '$\\mathsfbf{5}$',
+ u'\U0001d7f2': '$\\mathsfbf{6}$',
+ u'\U0001d7f3': '$\\mathsfbf{7}$',
+ u'\U0001d7f4': '$\\mathsfbf{8}$',
+ u'\U0001d7f5': '$\\mathsfbf{9}$',
+ u'\U0001d7f6': '$\\mathtt{0}$',
+ u'\U0001d7f7': '$\\mathtt{1}$',
+ u'\U0001d7f8': '$\\mathtt{2}$',
+ u'\U0001d7f9': '$\\mathtt{3}$',
+ u'\U0001d7fa': '$\\mathtt{4}$',
+ u'\U0001d7fb': '$\\mathtt{5}$',
+ u'\U0001d7fc': '$\\mathtt{6}$',
+ u'\U0001d7fd': '$\\mathtt{7}$',
+ u'\U0001d7fe': '$\\mathtt{8}$',
+ u'\U0001d7ff': '$\\mathtt{9}$'
+ }
+
+entity_mapping = {
+ '—':'{---}',
+ '–':'{--}',
+ '"':'{"}',
+ }
+
+def ValidateCitationKey(text):
+ """
+ removes characters not allowed in BibTeX keys
+
+ >>> from bibliograph.core.utils import _validKey
+ >>> _validKey(DummyEntry('Foo Bar'))
+ 'FooBar'
+
+ >>> _validKey(DummyEntry('my@id'))
+ 'myid'
+
+ """
+ # This substitution is based on the description of cite key restrictions at
+ # http://bibdesk.sourceforge.net/manual/BibDesk%20Help_2.html
+ return re.sub(u'[ "@\',\\#}{~%&$^]', u'', text)
+
+def BraceUppercase(text):
+ """ Convert uppercase letters to bibtex encoded uppercase
+
+ >>> from bibliograph.core.utils import _braceUppercase
+ >>> _braceUppercase('foo bar')
+ 'foo bar'
+
+ >>> _braceUppercase('Foo Bar')
+ '{F}oo {B}ar'
+ """
+ for uc in string.uppercase:
+ text = text.replace(uc, u'{%s}' % uc)
+ return text
+
+def resolveEntities(text):
+ for entity, entity_map in entity_mapping.iteritems():
+ text = text.replace(entity, entity_map)
+ return text
+
+def resolveUnicode(text):
+ #UTF-8 text as entry
+ for unichar, latexenc in utf8enc2latex_mapping.iteritems() :
+ text = text.replace(unichar, latexenc)
+ return text.replace(u'$}{$', u'')
+
+def escapeSpecialCharacters(text):
+ """
+ latex escaping some (not all) special characters
+ """
+ text.replace('\\', '\\\\')
+ escape = ['~', '#', '&', '%', '_']
+ for c in escape:
+ text = text.replace(c, '\\' + c )
+ return text
+
+#Calibre functions
+#Go from an unicode entry to ASCII Bibtex format without encoding
+#Option to go to official ASCII Bibtex or unofficial UTF-8
+def utf8ToBibtex(text, asccii_bibtex = True):
+ if len(text) == 0:
+ return ''
+ text.replace('\\', '\\\\')
+ text = resolveEntities(text)
+ if asccii_bibtex :
+ text = resolveUnicode(text)
+ return escapeSpecialCharacters(text)
+
+def bibtex_author_format(item):
+ #Format authors for Bibtex compliance (get a list as input)
+ return utf8ToBibtex(u' and'.join([author for author in item]))