From cdb4de1ace86a6d201aa705ff21baaa452ee7bb8 Mon Sep 17 00:00:00 2001 From: Fred Date: Tue, 9 Aug 2011 23:41:57 +0200 Subject: [PATCH] forgotten files added --- categoryview.py | 71 +++++++++ dataexport.py | 29 ++++ dateview.py | 52 +++++++ dateviewhisartvis.py | 52 +++++++ dateviewresearch.py | 52 +++++++ dateviewteacher.py | 52 +++++++ feedhandler.py | 139 +++++++++++++++++ feedparser.pyc | Bin 0 -> 103290 bytes grid.py | 49 ++++++ planetmo.py | 31 ++++ planettag.py | 78 ++++++++++ sanitize.py | 354 +++++++++++++++++++++++++++++++++++++++++++ statsview.py | 114 ++++++++++++++ temp_global.py | 90 +++++++++++ weeklypicks.py | 28 ++++ 15 files changed, 1191 insertions(+) create mode 100644 categoryview.py create mode 100644 dataexport.py create mode 100644 dateview.py create mode 100644 dateviewhisartvis.py create mode 100644 dateviewresearch.py create mode 100644 dateviewteacher.py create mode 100644 feedhandler.py create mode 100644 feedparser.pyc create mode 100644 grid.py create mode 100644 planetmo.py create mode 100644 planettag.py create mode 100644 sanitize.py create mode 100644 statsview.py create mode 100644 temp_global.py create mode 100644 weeklypicks.py diff --git a/categoryview.py b/categoryview.py new file mode 100644 index 0000000..decd644 --- /dev/null +++ b/categoryview.py @@ -0,0 +1,71 @@ +from main import * + +class CategoryView(TemplatePage): + cacheName = "CategoryView" + def generateSection(self,pair): + caption = pair[0] + categorylabel = pair[1] + output = [] + output.append(""" +

%(caption)s (Back to top)

+ + """) + return "".join(output) + def generateContent(self): + s = """ +

The categories represent what we see as roughly the primary focus of each blog -- this supplements PlanetTAG.

+
+ +
+ """ + thelist = [ + ['Pure mathematics', 'pure'], + ['Applied mathematics','applied'], + ['Teachers and Educators','teacher'], + ['Visualizations','visual'], + ['History','history'], + ['Art','art'], + ['Comics, recreational mathematics and other fun','fun'], + ['General scientific interest','general'], + ['Journalistic Writers','journalism'], + ['Journals, Publishers and similar feeds','journal'], + ['Commercial blogs','commercial'], + ['Communities','community'], + ['Institutions','institution'], + ['News','news'], + ['Carnivals','carnival'], + ] + return s + " ".join([self.generateSection(pair) for pair in thelist]) diff --git a/dataexport.py b/dataexport.py new file mode 100644 index 0000000..761f47e --- /dev/null +++ b/dataexport.py @@ -0,0 +1,29 @@ +from main import * + +class CsvView(CachedPage): + cacheName = "CsvView" + selfurl = "database.csv" + # self.response.headers['Content-Type'] = 'text/csv' + def generatePage(self): + output = [] + output.append( """title, homepage, person, category, posts_url, comments_url, priority, favicon, listtitle, language""") + for feed in Feed.gql("WHERE category IN :1 ORDER BY listtitle", ['pure', 'applied', 'teacher', 'history', 'visual','art','journalism','fun','journal', 'general','institution','commercial','community']): + output.append(""" "%(title)s",%(homepage)s,"%(person)s",%(category)s,%(url)s,%(comments)s,1,%(favicon)s, "%(listtitle)s",%(language)s \n""" % {'title': feed.title,'homepage': feed.homepage, 'person': feed.person , 'category':feed.category, 'url': feed.posts_url,'comments': feed.comments_url, 'favicon': feed.favicon, 'listtitle': feed.listtitle, 'language' : feed.language } ) + return "".join(output) + +class OPMLView(CachedPage): + cacheName = "OPMLView" + selfurl = "database-opml.xml" + def generatePage(self): + output = [] + output.append(""" + + Mathblogging.org Database export to OPML + + """) + for feed in Feed.gql("WHERE category IN :1 ORDER BY listtitle", ['pure', 'applied', 'teacher', 'history', 'visual','art','journalism','fun','journal', 'general','institution','commercial','community']): + output.append(""" + """ % {'title': feed.title,'homepage': feed.homepage, 'person': feed.person , 'category':feed.category, 'url': feed.posts_url,'comments': feed.comments_url, 'favicon': feed.favicon, 'listtitle': feed.listtitle, 'language' : feed.language } ) + output.append("""""") + return "".join(output) diff --git a/dateview.py b/dateview.py new file mode 100644 index 0000000..e1012bd --- /dev/null +++ b/dateview.py @@ -0,0 +1,52 @@ +from main import * + +class DateView(TemplatePage): + cacheName = "DateView" + def generateContent(self): + s = """
+ +
+

