diff --git a/resources/images/donate.svg b/resources/images/donate.svg index b17d0ec7a0..603e672f6f 100644 --- a/resources/images/donate.svg +++ b/resources/images/donate.svg @@ -1,24 +1,31 @@ + + sodipodi:docname="donate.svg"> + @@ -180,8 +187,8 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="7.851329" - inkscape:cx="92.691163" - inkscape:cy="92.473338" + inkscape:cx="60.937831" + inkscape:cy="61.488995" inkscape:current-layer="layer1" showgrid="false" inkscape:document-units="px" @@ -189,10 +196,11 @@ guidetolerance="0.1px" showguides="true" inkscape:guide-bbox="true" - inkscape:window-width="1106" - inkscape:window-height="958" - inkscape:window-x="597" - inkscape:window-y="25"> + inkscape:window-width="1680" + inkscape:window-height="997" + inkscape:window-x="-4" + inkscape:window-y="30" + inkscape:window-maximized="1"> - - + + + - + + image/svg+xml + id="feGaussianBlur5127" + stdDeviation="1.91024" /> + id="feGaussianBlur3096" + stdDeviation="4" /> + id="feGaussianBlur3099" + stdDeviation="2" /> + id="XMLID_12_" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,-0.1823,0,134.8566)"> + id="stop3102" + style="stop-color:#000000;stop-opacity:1" + offset="0" /> + id="stop3104" + style="stop-color:#000000;stop-opacity:0" + offset="1" /> + r="58" + transform="matrix(1.0859375,0,0,1.0859375,-3.9093733,-8.2531233)" + id="circle5091" + style="opacity:0.7;fill:#000000;fill-opacity:1;stroke:none;filter:url(#filter5097)" /> + id="stop3113" + style="stop-color:#eeeeee;stop-opacity:1" + offset="0.61540002" /> + id="stop3115" + style="stop-color:#dddddd;stop-opacity:1" + offset="0.82249999" /> + id="stop3117" + style="stop-color:#ffffff;stop-opacity:1" + offset="1" /> + style="fill:url(#XMLID_13_)" /> + id="stop3122" + style="stop-color:#2a94ec;stop-opacity:1" + offset="0" /> + id="stop3124" + style="stop-color:#0057ae;stop-opacity:1" + offset="1" /> + style="opacity:0.3;filter:url(#filter3547)"> + id="stop3132" + style="stop-color:#ffffff;stop-opacity:1" + offset="0" /> + id="stop3134" + style="stop-color:#ffffff;stop-opacity:0" + offset="1" /> + transform="matrix(1.0859375,0,0,1.0859375,-3.9093733,-8.2531233)" + id="g3137"> + d="m 27.6,69.6 c 0,23.159 18.841,42 42,42 23.159,0 42,-18.841 42,-42 0,-23.159 -18.841,-42 -42,-42 -23.159,0 -42,18.841 -42,42 z" + id="XMLID_10_" /> + height="139" + xlink:href="#XMLID_10_" /> @@ -240,30 +182,22 @@ transform="matrix(1.0859375,0,0,1.1113796,-3.201342,-9.3177223)" id="g5119" style="fill:#00316e;filter:url(#filter5125)"> \ No newline at end of file diff --git a/resources/images/lt.png b/resources/images/lt.png new file mode 100644 index 0000000000..c29efb9f88 Binary files /dev/null and b/resources/images/lt.png differ diff --git a/resources/images/news/elpais_impreso.png b/resources/images/news/elpais_impreso.png new file mode 100644 index 0000000000..35dcaf2d44 Binary files /dev/null and b/resources/images/news/elpais_impreso.png differ diff --git a/resources/recipes/ap.recipe b/resources/recipes/ap.recipe index 572c0aa392..0118cf0726 100644 --- a/resources/recipes/ap.recipe +++ b/resources/recipes/ap.recipe @@ -12,9 +12,9 @@ class AssociatedPress(BasicNewsRecipe): max_articles_per_feed = 15 html2lrf_options = ['--force-page-break-before-tag="chapter"'] - - - preprocess_regexps = [ (re.compile(i[0], re.IGNORECASE | re.DOTALL), i[1]) for i in + + + preprocess_regexps = [ (re.compile(i[0], re.IGNORECASE | re.DOTALL), i[1]) for i in [ (r'.*?' , lambda match : ''), (r'.*?', lambda match : ''), @@ -25,10 +25,10 @@ class AssociatedPress(BasicNewsRecipe): (r'

', lambda match : '

