From ea0920053f9c89909b70ebaf084b9b0fc0ea7950 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 26 May 2011 10:50:57 -0600 Subject: [PATCH 1/4] Fix #774849 (Schedule news download: inconsistent save behaviour) --- src/calibre/gui2/dialogs/scheduler.py | 18 +++--- src/calibre/gui2/dialogs/scheduler.ui | 79 ++++++++++++++++----------- 2 files changed, 55 insertions(+), 42 deletions(-) diff --git a/src/calibre/gui2/dialogs/scheduler.py b/src/calibre/gui2/dialogs/scheduler.py index b25d66979d..7d1d87b472 100644 --- a/src/calibre/gui2/dialogs/scheduler.py +++ b/src/calibre/gui2/dialogs/scheduler.py @@ -207,8 +207,9 @@ class SchedulerDialog(QDialog, Ui_Dialog): self.recipe_model.searched.connect(self.search.search_done, type=Qt.QueuedConnection) self.recipe_model.searched.connect(self.search_done) - self.search.setFocus(Qt.OtherFocusReason) + self.recipes.setFocus(Qt.OtherFocusReason) self.commit_on_change = True + self.previous_urn = None self.recipes.setModel(self.recipe_model) self.detail_box.setVisible(False) @@ -228,6 +229,9 @@ class SchedulerDialog(QDialog, Ui_Dialog): self.old_news.setValue(gconf['oldest_news']) + self.go_button.clicked.connect(self.search.do_search) + self.clear_search_button.clicked.connect(self.search.clear_clicked) + def set_pw_echo_mode(self, state): self.password.setEchoMode(self.password.Normal if state == Qt.Checked else self.password.Password) @@ -265,14 +269,9 @@ class SchedulerDialog(QDialog, Ui_Dialog): self.last_downloaded.setVisible(enabled) def current_changed(self, current, previous): - if self.commit_on_change: - if previous.isValid(): - if not self.commit(urn=getattr(previous.internalPointer(), - 'urn', None)): - self.commit_on_change = False - self.recipes.setCurrentIndex(previous) - else: - self.commit_on_change = True + if self.previous_urn is not None: + self.commit(urn=self.previous_urn) + self.previous_urn = None urn = self.current_urn if urn is not None: @@ -332,6 +331,7 @@ class SchedulerDialog(QDialog, Ui_Dialog): return True def initialize_detail_box(self, urn): + self.previous_urn = urn self.detail_box.setVisible(True) self.download_button.setVisible(True) self.detail_box.setCurrentIndex(0) diff --git a/src/calibre/gui2/dialogs/scheduler.ui b/src/calibre/gui2/dialogs/scheduler.ui index f26bfc7285..6acbb01dd8 100644 --- a/src/calibre/gui2/dialogs/scheduler.ui +++ b/src/calibre/gui2/dialogs/scheduler.ui @@ -17,21 +17,30 @@ :/images/scheduler.png:/images/scheduler.png - + - - - &Search: - - - search - - + + + + + + + + Go + + + + + + + + :/images/clear_left.png:/images/clear_left.png + + + + - - - - + QFrame::NoFrame @@ -44,7 +53,7 @@ 0 0 - 486 + 524 504 @@ -320,7 +329,7 @@ - + @@ -345,7 +354,17 @@ - + + + + + + + Qt::AlignCenter + + + + @@ -376,17 +395,7 @@ - - - - Qt::Horizontal - - - QDialogButtonBox::Save - - - - + Download all scheduled news sources at once @@ -394,15 +403,19 @@ Download &all scheduled + + + :/images/news.png:/images/news.png + - - - - + + + + Qt::Horizontal - - Qt::AlignCenter + + QDialogButtonBox::Save From 5744242319e151fd7ac6292afb2eef9967520cca Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 26 May 2011 10:58:48 -0600 Subject: [PATCH 2/4] Fix #788570 (Calibre Epub to Mobi does not handle hidden spans correctly) --- src/calibre/ebooks/mobi/mobiml.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/calibre/ebooks/mobi/mobiml.py b/src/calibre/ebooks/mobi/mobiml.py index 3c36a6166d..2275552c15 100644 --- a/src/calibre/ebooks/mobi/mobiml.py +++ b/src/calibre/ebooks/mobi/mobiml.py @@ -297,9 +297,11 @@ class MobiMLizer(object): if id_: # Keep anchors so people can use display:none # to generate hidden TOCs + tail = elem.tail elem.clear() elem.text = None elem.set('id', id_) + elem.tail = tail else: return tag = barename(elem.tag) @@ -309,7 +311,8 @@ class MobiMLizer(object): istates.append(istate) left = 0 display = style['display'] - isblock = not display.startswith('inline') + isblock = (not display.startswith('inline') and style['display'] != + 'none') isblock = isblock and style['float'] == 'none' isblock = isblock and tag != 'br' if isblock: From 87dec0e0640fb1013c55b0a2f2debad7963139d2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 26 May 2011 11:46:35 -0600 Subject: [PATCH 3/4] Update faz.net --- recipes/faznet.recipe | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/recipes/faznet.recipe b/recipes/faznet.recipe index 01a46d43ba..50a66c59b8 100644 --- a/recipes/faznet.recipe +++ b/recipes/faznet.recipe @@ -3,10 +3,7 @@ class AdvancedUserRecipe1303841067(BasicNewsRecipe): title = u'Faz.net' __author__ = 'schuster' - remove_tags = [dict(attrs={'class':['right', 'ArrowLinkRight', 'ModulVerlagsInfo', 'left', 'Head']}), - dict(id=['BreadCrumbs', 'tstag', 'FazFooterPrint']), - dict(name=['script', 'noscript', 'style'])] - oldest_article = 2 + oldest_article = 1 description = 'Frankfurter Allgemeine Zeitung' max_articles_per_feed = 100 no_stylesheets = True @@ -15,9 +12,9 @@ class AdvancedUserRecipe1303841067(BasicNewsRecipe): remove_javascript = True cover_url = 'http://www.faz.net/f30/Images/Logos/logo.gif' - def print_version(self, url): - return url.replace('.html', '~Afor~Eprint.html') - + remove_tags = [dict(attrs={'class':['LinkBoxModulSmall', 'ModulLesermeinungenFooter', 'ModulArtikelServices', 'SocialMediaUnten', 'ArrowLinkRight', 'ModulVerlagsInfo', 'AdData', 'FazFooter', 'Date']}), + dict(id=['FAZNavHeader', 'FAZNavMain', 'RightColumn', 'FazFooter', 'BreadCrumbs', 'FAZNavSubMain', 'FAZImgEvent']), + dict(name=['jksrdt'])] feeds = [(u'Politik', u'http://www.faz.net/s/RubA24ECD630CAE40E483841DB7D16F4211/Tpl~Epartner~SRss_.xml'), From d2036d1c3043caaf56e1cc968feace1ee3de9885 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 26 May 2011 13:31:04 -0600 Subject: [PATCH 4/4] Various German news sources by schuster --- recipes/aachener_nachrichten.recipe | 42 +++++++++++++++++++++ recipes/frankfurter_rundschau.recipe | 35 ++++++++++++++++++ recipes/rheinische_post.recipe | 55 ++++++++++++++++++++++++++++ resources/template-functions.json | 15 +++++--- 4 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 recipes/aachener_nachrichten.recipe create mode 100644 recipes/frankfurter_rundschau.recipe create mode 100644 recipes/rheinische_post.recipe diff --git a/recipes/aachener_nachrichten.recipe b/recipes/aachener_nachrichten.recipe new file mode 100644 index 0000000000..a2294fc472 --- /dev/null +++ b/recipes/aachener_nachrichten.recipe @@ -0,0 +1,42 @@ +from calibre.web.feeds.recipes import BasicNewsRecipe +class AdvancedUserRecipe(BasicNewsRecipe): + + title = u'Aachener Nachrichten' + __author__ = 'schuster' + oldest_article = 1 + max_articles_per_feed = 100 + use_embedded_content = False + language = 'de' + remove_javascript = True + cover_url = 'http://www.an-online.de/einwaage/images/an_logo.png' + masthead_url = 'http://www.an-online.de/einwaage/images/an_logo.png' + extra_css = ''' + .fliesstext_detail:{margin-bottom:10%;} + .headline_1:{margin-bottom:25%;} + b{font-family:Arial,Helvetica,sans-serif; font-weight:200;font-size:large;} + a{font-family:Arial,Helvetica,sans-serif; font-weight:400;font-size:large;} + ll{font-family:Arial,Helvetica,sans-serif; font-weight:100;font-size:large;} + h4{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;} + img {min-width:300px; max-width:600px; min-height:300px; max-height:800px} + dd{font-family:Arial,Helvetica,sans-serif;font-size:large;} + body{font-family:Helvetica,Arial,sans-serif;font-size:small;} + ''' + + + + keep_only_tags = [ + dict(name='span', attrs={'class':['fliesstext_detail', 'headline_1', 'autor_detail']}), + dict(id=['header-logo']) + ] + + feeds = [(u'Euregio', u'http://www.an-online.de/an/rss/Euregio.xml'), + (u'Aachen', u'http://www.an-online.de/an/rss/Aachen.xml'), + (u'Nordkreis', u'http://www.an-online.de/an/rss/Nordkreis.xml'), + (u'Düren', u'http://www.an-online.de/an/rss/Dueren.xml'), + (u'Eiffel', u'http://www.an-online.de/an/rss/Eifel.xml'), + (u'Eschweiler', u'http://www.an-online.de/an/rss/Eschweiler.xml'), + (u'Geilenkirchen', u'http://www.an-online.de/an/rss/Geilenkirchen.xml'), + (u'Heinsberg', u'http://www.an-online.de/an/rss/Heinsberg.xml'), + (u'Jülich', u'http://www.an-online.de/an/rss/Juelich.xml'), + (u'Stolberg', u'http://www.an-online.de/an/rss/Stolberg.xml'), + (u'Ratgebenr', u'http://www.an-online.de/an/rss/Ratgeber.xml')] diff --git a/recipes/frankfurter_rundschau.recipe b/recipes/frankfurter_rundschau.recipe new file mode 100644 index 0000000000..3c3bb32ca3 --- /dev/null +++ b/recipes/frankfurter_rundschau.recipe @@ -0,0 +1,35 @@ +from calibre.web.feeds.recipes import BasicNewsRecipe +class AdvancedUserRecipe(BasicNewsRecipe): + + title = u'Frankfurter Rundschau' + __author__ = 'schuster' + oldest_article = 1 + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + language = 'de' + remove_javascript = True + cover_url = 'http://www.fr-online.de/image/view/-/1474018/data/823538/-/logo.png' + extra_css = ''' + h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;} + h4{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;} + img {min-width:300px; max-width:600px; min-height:300px; max-height:800px} + p{font-family:Arial,Helvetica,sans-serif;font-size:small;} + body{font-family:Helvetica,Arial,sans-serif;font-size:small;} + ''' + + feeds = [(u'Startseite', u'http://www.fr-online.de/home/-/1472778/1472778/-/view/asFeed/-/index.xml'), + (u'Politik', u'http://www.fr-online.de/politik/-/1472596/1472596/-/view/asFeed/-/index.xml'), + (u'Meinungen', u'http://www.fr-online.de/politik/meinung/-/1472602/1472602/-/view/asFeed/-/index.xml'), + (u'Wirtschaft', u'http://www.fr-online.de/wirtschaft/-/1472780/1472780/-/view/asFeed/-/index.xml'), + (u'Sport', u'http://www.fr-online.de/sport/-/1472784/1472784/-/view/asFeed/-/index.xml'), + (u'Kultur', u'http://www.fr-online.de/kultur/-/1472786/1472786/-/view/asFeed/-/index.xml'), + (u'Panorama', u'http://www.fr-online.de/panorama/-/1472782/1472782/-/view/asFeed/-/index.xml'), + (u'Digital', u'http://www.fr-online.de/digital/-/1472406/1472406/-/view/asFeed/-/index.xml'), + (u'Wissenschaft', u'http://www.fr-online.de/wissenschaft/-/1472788/1472788/-/view/asFeed/-/index.xml') +] + + + def print_version(self, url): + return url.replace('index.html', 'view/printVersion/-/index.html') + diff --git a/recipes/rheinische_post.recipe b/recipes/rheinische_post.recipe new file mode 100644 index 0000000000..1d3efc710d --- /dev/null +++ b/recipes/rheinische_post.recipe @@ -0,0 +1,55 @@ +from calibre.web.feeds.recipes import BasicNewsRecipe +class AdvancedUserRecipe(BasicNewsRecipe): + + title = u'RP-online' + __author__ = 'schuster' + oldest_article = 2 + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + language = 'de' + remove_javascript = True + masthead_url = 'http://www.die-zeitungen.de/uploads/pics/LOGO_RP_ONLINE_01.jpg' + cover_url = 'http://www.manroland.com/com/pressinfo_images/com/RheinischePost_Logo_300dpi.jpg' + extra_css = ''' + h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;} + h4{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;} + img {min-width:300px; max-width:600px; min-height:300px; max-height:800px} + p{font-family:Arial,Helvetica,sans-serif;font-size:small;} + body{font-family:Helvetica,Arial,sans-serif;font-size:small;} + ''' + remove_tags_before = dict(id='article_content') + remove_tags_after = dict(id='article_content') + remove_tags = [dict(attrs={'class':['goodies', 'left', 'right', 'clear-all', 'teaser anzeigenwerbung', 'lesermeinung', 'goodiebox', 'goodiebox 1', 'goodiebox 2', 'goodiebox 3', 'boxframe', 'link']}), + dict(id=['click_Fotos_link']), + dict(name=['script', 'noscript', 'style', '_top', 'click_Fotos_link'])] + + feeds = [ (u'Top-News', u'http://www.ngz-online.de/app/feed/rss/topnews'), + (u'Politik', u'http://www.ngz-online.de/app/feed/rss/politik'), + (u'Wirtschaft', u'http://www.ngz-online.de/app/feed/rss/wirtschaft'), + (u'Panorama', u'http://www.ngz-online.de/app/feed/rss/panorama'), + (u'Sport', u'http://www.ngz-online.de/app/feed/rss/sport'), + (u'Tour de France', u'http://www.ngz-online.de/app/feed/rss/tourdefrance'), + (u'Fußball', u'http://www.ngz-online.de/app/feed/rss/fussball'), + (u'Fußball BuLi', u'http://www.ngz-online.de/app/feed/rss/bundesliga'), + (u'Formel 1', u'http://www.ngz-online.de/app/feed/rss/formel1'), + (u'US-Sport', u'http://www.ngz-online.de/app/feed/rss/us-sports'), + (u'Boxen', u'http://www.ngz-online.de/app/feed/rss/boxen'), + (u'Eishockey', u'http://www.ngz-online.de/app/feed/rss/eishockey'), + (u'Basketball', u'http://www.ngz-online.de/app/feed/rss/basketball'), + (u'Handball', u'http://www.ngz-online.de/app/feed/rss/handball'), + (u'Motorsport', u'http://www.ngz-online.de/app/feed/rss/motorsport'), + (u'Tennis', u'http://www.ngz-online.de/app/feed/rss/tennis'), + (u'Radsport', u'http://www.ngz-online.de/app/feed/rss/radsport'), + (u'Kultur', u'http://www.ngz-online.de/app/feed/rss/kultur'), + (u'Gesellschaft', u'http://www.ngz-online.de/app/feed/rss/gesellschaft'), + (u'Wissenschaft', u'http://www.ngz-online.de/app/feed/rss/wissen'), + (u'Gesundheit', u'http://www.ngz-online.de/app/feed/rss/gesundheit'), + (u'Digitale Welt', u'http://www.ngz-online.de/app/feed/rss/digitale'), + (u'Auto & Mobil', u'http://www.ngz-online.de/app/feed/rss/auto'), + (u'Reise & Welt', u'http://www.ngz-online.de/app/feed/rss/reise'), + (u'Beruf & Karriere', u'http://www.ngz-online.de/app/feed/rss/beruf'), + (u'Herzrasen', u'http://www.ngz-online.de/app/feed/rss/herzrasen'), + (u'About a Boy', u'http://www.ngz-online.de/app/feed/rss/about_a_boy'), + +] diff --git a/resources/template-functions.json b/resources/template-functions.json index 7656db4021..b0a2225dd4 100644 --- a/resources/template-functions.json +++ b/resources/template-functions.json @@ -1,19 +1,21 @@ { + "and": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n i = 0\n while i < len(args):\n if not args[i]:\n return ''\n i += 1\n return '1'\n", "contains": "def evaluate(self, formatter, kwargs, mi, locals,\n val, test, value_if_present, value_if_not):\n if re.search(test, val):\n return value_if_present\n else:\n return value_if_not\n", "divide": "def evaluate(self, formatter, kwargs, mi, locals, x, y):\n x = float(x if x else 0)\n y = float(y if y else 0)\n return unicode(x / y)\n", "uppercase": "def evaluate(self, formatter, kwargs, mi, locals, val):\n return val.upper()\n", "strcat": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n i = 0\n res = ''\n for i in range(0, len(args)):\n res += args[i]\n return res\n", "in_list": "def evaluate(self, formatter, kwargs, mi, locals, val, sep, pat, fv, nfv):\n l = [v.strip() for v in val.split(sep) if v.strip()]\n for v in l:\n if re.search(pat, v):\n return fv\n return nfv\n", - "substr": "def evaluate(self, formatter, kwargs, mi, locals, str_, start_, end_):\n return str_[int(start_): len(str_) if int(end_) == 0 else int(end_)]\n", + "multiply": "def evaluate(self, formatter, kwargs, mi, locals, x, y):\n x = float(x if x else 0)\n y = float(y if y else 0)\n return unicode(x * y)\n", "ifempty": "def evaluate(self, formatter, kwargs, mi, locals, val, value_if_empty):\n if val:\n return val\n else:\n return value_if_empty\n", "booksize": "def evaluate(self, formatter, kwargs, mi, locals):\n if mi.book_size is not None:\n try:\n return str(mi.book_size)\n except:\n pass\n return ''\n", "select": "def evaluate(self, formatter, kwargs, mi, locals, val, key):\n if not val:\n return ''\n vals = [v.strip() for v in val.split(',')]\n for v in vals:\n if v.startswith(key+':'):\n return v[len(key)+1:]\n return ''\n", + "strcmp": "def evaluate(self, formatter, kwargs, mi, locals, x, y, lt, eq, gt):\n v = strcmp(x, y)\n if v < 0:\n return lt\n if v == 0:\n return eq\n return gt\n", "first_non_empty": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n i = 0\n while i < len(args):\n if args[i]:\n return args[i]\n i += 1\n return ''\n", - "field": "def evaluate(self, formatter, kwargs, mi, locals, name):\n return formatter.get_value(name, [], kwargs)\n", + "re": "def evaluate(self, formatter, kwargs, mi, locals, val, pattern, replacement):\n return re.sub(pattern, replacement, val)\n", "subtract": "def evaluate(self, formatter, kwargs, mi, locals, x, y):\n x = float(x if x else 0)\n y = float(y if y else 0)\n return unicode(x - y)\n", "list_item": "def evaluate(self, formatter, kwargs, mi, locals, val, index, sep):\n if not val:\n return ''\n index = int(index)\n val = val.split(sep)\n try:\n return val[index]\n except:\n return ''\n", "shorten": "def evaluate(self, formatter, kwargs, mi, locals,\n val, leading, center_string, trailing):\n l = max(0, int(leading))\n t = max(0, int(trailing))\n if len(val) > l + len(center_string) + t:\n return val[0:l] + center_string + ('' if t == 0 else val[-t:])\n else:\n return val\n", - "re": "def evaluate(self, formatter, kwargs, mi, locals, val, pattern, replacement):\n return re.sub(pattern, replacement, val)\n", + "field": "def evaluate(self, formatter, kwargs, mi, locals, name):\n return formatter.get_value(name, [], kwargs)\n", "add": "def evaluate(self, formatter, kwargs, mi, locals, x, y):\n x = float(x if x else 0)\n y = float(y if y else 0)\n return unicode(x + y)\n", "lookup": "def evaluate(self, formatter, kwargs, mi, locals, val, *args):\n if len(args) == 2: # here for backwards compatibility\n if val:\n return formatter.vformat('{'+args[0].strip()+'}', [], kwargs)\n else:\n return formatter.vformat('{'+args[1].strip()+'}', [], kwargs)\n if (len(args) % 2) != 1:\n raise ValueError(_('lookup requires either 2 or an odd number of arguments'))\n i = 0\n while i < len(args):\n if i + 1 >= len(args):\n return formatter.vformat('{' + args[i].strip() + '}', [], kwargs)\n if re.search(args[i], val):\n return formatter.vformat('{'+args[i+1].strip() + '}', [], kwargs)\n i += 2\n", "template": "def evaluate(self, formatter, kwargs, mi, locals, template):\n template = template.replace('[[', '{').replace(']]', '}')\n return formatter.__class__().safe_format(template, kwargs, 'TEMPLATE', mi)\n", @@ -23,14 +25,15 @@ "sublist": "def evaluate(self, formatter, kwargs, mi, locals, val, start_index, end_index, sep):\n if not val:\n return ''\n si = int(start_index)\n ei = int(end_index)\n val = val.split(sep)\n try:\n if ei == 0:\n return sep.join(val[si:])\n else:\n return sep.join(val[si:ei])\n except:\n return ''\n", "test": "def evaluate(self, formatter, kwargs, mi, locals, val, value_if_set, value_not_set):\n if val:\n return value_if_set\n else:\n return value_not_set\n", "eval": "def evaluate(self, formatter, kwargs, mi, locals, template):\n from formatter import eval_formatter\n template = template.replace('[[', '{').replace(']]', '}')\n return eval_formatter.safe_format(template, locals, 'EVAL', None)\n", - "multiply": "def evaluate(self, formatter, kwargs, mi, locals, x, y):\n x = float(x if x else 0)\n y = float(y if y else 0)\n return unicode(x * y)\n", + "not": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n i = 0\n while i < len(args):\n if args[i]:\n return '1'\n i += 1\n return ''\n", "format_date": "def evaluate(self, formatter, kwargs, mi, locals, val, format_string):\n if not val:\n return ''\n try:\n dt = parse_date(val)\n s = format_date(dt, format_string)\n except:\n s = 'BAD DATE'\n return s\n", "capitalize": "def evaluate(self, formatter, kwargs, mi, locals, val):\n return capitalize(val)\n", "count": "def evaluate(self, formatter, kwargs, mi, locals, val, sep):\n return unicode(len(val.split(sep)))\n", "lowercase": "def evaluate(self, formatter, kwargs, mi, locals, val):\n return val.lower()\n", - "strcmp": "def evaluate(self, formatter, kwargs, mi, locals, x, y, lt, eq, gt):\n v = strcmp(x, y)\n if v < 0:\n return lt\n if v == 0:\n return eq\n return gt\n", - "switch": "def evaluate(self, formatter, kwargs, mi, locals, val, *args):\n if (len(args) % 2) != 1:\n raise ValueError(_('switch requires an odd number of arguments'))\n i = 0\n while i < len(args):\n if i + 1 >= len(args):\n return args[i]\n if re.search(args[i], val):\n return args[i+1]\n i += 2\n", + "substr": "def evaluate(self, formatter, kwargs, mi, locals, str_, start_, end_):\n return str_[int(start_): len(str_) if int(end_) == 0 else int(end_)]\n", "assign": "def evaluate(self, formatter, kwargs, mi, locals, target, value):\n locals[target] = value\n return value\n", + "switch": "def evaluate(self, formatter, kwargs, mi, locals, val, *args):\n if (len(args) % 2) != 1:\n raise ValueError(_('switch requires an odd number of arguments'))\n i = 0\n while i < len(args):\n if i + 1 >= len(args):\n return args[i]\n if re.search(args[i], val):\n return args[i+1]\n i += 2\n", + "or": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n i = 0\n while i < len(args):\n if args[i]:\n return '1'\n i += 1\n return ''\n", "raw_field": "def evaluate(self, formatter, kwargs, mi, locals, name):\n return unicode(getattr(mi, name, None))\n", "cmp": "def evaluate(self, formatter, kwargs, mi, locals, x, y, lt, eq, gt):\n x = float(x if x else 0)\n y = float(y if y else 0)\n if x < y:\n return lt\n if x == y:\n return eq\n return gt\n" } \ No newline at end of file