The latests posts

+ + + + + + + + + """ + for post in Post.gql("WHERE category IN :1 ORDER BY timestamp_created DESC LIMIT 150", ['history','fun','general','commercial','art','visual','pure','applied','teacher','journalism']): + s = s + """ + + + + + """ % {'time': post.printShortTime_created(), 'homepage': post.homepage, 'service': post.service, 'title': post.title, 'link': post.link } + return s + "
+ Date + + Blog + + Post +
+
+ %(time)s +
+
+ + +
+ %(title)s +
+
" diff --git a/dateviewhisartvis.py b/dateviewhisartvis.py new file mode 100644 index 0000000..3fb42be --- /dev/null +++ b/dateviewhisartvis.py @@ -0,0 +1,52 @@ +from main import * + +class DateViewHisArtVis(TemplatePage): + cacheName = "DateViewHisArtVis" + def generateContent(self): + s = """
+ +
+

The latests posts 'Art, Visual, History'

+ + + + + + + + + """ + for post in Post.gql("WHERE category IN :1 ORDER BY timestamp_created DESC LIMIT 150", ['history','art','visual']): + s = s + """ + + + + + """ % {'time': post.printShortTime_created(), 'homepage': post.homepage, 'service': post.service, 'title': post.title, 'link': post.link } + return s + "
+ Date + + Blog + + Post +
+
+ %(time)s +
+
+ + +
+ %(title)s +
+
" diff --git a/dateviewresearch.py b/dateviewresearch.py new file mode 100644 index 0000000..50f064a --- /dev/null +++ b/dateviewresearch.py @@ -0,0 +1,52 @@ +from main import * + +class DateViewResearch(TemplatePage): + cacheName = "DateViewResearch" + def generateContent(self): + s = """
+ +
+

The latests posts 'Pure, Applied'

+ + + + + + + + + """ + for post in Post.gql("WHERE category IN :1 ORDER BY timestamp_created DESC LIMIT 150", ['pure','applied']): + s = s + """ + + + + + """ % {'time': post.printShortTime_created(), 'homepage': post.homepage, 'service': post.service, 'title': post.title, 'link': post.link } + return s + "
+ Date + + Blog + + Post +
+
+ %(time)s +
+
+ + +
+ %(title)s +
+
" diff --git a/dateviewteacher.py b/dateviewteacher.py new file mode 100644 index 0000000..636726e --- /dev/null +++ b/dateviewteacher.py @@ -0,0 +1,52 @@ +from main import * + +class DateViewTeacher(TemplatePage): + cacheName = "DateViewTeacher" + def generateContent(self): + s = """
+ +
+

The latests posts 'Teachers, Educators'