'), (r'Learn more about our Privacy Policy.*?', lambda match : ''), ] - ] - + ] + + - feeds = [ ('AP Headlines', 'http://hosted.ap.org/lineups/TOPHEADS-rss_2.0.xml?SITE=ORAST&SECTION=HOME'), ('AP US News', 'http://hosted.ap.org/lineups/USHEADS-rss_2.0.xml?SITE=CAVIC&SECTION=HOME'), ('AP World News', 'http://hosted.ap.org/lineups/WORLDHEADS-rss_2.0.xml?SITE=SCAND&SECTION=HOME'), @@ -38,4 +38,4 @@ class AssociatedPress(BasicNewsRecipe): ('AP Health News', 'http://hosted.ap.org/lineups/HEALTHHEADS-rss_2.0.xml?SITE=FLDAY&SECTION=HOME'), ('AP Science News', 'http://hosted.ap.org/lineups/SCIENCEHEADS-rss_2.0.xml?SITE=OHCIN&SECTION=HOME'), ('AP Strange News', 'http://hosted.ap.org/lineups/STRANGEHEADS-rss_2.0.xml?SITE=WCNC&SECTION=HOME'), - ] \ No newline at end of file + ] diff --git a/resources/recipes/elpais_impreso.recipe b/resources/recipes/elpais_impreso.recipe new file mode 100644 index 0000000000..b30db0707a --- /dev/null +++ b/resources/recipes/elpais_impreso.recipe @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +__license__ = 'GPL v3' +__copyright__ = '2010, Darko Miletic ' +''' +www.elpais.com/diario/ +''' + +from calibre import strftime +from calibre.web.feeds.news import BasicNewsRecipe + +class ElPaisImpresa(BasicNewsRecipe): + title = 'El País - edicion impresa' + __author__ = 'Darko Miletic' + description = 'el periodico global en Español' + publisher = 'EDICIONES EL PAIS, S.L.' + category = 'news, politics,Spain,actualidad,noticias,informacion,videos,fotografias,audios,graficos,nacional,internacional,deportes,economia,tecnologia,cultura,gente,television,sociedad,opinion,blogs,foros,chats,encuestas,entrevistas,participacion' + no_stylesheets = True + encoding = 'latin1' + use_embedded_content = False + language = 'es' + publication_type = 'newspaper' + masthead_url = 'http://www.elpais.com/im/tit_logo_global.gif' + index = 'http://www.elpais.com/diario/' + extra_css = ' p{text-align: justify} body{ text-align: left; font-family: Georgia,"Times New Roman",Times,serif } h2{font-family: Arial,Helvetica,sans-serif} img{margin-bottom: 0.4em} ' + + conversion_options = { + 'comment' : description + , 'tags' : category + , 'publisher' : publisher + , 'language' : language + } + + feeds = [ + (u'Internacional' , index + u'internacional/' ) + ,(u'España' , index + u'espana/' ) + ,(u'Economia' , index + u'economia/' ) + ,(u'Opinion' , index + u'opinion/' ) + ,(u'Viñetas' , index + u'vineta/' ) + ,(u'Sociedad' , index + u'sociedad/' ) + ,(u'Cultura' , index + u'cultura/' ) + ,(u'Tendencias' , index + u'tendencias/' ) + ,(u'Gente' , index + u'gente/' ) + ,(u'Obituarios' , index + u'obituarios/' ) + ,(u'Deportes' , index + u'deportes/' ) + ,(u'Pantallas' , index + u'radioytv/' ) + ,(u'Ultima' , index + u'ultima/' ) + ,(u'Educacion' , index + u'educacion/' ) + ,(u'Saludo' , index + u'salud/' ) + ,(u'Ciberpais' , index + u'ciberpais/' ) + ,(u'EP3' , index + u'ep3/' ) + ,(u'Cine' , index + u'cine/' ) + ,(u'Babelia' , index + u'babelia/' ) + ,(u'El viajero' , index + u'viajero/' ) + ,(u'Negocios' , index + u'negocios/' ) + ,(u'Domingo' , index + u'domingo/' ) + ,(u'El Pais semanal' , index + u'eps/' ) + ,(u'Quadern Catalunya' , index + u'quadern-catalunya/' ) + ] + + keep_only_tags=[dict(attrs={'class':['cabecera_noticia','contenido_noticia']})] + remove_attributes=['width','height'] + remove_tags=[dict(name='link')] + + def parse_index(self): + totalfeeds = [] + lfeeds = self.get_feeds() + for feedobj in lfeeds: + feedtitle, feedurl = feedobj + self.report_progress(0, _('Fetching feed')+' %s...'%(feedtitle if feedtitle else feedurl)) + articles = [] + soup = self.index_to_soup(feedurl) + for item in soup.findAll('a',attrs={'class':['g19r003','g19i003','g17r003','g17i003']}): + url = 'http://www.elpais.com' + item['href'].rpartition('/')[0] + title = self.tag_to_string(item) + date = strftime(self.timefmt) + articles.append({ + 'title' :title + ,'date' :date + ,'url' :url + ,'description':'' + }) + totalfeeds.append((feedtitle, articles)) + return totalfeeds + + def print_version(self, url): + return url + '?print=1' diff --git a/resources/recipes/greader.recipe b/resources/recipes/greader.recipe index cbf4c0226b..2c9d5aa015 100644 --- a/resources/recipes/greader.recipe +++ b/resources/recipes/greader.recipe @@ -4,29 +4,27 @@ from calibre import __appname__ class GoogleReader(BasicNewsRecipe): title = 'Google Reader' - description = 'This recipe downloads feeds you have tagged from your Google Reader account.' + description = 'This recipe fetches from your Google Reader account unread Starred items and unread Feeds you have placed in a folder via the manage subscriptions feature.' needs_subscription = True - __author__ = 'davec' + __author__ = 'davec, rollercoaster, Starson17' base_url = 'http://www.google.com/reader/atom/' - max_articles_per_feed = 50 + oldest_article = 365 + max_articles_per_feed = 250 get_options = '?n=%d&xt=user/-/state/com.google/read' % max_articles_per_feed use_embedded_content = True def get_browser(self): - br = BasicNewsRecipe.get_browser() - + br = BasicNewsRecipe.get_browser(self) if self.username is not None and self.password is not None: request = urllib.urlencode([('Email', self.username), ('Passwd', self.password), - ('service', 'reader'), ('source', __appname__)]) + ('service', 'reader'), ('accountType', 'HOSTED_OR_GOOGLE'), ('source', __appname__)]) response = br.open('https://www.google.com/accounts/ClientLogin', request) - sid = re.search('SID=(\S*)', response.read()).group(1) - + auth = re.search('Auth=(\S*)', response.read()).group(1) cookies = mechanize.CookieJar() br = mechanize.build_opener(mechanize.HTTPCookieProcessor(cookies)) - cookies.set_cookie(mechanize.Cookie(None, 'SID', sid, None, False, '.google.com', True, True, '/', True, False, None, True, '', '', None)) + br.addheaders = [('Authorization', 'GoogleLogin auth='+auth)] return br - def get_feeds(self): feeds = [] soup = self.index_to_soup('http://www.google.com/reader/api/0/tag/list') diff --git a/resources/recipes/greader_uber.recipe b/resources/recipes/greader_uber.recipe index ee48e7069d..5e02cdef5d 100644 --- a/resources/recipes/greader_uber.recipe +++ b/resources/recipes/greader_uber.recipe @@ -3,10 +3,10 @@ from calibre.web.feeds.recipes import BasicNewsRecipe from calibre import __appname__ class GoogleReaderUber(BasicNewsRecipe): - title = 'Google Reader Uber' - description = 'This recipe downloads all unread feedsfrom your Google Reader account.' + title = 'Google Reader uber' + description = 'Fetches all feeds from your Google Reader account including the uncategorized items.' needs_subscription = True - __author__ = 'rollercoaster, davec' + __author__ = 'davec, rollercoaster, Starson17' base_url = 'http://www.google.com/reader/atom/' oldest_article = 365 max_articles_per_feed = 250 @@ -14,20 +14,17 @@ class GoogleReaderUber(BasicNewsRecipe): use_embedded_content = True def get_browser(self): - br = BasicNewsRecipe.get_browser() - + br = BasicNewsRecipe.get_browser(self) if self.username is not None and self.password is not None: request = urllib.urlencode([('Email', self.username), ('Passwd', self.password), - ('service', 'reader'), ('source', __appname__)]) + ('service', 'reader'), ('accountType', 'HOSTED_OR_GOOGLE'), ('source', __appname__)]) response = br.open('https://www.google.com/accounts/ClientLogin', request) - sid = re.search('SID=(\S*)', response.read()).group(1) - + auth = re.search('Auth=(\S*)', response.read()).group(1) cookies = mechanize.CookieJar() br = mechanize.build_opener(mechanize.HTTPCookieProcessor(cookies)) - cookies.set_cookie(mechanize.Cookie(None, 'SID', sid, None, False, '.google.com', True, True, '/', True, False, None, True, '', '', None)) + br.addheaders = [('Authorization', 'GoogleLogin auth='+auth)] return br - def get_feeds(self): feeds = [] soup = self.index_to_soup('http://www.google.com/reader/api/0/tag/list') diff --git a/resources/recipes/orlando_sentinel.recipe b/resources/recipes/orlando_sentinel.recipe new file mode 100644 index 0000000000..7a59f6f6ba --- /dev/null +++ b/resources/recipes/orlando_sentinel.recipe @@ -0,0 +1,38 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class AdvancedUserRecipe1279258912(BasicNewsRecipe): + title = u'Orlando Sentinel' + oldest_article = 3 + max_articles_per_feed = 100 + + feeds = [ + (u'News', u'http://feeds.feedburner.com/orlandosentinel/news'), + (u'Opinion', u'http://feeds.feedburner.com/orlandosentinel/news/opinion'), + (u'Business', u'http://feeds.feedburner.com/orlandosentinel/business'), + (u'Technology', u'http://feeds.feedburner.com/orlandosentinel/technology'), + (u'Space and Science', u'http://feeds.feedburner.com/orlandosentinel/news/space'), + (u'Entertainment', u'http://feeds.feedburner.com/orlandosentinel/entertainment'), + (u'Life and Family', u'http://feeds.feedburner.com/orlandosentinel/features/lifestyle'), + ] + __author__ = 'rty' + pubisher = 'OrlandoSentinel.com' + description = 'Orlando, Florida, Newspaper' + category = 'News, Orlando, Florida' + + + remove_javascript = True + use_embedded_content = False + no_stylesheets = True + language = 'en' + encoding = 'utf-8' + conversion_options = {'linearize_tables':True} + masthead_url = 'http://www.orlandosentinel.com/media/graphic/2009-07/46844851.gif' + keep_only_tags = [ + dict(name='div', attrs={'class':'story'}) + ] + remove_tags = [ + dict(name='div', attrs={'class':['articlerail','tools','comment-group','clearfix']}), + ] + remove_tags_after = [ + dict(name='p', attrs={'class':'copyright'}), + ] diff --git a/resources/recipes/waco_tribune.recipe b/resources/recipes/waco_tribune.recipe new file mode 100644 index 0000000000..18eb61fb26 --- /dev/null +++ b/resources/recipes/waco_tribune.recipe @@ -0,0 +1,34 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class AdvancedUserRecipe1278773519(BasicNewsRecipe): + title = u'Waco Tribune Herald' + __author__ = 'rty' + pubisher = 'A Robinson Media Company' + description = 'Waco, Texas, Newspaper' + category = 'News, Texas, Waco' + oldest_article = 7 + max_articles_per_feed = 100 + + feeds = [ + (u'News', u'http://www.wacotrib.com/news/index.rss2'), + (u'Sports', u'http://www.wacotrib.com/sports/index.rss2'), + (u'AccessWaco', u'http://www.wacotrib.com/accesswaco/index.rss2'), + (u'Opinions', u'http://www.wacotrib.com/opinion/index.rss2') + ] + + remove_javascript = True + use_embedded_content = False + no_stylesheets = True + language = 'en' + encoding = 'utf-8' + conversion_options = {'linearize_tables':True} + masthead_url = 'http://media.wacotrib.com/designimages/wacotrib_logo.jpg' + keep_only_tags = [ + dict(name='div', attrs={'class':'twoColumn left'}), + ] + remove_tags = [ + dict(name='div', attrs={'class':'right blueLinks'}), + ] + remove_tags_after = [ + dict(name='div', attrs={'class':'dottedRule'}), + ] diff --git a/resources/templates/rtf.xsl b/resources/templates/rtf.xsl index 9199654665..74696f0857 100644 --- a/resources/templates/rtf.xsl +++ b/resources/templates/rtf.xsl @@ -111,7 +111,6 @@ or (@shadow = 'true') or (@hidden = 'true') or (@outline = 'true') - "> @@ -277,6 +276,26 @@ ] + + + + + + + + + + + + + + + + + + + + diff --git a/setup/installer/linux/freeze.py b/setup/installer/linux/freeze.py index 8c56ed4fb7..382c7ffeee 100644 --- a/setup/installer/linux/freeze.py +++ b/setup/installer/linux/freeze.py @@ -40,6 +40,7 @@ class LinuxFreeze(Command): '/usr/bin/pdftohtml', '/usr/lib/libwmflite-0.2.so.7', '/usr/lib/liblcms.so.1', + '/usr/lib/liblcms2.so.2', '/usr/lib/libstlport.so.5.1', '/tmp/calibre-mount-helper', '/usr/lib/libunrar.so', @@ -50,10 +51,9 @@ class LinuxFreeze(Command): '/usr/lib/libpodofo.so.0.8.1', '/lib/libz.so.1', '/lib/libuuid.so.1', - '/usr/lib/libtiff.so.3', + '/usr/lib/libtiff.so.5', '/lib/libbz2.so.1', - '/usr/lib/libpoppler.so.5', - '/usr/lib/libpoppler-qt4.so.3', + '/usr/lib/libpoppler.so.6', '/usr/lib/libxml2.so.2', '/usr/lib/libopenjpeg.so.2', '/usr/lib/libxslt.so.1', @@ -62,10 +62,10 @@ class LinuxFreeze(Command): '/usr/lib/libgthread-2.0.so.0', stdcpp, ffi, - '/usr/lib/libpng12.so.0', + '/usr/lib/libpng14.so.14', '/usr/lib/libexslt.so.0', - '/usr/lib/libMagickWand.so.2', - '/usr/lib/libMagickCore.so.2', + '/usr/lib/libMagickWand.so.3', + '/usr/lib/libMagickCore.so.3', '/usr/lib/libgcrypt.so.11', '/usr/lib/libgpg-error.so.0', '/usr/lib/libphonon.so.4', diff --git a/setup/installer/windows/freeze.py b/setup/installer/windows/freeze.py index 0b04cc11cc..29809907ab 100644 --- a/setup/installer/windows/freeze.py +++ b/setup/installer/windows/freeze.py @@ -13,7 +13,7 @@ from setup import Command, modules, functions, basenames, __version__, \ from setup.build_environment import msvc, MT, RC from setup.installer.windows.wix import WixMixIn -QT_DIR = 'C:\\Qt\\4.6.0' +QT_DIR = 'C:\\Qt\\4.6.3' QT_DLLS = ['Core', 'Gui', 'Network', 'Svg', 'WebKit', 'Xml', 'XmlPatterns'] LIBUSB_DIR = 'C:\\libusb' LIBUNRAR = 'C:\\Program Files\\UnrarDLL\\unrar.dll' 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/android/driver.py b/src/calibre/devices/android/driver.py index 5642235b31..5d9d094b26 100644 --- a/src/calibre/devices/android/driver.py +++ b/src/calibre/devices/android/driver.py @@ -30,7 +30,8 @@ class ANDROID(USBMS): 0x18d1 : { 0x4e11 : [0x0100, 0x226], 0x4e12: [0x0100, 0x226]}, # Samsung - 0x04e8 : { 0x681d : [0x0222, 0x0400], 0x681c : [0x0222, 0x0224]}, + 0x04e8 : { 0x681d : [0x0222, 0x0400], + 0x681c : [0x0222, 0x0224, 0x0400]}, # Acer 0x502 : { 0x3203 : [0x0100]}, @@ -70,6 +71,16 @@ class ANDROID(USBMS): dirs = [x.strip() for x in dirs.split(',')] self.EBOOK_DIR_MAIN = dirs + def get_main_ebook_dir(self, for_upload=False): + dirs = self.EBOOK_DIR_MAIN + if not for_upload: + def aldiko_tweak(x): + return 'eBooks' if x == 'eBooks/import' else x + if isinstance(dirs, basestring): + dirs = [dirs] + dirs = list(map(aldiko_tweak, dirs)) + return dirs + class S60(USBMS): name = 'S60 driver' 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/devices/prs505/sony_cache.py b/src/calibre/devices/prs505/sony_cache.py index b87ca937bc..3ac35df9b2 100644 --- a/src/calibre/devices/prs505/sony_cache.py +++ b/src/calibre/devices/prs505/sony_cache.py @@ -10,10 +10,10 @@ from base64 import b64decode from uuid import uuid4 from lxml import etree -from calibre import prints, guess_type +from calibre import prints, guess_type, isbytestring from calibre.devices.errors import DeviceError from calibre.devices.usbms.driver import debug_print -from calibre.constants import DEBUG +from calibre.constants import DEBUG, preferred_encoding from calibre.ebooks.chardet import xml_to_unicode from calibre.ebooks.metadata import authors_to_string, title_sort @@ -473,6 +473,13 @@ class XMLCache(object): # if the case of a tie, and hope it is right. timestamp = os.path.getmtime(path) rec_date = record.get('date', None) + + def clean(x): + if isbytestring(x): + x = x.decode(preferred_encoding, 'replace') + x.replace(u'\0', '') + return x + if not getattr(book, '_new_book', False): # book is not new if strftime(timestamp, zone=time.gmtime) == rec_date: gtz_count += 1 @@ -486,19 +493,19 @@ class XMLCache(object): tz = time.gmtime debug_print("Using GMT TZ for new book", book.lpath) date = strftime(timestamp, zone=tz) - record.set('date', date) + record.set('date', clean(date)) - record.set('size', str(os.stat(path).st_size)) + record.set('size', clean(str(os.stat(path).st_size))) title = book.title if book.title else _('Unknown') - record.set('title', title) + record.set('title', clean(title)) ts = book.title_sort if not ts: ts = title_sort(title) - record.set('titleSorter', ts) + record.set('titleSorter', clean(ts)) if self.use_author_sort and book.author_sort is not None: - record.set('author', book.author_sort) + record.set('author', clean(book.author_sort)) else: - record.set('author', authors_to_string(book.authors)) + record.set('author', clean(authors_to_string(book.authors))) ext = os.path.splitext(path)[1] if ext: ext = ext[1:].lower() @@ -506,7 +513,7 @@ class XMLCache(object): if mime is None: mime = guess_type('a.'+ext)[0] if mime is not None: - record.set('mime', mime) + record.set('mime', clean(mime)) if 'sourceid' not in record.attrib: record.set('sourceid', '1') if 'id' not in record.attrib: diff --git a/src/calibre/devices/scanner.py b/src/calibre/devices/scanner.py index ceba5d37d0..dd789dd668 100644 --- a/src/calibre/devices/scanner.py +++ b/src/calibre/devices/scanner.py @@ -98,6 +98,9 @@ class LinuxScanner(object): def __call__(self): ans = set([]) + if not self.ok: + raise RuntimeError('DeviceScanner requires the /sys filesystem to work.') + for x in os.listdir(self.base): base = os.path.join(self.base, x) ven = os.path.join(base, 'idVendor') @@ -145,8 +148,6 @@ class DeviceScanner(object): def __init__(self, *args): if isosx and osx_scanner is None: raise RuntimeError('The Python extension usbobserver must be available on OS X.') - if islinux and not linux_scanner.ok: - raise RuntimeError('DeviceScanner requires the /sys filesystem to work.') self.scanner = win_scanner if iswindows else osx_scanner if isosx else linux_scanner self.devices = [] diff --git a/src/calibre/devices/usbms/books.py b/src/calibre/devices/usbms/books.py index 42d0f3c863..cdba980642 100644 --- a/src/calibre/devices/usbms/books.py +++ b/src/calibre/devices/usbms/books.py @@ -72,13 +72,13 @@ class Book(MetaInformation): def thumbnail(self): return None - def smart_update(self, other): + def smart_update(self, other, replace_metadata=False): ''' Merge the information in C{other} into self. In case of conflicts, the information in C{other} takes precedence, unless the information in C{other} is NULL. ''' - MetaInformation.smart_update(self, other, replace_tags=True) + MetaInformation.smart_update(self, other, replace_metadata) for attr in self.BOOK_ATTRS: if hasattr(other, attr): @@ -116,7 +116,7 @@ class BookList(_BookList): self.append(book) return True if replace_metadata: - self[b].smart_update(book) + self[b].smart_update(book, replace_metadata=True) return True return False @@ -132,6 +132,8 @@ class CollectionsBookList(BookList): return True def get_collections(self, collection_attributes): + from calibre.devices.usbms.driver import debug_print + debug_print('Starting get_collections:', prefs['manage_device_metadata']) collections = {} series_categories = set([]) # This map of sets is used to avoid linear searches when testing for @@ -146,14 +148,19 @@ class CollectionsBookList(BookList): # book in all existing collections. Do not add any new ones. attrs = ['device_collections'] if getattr(book, '_new_book', False): - if prefs['preserve_user_collections']: + if prefs['manage_device_metadata'] == 'manual': # Ensure that the book is in all the book's existing # collections plus all metadata collections attrs += collection_attributes else: - # The book's existing collections are ignored. Put the book - # in collections defined by its metadata. + # For new books, both 'on_send' and 'on_connect' do the same + # thing. The book's existing collections are ignored. Put + # the book in collections defined by its metadata. attrs = collection_attributes + elif prefs['manage_device_metadata'] == 'on_connect': + # For existing books, modify the collections only if the user + # specified 'on_connect' + attrs = collection_attributes for attr in attrs: attr = attr.strip() val = getattr(book, attr, None) diff --git a/src/calibre/devices/usbms/device.py b/src/calibre/devices/usbms/device.py index 55790420f2..c07b7fd761 100644 --- a/src/calibre/devices/usbms/device.py +++ b/src/calibre/devices/usbms/device.py @@ -732,7 +732,7 @@ class Device(DeviceConfig, DevicePlugin): traceback.print_exc() self._main_prefix = self._card_a_prefix = self._card_b_prefix = None - def get_main_ebook_dir(self): + def get_main_ebook_dir(self, for_upload=False): return self.EBOOK_DIR_MAIN def _sanity_check(self, on_card, files): @@ -750,7 +750,7 @@ class Device(DeviceConfig, DevicePlugin): path = os.path.join(self._card_b_prefix, *(self.EBOOK_DIR_CARD_B.split('/'))) else: - candidates = self.get_main_ebook_dir() + candidates = self.get_main_ebook_dir(for_upload=True) if isinstance(candidates, basestring): candidates = [candidates] candidates = [ diff --git a/src/calibre/devices/usbms/driver.py b/src/calibre/devices/usbms/driver.py index 377ec36c16..73a329be58 100644 --- a/src/calibre/devices/usbms/driver.py +++ b/src/calibre/devices/usbms/driver.py @@ -58,7 +58,7 @@ class USBMS(CLI, Device): debug_print ('USBMS: Fetching list of books from device. oncard=', oncard) - dummy_bl = BookList(None, None, None) + dummy_bl = self.booklist_class(None, None, None) if oncard == 'carda' and not self._card_a_prefix: self.report_progress(1.0, _('Getting list of books on device...')) @@ -78,6 +78,8 @@ class USBMS(CLI, Device): self.EBOOK_DIR_CARD_B if oncard == 'cardb' else \ self.get_main_ebook_dir() + debug_print ('USBMS: dirs are:', prefix, ebook_dirs) + # get the metadata cache bl = self.booklist_class(oncard, prefix, self.settings) need_sync = self.parse_metadata_cache(bl, prefix, self.METADATA_CACHE) diff --git a/src/calibre/ebooks/epub/fix/container.py b/src/calibre/ebooks/epub/fix/container.py index 7a7c17427a..b9af66d708 100644 --- a/src/calibre/ebooks/epub/fix/container.py +++ b/src/calibre/ebooks/epub/fix/container.py @@ -5,7 +5,7 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' -import os, posixpath, urllib, sys +import os, posixpath, urllib, sys, re from lxml import etree @@ -160,8 +160,26 @@ class Container(object): mt = mimetype.lower() if mt.endswith('+xml'): parser = etree.XMLParser(no_network=True, huge_tree=not iswindows) - return etree.fromstring(xml_to_unicode(raw, - strip_encoding_pats=True, assume_utf8=True)[0], parser=parser) + raw = xml_to_unicode(raw, + strip_encoding_pats=True, assume_utf8=True, + resolve_entities=True)[0].strip() + idx = raw.find(' -1: + pre = raw[:idx] + raw = raw[idx:] + if ']+)', pre): + val = match.group(2) + if val.startswith('"') and val.endswith('"'): + val = val[1:-1] + user_entities[match.group(1)] = val + if user_entities: + pat = re.compile(r'&(%s);'%('|'.join(user_entities.keys()))) + raw = pat.sub(lambda m:user_entities[m.group(1)], raw) + return etree.fromstring(raw, parser=parser) return raw def write(self, path): diff --git a/src/calibre/ebooks/epub/fix/epubcheck.py b/src/calibre/ebooks/epub/fix/epubcheck.py index f5c8086e7c..fd913a654b 100644 --- a/src/calibre/ebooks/epub/fix/epubcheck.py +++ b/src/calibre/ebooks/epub/fix/epubcheck.py @@ -21,7 +21,7 @@ class Epubcheck(ePubFixer): def long_description(self): return _('Workarounds for bugs in the latest release of epubcheck. ' 'epubcheck reports many things as errors that are not ' - 'actually errors. %prog will try to detect these and replace ' + 'actually errors. epub-fix will try to detect these and replace ' 'them with constructs that epubcheck likes. This may cause ' 'significant changes to your epub, complain to the epubcheck ' 'project.') diff --git a/src/calibre/ebooks/epub/fix/unmanifested.py b/src/calibre/ebooks/epub/fix/unmanifested.py index 71913e9d50..da7a9a9d0e 100644 --- a/src/calibre/ebooks/epub/fix/unmanifested.py +++ b/src/calibre/ebooks/epub/fix/unmanifested.py @@ -18,7 +18,7 @@ class Unmanifested(ePubFixer): @property def long_description(self): - return _('Fix unmanifested files. %prog can either add them to ' + return _('Fix unmanifested files. epub-fix can either add them to ' 'the manifest or delete them as specified by the ' 'delete unmanifested option.') diff --git a/src/calibre/ebooks/metadata/__init__.py b/src/calibre/ebooks/metadata/__init__.py index 0dbffd5f7f..e45334777e 100644 --- a/src/calibre/ebooks/metadata/__init__.py +++ b/src/calibre/ebooks/metadata/__init__.py @@ -268,10 +268,12 @@ class MetaInformation(object): ): prints(x, getattr(self, x, 'None')) - def smart_update(self, mi, replace_tags=False): + def smart_update(self, mi, replace_metadata=False): ''' - Merge the information in C{mi} into self. In case of conflicts, the information - in C{mi} takes precedence, unless the information in mi is NULL. + Merge the information in C{mi} into self. In case of conflicts, the + information in C{mi} takes precedence, unless the information in mi is + NULL. If replace_metadata is True, then the information in mi always + takes precedence. ''' if mi.title and mi.title != _('Unknown'): self.title = mi.title @@ -285,13 +287,16 @@ class MetaInformation(object): 'cover', 'guide', 'book_producer', 'timestamp', 'lccn', 'lcc', 'ddc', 'pubdate', 'rights', 'publication_type', 'uuid'): - if hasattr(mi, attr): + if replace_metadata: + setattr(self, attr, getattr(mi, attr, 1.0 if \ + attr == 'series_index' else None)) + elif hasattr(mi, attr): val = getattr(mi, attr) if val is not None: setattr(self, attr, val) if mi.tags: - if replace_tags: + if replace_metadata: self.tags = mi.tags else: self.tags += mi.tags 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/convert/regex_builder.py b/src/calibre/gui2/convert/regex_builder.py index 6fa0fa5fe4..b10772b86c 100644 --- a/src/calibre/gui2/convert/regex_builder.py +++ b/src/calibre/gui2/convert/regex_builder.py @@ -28,9 +28,10 @@ class RegexBuilder(QDialog, Ui_RegexBuilder): if not db or not book_id: self.button_box.addButton(QDialogButtonBox.Open) - else: - self.select_format(db, book_id) - + elif not self.select_format(db, book_id): + self.cancelled = True + return + self.cancelled = False self.connect(self.button_box, SIGNAL('clicked(QAbstractButton*)'), self.button_clicked) self.connect(self.regex, SIGNAL('textChanged(QString)'), self.regex_valid) self.connect(self.test, SIGNAL('clicked()'), self.do_test) @@ -79,10 +80,12 @@ class RegexBuilder(QDialog, Ui_RegexBuilder): format = d.format() if not format: - error_dialog(self, _('No formats available'), _('Cannot build regex using the GUI builder without a book.')) - QDialog.reject() - else: - self.open_book(db.format_abspath(book_id, format, index_is_id=True)) + error_dialog(self, _('No formats available'), + _('Cannot build regex using the GUI builder without a book.'), + show=True) + return False + self.open_book(db.format_abspath(book_id, format, index_is_id=True)) + return True def open_book(self, pathtoebook): self.iterator = EbookIterator(pathtoebook) @@ -117,6 +120,8 @@ class RegexEdit(QWidget, Ui_Edit): def builder(self): bld = RegexBuilder(self.db, self.book_id, self.edit.text(), self) + if bld.cancelled: + return if bld.exec_() == bld.Accepted: self.edit.setText(bld.regex.text()) diff --git a/src/calibre/gui2/convert/structure_detection.ui b/src/calibre/gui2/convert/structure_detection.ui index e4414473f5..2e97c0d3ca 100644 --- a/src/calibre/gui2/convert/structure_detection.ui +++ b/src/calibre/gui2/convert/structure_detection.ui @@ -28,7 +28,11 @@ - + + + 20 + + diff --git a/src/calibre/gui2/convert/xexp_edit.ui b/src/calibre/gui2/convert/xexp_edit.ui index 1b0196a8a1..f98eb8b1b8 100644 --- a/src/calibre/gui2/convert/xexp_edit.ui +++ b/src/calibre/gui2/convert/xexp_edit.ui @@ -43,6 +43,15 @@ 0 + + + 500 + 16777215 + + + + 30 + diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index 2a9c81e8ee..96232fe85f 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -10,9 +10,10 @@ from functools import partial from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateEdit, \ QDate, QGroupBox, QVBoxLayout, QPlainTextEdit, QSizePolicy, \ - QSpacerItem, QIcon, QCheckBox, QWidget, QHBoxLayout, SIGNAL + QSpacerItem, QIcon, QCheckBox, QWidget, QHBoxLayout, SIGNAL, \ + QPushButton -from calibre.utils.date import qt_to_dt +from calibre.utils.date import qt_to_dt, now from calibre.gui2.widgets import TagsLineEdit, EnComboBox from calibre.gui2 import UNDEFINED_QDATE from calibre.utils.config import tweaks @@ -132,20 +133,30 @@ class DateEdit(QDateEdit): def focusInEvent(self, x): self.setSpecialValueText('') + QDateEdit.focusInEvent(self, x) def focusOutEvent(self, x): self.setSpecialValueText(_('Undefined')) + QDateEdit.focusOutEvent(self, x) + + def set_to_today(self): + self.setDate(now()) class DateTime(Base): def setup_ui(self, parent): - self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent), - DateEdit(parent)] + cm = self.col_metadata + self.widgets = [QLabel('&'+cm['name']+':', parent), DateEdit(parent), + QLabel(''), QPushButton(_('Set \'%s\' to today')%cm['name'], parent)] w = self.widgets[1] - w.setDisplayFormat('dd MMM yyyy') + format = cm['display'].get('date_format','') + if not format: + format = 'dd MMM yyyy' + w.setDisplayFormat(format) w.setCalendarPopup(True) w.setMinimumDate(UNDEFINED_QDATE) w.setSpecialValueText(_('Undefined')) + self.widgets[3].clicked.connect(w.set_to_today) def setter(self, val): if val is None: diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index e2a99864ec..bc8ba7c381 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -33,6 +33,7 @@ from calibre.devices.apple.driver import ITUNES_ASYNC from calibre.devices.folder_device.driver import FOLDER_DEVICE from calibre.ebooks.metadata.meta import set_metadata from calibre.constants import DEBUG +from calibre.utils.config import prefs # }}} @@ -764,6 +765,7 @@ class DeviceMixin(object): # {{{ 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)) def info_read(self, job): ''' @@ -1424,19 +1426,25 @@ class DeviceMixin(object): # {{{ aus = re.sub('(?u)\W|[_]', '', aus) self.db_book_title_cache[title]['author_sort'][aus] = mi self.db_book_title_cache[title]['db_ids'][mi.application_id] = mi - self.db_book_uuid_cache[mi.uuid] = mi.application_id + self.db_book_uuid_cache[mi.uuid] = mi # Now iterate through all the books on the device, setting the # in_library field Fastest and most accurate key is the uuid. Second is # the application_id, which is really the db key, but as this can # accidentally match across libraries we also verify the title. The # db_id exists on Sony devices. Fallback is title and author match + + update_metadata = prefs['manage_device_metadata'] == 'on_connect' for booklist in booklists: for book in booklist: if getattr(book, 'uuid', None) in self.db_book_uuid_cache: + if update_metadata: + book.smart_update(self.db_book_uuid_cache[book.uuid], + replace_metadata=True) book.in_library = True # ensure that the correct application_id is set - book.application_id = self.db_book_uuid_cache[book.uuid] + book.application_id = \ + self.db_book_uuid_cache[book.uuid].application_id continue book_title = book.title.lower() if book.title else '' @@ -1446,11 +1454,15 @@ class DeviceMixin(object): # {{{ if d is not None: if getattr(book, 'application_id', None) in d['db_ids']: book.in_library = True - book.smart_update(d['db_ids'][book.application_id]) + if update_metadata: + book.smart_update(d['db_ids'][book.application_id], + replace_metadata=True) continue if book.db_id in d['db_ids']: book.in_library = True - book.smart_update(d['db_ids'][book.db_id]) + if update_metadata: + book.smart_update(d['db_ids'][book.db_id], + replace_metadata=True) continue if book.authors: # Compare against both author and author sort, because @@ -1459,14 +1471,21 @@ class DeviceMixin(object): # {{{ book_authors = re.sub('(?u)\W|[_]', '', book_authors) if book_authors in d['authors']: book.in_library = True - book.smart_update(d['authors'][book_authors]) + if update_metadata: + book.smart_update(d['authors'][book_authors], + replace_metadata=True) elif book_authors in d['author_sort']: book.in_library = True - book.smart_update(d['author_sort'][book_authors]) + if update_metadata: + book.smart_update(d['author_sort'][book_authors], + replace_metadata=True) # Set author_sort if it isn't already asort = getattr(book, 'author_sort', None) if not asort and book.authors: book.author_sort = self.library_view.model().db.author_sort_from_authors(book.authors) + if update_metadata: + if self.device_manager.is_device_connected: + self.device_manager.sync_booklists(None, booklists) # }}} diff --git a/src/calibre/gui2/dialogs/config/__init__.py b/src/calibre/gui2/dialogs/config/__init__.py index bf9dc0a623..b064dc53c2 100644 --- a/src/calibre/gui2/dialogs/config/__init__.py +++ b/src/calibre/gui2/dialogs/config/__init__.py @@ -334,7 +334,6 @@ class ConfigDialog(ResizableDialog, Ui_Dialog): def __init__(self, parent, library_view, server=None): ResizableDialog.__init__(self, parent) - self.ICON_SIZES = {0:QSize(48, 48), 1:QSize(32,32), 2:QSize(24,24)} self._category_model = CategoryModel() self.category_view.currentChanged = self.category_current_changed @@ -389,10 +388,6 @@ class ConfigDialog(ResizableDialog, Ui_Dialog): self.add_custcol_button.clicked.connect(self.add_custcol) self.edit_custcol_button.clicked.connect(self.edit_custcol) - icons = config['toolbar_icon_size'] - self.toolbar_button_size.setCurrentIndex(0 if icons == self.ICON_SIZES[0] else 1 if icons == self.ICON_SIZES[1] else 2) - self.show_toolbar_text.setChecked(config['show_text_in_toolbar']) - output_formats = sorted(available_output_formats()) output_formats.remove('oeb') for f in output_formats: @@ -845,8 +840,6 @@ class ConfigDialog(ResizableDialog, Ui_Dialog): must_restart = self.apply_custom_column_changes() - config['toolbar_icon_size'] = self.ICON_SIZES[self.toolbar_button_size.currentIndex()] - config['show_text_in_toolbar'] = bool(self.show_toolbar_text.isChecked()) config['separate_cover_flow'] = bool(self.separate_cover_flow.isChecked()) config['disable_tray_notification'] = not self.systray_notifications.isChecked() p = {0:'normal', 1:'high', 2:'low'}[self.priority.currentIndex()] diff --git a/src/calibre/gui2/dialogs/config/add_save.py b/src/calibre/gui2/dialogs/config/add_save.py index b1f5621f44..8eb6cf7bd0 100644 --- a/src/calibre/gui2/dialogs/config/add_save.py +++ b/src/calibre/gui2/dialogs/config/add_save.py @@ -45,7 +45,12 @@ class AddSave(QTabWidget, Ui_TabWidget): self.metadata_box.layout().insertWidget(0, self.filename_pattern) self.opt_swap_author_names.setChecked(prefs['swap_author_names']) self.opt_add_formats_to_existing.setChecked(prefs['add_formats_to_existing']) - self.preserve_user_collections.setChecked(prefs['preserve_user_collections']) + if prefs['manage_device_metadata'] == 'manual': + self.manage_device_metadata.setCurrentIndex(0) + elif prefs['manage_device_metadata'] == 'on_send': + self.manage_device_metadata.setCurrentIndex(1) + else: + self.manage_device_metadata.setCurrentIndex(2) help = '\n'.join(textwrap.wrap(c.get_option('template').help, 75)) self.save_template.initialize('save_to_disk', opts.template, help) self.send_template.initialize('send_to_device', opts.send_template, help) @@ -72,12 +77,14 @@ class AddSave(QTabWidget, Ui_TabWidget): prefs['filename_pattern'] = pattern prefs['swap_author_names'] = bool(self.opt_swap_author_names.isChecked()) prefs['add_formats_to_existing'] = bool(self.opt_add_formats_to_existing.isChecked()) - prefs['preserve_user_collections'] = bool(self.preserve_user_collections.isChecked()) - + if self.manage_device_metadata.currentIndex() == 0: + prefs['manage_device_metadata'] = 'manual' + elif self.manage_device_metadata.currentIndex() == 1: + prefs['manage_device_metadata'] = 'on_send' + else: + prefs['manage_device_metadata'] = 'on_connect' return True - - if __name__ == '__main__': from PyQt4.Qt import QApplication app=QApplication([]) diff --git a/src/calibre/gui2/dialogs/config/add_save.ui b/src/calibre/gui2/dialogs/config/add_save.ui index 64a8137aa1..c8ee0419a9 100644 --- a/src/calibre/gui2/dialogs/config/add_save.ui +++ b/src/calibre/gui2/dialogs/config/add_save.ui @@ -6,7 +6,7 @@ 0 0 - 588 + 671 516 @@ -177,32 +177,81 @@ Title match ignores leading indefinite articles ("the", "a", Sending to &device - - - + + + + + + 0 + 0 + + - Preserve device collections. + Metadata &management: + + + manage_device_metadata - + + + + + 0 + 0 + + + + + Manual management + + + + + Only on send + + + + + Automatic management + + + + + + + + Qt::Horizontal + + + + 313 + 20 + + + + + - If checked, collections will not be deleted even if a book with changed metadata is resent and the collection is not in the book's metadata. In addition, editing collections in the device view will be enabled. If unchecked, collections will be always reflect only the metadata in the calibre library. + <li><b>Manual Management</b>: Calibre updates the metadata and adds collections only when a book is sent. With this option, calibre will never remove a collection.</li> +<li><b>Only on send</b>: Calibre updates metadata and adds/removes collections for a book only when it is sent to the device. </li> +<li><b>Automatic management</b>: Calibre automatically keeps metadata on the device in sync with the calibre library, on every connect</li></ul> true - + - + - + Here you can control how calibre will save your books when you click the Send to Device button. This setting can be overriden for individual devices by customizing the device interface plugins in Preferences->Plugins @@ -212,7 +261,7 @@ Title match ignores leading indefinite articles ("the", "a", - + diff --git a/src/calibre/gui2/dialogs/config/config.ui b/src/calibre/gui2/dialogs/config/config.ui index b473ee7846..5f890631b2 100644 --- a/src/calibre/gui2/dialogs/config/config.ui +++ b/src/calibre/gui2/dialogs/config/config.ui @@ -422,54 +422,6 @@ - - - Toolbar - - - - - - - Large - - - - - Medium - - - - - Small - - - - - - - - &Button size in toolbar - - - toolbar_button_size - - - - - - - Show &text in toolbar buttons - - - true - - - - - - - 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 9a4bb22f82..2474685522 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -176,12 +176,6 @@ class ToolbarMixin(object): # {{{ def show_help(self, *args): open_url(QUrl('http://calibre-ebook.com/user_manual')) - def read_toolbar_settings(self): - self.tool_bar.setIconSize(config['toolbar_icon_size']) - self.tool_bar.setToolButtonStyle( - Qt.ToolButtonTextUnderIcon if \ - config['show_text_in_toolbar'] else \ - Qt.ToolButtonIconOnly) # }}} @@ -409,7 +403,8 @@ class StatusBar(QStatusBar): # {{{ self.clearMessage() def message_changed(self, msg): - if not msg or msg.isEmpty() or msg.isNull(): + if not msg or msg.isEmpty() or msg.isNull() or \ + not unicode(msg).strip(): extra = '' if self.device_string: extra = ' ..::.. ' + self.device_string diff --git a/src/calibre/gui2/layout.py b/src/calibre/gui2/layout.py index f3b650f531..c1ff3ab505 100644 --- a/src/calibre/gui2/layout.py +++ b/src/calibre/gui2/layout.py @@ -5,48 +5,21 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' +from operator import attrgetter + 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, QComboBox + QVBoxLayout, QSizePolicy, QLabel, QHBoxLayout from calibre.constants import __appname__, filesystem_encoding from calibre.gui2.search_box import SearchBox2, SavedSearchBox from calibre.gui2.throbber import ThrobbingButton -from calibre.gui2 import NONE +from calibre.gui2 import NONE, config +from calibre.gui2.widgets import ComboBoxWithHelp from calibre import human_readable -class ToolBar(QToolBar): # {{{ - - def __init__(self, parent=None): - QToolBar.__init__(self, parent) - self.setContextMenuPolicy(Qt.PreventContextMenu) - self.setMovable(False) - self.setFloatable(False) - self.setOrientation(Qt.Horizontal) - self.setAllowedAreas(Qt.TopToolBarArea|Qt.BottomToolBarArea) - self.setIconSize(QSize(48, 48)) - self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) - - def add_actions(self, *args): - self.left_space = QWidget(self) - self.left_space.setSizePolicy(QSizePolicy.Expanding, - QSizePolicy.Minimum) - self.addWidget(self.left_space) - for action in args: - if action is None: - self.addSeparator() - else: - self.addAction(action) - self.right_space = QWidget(self) - self.right_space.setSizePolicy(QSizePolicy.Expanding, - QSizePolicy.Minimum) - self.addWidget(self.right_space) - - def contextMenuEvent(self, *args): - pass - -# }}} +ICON_SIZE = 48 # Location View {{{ @@ -165,7 +138,7 @@ class LocationModel(QAbstractListModel): # {{{ class LocationView(QListView): - unmount_device = pyqtSignal() + umount_device = pyqtSignal() location_selected = pyqtSignal(object) def __init__(self, parent): @@ -190,22 +163,27 @@ class LocationView(QListView): self.setTabKeyNavigation(True) self.setProperty("showDropIndicator", True) self.setSelectionMode(self.SingleSelection) - self.setIconSize(QSize(40, 40)) + self.setIconSize(QSize(ICON_SIZE, ICON_SIZE)) self.setMovement(self.Static) self.setFlow(self.LeftToRight) - self.setGridSize(QSize(175, 90)) + self.setGridSize(QSize(175, ICON_SIZE)) self.setViewMode(self.ListMode) self.setWordWrap(True) self.setObjectName("location_view") - self.setMaximumHeight(74) + self.setMaximumSize(QSize(600, ICON_SIZE+16)) + self.setMinimumWidth(400) def eject_clicked(self, *args): - self.unmount_device.emit() + 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() @@ -247,12 +225,15 @@ 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) @@ -280,12 +261,7 @@ class SearchBar(QWidget): # {{{ self._layout = l = QHBoxLayout() self.setLayout(self._layout) - self.restriction_label = QLabel(_("&Restrict to:")) - l.addWidget(self.restriction_label) - self.restriction_label.setSizePolicy(QSizePolicy.Minimum, - QSizePolicy.Minimum) - - x = QComboBox(self) + x = ComboBoxWithHelp(self) x.setMaximumSize(QSize(150, 16777215)) x.setObjectName("search_restriction") x.setToolTip(_("Books display will be restricted to those matching the selected saved search")) @@ -344,38 +320,88 @@ class SearchBar(QWidget): # {{{ x.setToolTip(_("Delete current saved search")) self.label.setBuddy(parent.search) - self.restriction_label.setBuddy(parent.search_restriction) # }}} -class LocationBar(ToolBar): # {{{ +class ToolBar(QToolBar): # {{{ def __init__(self, actions, donate, location_view, parent=None): - ToolBar.__init__(self, parent) - - for ac in actions: - self.addAction(ac) - - self.addWidget(location_view) - self.w = QWidget() - self.w.setLayout(QVBoxLayout()) - self.w.layout().addWidget(donate) - donate.setAutoRaise(True) - donate.setCursor(Qt.PointingHandCursor) - self.addWidget(self.w) - self.setIconSize(QSize(50, 50)) + QToolBar.__init__(self, parent) + self.setContextMenuPolicy(Qt.PreventContextMenu) + self.setMovable(False) + self.setFloatable(False) + self.setOrientation(Qt.Horizontal) + self.setAllowedAreas(Qt.TopToolBarArea|Qt.BottomToolBarArea) + self.setIconSize(QSize(ICON_SIZE, ICON_SIZE)) self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) - def button_for_action(self, ac): - b = QToolButton(self) - b.setDefaultAction(ac) - for x in ('ToolTip', 'StatusTip', 'WhatsThis'): - getattr(b, 'set'+x)(b.text()) + self.showing_device = False + self.all_actions = actions + self.donate = donate + self.location_view = location_view + self.d_widget = QWidget() + self.d_widget.setLayout(QVBoxLayout()) + self.d_widget.layout().addWidget(donate) + donate.setAutoRaise(True) + donate.setCursor(Qt.PointingHandCursor) + self.build_bar() + + 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' + o = attrgetter(order_field+'_order') + sepvals = [2] if self.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) + 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'): + ch.setPopupMode(ch.MenuButtonPopup) + + + 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) + + def count_changed(self, new_count): + text = _('%d books')%new_count + a = self.choose_action + a.setText(text) + + def resizeEvent(self, ev): + style = Qt.ToolButtonTextUnderIcon + if self.size().width() < 1260: + style = Qt.ToolButtonIconOnly + self.setToolButtonStyle(style) + QToolBar.resizeEvent(self, ev) - return b # }}} +class Action(QAction): + pass + class MainWindowMixin(object): def __init__(self): @@ -390,12 +416,19 @@ class MainWindowMixin(object): self.centralwidget.setLayout(self._central_widget_layout) self.resize(1012, 740) self.donate_button = ThrobbingButton(self.centralwidget) - self.donate_button.set_normal_icon_size(64, 64) + self.donate_button.set_normal_icon_size(ICON_SIZE, ICON_SIZE) # Actions {{{ - def ac(name, text, icon, shortcut=None, tooltip=None): - action = QAction(QIcon(I(icon)), text, self) + all_actions = [] + + def ac(normal_order, device_order, separator_before, + name, text, icon, shortcut=None, tooltip=None): + action = Action(QIcon(I(icon)), text, self) + action.normal_order = normal_order + action.device_order = device_order + action.separator_before = separator_before + action.action_name = name text = tooltip if tooltip else text action.setToolTip(text) action.setStatusTip(text) @@ -405,56 +438,46 @@ class MainWindowMixin(object): if shortcut: action.setShortcut(shortcut) setattr(self, 'action_'+name, action) + all_actions.append(action) - ac('add', _('Add books'), 'add_book.svg', _('A')) - ac('del', _('Remove books'), 'trash.svg', _('Del')) - ac('edit', _('Edit meta info'), 'edit_input.svg', _('E')) - ac('merge', _('Merge book records'), 'merge_books.svg', _('M')) - ac('sync', _('Send to device'), 'sync.svg') - ac('save', _('Save to disk'), 'save.svg', _('S')) - ac('news', _('Fetch news'), 'news.svg', _('F')) - ac('convert', _('Convert books'), 'convert.svg', _('C')) - ac('view', _('View'), 'view.svg', _('V')) - ac('open_containing_folder', _('Open containing folder'), + ac(0, 7, 0, 'add', _('Add books'), 'add_book.svg', _('A')) + ac(1, 1, 0, 'edit', _('Edit metadata'), 'edit_input.svg', _('E')) + ac(2, 2, 3, 'convert', _('Convert books'), 'convert.svg', _('C')) + ac(3, 3, 0, 'view', _('View'), 'view.svg', _('V')) + ac(4, 4, 3, 'choose_library', _('%d books')%0, 'lt.png', + tooltip=_('Choose calibre library to work with')) + ac(5, 5, 3, 'news', _('Fetch news'), 'news.svg', _('F')) + ac(6, 6, 0, 'save', _('Save to disk'), 'save.svg', _('S')) + ac(7, 0, 0, 'sync', _('Send to device'), 'sync.svg') + ac(8, 8, 3, 'del', _('Remove books'), 'trash.svg', _('Del')) + ac(9, 9, 3, 'help', _('Help'), 'help.svg', _('F1'), _("Browse the calibre User Manual")) + ac(10, 10, 0, 'preferences', _('Preferences'), 'config.svg', _('Ctrl+P')) + + ac(-1, -1, 0, 'merge', _('Merge book records'), 'merge_books.svg', _('M')) + ac(-1, -1, 0, 'open_containing_folder', _('Open containing folder'), 'document_open.svg') - ac('show_book_details', _('Show book details'), + ac(-1, -1, 0, 'show_book_details', _('Show book details'), 'dialog_information.svg') - ac('books_by_same_author', _('Books by same author'), + ac(-1, -1, 0, 'books_by_same_author', _('Books by same author'), 'user_profile.svg') - ac('books_in_this_series', _('Books in this series'), + ac(-1, -1, 0, 'books_in_this_series', _('Books in this series'), 'books_in_series.svg') - ac('books_by_this_publisher', _('Books by this publisher'), + ac(-1, -1, 0, 'books_by_this_publisher', _('Books by this publisher'), 'publisher.png') - ac('books_with_the_same_tags', _('Books with the same tags'), + ac(-1, -1, 0, 'books_with_the_same_tags', _('Books with the same tags'), 'tags.svg') - ac('preferences', _('Preferences'), 'config.svg', _('Ctrl+P')) - ac('help', _('Help'), 'help.svg', _('F1'), _("Browse the calibre User Manual")) # }}} - self.tool_bar = ToolBar(self) - self.addToolBar(Qt.BottomToolBarArea, self.tool_bar) - self.tool_bar.add_actions(self.action_convert, self.action_view, - None, self.action_edit, None, - self.action_save, self.action_del, - None, - self.action_help, None, self.action_preferences) - self.location_view = LocationView(self.centralwidget) self.search_bar = SearchBar(self) - self.location_bar = LocationBar([self.action_add, self.action_sync, - self.action_news], self.donate_button, self.location_view, self) - self.addToolBar(Qt.TopToolBarArea, self.location_bar) + self.tool_bar = ToolBar(all_actions, self.donate_button, self.location_view, self) + self.addToolBar(Qt.TopToolBarArea, self.tool_bar) l = self.centralwidget.layout() l.addWidget(self.search_bar) - for ch in list(self.tool_bar.children()) + list(self.location_bar.children()): - if isinstance(ch, QToolButton): - ch.setCursor(Qt.PointingHandCursor) - ch.setAutoRaise(True) - if ch is not self.donate_button: - ch.setPopupMode(ch.MenuButtonPopup) - + def read_toolbar_settings(self): + pass diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index 529055ecd2..40f7a2e4e0 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -96,7 +96,7 @@ class DateDelegate(QStyledItemDelegate): # {{{ def displayText(self, val, locale): d = val.toDate() - if d == UNDEFINED_QDATE: + if d <= UNDEFINED_QDATE: return '' return format_date(d.toPyDate(), 'dd MMM yyyy') @@ -116,7 +116,7 @@ class PubDateDelegate(QStyledItemDelegate): # {{{ def displayText(self, val, locale): d = val.toDate() - if d == UNDEFINED_QDATE: + if d <= UNDEFINED_QDATE: return '' format = tweaks['gui_pubdate_display_format'] if format is None: @@ -194,7 +194,7 @@ class CcDateDelegate(QStyledItemDelegate): # {{{ def displayText(self, val, locale): d = val.toDate() - if d == UNDEFINED_QDATE: + if d <= UNDEFINED_QDATE: return '' return format_date(d.toPyDate(), self.format) @@ -217,7 +217,7 @@ class CcDateDelegate(QStyledItemDelegate): # {{{ def setModelData(self, editor, model, index): val = editor.date() - if val == UNDEFINED_QDATE: + if val <= UNDEFINED_QDATE: val = None model.setData(index, QVariant(val), Qt.EditRole) diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 3bbab52b33..89008735fe 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -944,7 +944,7 @@ class DeviceBooksModel(BooksModel): # {{{ (cname == 'collections' and \ callable(getattr(self.db, 'supports_collections', None)) and \ self.db.supports_collections() and \ - prefs['preserve_user_collections']): + prefs['manage_device_metadata']=='manual'): flags |= Qt.ItemIsEditable return flags @@ -1216,7 +1216,9 @@ class DeviceBooksModel(BooksModel): # {{{ return done def set_editable(self, editable): - self.editable = editable + # Cannot edit if metadata is sent on connect. Reason: changes will + # revert to what is in the library on next connect. + self.editable = editable and prefs['manage_device_metadata']!='on_connect' def set_search_restriction(self, s): pass diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index 9d85dce075..c6c32f86f7 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -503,7 +503,7 @@ class DeviceBooksView(BooksView): # {{{ self.edit_collections_menu.setVisible( callable(getattr(self._model.db, 'supports_collections', None)) and \ self._model.db.supports_collections() and \ - prefs['preserve_user_collections']) + prefs['manage_device_metadata'] == 'manual') self.context_menu.popup(event.globalPos()) event.accept() diff --git a/src/calibre/gui2/search_restriction_mixin.py b/src/calibre/gui2/search_restriction_mixin.py index 3a71fa3de0..a4186ad8d1 100644 --- a/src/calibre/gui2/search_restriction_mixin.py +++ b/src/calibre/gui2/search_restriction_mixin.py @@ -7,11 +7,13 @@ Created on 10 Jun 2010 class SearchRestrictionMixin(object): def __init__(self): - self.search_restriction.activated[str].connect(self.apply_search_restriction) + self.search_restriction.initialize(help_text=_('Restrict to')) + self.search_restriction.activated[int].connect(self.apply_search_restriction) self.library_view.model().count_changed_signal.connect(self.restriction_count_changed) self.search_restriction.setSizeAdjustPolicy(self.search_restriction.AdjustToMinimumContentsLengthWithIcon) self.search_restriction.setMinimumContentsLength(10) self.search_restriction.setStatusTip(self.search_restriction.toolTip()) + self.search_count.setText(_("(all books)")) ''' Adding and deleting books while restricted creates a complexity. When added, @@ -27,8 +29,8 @@ class SearchRestrictionMixin(object): if self.restriction_in_effect: self.set_number_of_books_shown() - def apply_search_restriction(self, r): - r = unicode(r) + def apply_search_restriction(self, i): + r = unicode(self.search_restriction.currentText()) if r is not None and r != '': self.restriction_in_effect = True restriction = 'search:"%s"'%(r) diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 6bd7b2b502..ba4c637932 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -167,8 +167,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, ToolbarMixin, # {{{ self.eject_action = self.system_tray_menu.addAction( QIcon(I('eject.svg')), _('&Eject connected device')) self.eject_action.setEnabled(False) - if not config['show_donate_button']: - self.donate_button.setVisible(False) self.addAction(self.quit_action) self.action_restart = QAction(_('&Restart'), self) self.addAction(self.action_restart) @@ -220,8 +218,9 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, ToolbarMixin, # {{{ if self.system_tray_icon.isVisible() and opts.start_in_tray: self.hide_windows() - self.library_view.model().count_changed_signal.connect \ - (self.location_view.count_changed) + for t in (self.location_view, self.tool_bar): + self.library_view.model().count_changed_signal.connect \ + (t.count_changed) if not gprefs.get('quick_start_guide_added', False): from calibre.ebooks.metadata import MetaInformation mi = MetaInformation(_('Calibre Quick Start Guide'), ['John Schember']) @@ -274,8 +273,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, ToolbarMixin, # {{{ SIGNAL('start_recipe_fetch(PyQt_PyObject)'), self.download_scheduled_recipe, Qt.QueuedConnection) - self.location_view.setCurrentIndex(self.location_view.model().index(0)) - self.keyboard_interrupt.connect(self.quit, type=Qt.QueuedConnection) AddAction.__init__(self) diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py index e3fd503872..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()) @@ -538,6 +539,53 @@ class HistoryLineEdit(QComboBox): def text(self): return self.currentText() +class ComboBoxWithHelp(QComboBox): + ''' + A combobox where item 0 is help text. CurrentText will return '' for item 0. + Be sure to always fetch the text with currentText. Don't use the signals + that pass a string, because they will not correct the text. + ''' + def __init__(self, parent=None): + QComboBox.__init__(self, parent) + self.currentIndexChanged[int].connect(self.index_changed) + self.help_text = '' + self.state_set = False + + def initialize(self, help_text=_('Search')): + self.help_text = help_text + self.set_state() + + def set_state(self): + if not self.state_set: + if self.currentIndex() == 0: + self.setItemText(0, self.help_text) + self.setStyleSheet('QComboBox { color: gray }') + else: + self.setItemText(0, '') + self.setStyleSheet('QComboBox { color: black }') + + def index_changed(self, index): + self.state_set = False + self.set_state() + + def currentText(self): + if self.currentIndex() == 0: + return '' + return QComboBox.currentText(self) + + def itemText(self, idx): + if idx == 0: + return '' + return QComboBox.itemText(self, idx) + + def showPopup(self): + self.setItemText(0, '') + QComboBox.showPopup(self) + + def hidePopup(self): + QComboBox.hidePopup(self) + self.set_state() + class PythonHighlighter(QSyntaxHighlighter): Rules = [] diff --git a/src/calibre/library/caches.py b/src/calibre/library/caches.py index d46ae23d90..af950a36fc 100644 --- a/src/calibre/library/caches.py +++ b/src/calibre/library/caches.py @@ -209,13 +209,13 @@ class ResultCache(SearchQueryParser): if query == 'false': for item in self._data: if item is None: continue - if item[loc] is None or item[loc] == UNDEFINED_DATE: + if item[loc] is None or item[loc] <= UNDEFINED_DATE: matches.add(item[0]) return matches if query == 'true': for item in self._data: if item is None: continue - if item[loc] is not None and item[loc] != UNDEFINED_DATE: + if item[loc] is not None and item[loc] > UNDEFINED_DATE: matches.add(item[0]) return matches 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/custom_columns.py b/src/calibre/library/custom_columns.py index e039f5a817..5b459c6d2a 100644 --- a/src/calibre/library/custom_columns.py +++ b/src/calibre/library/custom_columns.py @@ -12,6 +12,7 @@ from math import floor from calibre import prints from calibre.constants import preferred_encoding +from calibre.library.field_metadata import FieldMetadata from calibre.utils.date import parse_date class CustomColumns(object): @@ -30,6 +31,10 @@ class CustomColumns(object): def __init__(self): + # Verify that CUSTOM_DATA_TYPES is a (possibly improper) subset of + # VALID_DATA_TYPES + if len(self.CUSTOM_DATA_TYPES - FieldMetadata.VALID_DATA_TYPES) > 0: + raise ValueError('Unknown custom column type in set') # Delete marked custom columns for record in self.conn.get( 'SELECT id FROM custom_columns WHERE mark_for_delete=1'): diff --git a/src/calibre/library/field_metadata.py b/src/calibre/library/field_metadata.py index 626683fee5..f29b432eec 100644 --- a/src/calibre/library/field_metadata.py +++ b/src/calibre/library/field_metadata.py @@ -30,8 +30,8 @@ class FieldMetadata(dict): label: the actual column label. No prefixing. - datatype: the type of the information in the field. Valid values are float, - int, rating, bool, comments, datetime, text. + datatype: the type of information in the field. Valid values are listed in + VALID_DATA_TYPES below. is_multiple: valid for the text datatype. If None, the field is to be treated as a single term. If not None, it contains a string, and the field is assumed to contain a list of terms separated by that string @@ -65,6 +65,10 @@ class FieldMetadata(dict): rec_index: the index of the field in the db metadata record. ''' + + VALID_DATA_TYPES = frozenset([None, 'rating', 'text', 'comments', 'datetime', + 'int', 'float', 'bool', 'series']) + _field_metadata = [ ('authors', {'table':'authors', 'column':'name', @@ -296,6 +300,8 @@ class FieldMetadata(dict): self._search_term_map = {} self.custom_label_to_key_map = {} for k,v in self._field_metadata: + if v['kind'] == 'field' and v['datatype'] not in self.VALID_DATA_TYPES: + raise ValueError('Unknown datatype %s for field %s'%(v['datatype'], k)) self._tb_cats[k] = v self._tb_cats[k]['label'] = k self._tb_cats[k]['display'] = {} @@ -377,6 +383,8 @@ class FieldMetadata(dict): key = self.custom_field_prefix + label if key in self._tb_cats: raise ValueError('Duplicate custom field [%s]'%(label)) + if datatype not in self.VALID_DATA_TYPES: + raise ValueError('Unknown datatype %s for field %s'%(datatype, key)) self._tb_cats[key] = {'table':table, 'column':column, 'datatype':datatype, 'is_multiple':is_multiple, 'kind':'field', 'name':name, diff --git a/src/calibre/translations/calibre.pot b/src/calibre/translations/calibre.pot index 02db8dde80..16a7eae7ec 100644 --- a/src/calibre/translations/calibre.pot +++ b/src/calibre/translations/calibre.pot @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: calibre 0.7.8\n" -"POT-Creation-Date: 2010-07-09 15:14+MDT\n" -"PO-Revision-Date: 2010-07-09 15:14+MDT\n" +"POT-Creation-Date: 2010-07-10 10:05+MDT\n" +"PO-Revision-Date: 2010-07-10 10:05+MDT\n" "Last-Translator: Automatically generated\n" "Language-Team: LANGUAGE\n" "MIME-Version: 1.0\n" @@ -26,7 +26,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/nook/driver.py:71 #: /home/kovid/work/calibre/src/calibre/devices/prs500/books.py:267 #: /home/kovid/work/calibre/src/calibre/devices/prs505/sony_cache.py:492 -#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:396 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:398 #: /home/kovid/work/calibre/src/calibre/ebooks/chm/input.py:97 #: /home/kovid/work/calibre/src/calibre/ebooks/chm/input.py:100 #: /home/kovid/work/calibre/src/calibre/ebooks/chm/metadata.py:56 @@ -110,10 +110,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:110 #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:135 #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:137 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:898 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:907 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1190 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1193 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:899 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:908 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1191 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1194 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf.py:47 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:120 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:155 @@ -629,30 +629,30 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:64 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:67 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:70 -#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:130 -#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:137 -#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:160 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:132 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:139 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:162 msgid "Getting list of books on device..." msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:219 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:263 -#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:244 -#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:262 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:246 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:264 msgid "Removing books from device..." msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:267 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:274 -#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:269 -#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:274 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:271 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:276 msgid "Removing books from device metadata listing..." msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:279 #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:313 -#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:208 -#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:238 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:210 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:240 msgid "Adding books to device metadata listing..." msgstr "" @@ -813,12 +813,12 @@ msgstr "" msgid "Get device information..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:188 #: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:190 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:192 msgid "Transferring books to device..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:305 +#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:307 msgid "Sending metadata to device..." msgstr "" @@ -1301,7 +1301,7 @@ msgid "Workaround epubcheck bugs" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/epub/fix/epubcheck.py:22 -msgid "Workarounds for bugs in the latest release of epubcheck. epubcheck reports many things as errors that are not actually errors. %prog will try to detect these and replace them with constructs that epubcheck likes. This may cause significant changes to your epub, complain to the epubcheck project." +msgid "Workarounds for bugs in the latest release of epubcheck. epubcheck reports many things as errors that are not actually errors. epub-fix will try to detect these and replace them with constructs that epubcheck likes. This may cause significant changes to your epub, complain to the epubcheck project." msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/epub/fix/main.py:19 @@ -1322,7 +1322,7 @@ msgid "Fix unmanifested files" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/epub/fix/unmanifested.py:21 -msgid "Fix unmanifested files. %prog can either add them to the manifest or delete them as specified by the delete unmanifested option." +msgid "Fix unmanifested files. epub-fix can either add them to the manifest or delete them as specified by the delete unmanifested option." msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/epub/fix/unmanifested.py:32 @@ -2580,14 +2580,14 @@ msgid "Main memory" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions.py:519 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:444 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:453 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:445 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:454 msgid "Storage Card A" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions.py:520 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:446 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:455 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:447 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:456 msgid "Storage Card B" msgstr "" @@ -2645,7 +2645,7 @@ msgid "Failed to download metadata:" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions.py:659 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:637 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:638 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:523 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:951 #: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:53 @@ -2797,7 +2797,7 @@ msgid "The specified directory could not be processed." msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/add.py:263 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:840 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:841 msgid "No books" msgstr "" @@ -2942,12 +2942,12 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:267 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:269 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:270 -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:248 -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:253 -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:259 -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:261 -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:263 -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:265 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:132 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:137 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:143 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:145 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:147 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:149 #: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:75 #: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:80 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:186 @@ -3012,7 +3012,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:47 #: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:73 #: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:78 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:467 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:274 msgid "None" msgstr "" @@ -3836,12 +3836,12 @@ msgid "Footer regular expression:" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:56 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:77 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:76 msgid "Invalid regular expression" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/structure_detection.py:57 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:78 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:77 msgid "Invalid regular expression: %s" msgstr "" @@ -4109,250 +4109,250 @@ msgstr "" msgid "tags to remove" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:48 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:49 #: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:135 msgid "No details available." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:154 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:155 msgid "Device no longer connected." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:270 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:271 msgid "Get device information" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:281 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:282 msgid "Get list of books on device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:291 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:292 msgid "Get annotations from device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:300 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:301 msgid "Send metadata to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:305 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:306 msgid "Send collections to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:329 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:330 msgid "Upload %d books to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:344 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:345 msgid "Delete books from device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:361 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:362 msgid "Download books from device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:371 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:372 msgid "View book on device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:407 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:408 msgid "Set default send to device action" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:413 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:420 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:422 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:424 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:414 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:421 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:423 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:425 msgid "Email to" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:424 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:425 msgid " and delete from library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:433 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:434 msgid "Send to main memory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:435 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:436 msgid "Send to storage card A" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:437 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:438 msgid "Send to storage card B" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:442 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:451 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:443 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:452 msgid "Main Memory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:469 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:470 msgid "Send and delete from library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:470 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:471 msgid "Send specific format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:509 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:510 msgid "Connect to folder" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:515 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:516 msgid "Connect to iTunes" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:520 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:521 msgid "Eject device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:528 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:529 msgid "Fetch annotations (experimental)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:638 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:639 msgid "Error communicating with device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:659 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:660 msgid "Select folder to open as device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:704 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:705 msgid "Failed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:710 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:711 msgid "Error talking to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:711 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:712 msgid "There was a temporary error talking to the device. Please unplug and reconnect the device and or reboot." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:753 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:754 msgid "Device: " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:755 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:756 msgid " detected." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:841 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:842 msgid "selected to send" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:846 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:847 msgid "Choose format to send to device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:855 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:856 msgid "No device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:856 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:857 msgid "Cannot send: No device is connected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:859 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:863 -msgid "No card" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/device.py:860 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:864 +msgid "No card" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:861 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:865 msgid "Cannot send: Device has no storage card" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:905 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:906 msgid "E-book:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:908 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:909 msgid "Attached, you will find the e-book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:909 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:910 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:181 msgid "by" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:910 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:911 msgid "in the %s format." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:923 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:924 msgid "Sending email to" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:953 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:961 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1053 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1115 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1234 -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1242 -msgid "No suitable formats" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/device.py:954 -msgid "Auto convert the following books before sending via email?" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/device.py:962 -msgid "Could not email the following books as no suitable formats were found:" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:980 -msgid "Failed to email books" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:981 -msgid "Failed to email the following books:" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:985 -msgid "Sent by email:" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1012 -msgid "News:" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1013 -msgid "Attached is the" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1024 -msgid "Sent news to" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/device.py:1054 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:1116 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:1235 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1243 +msgid "No suitable formats" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:955 +msgid "Auto convert the following books before sending via email?" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:963 +msgid "Could not email the following books as no suitable formats were found:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:981 +msgid "Failed to email books" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:982 +msgid "Failed to email the following books:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:986 +msgid "Sent by email:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1013 +msgid "News:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1014 +msgid "Attached is the" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1025 +msgid "Sent news to" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1055 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1117 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1236 msgid "Auto convert the following books before uploading to the device?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1084 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1085 msgid "Sending catalogs to device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1148 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1149 msgid "Sending news to device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1201 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1202 msgid "Sending books to device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1243 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1244 msgid "Could not upload the following books to the device, as no suitable formats were found. Convert the book(s) to a format supported by your device first." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1304 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1305 msgid "No space on device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1305 +#: /home/kovid/work/calibre/src/calibre/gui2/device.py:1306 msgid "

