]> git.sur5r.net Git - i3/i3.github.io/commitdiff
remove obsolete blog controller
authorMichael Stapelberg <michael@stapelberg.de>
Mon, 16 Jun 2014 20:28:10 +0000 (22:28 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Mon, 16 Jun 2014 20:28:10 +0000 (22:28 +0200)
_controllers/blog/__init__.py [deleted file]
_controllers/blog/archives.py [deleted file]
_controllers/blog/categories.py [deleted file]
_controllers/blog/chronological.py [deleted file]
_controllers/blog/feed.py [deleted file]
_controllers/blog/permapage.py [deleted file]
_controllers/blog/post.py [deleted file]
_controllers/org.py [deleted file]

diff --git a/_controllers/blog/__init__.py b/_controllers/blog/__init__.py
deleted file mode 100644 (file)
index ae31be8..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-import logging
-
-from blogofile.cache import bf
-
-import archives
-import categories
-import chronological
-import feed
-import permapage
-import post
-
-config = {
-        "name": "Blog",
-        "description": "Creates a Blog",
-        "priority": 90.0,
-
-        #Posts
-        "post.date_format": "%Y/%m/%d %H:%M:%S"
-        }
-
-def run():
-    blog = bf.config.controllers.blog
-
-    #Parse the posts
-    blog.posts = post.parse_posts("_posts")
-    blog.dir = bf.util.path_join(bf.writer.output_dir, blog.path)
-
-    # Find all the categories and archives before we write any pages
-    blog.archived_posts = {} ## "/archive/Year/Month" -> [post, post, ... ]
-    blog.archive_links = []  ## [("/archive/2009/12", name, num_in_archive1), ...] (sorted in reverse by date)
-    blog.categorized_posts = {} ## "Category Name" -> [post, post, ... ]
-    blog.all_categories = [] ## [("Category 1",num_in_category_1), ...] (sorted alphabetically)
-    archives.sort_into_archives()
-    categories.sort_into_categories()
-
-    blog.logger = logging.getLogger(config['name'])
-    
-    permapage.run()
-    chronological.run()
-    archives.run()
-    categories.run()
-    feed.run()
-
diff --git a/_controllers/blog/archives.py b/_controllers/blog/archives.py
deleted file mode 100644 (file)
index ed9e45f..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-################################################################################
-## Archives controller
-##
-## Writes out yearly, monthly, and daily archives.
-## Each archive is navigable to the next and previous archive
-## in which posts were made.
-################################################################################
-
-import operator
-
-from blogofile.cache import bf
-import chronological
-
-blog = bf.config.controllers.blog
-
-
-def run():
-    write_monthly_archives()
-
-
-def sort_into_archives():
-    #This is run in 0.initial.py
-    for post in blog.posts:
-        link = post.date.strftime("archive/%Y/%m")
-        try:
-            blog.archived_posts[link].append(post)
-        except KeyError:
-            blog.archived_posts[link] = [post]
-    for archive, posts in sorted(
-        blog.archived_posts.items(), key=operator.itemgetter(0), reverse=True):
-        name = posts[0].date.strftime("%B %Y")
-        blog.archive_links.append((archive, name, len(posts)))
-
-
-def write_monthly_archives():
-    for link, posts in blog.archived_posts.items():
-        name = posts[0].date.strftime("%B %Y")
-        chronological.write_blog_chron(posts, root=link)
diff --git a/_controllers/blog/categories.py b/_controllers/blog/categories.py
deleted file mode 100644 (file)
index 24b6e66..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-import os
-import shutil
-import operator
-import feed
-from blogofile.cache import bf
-
-blog = bf.config.controllers.blog
-
-
-def run():
-    write_categories()
-
-
-def sort_into_categories():
-    categories = set()
-    for post in blog.posts:
-        categories.update(post.categories)
-    for category in categories:
-        category_posts = [post for post in blog.posts
-                            if category in post.categories]
-        blog.categorized_posts[category] = category_posts
-    for category, posts in sorted(
-        blog.categorized_posts.items(), key=operator.itemgetter(0)):
-        blog.all_categories.append((category, len(posts)))
-
-
-def write_categories():
-    """Write all the blog posts in categories"""
-    root = bf.util.path_join(blog.path, blog.category_dir)
-    #Find all the categories:
-    categories = set()
-    for post in blog.posts:
-        categories.update(post.categories)
-    for category, category_posts in blog.categorized_posts.items():
-        page_num = 1
-        while True:
-            path = bf.util.path_join(root, category.url_name,
-                                str(page_num), "index.html")
-            page_posts = category_posts[:blog.posts_per_page]
-            category_posts = category_posts[blog.posts_per_page:]
-            #Forward and back links
-            if page_num > 1:
-                prev_link = bf.util.site_path_helper(
-                    blog.path, blog.category_dir, category.url_name,
-                                           str(page_num - 1))
-            else:
-                prev_link = None
-            if len(category_posts) > 0:
-                next_link = bf.util.site_path_helper(
-                    blog.path, blog.category_dir, category.url_name,
-                                           str(page_num + 1))
-            else:
-                next_link = None
-            
-            env = {
-                "category": category,
-                "posts": page_posts,
-                "prev_link": prev_link,
-                "next_link": next_link
-            }
-            bf.writer.materialize_template("chronological.mako", path, env)
-            
-            #Copy category/1 to category/index.html
-            if page_num == 1:
-                shutil.copyfile(
-                        bf.util.path_join(bf.writer.output_dir, path),
-                        bf.util.path_join(
-                                bf.writer.output_dir, root, category.url_name,
-                                "index.html"))
-            #Prepare next iteration
-            page_num += 1
-            if len(category_posts) == 0:
-                break
diff --git a/_controllers/blog/chronological.py b/_controllers/blog/chronological.py
deleted file mode 100644 (file)
index 1cd019a..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-# Write all the blog posts in reverse chronological order
-import os
-from blogofile.cache import bf
-
-blog = bf.config.controllers.blog
-
-
-def run():
-    write_blog_chron(posts=blog.posts, root=blog.pagination_dir.lstrip("/"))
-    write_blog_first_page()
-
-
-def write_blog_chron(posts, root):
-    page_num = 1
-    post_num = 0
-    html = []
-    while len(posts) > post_num:
-        #Write the pages, num_per_page posts per page:
-        page_posts = posts[post_num:post_num + blog.posts_per_page]
-        post_num += blog.posts_per_page
-        if page_num > 1:
-            prev_link = "../" + str(page_num - 1)
-        else:
-            prev_link = None
-        if len(posts) > post_num:
-            next_link = "../" + str(page_num + 1)
-        else:
-            next_link = None
-        page_dir = bf.util.path_join(blog.path, root, str(page_num))
-        fn = bf.util.path_join(page_dir, "index.html")
-        env = {
-            "posts": page_posts,
-            "next_link": next_link,
-            "prev_link": prev_link
-        }
-        bf.writer.materialize_template("chronological.mako", fn, env)
-        page_num += 1
-
-
-def write_blog_first_page():
-    if not blog.custom_index:
-        page_posts = blog.posts[:blog.posts_per_page]
-        path = bf.util.path_join(blog.path, "index.html")
-        blog.logger.info(u"Writing blog index page: " + path)
-        if len(blog.posts) > blog.posts_per_page:
-            next_link = bf.util.site_path_helper(
-                    blog.path, blog.pagination_dir+"/2")
-        else:
-            next_link = None
-        env = {
-            "posts": page_posts,
-            "next_link": next_link,
-            "prev_link": None
-        }
-        bf.writer.materialize_template("chronological.mako", path, env)
diff --git a/_controllers/blog/feed.py b/_controllers/blog/feed.py
deleted file mode 100644 (file)
index 38ebc81..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-from blogofile.cache import bf
-
-blog = bf.config.controllers.blog
-
-
-def run():
-    write_feed(blog.posts, blog.path, blog.path + "/rss.xml", "rss.mako")
-    write_feed(blog.posts, blog.path, blog.path + "/atom.xml", "atom.mako")
-
-def write_feed(posts, root, path, template):
-    blog.logger.info("Writing RSS/Atom feed: " + path)
-    env = {"posts": posts, "root": root}
-    bf.writer.materialize_template(template, path, env)
diff --git a/_controllers/blog/permapage.py b/_controllers/blog/permapage.py
deleted file mode 100644 (file)
index 6f8df33..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-import urlparse
-from blogofile.cache import bf
-import re
-
-blog = bf.config.controllers.blog
-
-
-def run():
-    write_permapages()
-
-
-def write_permapages():
-    "Write blog posts to their permalink locations"
-    site_re = re.compile(bf.config.site.url, re.IGNORECASE)
-    num_posts = len(blog.posts)
-    
-    for i, post in enumerate(blog.posts):
-        if post.permalink:
-            path = site_re.sub("", post.permalink)
-            blog.logger.info(u"Writing permapage for post: {0}".format(path))
-        else:
-            #Permalinks MUST be specified. No permalink, no page.
-            blog.logger.info(u"Post has no permalink: {0}".format(post.title))
-            continue
-
-        env = {
-            "post": post,
-            "posts": blog.posts
-        }
-
-        #Find the next and previous posts chronologically
-        if i < num_posts - 1:
-            env['prev_post'] = blog.posts[i + 1]
-        if i > 0:
-            env['next_post'] = blog.posts[i - 1]
-        
-        bf.writer.materialize_template(
-                "permapage.mako", bf.util.path_join(path, "index.html"), env)
diff --git a/_controllers/blog/post.py b/_controllers/blog/post.py
deleted file mode 100644 (file)
index c95b580..0000000
+++ /dev/null
@@ -1,342 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-"""
-post.py parses post sources from the ./_post directory.
-"""
-
-__author__ = "Ryan McGuire (ryan@enigmacurry.com)"
-__date__   = "Mon Feb  2 21:21:04 2009"
-
-import os
-import sys
-import datetime
-import re
-import operator
-import urlparse
-import hashlib
-import codecs
-
-import pytz
-import yaml
-import logging
-import BeautifulSoup
-
-import blogofile_bf as bf
-
-logger = logging.getLogger("blogofile.post")
-
-config = bf.config.controllers.blog.post
-config.mod = sys.modules[globals()["__name__"]]
-
-# These are all the Blogofile reserved field names for posts. It is not
-# recommended that users re-use any of these field names for purposes other
-# than the one stated.
-reserved_field_names = {
-    "title"      :"A one-line free-form title for the post",
-    "date"       :"The date that the post was originally created",
-    "updated"    :"The date that the post was last updated",
-    "categories" :"A list of categories that the post pertains to, "\
-        "each seperated by commas",
-    "tags"       :"A list of tags that the post pertains to, "\
-        "each seperated by commas",
-    "permalink"  :"The full permanent URL for this post. "\
-        "Automatically created if not provided",
-    "path"       :"The path from the permalink of the post",
-    "guid"       :"A unique hash for the post, if not provided it "\
-        "is assumed that the permalink is the guid",
-    "slug"       :"The title part of the URL for the post, if not "\
-        "provided it is automatically generated from the title."\
-        "It is not used if permalink does not contain :title",
-    "author"     :"The name of the author of the post",
-    "filters"    :"The filter chain to apply to the entire post. "\
-        "If not specified, a default chain based on the file extension is "\
-        "applied. If set to 'None' it disables all filters, even default ones.",
-    "filter"     :"synonym for filters",
-    "draft"      :"If 'true' or 'True', the post is considered to be only a "\
-        "draft and not to be published.",
-    "source"     :"Reserved internally",
-    "yaml"       :"Reserved internally",
-    "content"    :"Reserved internally",
-    "filename"   :"Reserved internally"
-    }
-
-
-class PostParseException(Exception):
-
-    def __init__(self, value):
-        self.value = value
-
-    def __str__(self):
-        return repr(self.value)
-
-
-class Post(object):
-    """
-    Class to describe a blog post and associated metadata
-    """
-    def __init__(self, source, filename="Untitled"):
-        self.source = source
-        self.yaml = None
-        self.title = None
-        self.__timezone = bf.config.controllers.blog.timezone
-        self.date = None
-        self.updated = None
-        self.categories = set()
-        self.tags = set()
-        self.permalink = None
-        self.content = u""
-        self.excerpt = u""
-        self.filename = filename
-        self.author = ""
-        self.guid = None
-        self.slug = None
-        self.draft = False
-        self.filters = None
-        self.__parse()
-        self.__post_process()
-        
-    def __repr__(self): #pragma: no cover
-        return u"<Post title='{0}' date='{1}'>".format(
-            self.title, self.date.strftime("%Y/%m/%d %H:%M:%S"))
-     
-    def __parse(self):
-        """Parse the yaml and fill fields"""
-        yaml_sep = re.compile("^---$", re.MULTILINE)
-        content_parts = yaml_sep.split(self.source, maxsplit=2)
-        if len(content_parts) < 2:
-            raise PostParseException(u"{0}: Post has no YAML section".format(
-                    self.filename))
-        else:
-            #Extract the yaml at the top
-            self.__parse_yaml(content_parts[1])
-            post_src = content_parts[2]
-        self.__apply_filters(post_src)
-        #Do post excerpting
-        self.__parse_post_excerpting()
-
-    def __apply_filters(self, post_src):
-        """Apply filters to the post"""
-        #Apply block level filters (filters on only part of the post)
-        # TODO: block level filters on posts
-        #Apply post level filters (filters on the entire post)
-        #If filter is unspecified, use the default filter based on
-        #the file extension:
-        if self.filters is None:
-            try:
-                file_extension = os.path.splitext(self.filename)[-1][1:]
-                self.filters = bf.config.controllers.blog.post_default_filters[
-                    file_extension]
-            except KeyError:
-                self.filters = []
-        self.content = bf.filter.run_chain(self.filters, post_src)
-        
-    def __parse_post_excerpting(self):
-        if bf.config.controllers.blog.post_excerpts.enabled:
-            length = bf.config.controllers.blog.post_excerpts.word_length
-            try:
-                self.excerpt = bf.config.post_excerpt(self.content, length)
-            except AttributeError:
-                self.excerpt = self.__excerpt(length)
-
-    def __excerpt(self, num_words=50):
-        #Default post excerpting function
-        #Can be overridden in _config.py by
-        #defining post_excerpt(content,num_words)
-        if len(self.excerpt) == 0:
-             """Retrieve excerpt from article"""
-             s = BeautifulSoup.BeautifulSoup(self.content)
-             # get rid of javascript, noscript and css
-             [[tree.extract() for tree in s(elem)] for elem in (
-                     'script', 'noscript', 'style')]
-             # get rid of doctype
-             subtree = s.findAll(text=re.compile("DOCTYPE|xml"))
-             [tree.extract() for tree in subtree]
-             # remove headers
-             [[tree.extract() for tree in s(elem)] for elem in (
-                     'h1', 'h2', 'h3', 'h4', 'h5', 'h6')]
-             text = ''.join(s.findAll(text=True))\
-                                 .replace("\n", "").split(" ")
-             return " ".join(text[:num_words]) + '...'
-        
-    def __post_process(self):
-        # fill in empty default value
-        if not self.title:
-            self.title = u"Untitled - {0}".format(
-                    datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
-        
-        if not self.slug:
-            self.slug = re.sub("[ ?]", "-", self.title).lower()
-
-        if not self.date:
-            self.date = datetime.datetime.now(pytz.timezone(self.__timezone))
-        if not self.updated:
-            self.updated = self.date
-
-        if not self.categories or len(self.categories) == 0:
-            self.categories = set([Category('Uncategorized')])
-        if not self.permalink and \
-                bf.config.controllers.blog.auto_permalink.enabled:
-            self.permalink = bf.config.site.url.rstrip("/") + \
-                bf.config.controllers.blog.auto_permalink.path
-            self.permalink = \
-                    re.sub(":blog_path", bf.config.blog.path, self.permalink)
-            self.permalink = \
-                    re.sub(":year", self.date.strftime("%Y"), self.permalink)
-            self.permalink = \
-                    re.sub(":month", self.date.strftime("%m"), self.permalink)
-            self.permalink = \
-                    re.sub(":day", self.date.strftime("%d"), self.permalink)
-            self.permalink = \
-                    re.sub(":title", self.slug, self.permalink)
-
-            # TODO: slugification should be abstracted out somewhere reusable
-            self.permalink = re.sub(
-                    ":filename", re.sub(
-                            "[ ?]", "-", self.filename).lower(), self.permalink)
-
-            # Generate sha hash based on title
-            self.permalink = re.sub(":uuid", hashlib.sha1(
-                    self.title.encode('utf-8')).hexdigest(), self.permalink)
-
-        logger.debug(u"Permalink: {0}".format(self.permalink))
-     
-    def __parse_yaml(self, yaml_src):
-        y = yaml.load(yaml_src)
-        # Load all the fields that require special processing first:
-        fields_need_processing = ('permalink', 'guid', 'date', 'updated',
-                                  'categories', 'tags', 'draft')
-        try:
-            self.permalink = y['permalink']
-            if self.permalink.startswith("/"):
-                self.permalink = urlparse.urljoin(bf.config.site.url,
-                        self.permalink)
-            #Ensure that the permalink is for the same site as bf.config.site.url
-            if not self.permalink.startswith(bf.config.site.url):
-                raise PostParseException(u"{0}: permalink for a different site"
-                        " than configured".format(self.filename))
-            logger.debug(u"path from permalink: {0}".format(self.path))
-        except KeyError:
-            pass
-        try:
-            self.guid = y['guid']
-        except KeyError:
-            self.guid = self.permalink
-        try:
-            self.date = pytz.timezone(self.__timezone).localize(
-                datetime.datetime.strptime(y['date'], config.date_format))
-        except KeyError:
-            pass
-        try:
-            self.updated = pytz.timezone(self.__timezone).localize(
-                datetime.datetime.strptime(y['updated'], config.date_format))
-        except KeyError:
-            pass
-        try:
-            self.categories = set([Category(x.strip()) for x in \
-                                       y['categories'].split(",")])
-        except:
-            pass
-        try:
-            self.tags = set([x.strip() for x in y['tags'].split(",")])
-        except:
-            pass
-        try:
-            self.filters = y['filter'] #filter is a synonym for filters
-        except KeyError:
-            pass
-        try:
-            if y['draft']:
-                self.draft = True
-                logger.info(u"Post {0} is set to draft, "
-                        "ignoring this post".format(self.filename))
-            else:
-                self.draft = False
-        except KeyError:
-            self.draft = False
-        # Load the rest of the fields that don't need processing:
-        for field, value in y.items():
-            if field not in fields_need_processing:
-                setattr(self,field,value)
-        
-    def permapath(self):
-        """Get just the path portion of a permalink"""
-        return urlparse.urlparse(self.permalink)[2]
-
-    def __cmp__(self, other_post):
-        "Posts should be comparable by date"
-        return cmp(self.date, other_post.date)
-
-    def __eq__(self, other_post):
-        return self is other_post
-
-    def __getattr__(self, name):
-        if name == "path":
-            #Always generate the path from the permalink
-            return self.permapath()
-        else:
-            raise AttributeError, name
-
-
-class Category(object):
-
-    def __init__(self, name):
-        self.name = unicode(name)
-        # TODO: slugification should be abstracted out somewhere reusable
-        # TODO: consider making url_name and path read-only properties?
-        self.url_name = self.name.lower().replace(" ", "-")
-        self.path = bf.util.site_path_helper(
-                bf.config.controllers.blog.path,
-                bf.config.controllers.blog.category_dir,
-                self.url_name)
-
-    def __eq__(self, other):
-        if self.name == other.name:
-            return True
-        return False
-
-    def __hash__(self):
-        return hash(self.name)
-
-    def __repr__(self):
-        return self.name
-    
-    def __cmp__(self, other):
-        return cmp(self.name, other.name)
-
-
-def parse_posts(directory):
-    """Retrieve all the posts from the directory specified.
-
-    Returns a list of the posts sorted in reverse by date."""
-    posts = []
-    post_filename_re = re.compile(
-        ".*((\.textile$)|(\.markdown$)|(\.org$)|(\.html$)|(\.txt$)|(\.rst$))")
-    if not os.path.isdir("_posts"):
-        logger.warn("This site has no _posts directory.")
-        return []
-    post_paths = [f.decode("utf-8") for f in bf.util.recursive_file_list(
-            directory, post_filename_re) if post_filename_re.match(f)]
-
-    for post_path in post_paths:
-        post_fn = os.path.split(post_path)[1]
-        logger.debug(u"Parsing post: {0}".format(post_path))
-        #IMO codecs.open is broken on Win32.
-        #It refuses to open files without replacing newlines with CR+LF
-        #reverting to regular open and decode:
-        try:
-            src = open(post_path, "r").read().decode(
-                    bf.config.controllers.blog.post_encoding)
-        except:
-            logger.exception(u"Error reading post: {0}".format(post_path))
-            raise
-        try:
-            p = Post(src, filename=post_fn)
-        except PostParseException as e:
-            logger.warning(u"{0} : Skipping this post.".format(e.value))
-            continue
-        #Exclude some posts
-        if not (p.permalink is None or p.draft is True):
-            posts.append(p)
-    posts.sort(key=operator.attrgetter('date'), reverse=True)
-    return posts
diff --git a/_controllers/org.py b/_controllers/org.py
deleted file mode 100644 (file)
index baf6a2c..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-"""
-org.py convert org source file into html file 
-"""
-
-__author__ = "Jaemok Jeong(jmjeong@gmail.com)"
-__date__   = "Tue Aug 11 12:50:17 2009"
-
-
-import os
-import tempfile
-import logging
-import re
-import sys
-import commands
-import codecs
-import datetime
-import pytz
-from BeautifulSoup import BeautifulSoup
-
-import blogofile_bf as bf
-
-logger = logging.getLogger("blogofile.org")
-
-
-class EmacsNotFoundException(Exception):
-    pass
-
-
-post = bf.config.controllers.blog.post.mod
-
-
-class org(object):
-    """
-        Class to Convert org file into html file
-
-        It composes org-content with source, preamble, and postample.
-        Launches emacs and convert the org-content into html file.
-
-        Generated html file is processed with BeautifulSoup module to
-        extract body section and title and categories.
-
-        self.content  = body
-        self.title    = title (which is first '*' in org-file)
-        self.category = categories (which is tags in first '*' in org-file)
-        self.date     = date (which is scheduled file?)
-
-       """
-    def __init__(self, source):
-        self.source = source
-        return self.__convert()
-        
-    def __convert(self):
-        temp_file = tempfile.NamedTemporaryFile(suffix='.org')
-        try:
-            temp_file.write(bf.config.blog.emacs_orgmode_preamble)
-            temp_file.write("\n")
-        except AttributeError:
-            pass
-        temp_file.write(self.source.encode(bf.config.blog_post_encoding))
-        temp_file.flush()
-
-        pname = ""
-        try:
-            pname = bf.config.blog.emacs_binary
-        except AttributeError:
-            raise EmacsNotFoundException("Emacs binary is not defined")
-
-        pname += " --batch"
-        try:
-            if bf.config.blog.emacs_preload_elisp:
-                pname += " --load={0}".format(
-                        bf.config.blog.emacs_preload_elisp)
-        except AttributeError:
-            pass
-
-        pname += " --visit={0} --funcall org-export-as-html-batch".format(
-                temp_file.name)
-        logger.debug("Exec name::: %s" % pname)
-
-        status, output = commands.getstatusoutput(pname)
-        logger.debug("Convert output:::\n\t%s"%output)
-        if status:
-            raise EmacsNotFoundException("orgfile filter failed")
-        
-        html = temp_file.name[:-4] + '.html'
-        temp_file.close()
-
-        #IMO codecs.open is broken on Win32.
-        #It refuses to open files without replacing newlines with CR+LF
-        #reverting to regular open and decode:
-        content = open(html, "rb").read().decode(bf.config.blog_post_encoding)
-
-        # remote the temporary file
-        os.remove(html)
-
-        soup = BeautifulSoup(content)
-
-        # the first h2 section will be used for title, category, and date
-        metaline = soup.find('div', {'id': 'outline-container-1'}).h2
-
-        # extract title
-        try:
-            self.title = re.sub('&nbsp;', '', metaline.contents[0]).strip()
-        except AttributeError:
-            self.title = None
-
-        # extract category
-        try:
-            categories = metaline('span', {'class':'tag'})[0].string
-            self.categories = set([post.Category(x)
-                    for x in categories.split('&nbsp;')])
-        except:
-            self.categories = None
-
-        # extract date
-        try:
-            date = metaline('span', {'class':'timestamp'})[0].string # 2009-08-22 Sat 15:22
-            # date_format = "%Y/%m/%d %H:%M:%S"
-            self.date = datetime.datetime.strptime(date, "%Y-%m-%d %a %H:%M")
-            self.date = self.date.replace(
-                    tzinfo=pytz.timezone(bf.config.blog_timezone))
-        except:
-            self.date = None
-
-        # delete first h2 section (which is title and category)
-        try:
-            metaline.extract()
-        except AttributeError:
-            pass
-
-        # print soup.body
-        try:
-            toc = soup.find('div',{'id': 'table-of-contents'})
-            content = soup.find('div', {'id': 'outline-container-1'})
-
-            if toc != None:
-                content = str(toc) + str(content)
-                
-            self.content = str(content).decode(bf.config.blog_post_encoding)
-        except:
-            pass
-
-
-if __name__ == '__main__':
-    import doctest
-    doctest.testmod(verbose=True)
-