+ + + + + + + + + """ + for post in Post.gql("WHERE category IN :1 ORDER BY timestamp_created DESC LIMIT 150", ['teacher']): + s = s + """ + + + + + """ % {'time': post.printShortTime_created(), 'homepage': post.homepage, 'service': post.service, 'title': post.title, 'link': post.link } + return s + "
+ Date + + Blog + + Post +
+
+ %(time)s +
+
+ + +
+ %(title)s +
+
" diff --git a/feedhandler.py b/feedhandler.py new file mode 100644 index 0000000..d41f4dc --- /dev/null +++ b/feedhandler.py @@ -0,0 +1,139 @@ +from main import * + +class FeedHandlerBase(CachedPage): + selfurl = "feed" + def generatePage(self): + output = [] + output.append( """ + + Mathblogging.org + + + 2010-11-10T21:50:23-05:00 + http://www.mathblogging.org/ + + mathblogging.org + mathblogging.network@gmail.com + """ % {'url':self.selfurl}) + for entry in self.query(): + output.append(""" + [[%(service)s]] %(title)s + + %(service)s + %(homepage)s + + + + %(tcreated)s + %(tupdated)s + %(link)s + Length: approx %(length)d words. + """ % {'service': entry.service,'title': entry.title, 'homepage': entry.homepage , 'link':entry.link, 'tcreated': entry.printTime_created_rfc3339(), 'tupdated':entry.printTime_updated_rfc3339(), 'length': entry.length/5} ) + output.append("") + return "".join(output) + + +class FeedHandlerAll(FeedHandlerBase): + selfurl = "feed_all" + cacheName = "FeedAll" + def query(self): + return Post.gql("ORDER BY timestamp_created DESC LIMIT 150") + +class FeedHandlerCategory(FeedHandlerBase): + def query(self): + return Post.gql("WHERE category = :1 ORDER BY timestamp_created DESC LIMIT 150", self.thecategory) + +class FeedHandlerCategories(FeedHandlerBase): + def query(self): + return Post.gql("WHERE category IN :1 ORDER BY timestamp_created DESC LIMIT 150", self.thecategories) + +class PlanetMOfeed(FeedHandlerBase): + selfurl = "planetmo-feed" + cacheName = "PlanetMOfeed" + def query(self): + return Post.gql("WHERE tags IN :1 ORDER BY timestamp_created DESC LIMIT 150", ['Planetmo','Mathoverflow', 'Math Overflow','Mo','MO']) + +class FeedHandlerResearchers(FeedHandlerCategories): + selfurl = "feed_researchers" + cacheName = "FeedResearchers" + thecategories = ['pure','applied','history'] + +class FeedHandlerPure(FeedHandlerCategory): + selfurl = "" + cacheName = "FeedPure" + thecategory = "pure" + +class FeedHandlerApplied(FeedHandlerCategory): + selfurl = "" + cacheName = "FeedApplied" + thecategory = "applied" + +class FeedHandlerHistory(FeedHandlerCategory): + selfurl = "" + cacheName = "FeedHistory" + thecategory = "history" + +class FeedHandlerVisual(FeedHandlerCategory): + selfurl = "" + cacheName = "FeedVisual" + thecategory = "visual" + +class FeedHandlerArt(FeedHandlerCategory): + selfurl = "" + cacheName = "FeedArt" + thecategory = "art" + +class FeedHandlerFun(FeedHandlerCategory): + selfurl = "" + cacheName = "FeedFun" + thecategory = "fun" + +class FeedHandlerGeneral(FeedHandlerCategory): + selfurl = "" + cacheName = "FeedGeneral" + thecategory = "general" + +class FeedHandlerJournals(FeedHandlerCategory): + selfurl = "" + cacheName = "FeedJournals" + thecategory = "journal" + +class FeedHandlerTeachers(FeedHandlerCategory): + selfurl = "" + cacheName = "FeedTeachers" + thecategory = "teacher" + +class FeedHandlerJournalism(FeedHandlerCategory): + selfurl = "" + cacheName = "FeedJournalism" + thecategory = "journalism" + +class FeedHandlerInstitutions(FeedHandlerCategory): + selfurl = "" + cacheName = "FeedInstitutions" + thecategory = "institution" + +class FeedHandlerCommunities(FeedHandlerCategory): + selfurl = "" + cacheName = "FeedCommunities" + thecategory = "community" + +class FeedHandlerCommercial(FeedHandlerCategory): + selfurl = "" + cacheName = "FeedCommercial" + thecategory = "commercial" + +class FeedHandlerNewssite(FeedHandlerCategory): + selfurl = "" + cacheName = "FeedNewssite" + thecategory = "news" + +class FeedHandlerCarnival(FeedHandlerCategory): + selfurl = "" + cacheName = "FeedCarnival" + thecategory = "carnival" + +class FeedHandlerPeople(FeedHandlerCategories): + selfurl = "" + cacheName = "FeedPeople" + thecategories = ["pure","applied","visual","history","fun","teacher","journalism","general","art"] diff --git a/feedparser.pyc b/feedparser.pyc new file mode 100644 index 0000000000000000000000000000000000000000..807bd98748b41b1e718c8dfadf580df028644767 GIT binary patch literal 103290 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≤wN#`U{(=ToVT=)PT#yEI`Jb+fsz$^uisDSe9nVsWZD(k#17j=23F3;<7 zNtYLN8P(;zx{T;j(FJ}N&sJR~bQ#v=GMCVd>dZ&mYEN=H>{M0GhG|sXeoS7Z>9L!8 z=hiMAo3>D)U0*yhoDK7mZ>rZhPC+2e*#K$so62Mw_t&`Vpkm+Mf$({n3xcfc;FhBr z8&)D&9eAt)Y_Fq3|0`!AX!Sc&Cy+cQV_1&|k z*tcZ;Hwy8uw7mG>Q(M!mTQ=?NTej(uzMVS`_Pv{2tNQ2(eWBKsJ +