Cannot upload books to device there is no more free space available " msgstr "" @@ -4613,7 +4613,7 @@ msgid "Access log:" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:794 -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:332 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:331 msgid "Failed to start content server" msgstr "" @@ -4671,27 +4671,27 @@ msgstr "" msgid "The following books had formats listed in the database that are not actually available. The entries for the formats have been removed. You should check them manually. This can happen if you manipulate the files in the library folder directly." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:113 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:133 msgid "TabWidget" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:114 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:134 msgid "Here you can control how calibre will read metadata from the files you add to it. calibre can either read metadata from the contents of the file, or from the filename." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:115 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:135 msgid "Read metadata only from &file name" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:116 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:136 msgid "Swap the firstname and lastname of the author. This affects only metadata read from file names." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:117 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:137 msgid "&Swap author firstname and lastname" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:118 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:138 msgid "" "If an existing book with a similar title and author is found that does not have the format being added, the format is added\n" "to the existing book, instead of creating a new entry. If the existing book already has the format, then it is silently ignored.\n" @@ -4699,81 +4699,93 @@ msgid "" "Title match ignores leading indefinite articles (\"the\", \"a\", \"an\"), punctuation, case, etc. Author match is exact." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:122 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:142 msgid "If books with similar titles and authors found, &merge the new files automatically" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:123 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:143 msgid "&Configure metadata from file name" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:124 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:144 msgid "&Adding books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:125 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:145 msgid "Here you can control how calibre will save your books when you click the Save to Disk button:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:126 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:146 msgid "Save &cover separately" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:127 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:147 msgid "Update &metadata in saved copies" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:128 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:148 msgid "Save metadata in &OPF file" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:129 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:149 msgid "Convert non-English characters to &English equivalents" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:130 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:150 msgid "Format &dates as:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:131 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:151 msgid "File &formats to save:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:132 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:152 msgid "Replace space with &underscores" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:133 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:153 msgid "Change paths to &lowercase" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:134 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:154 msgid "&Saving books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:135 -msgid "Preserve device collections." +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:155 +msgid "Metadata &management:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:136 -msgid "If checked, collections will not be deleted even if a book with changed metadata is resent and the collection is not in the book's metadata. In addition, editing collections in the device view will be enabled. If unchecked, collections will be always reflect only the metadata in the calibre library." +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:156 +msgid "Manual management" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:137 -msgid " " +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:157 +msgid "Only on send" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:138 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:158 +msgid "Automatic management" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:159 +msgid "" +"

  • Manual Management: Calibre updates the metadata and adds collections only when a book is sent. With this option, calibre will never remove a collection.
  • \n" +"
  • Only on send: Calibre updates metadata and adds/removes collections for a book only when it is sent to the device.
  • \n" +"
  • Automatic management: Calibre automatically keeps metadata on the device in sync with the calibre library, on every connect
  • " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:162 msgid "Here you can control how calibre will save your books when you click the Send to Device button. This setting can be overriden for individual devices by customizing the device interface plugins in Preferences->Plugins" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:139 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/add_save_ui.py:163 msgid "Sending to &device" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/config_ui.py:554 #: /home/kovid/work/calibre/src/calibre/gui2/init.py:168 -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:290 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:425 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:174 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:201 msgid "Preferences" msgstr "" @@ -6410,11 +6422,11 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:126 #: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:129 #: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:132 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:84 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:88 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:93 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:98 -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:100 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:83 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:87 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:92 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:97 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:99 msgid "No match" msgstr "" @@ -6503,7 +6515,8 @@ msgid "Add Empty book. (Book entry with no formats)" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/init.py:103 -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:276 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:409 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:160 msgid "Save to disk" msgstr "" @@ -6512,17 +6525,18 @@ msgid "Save to disk in a single directory" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/init.py:107 -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:394 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:393 msgid "Save only %s format to disk" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/init.py:111 -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:397 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:396 msgid "Save only %s format to disk in a single directory" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/init.py:120 -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:282 +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:412 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:166 msgid "View" msgstr "" @@ -6566,46 +6580,46 @@ msgstr "" msgid "Run welcome wizard" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:205 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:191 msgid "Similar books..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:237 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:223 msgid "Add books to library" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:225 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:232 #: /home/kovid/work/calibre/src/calibre/gui2/init.py:239 -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:246 -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:253 msgid "Manage collections" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:333 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:319 msgid "Cover Browser" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:351 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:337 msgid "Tag Browser" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:372 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:358 msgid "version" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:373 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:359 msgid "created by Kovid Goyal" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:391 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:377 msgid "Connected " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:400 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:386 msgid "Update found" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:445 -#: /home/kovid/work/calibre/src/calibre/gui2/init.py:454 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:430 +#: /home/kovid/work/calibre/src/calibre/gui2/init.py:439 msgid "Book Details" msgstr "" @@ -6668,6 +6682,215 @@ msgstr "" msgid " - Jobs" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:64 +msgid "" +"Library\n" +"%d books" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:65 +msgid "" +"Reader\n" +"%s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:66 +msgid "" +"Card A\n" +"%s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:67 +msgid "" +"Card B\n" +"%s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:71 +msgid "Click to see the books available on your computer" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:74 +msgid "Click to see the books in the main memory of your reader" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:75 +msgid "Click to see the books on storage card A in your reader" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:76 +msgid "Click to see the books on storage card B in your reader" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:84 +msgid "Books located at" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:100 +msgid "free" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:287 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:134 +msgid "Books display will be restricted to those matching the selected saved search" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:300 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:136 +msgid "Advanced search" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:309 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:140 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:141 +msgid "

    Search the list of books by title, author, publisher, tags, comments, etc.

    Words separated by spaces are ANDed" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:316 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:142 +msgid "Reset Quick Search" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:328 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:144 +msgid "Copy current search text (instead of search name)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:334 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:146 +msgid "Save current search under the name shown in the box" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:340 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:148 +msgid "Delete current saved search" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:404 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:150 +msgid "Add books" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:404 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:151 +msgid "A" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:405 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:152 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:153 +msgid "Remove books" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:405 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:154 +msgid "Del" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:406 +msgid "Edit meta info" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:406 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:156 +msgid "E" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:407 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:157 +msgid "Merge book records" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:407 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:158 +msgid "M" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:408 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:159 +msgid "Send to device" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:409 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:161 +msgid "S" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:410 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:162 +msgid "Fetch news" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:410 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:163 +msgid "F" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:411 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:164 +msgid "Convert books" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:411 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:165 +msgid "C" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:412 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:167 +msgid "V" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:413 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:168 +msgid "Open containing folder" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:415 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:169 +msgid "Show book details" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:417 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:170 +msgid "Books by same author" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:419 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:171 +msgid "Books in this series" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:421 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:172 +msgid "Books by this publisher" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:423 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:173 +msgid "Books with the same tags" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:425 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:176 +msgid "Ctrl+P" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:426 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:177 +msgid "Help" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:426 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:178 +msgid "Browse the calibre User Manual" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:426 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:179 +msgid "F1" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:284 msgid "N" msgstr "" @@ -6949,160 +7172,34 @@ msgstr "" msgid "try deleting the file" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:247 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:131 msgid "calibre" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:249 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:133 msgid "&Restrict to:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:250 -msgid "Books display will be restricted to those matching the selected saved search" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:251 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:135 msgid "set in ui.py" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:252 -msgid "Advanced search" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:254 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:138 msgid "Alt+S" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:255 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:139 msgid "&Search:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:256 -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:257 -msgid "

    Search the list of books by title, author, publisher, tags, comments, etc.

    Words separated by spaces are ANDed" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:258 -msgid "Reset Quick Search" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:260 -msgid "Copy current search text (instead of search name)" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:262 -msgid "Save current search under the name shown in the box" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:264 -msgid "Delete current saved search" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:266 -msgid "Add books" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:267 -msgid "A" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:268 -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:269 -msgid "Remove books" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:270 -msgid "Del" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:271 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:155 msgid "Edit meta information" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:272 -msgid "E" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:273 -msgid "Merge book records" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:274 -msgid "M" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:275 -msgid "Send to device" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:277 -msgid "S" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:278 -msgid "Fetch news" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:279 -msgid "F" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:280 -msgid "Convert E-books" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:281 -msgid "C" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:283 -msgid "V" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:284 -msgid "Open containing folder" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:285 -msgid "Show book details" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:286 -msgid "Books by same author" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:287 -msgid "Books in this series" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:288 -msgid "Books by this publisher" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:289 -msgid "Books with the same tags" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:291 +#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:175 msgid "Configure calibre" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:292 -msgid "Ctrl+P" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:293 -msgid "Help" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:294 -msgid "Browse the calibre User Manual" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:295 -msgid "F1" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/main_window.py:20 msgid "Redirect console output to a dialog window (both stdout and stderr). Useful on windows where GUI apps do not have a output streams." msgstr "" @@ -7129,6 +7226,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:93 #: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:262 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:553 msgid "Search" msgstr "" @@ -7148,15 +7246,19 @@ msgstr "" msgid "Choose saved search or enter name for new saved search" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_restriction_mixin.py:47 +#: /home/kovid/work/calibre/src/calibre/gui2/search_restriction_mixin.py:10 +msgid "Restrict to" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/search_restriction_mixin.py:48 msgid "({0} of {1})" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_restriction_mixin.py:53 +#: /home/kovid/work/calibre/src/calibre/gui2/search_restriction_mixin.py:54 msgid "(all books)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_restriction_mixin.py:55 +#: /home/kovid/work/calibre/src/calibre/gui2/search_restriction_mixin.py:56 msgid "({0} of all)" msgstr "" @@ -7358,64 +7460,64 @@ msgstr "" msgid "Calibre Quick Start Guide" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:376 -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:381 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:375 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:380 msgid "Cannot configure" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:377 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:376 msgid "Cannot configure while there are running jobs." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:382 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:381 msgid "Cannot configure before calibre is restarted." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:425 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:424 msgid "No detailed info available" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:426 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:425 msgid "No detailed information is available for books on the device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:478 -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:506 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:477 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:505 msgid "Conversion Error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:479 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:478 msgid "

    Could not convert: %s

    It is a DRMed book. You must first remove the DRM using third party tools." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:492 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:491 msgid "Recipe Disabled" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:507 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:506 msgid "Failed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:547 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:546 msgid "is the result of the efforts of many volunteers from all over the world. If you find it useful, please consider donating to support its development. Your donation helps keep calibre development going." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:573 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:572 msgid "There are active jobs. Are you sure you want to quit?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:576 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:575 msgid "" " is communicating with the device!
    \n" " Quitting may cause corruption on the device.
    \n" " Are you sure you want to quit?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:580 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:579 msgid "WARNING: Active jobs" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:633 +#: /home/kovid/work/calibre/src/calibre/gui2/ui.py:632 msgid "will keep running in the system tray. To close it, choose Quit in the context menu of the system tray." msgstr "" @@ -7883,91 +7985,43 @@ msgstr "" msgid "Print eBook" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:239 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:238 msgid "Copy Image" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:240 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:239 msgid "Paste Image" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:270 -msgid "" -"Library\n" -"%d books" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:271 -msgid "" -"Reader\n" -"%s" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:272 -msgid "" -"Card A\n" -"%s" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:273 -msgid "" -"Card B\n" -"%s" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:277 -msgid "Click to see the books available on your computer" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:280 -msgid "Click to see the books in the main memory of your reader" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:281 -msgid "Click to see the books on storage card A in your reader" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:282 -msgid "Click to see the books on storage card B in your reader" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:290 -msgid "Books located at" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:306 -msgid "free" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:557 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:364 msgid "Change Case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:558 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:365 msgid "Upper Case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:559 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:366 msgid "Lower Case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:560 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:367 msgid "Swap Case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:561 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:368 msgid "Title Case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:983 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:837 msgid "Drag to resize" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:1015 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:869 msgid "Show" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:1022 +#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:876 msgid "Hide" msgstr "" @@ -8949,7 +9003,7 @@ msgid "User-created tag browser categories" msgstr "" #: /home/kovid/work/calibre/src/calibre/utils/config.py:702 -msgid "Preserve all collections even if not in library metadata." +msgid "How and when calibre updates metadata on the device." msgstr "" #: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:43 diff --git a/src/calibre/utils/bibtex.py b/src/calibre/utils/bibtex.py new file mode 100644 index 0000000000..f4fc62d9d0 --- /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 os, 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])) diff --git a/src/calibre/utils/config.py b/src/calibre/utils/config.py index f24a6d2e30..5c4bd55644 100644 --- a/src/calibre/utils/config.py +++ b/src/calibre/utils/config.py @@ -698,8 +698,8 @@ def _prefs(): # calibre server can execute searches c.add_opt('saved_searches', default={}, help=_('List of named saved searches')) c.add_opt('user_categories', default={}, help=_('User-created tag browser categories')) - c.add_opt('preserve_user_collections', default=True, - help=_('Preserve all collections even if not in library metadata.')) + c.add_opt('manage_device_metadata', default='manual', + help=_('How and when calibre updates metadata on the device.')) c.add_opt('migrated', default=False, help='For Internal use. Don\'t modify.') return c