%(caption)s

+ View Image +
""" % {'category': categorylabel, 'caption': caption}) + for feed in Feed.gql("WHERE category = :1 ORDER BY listtitle", categorylabel): + output.append("""
%(title)s
""" % { 'homepage': feed.homepage, 'title': feed.title }) + for entry in Post.gql("WHERE service = :1 ORDER BY timestamp_created DESC LIMIT 7", feed.title): + output.append("""
%(title)s
""" % {'link': entry.link, 'title': entry.title}) + output.append(" ") + output.append("
") + return "".join(output) + def generatePage(self): + s = """ + + + + + + + Categories Grid + + + + +
""" + thelist = [ + ['Pure mathematics', 'pure'], + ['Applied mathematics','applied'], + ['Teachers and Educators','teacher'], + ['Visualizations','visual'], + ['History','history'], + ['Art','art'], + ['Comics, recreational mathematics and other fun','fun'], + ['General scientific interest','general'], + ['Journalistic Writers','journalism'], + ['Journals, Publishers and similar feeds','journal'], + ['Commercial blogs','commercial'], + ['Communities','community'], + ['Institutions','institution'] + ] + return s + " ".join([self.generateSection(pair) for pair in thelist]) + """
""" diff --git a/planetmo.py b/planetmo.py new file mode 100644 index 0000000..a8de15d --- /dev/null +++ b/planetmo.py @@ -0,0 +1,31 @@ +from main import * + +import counter + + +class PlanetMO(TemplatePage): + cacheName = "PlanetMO" + def generateContent(self): + output = [] + output.append( """

PlanetMO PlanetMO feed

+ +At PlanetMO we collect recent posts tagged "mathoverflow", "math overflow", "mo" or "planetmo".""") + + for entry in Post.gql("WHERE tags IN :1 ORDER BY timestamp_created DESC LIMIT 150", ['Planetmo','Mathoverflow', 'Math Overflow','Mo','MO']): + output.append( """
+
+

%(title)s

+
Posted on %(service)s at %(tcreated)s. +
+
+ Tags: """ % {"link":entry.link, "title":entry.title, "homepage":entry.homepage, "service":entry.service, "tcreated":entry.printShortTime_created()} ) + for tag in entry.tags: + output.append(tag) + output.append(", ") + output.append( """
+
+
+ """ ) + output.append( entry.content ) + output.append( """
""" ) + return "".join(output) diff --git a/planettag.py b/planettag.py new file mode 100644 index 0000000..597d1fa --- /dev/null +++ b/planettag.py @@ -0,0 +1,78 @@ +from main import * + +import counter + +memcachekey = "TagListMemCacheKey" + +class TagListWorker(webapp.RequestHandler): + def get(self): + try: + logging.info("TagListWorker: generating tag list") + all_tag = [ tag for entry in Post.all() for tag in entry.tags ] + common_tags = counter.Counter(all_tag) + memcache.set(memcachekey, common_tags, 10800) + except Exception, e: + self.response.set_status(200) + logging.warning("TagListWorker failed: \n" + str(e)) + +class PlanetTag(TemplatePage): + cacheName = "" + def generateContent(self): + tagname = self.request.get('content') + logging.info("PlanetTag: tagname '" + tagname + "'") + output = [] + output.append( """

PlanetTAG

+ +

Click on a tag to see a list of recent posts. Right now, you chose ==%(tagname)s==.

+

For convenience, we filter out the dominant tags Mathematics, Math, Maths, Matemáticas, Matematica and the infamous Uncategorized (as well as some error generating tags).

+ +
""" % {"tagname":tagname}) + for entry in Post.gql("WHERE tags = :1 ORDER BY timestamp_created DESC LIMIT 20",tagname): + output.append( """
+
+

%(title)s

+
Posted on %(service)s at %(tcreated)s. +
+
+ Tags: """ % {"link":entry.link, "title":entry.title, "homepage":entry.homepage, "service":entry.service, "tcreated":entry.printShortTime_created()} ) + for tag in entry.tags: + output.append(tag) + output.append(", ") + output.append( """
+
+
+

""" ) + output.append( entry.content ) + output.append( """

""" ) + output.append( """ + +""" ) + return "".join(output) diff --git a/sanitize.py b/sanitize.py new file mode 100644 index 0000000..c98b14d --- /dev/null +++ b/sanitize.py @@ -0,0 +1,354 @@ +""" +sanitize: bringing sanitiy to world of messed-up data +""" + +__author__ = ["Mark Pilgrim ", + "Aaron Swartz "] +__contributors__ = ["Sam Ruby "] +__license__ = "BSD" +__version__ = "0.25" + +_debug = 0 + +# If you want sanitize to automatically run HTML markup through HTML Tidy, set +# this to 1. Requires mxTidy +# or utidylib . +TIDY_MARKUP = 0 + +# List of Python interfaces for HTML Tidy, in order of preference. Only useful +# if TIDY_MARKUP = 1 +PREFERRED_TIDY_INTERFACES = ["uTidy", "mxTidy"] + +import sgmllib, re + +# chardet library auto-detects character encodings +# Download from http://chardet.feedparser.org/ +try: + import chardet + if _debug: + import chardet.constants + chardet.constants._debug = 1 + + _chardet = lambda data: chardet.detect(data)['encoding'] +except: + chardet = None + _chardet = lambda data: None + +class _BaseHTMLProcessor(sgmllib.SGMLParser): + elements_no_end_tag = ['area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', + 'img', 'input', 'isindex', 'link', 'meta', 'param'] + + _r_barebang = re.compile(r'') + + def __init__(self, encoding): + self.encoding = encoding + if _debug: sys.stderr.write('entering BaseHTMLProcessor, encoding=%s\n' % self.encoding) + sgmllib.SGMLParser.__init__(self) + + def reset(self): + self.pieces = [] + sgmllib.SGMLParser.reset(self) + + def _shorttag_replace(self, match): + tag = match.group(1) + if tag in self.elements_no_end_tag: + return '<' + tag + ' />' + else: + return '<' + tag + '>' + + def feed(self, data): + data = self._r_barebang.sub(r'<!\1', data) + data = self._r_bareamp.sub("&", data) + data = self._r_shorttag.sub(self._shorttag_replace, data) + if self.encoding and type(data) == type(u''): + data = data.encode(self.encoding) + sgmllib.SGMLParser.feed(self, data) + + def normalize_attrs(self, attrs): + # utility method to be called by descendants + attrs = [(k.lower(), v) for k, v in attrs] + attrs = [(k, k in ('rel', 'type') and v.lower() or v) for k, v in attrs] + return attrs + + def unknown_starttag(self, tag, attrs): + # called for each start tag + # attrs is a list of (attr, value) tuples + # e.g. for
, tag='pre', attrs=[('class', 'screen')]
+        if _debug: sys.stderr.write('_BaseHTMLProcessor, unknown_starttag, tag=%s\n' % tag)
+        uattrs = []
+        # thanks to Kevin Marks for this breathtaking hack to deal with (valid) high-bit attribute values in UTF-8 feeds
+        for key, value in attrs:
+            if type(value) != type(u''):
+                value = unicode(value, self.encoding)
+            uattrs.append((unicode(key, self.encoding), value))
+        strattrs = u''.join([u' %s="%s"' % (key, value) for key, value in uattrs]).encode(self.encoding)
+        if tag in self.elements_no_end_tag:
+            self.pieces.append('<%(tag)s%(strattrs)s />' % locals())
+        else:
+            self.pieces.append('<%(tag)s%(strattrs)s>' % locals())
+
+    def unknown_endtag(self, tag):
+        # called for each end tag, e.g. for 
, tag will be 'pre' + # Reconstruct the original end tag. + if tag not in self.elements_no_end_tag: + self.pieces.append("" % locals()) + + def handle_charref(self, ref): + # called for each character reference, e.g. for ' ', ref will be '160' + # Reconstruct the original character reference. + self.pieces.append('&#%(ref)s;' % locals()) + + def handle_entityref(self, ref): + # called for each entity reference, e.g. for '©', ref will be 'copy' + # Reconstruct the original entity reference. + self.pieces.append('&%(ref)s;' % locals()) + + def handle_data(self, text): + # called for each block of plain text, i.e. outside of any tag and + # not containing any character or entity references + # Store the original text verbatim. + if _debug: sys.stderr.write('_BaseHTMLProcessor, handle_text, text=%s\n' % text) + self.pieces.append(text) + + def handle_comment(self, text): + # called for each HTML comment, e.g. + # Reconstruct the original comment. + self.pieces.append('' % locals()) + + def handle_pi(self, text): + # called for each processing instruction, e.g. + # Reconstruct original processing instruction. + self.pieces.append('' % locals()) + + def handle_decl(self, text): + # called for the DOCTYPE, if present, e.g. + # + # Reconstruct original DOCTYPE + self.pieces.append('' % locals()) + + _new_declname_match = re.compile(r'[a-zA-Z][-_.a-zA-Z0-9:]*\s*').match + def _scan_name(self, i, declstartpos): + rawdata = self.rawdata + n = len(rawdata) + if i == n: + return None, -1 + m = self._new_declname_match(rawdata, i) + if m: + s = m.group() + name = s.strip() + if (i + len(s)) == n: + return None, -1 # end of buffer + return name.lower(), m.end() + else: + self.handle_data(rawdata) +# self.updatepos(declstartpos, i) + return None, -1 + + def output(self): + '''Return processed HTML as a single string''' + return ''.join([str(p) for p in self.pieces]) + +class _HTMLSanitizer(_BaseHTMLProcessor): + acceptable_elements = ['a', 'abbr', 'acronym', 'address', 'area', 'b', 'big', + 'blockquote', 'br', 'button', 'caption', 'center', 'cite', 'code', 'col', + 'colgroup', 'dd', 'del', 'dfn', 'dir', 'div', 'dl', 'dt', 'em', 'fieldset', + 'font', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'input', + 'ins', 'kbd', 'label', 'legend', 'li', 'map', 'menu', 'ol', 'optgroup', + 'option', 'p', 'pre', 'q', 's', 'samp', 'select', 'small', 'span', 'strike', + 'strong', 'sub', 'sup', 'table', 'textarea', 'tbody', 'td', 'tfoot', 'th', + 'thead', 'tr', 'tt', 'u', 'ul', 'var'] + + acceptable_attributes = ['abbr', 'accept', 'accept-charset', 'accesskey', + 'action', 'align', 'alt', 'axis', 'border', 'cellpadding', 'cellspacing', + 'char', 'charoff', 'charset', 'checked', 'cite', 'class', 'clear', 'cols', + 'colspan', 'color', 'compact', 'coords', 'datetime', 'dir', 'disabled', + 'enctype', 'for', 'frame', 'headers', 'height', 'href', 'hreflang', 'hspace', + 'id', 'ismap', 'label', 'lang', 'longdesc', 'maxlength', 'media', 'method', + 'multiple', 'name', 'nohref', 'noshade', 'nowrap', 'prompt', 'readonly', + 'rel', 'rev', 'rows', 'rowspan', 'rules', 'scope', 'selected', 'shape', 'size', + 'span', 'src', 'start', 'summary', 'tabindex', 'target', 'title', 'type', + 'usemap', 'valign', 'value', 'vspace', 'width'] + + ignorable_elements = ['script', 'applet', 'style'] + + def reset(self): + _BaseHTMLProcessor.reset(self) + self.tag_stack = [] + self.ignore_level = 0 + + def feed(self, data): + _BaseHTMLProcessor.feed(self, data) + while self.tag_stack: + _BaseHTMLProcessor.unknown_endtag(self, self.tag_stack.pop()) + + def unknown_starttag(self, tag, attrs): + if tag in self.ignorable_elements: + self.ignore_level += 1 + return + + if self.ignore_level: + return + + if tag in self.acceptable_elements: + attrs = self.normalize_attrs(attrs) + attrs = [(key, value) for key, value in attrs if key in self.acceptable_attributes] + if tag not in self.elements_no_end_tag: + self.tag_stack.append(tag) + _BaseHTMLProcessor.unknown_starttag(self, tag, attrs) + + def unknown_endtag(self, tag): + if tag in self.ignorable_elements: + self.ignore_level -= 1 + return + + if self.ignore_level: + return + + if tag in self.acceptable_elements and tag not in self.elements_no_end_tag: + match = False + while self.tag_stack: + top = self.tag_stack.pop() + if top == tag: + match = True + break + _BaseHTMLProcessor.unknown_endtag(self, top) + + if match: + _BaseHTMLProcessor.unknown_endtag(self, tag) + + def handle_pi(self, text): + pass + + def handle_decl(self, text): + pass + + def handle_data(self, text): + if not self.ignore_level: + text = text.replace('<', '') + _BaseHTMLProcessor.handle_data(self, text) + +def HTML(htmlSource, encoding='utf8'): + p = _HTMLSanitizer(encoding) + p.feed(htmlSource) + data = p.output() + if TIDY_MARKUP: + # loop through list of preferred Tidy interfaces looking for one that's installed, + # then set up a common _tidy function to wrap the interface-specific API. + _tidy = None + for tidy_interface in PREFERRED_TIDY_INTERFACES: + try: + if tidy_interface == "uTidy": + from tidy import parseString as _utidy + def _tidy(data, **kwargs): + return str(_utidy(data, **kwargs)) + break + elif tidy_interface == "mxTidy": + from mx.Tidy import Tidy as _mxtidy + def _tidy(data, **kwargs): + nerrors, nwarnings, data, errordata = _mxtidy.tidy(data, **kwargs) + return data + break + except: + pass + if _tidy: + utf8 = type(data) == type(u'') + if utf8: + data = data.encode('utf-8') + data = _tidy(data, output_xhtml=1, numeric_entities=1, wrap=0, char_encoding="utf8") + if utf8: + data = unicode(data, 'utf-8') + if data.count(''): + data = data.split('>', 1)[1] + if data.count(' + + + + + + + + """) + for feed in Feed.gql("WHERE category IN :1 ORDER BY comments_day DESC", ['history','fun','general','commercial','art','visual','pure','applied','teacher','journalism']): + output.append(""" + + + + """ % {'comments_day': feed.comments_day, 'homepage': feed.homepage, 'title': feed.title }) + output.append(""" + +
+ + Comments last 24h +
+ %(comments_day)i + + %(title)s +
""") + + output.append(""" + + + + + + + + """) + for feed in Feed.gql("WHERE category IN :1 ORDER BY comments_week DESC", ['history','fun','general','commercial','art','visual','pure','applied','teacher','journalism']): + output.append(""" + + + + """ % {'comments_week': feed.comments_week, 'homepage': feed.homepage, 'title': feed.title }) + output.append(""" + +
+ + Comments last week +
+ %(comments_week)i + + %(title)s +
""") + + output.append(""" + + + + + + + + """) + for feed in Feed.gql("WHERE category IN :1 ORDER BY posts_day DESC", ['history','fun','general','commercial','art','visual','pure','applied','teacher','journalism']): + output.append(""" + + + + """ % {'posts_week': feed.posts_week, 'homepage': feed.homepage, 'title': feed.title }) + output.append(""" + +
+ + Posts last week +
+ %(posts_week)i + + %(title)s +
""") + + output.append(""" + + + + + + + + """) + for feed in Feed.gql("WHERE category IN :1 ORDER BY posts_day DESC", ['history','fun','general','commercial','art','visual','pure','applied','teacher','journalism']): + output.append(""" + + + + """ % {'posts_month': feed.posts_month, 'homepage': feed.homepage, 'title': feed.title }) + output.append(""" + +
+ + Posts last month +
+ %(posts_month)i + + %(title)s +
""") + return "".join(output) + + + diff --git a/temp_global.py b/temp_global.py new file mode 100644 index 0000000..52e870d --- /dev/null +++ b/temp_global.py @@ -0,0 +1,90 @@ +header = """ + + + + + + + + Mathblogging.org + + + + + +

Mathblogging.org beta

+""" + +menu = """ + + + +""" + +disqus = """ + +
+
+
+ + +blog comments powered by Disqus +
+ +""" + +footer = """ + + + +""" diff --git a/weeklypicks.py b/weeklypicks.py new file mode 100644 index 0000000..b0d190a --- /dev/null +++ b/weeklypicks.py @@ -0,0 +1,28 @@ +from main import * + +import counter + + +class WeeklyPicks(TemplatePage): + cacheName = "WeeklyPicks" + def generateContent(self): + output = [] + output.append( """

Weekly picks Weekly picks

+ +Our weekly picks, crossposted from Mathblogging.org -- the blog. +""") + + for entry in Post.gql("WHERE tags IN :1 ORDER BY timestamp_created DESC LIMIT 150", ['Weekly Picks']): + output.append( """
+
+

%(title)s

+
Posted %(tcreated)s. +
+
""" % {"link":entry.link, "title":entry.title, "homepage":entry.homepage, "service":entry.service, "tcreated":entry.printShortTime_created()} ) + output.append( """
+
+
+

""" ) + output.append( entry.content ) + output.append( """

""" ) + return "".join(output)