← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands-website/anti_spam into lp:widelands-website

 

kaputtnik has proposed merging lp:~widelands-dev/widelands-website/anti_spam into lp:widelands-website.

Commit message:
Hide all posts/topics which are potentially spam using a keyword filter.

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #1614403 in Widelands Website: "Ideas to prevent spammers, make their work harder"
  https://bugs.launchpad.net/widelands-website/+bug/1614403

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands-website/anti_spam/+merge/307869

Hide all posts/topics which are potentially spam using a keyword filter.

Add a boolean 'hided' field to pybb.Post.

Post filter: Applies if a post contains 'vashikaran' AND 'baba'. This catches each case insentive occurrence of this strings, so 'VaShIkaRan' is caught as well as 'babaco' or 'blabababla'. Because 'Baba' is also known as 'Bye-bye' these keywords must occur both.

Topic name filter: Applies if ' baba ' (as a word) OR 'ji' is used. Also case insensitive. Should catch ' baBaJi' as 'baBa ji' or ' baba '

The filters are set in pybb/views.py

When commiting on the server, ./manage.py migrate must be run before the website is restartet. This adds the 'hided' field to all columns in the database with default value 'False'.

-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands-website/anti_spam into lp:widelands-website.
=== added directory 'akismet-0.2.0'
=== added file 'akismet-0.2.0/README.txt'
--- akismet-0.2.0/README.txt	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/README.txt	2016-10-06 17:53:22 +0000
@@ -0,0 +1,52 @@
+# Version 0.2.0
+# Copyright Michael Foord 2005-2009
+# akismet.py
+# Python interface to the akismet API
+# E-mail fuzzyman@xxxxxxxxxxxxxxxx
+
+# http://www.voidspace.org.uk/python/modules.shtml#akismet
+# http://akismet.com
+
+# Released subject to the BSD License
+# See http://www.voidspace.org.uk/python/license.shtml
+
+A python interface to the `Akismet <http://akismet.com>`_ API.
+This is a web service for blocking SPAM comments to blogs - or other online 
+services.
+
+You will need a Wordpress API key, from `wordpress.com <http://wordpress.com>`_.
+
+You should pass in the keyword argument 'agent' to the name of your program,
+when you create an Akismet instance. This sets the ``user-agent`` to a useful
+value.
+
+The default is : ::
+
+    Python Interface by Fuzzyman | akismet.py/0.2.0
+
+Whatever you pass in, will replace the *Python Interface by Fuzzyman* part.
+**0.2.0** will change with the version of this interface.
+
+Usage example::
+    
+    from akismet import Akismet
+    
+    api = Akismet(agent='Test Script')
+    # if apikey.txt is in place,
+    # the key will automatically be set
+    # or you can call api.setAPIKey()
+    #
+    if api.key is None:
+        print "No 'apikey.txt' file."
+    elif not api.verify_key():
+        print "The API key is invalid."
+    else:
+        # data should be a dictionary of values
+        # They can all be filled in with defaults
+        # from a CGI environment
+        if api.comment_check(comment, data):
+            print 'This comment is spam.'
+        else:
+            print 'This comment is ham.'
+
+As of version 0.2.0 akismet.py can be used with Google AppEngine.
\ No newline at end of file

=== added file 'akismet-0.2.0/akismet.py'
--- akismet-0.2.0/akismet.py	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/akismet.py	2016-10-06 17:53:22 +0000
@@ -0,0 +1,372 @@
+# Version 0.2.0
+# 2009/06/18
+
+# Copyright Michael Foord 2005-2009
+# akismet.py
+# Python interface to the akismet API
+# E-mail fuzzyman@xxxxxxxxxxxxxxxx
+
+# http://www.voidspace.org.uk/python/modules.shtml
+# http://akismet.com
+
+# Released subject to the BSD License
+# See http://www.voidspace.org.uk/python/license.shtml
+
+
+"""
+A python interface to the `Akismet <http://akismet.com>`_ API.
+This is a web service for blocking SPAM comments to blogs - or other online 
+services.
+
+You will need a Wordpress API key, from `wordpress.com <http://wordpress.com>`_.
+
+You should pass in the keyword argument 'agent' to the name of your program,
+when you create an Akismet instance. This sets the ``user-agent`` to a useful
+value.
+
+The default is : ::
+
+    Python Interface by Fuzzyman | akismet.py/0.2.0
+
+Whatever you pass in, will replace the *Python Interface by Fuzzyman* part.
+**0.2.0** will change with the version of this interface.
+
+Usage example::
+    
+    from akismet import Akismet
+    
+    api = Akismet(agent='Test Script')
+    # if apikey.txt is in place,
+    # the key will automatically be set
+    # or you can call api.setAPIKey()
+    #
+    if api.key is None:
+        print "No 'apikey.txt' file."
+    elif not api.verify_key():
+        print "The API key is invalid."
+    else:
+        # data should be a dictionary of values
+        # They can all be filled in with defaults
+        # from a CGI environment
+        if api.comment_check(comment, data):
+            print 'This comment is spam.'
+        else:
+            print 'This comment is ham.'
+"""
+
+
+import os, sys
+from urllib import urlencode
+
+import socket
+if hasattr(socket, 'setdefaulttimeout'):
+    # Set the default timeout on sockets to 5 seconds
+    socket.setdefaulttimeout(5)
+
+__version__ = '0.2.0'
+
+__all__ = (
+    '__version__',
+    'Akismet',
+    'AkismetError',
+    'APIKeyError',
+    )
+
+__author__ = 'Michael Foord <fuzzyman AT voidspace DOT org DOT uk>'
+
+__docformat__ = "restructuredtext en"
+
+user_agent = "%s | akismet.py/%s"
+DEFAULTAGENT = 'Python Interface by Fuzzyman/%s'
+
+isfile = os.path.isfile
+
+urllib2 = None
+try:
+    from google.appengine.api import urlfetch
+except ImportError:
+    import urllib2
+
+if urllib2 is None:
+    def _fetch_url(url, data, headers):
+        req = urlfetch.fetch(url=url, payload=data, method=urlfetch.POST, headers=headers)
+        if req.status_code == 200:
+            return req.content
+        raise Exception('Could not fetch Akismet URL: %s Response code: %s' % 
+                        (url, req.status_code))
+else:
+    def _fetch_url(url, data, headers):
+        req = urllib2.Request(url, data, headers)
+        h = urllib2.urlopen(req)
+        resp = h.read()
+        return resp
+
+
+class AkismetError(Exception):
+    """Base class for all akismet exceptions."""
+
+class APIKeyError(AkismetError):
+    """Invalid API key."""
+
+class Akismet(object):
+    """A class for working with the akismet API"""
+
+    baseurl = 'rest.akismet.com/1.1/'
+
+    def __init__(self, key=None, blog_url=None, agent=None):
+        """Automatically calls ``setAPIKey``."""
+        if agent is None:
+            agent = DEFAULTAGENT % __version__
+        self.user_agent = user_agent % (agent, __version__)
+        self.setAPIKey(key, blog_url)
+
+
+    def _getURL(self):
+        """
+        Fetch the url to make requests to.
+        
+        This comprises of api key plus the baseurl.
+        """
+        return 'http://%s.%s' % (self.key, self.baseurl)
+    
+    
+    def _safeRequest(self, url, data, headers):
+        try:
+            resp = _fetch_url(url, data, headers)
+        except Exception, e:
+            raise AkismetError(str(e))
+        return resp
+
+
+    def setAPIKey(self, key=None, blog_url=None):
+        """
+        Set the wordpress API key for all transactions.
+        
+        If you don't specify an explicit API ``key`` and ``blog_url`` it will
+        attempt to load them from a file called ``apikey.txt`` in the current
+        directory.
+        
+        This method is *usually* called automatically when you create a new
+        ``Akismet`` instance.
+        """
+        if key is None and isfile('apikey.txt'):
+            the_file = [l.strip() for l in open('apikey.txt').readlines()
+                if l.strip() and not l.strip().startswith('#')]
+            try:
+                self.key = the_file[0]
+                self.blog_url = the_file[1]
+            except IndexError:
+                raise APIKeyError("Your 'apikey.txt' is invalid.")
+        else:
+            self.key = key
+            self.blog_url = blog_url
+
+
+    def verify_key(self):
+        """
+        This equates to the ``verify-key`` call against the akismet API.
+        
+        It returns ``True`` if the key is valid.
+        
+        The docs state that you *ought* to call this at the start of the
+        transaction.
+        
+        It raises ``APIKeyError`` if you have not yet set an API key.
+        
+        If the connection to akismet fails, it allows the normal ``HTTPError``
+        or ``URLError`` to be raised.
+        (*akismet.py* uses `urllib2 <http://docs.python.org/lib/module-urllib2.html>`_)
+        """
+        if self.key is None:
+            raise APIKeyError("Your have not set an API key.")
+        data = { 'key': self.key, 'blog': self.blog_url }
+        # this function *doesn't* use the key as part of the URL
+        url = 'http://%sverify-key' % self.baseurl
+        # we *don't* trap the error here
+        # so if akismet is down it will raise an HTTPError or URLError
+        headers = {'User-Agent' : self.user_agent}
+        resp = self._safeRequest(url, urlencode(data), headers)
+        if resp.lower() == 'valid':
+            return True
+        else:
+            return False
+
+    def _build_data(self, comment, data):
+        """
+        This function builds the data structure required by ``comment_check``,
+        ``submit_spam``, and ``submit_ham``.
+        
+        It modifies the ``data`` dictionary you give it in place. (and so
+        doesn't return anything)
+        
+        It raises an ``AkismetError`` if the user IP or user-agent can't be
+        worked out.
+        """
+        data['comment_content'] = comment
+        if not 'user_ip' in data:
+            try:
+                val = os.environ['REMOTE_ADDR']
+            except KeyError:
+                raise AkismetError("No 'user_ip' supplied")
+            data['user_ip'] = val
+        if not 'user_agent' in data:
+            try:
+                val = os.environ['HTTP_USER_AGENT']
+            except KeyError:
+                raise AkismetError("No 'user_agent' supplied")
+            data['user_agent'] = val
+        #
+        data.setdefault('referrer', os.environ.get('HTTP_REFERER', 'unknown'))
+        data.setdefault('permalink', '')
+        data.setdefault('comment_type', 'comment')
+        data.setdefault('comment_author', '')
+        data.setdefault('comment_author_email', '')
+        data.setdefault('comment_author_url', '')
+        data.setdefault('SERVER_ADDR', os.environ.get('SERVER_ADDR', ''))
+        data.setdefault('SERVER_ADMIN', os.environ.get('SERVER_ADMIN', ''))
+        data.setdefault('SERVER_NAME', os.environ.get('SERVER_NAME', ''))
+        data.setdefault('SERVER_PORT', os.environ.get('SERVER_PORT', ''))
+        data.setdefault('SERVER_SIGNATURE', os.environ.get('SERVER_SIGNATURE',
+            ''))
+        data.setdefault('SERVER_SOFTWARE', os.environ.get('SERVER_SOFTWARE',
+            ''))
+        data.setdefault('HTTP_ACCEPT', os.environ.get('HTTP_ACCEPT', ''))
+        data.setdefault('blog', self.blog_url)
+
+
+    def comment_check(self, comment, data=None, build_data=True, DEBUG=False):
+        """
+        This is the function that checks comments.
+        
+        It returns ``True`` for spam and ``False`` for ham.
+        
+        If you set ``DEBUG=True`` then it will return the text of the response,
+        instead of the ``True`` or ``False`` object.
+        
+        It raises ``APIKeyError`` if you have not yet set an API key.
+        
+        If the connection to Akismet fails then the ``HTTPError`` or
+        ``URLError`` will be propogated.
+        
+        As a minimum it requires the body of the comment. This is the
+        ``comment`` argument.
+        
+        Akismet requires some other arguments, and allows some optional ones.
+        The more information you give it, the more likely it is to be able to
+        make an accurate diagnosise.
+        
+        You supply these values using a mapping object (dictionary) as the
+        ``data`` argument.
+        
+        If ``build_data`` is ``True`` (the default), then *akismet.py* will
+        attempt to fill in as much information as possible, using default
+        values where necessary. This is particularly useful for programs
+        running in a {acro;CGI} environment. A lot of useful information
+        can be supplied from evironment variables (``os.environ``). See below.
+        
+        You *only* need supply values for which you don't want defaults filled
+        in for. All values must be strings.
+        
+        There are a few required values. If they are not supplied, and
+        defaults can't be worked out, then an ``AkismetError`` is raised.
+        
+        If you set ``build_data=False`` and a required value is missing an
+        ``AkismetError`` will also be raised.
+        
+        The normal values (and defaults) are as follows : ::
+        
+            'user_ip':          os.environ['REMOTE_ADDR']       (*)
+            'user_agent':       os.environ['HTTP_USER_AGENT']   (*)
+            'referrer':         os.environ.get('HTTP_REFERER', 'unknown') [#]_
+            'permalink':        ''
+            'comment_type':     'comment' [#]_
+            'comment_author':   ''
+            'comment_author_email': ''
+            'comment_author_url': ''
+            'SERVER_ADDR':      os.environ.get('SERVER_ADDR', '')
+            'SERVER_ADMIN':     os.environ.get('SERVER_ADMIN', '')
+            'SERVER_NAME':      os.environ.get('SERVER_NAME', '')
+            'SERVER_PORT':      os.environ.get('SERVER_PORT', '')
+            'SERVER_SIGNATURE': os.environ.get('SERVER_SIGNATURE', '')
+            'SERVER_SOFTWARE':  os.environ.get('SERVER_SOFTWARE', '')
+            'HTTP_ACCEPT':      os.environ.get('HTTP_ACCEPT', '')
+        
+        (*) Required values
+        
+        You may supply as many additional 'HTTP_*' type values as you wish.
+        These should correspond to the http headers sent with the request.
+        
+        .. [#] Note the spelling "referrer". This is a required value by the
+            akismet api - however, referrer information is not always
+            supplied by the browser or server. In fact the HTTP protocol
+            forbids relying on referrer information for functionality in 
+            programs.
+        .. [#] The `API docs <http://akismet.com/development/api/>`_ state that this value
+            can be " *blank, comment, trackback, pingback, or a made up value*
+            *like 'registration'* ".
+        """
+        if self.key is None:
+            raise APIKeyError("Your have not set an API key.")
+        if data is None:
+            data = {}
+        if build_data:
+            self._build_data(comment, data)
+        if 'blog' not in data:
+            data['blog'] = self.blog_url
+        url = '%scomment-check' % self._getURL()
+        # we *don't* trap the error here
+        # so if akismet is down it will raise an HTTPError or URLError
+        headers = {'User-Agent' : self.user_agent}
+        resp = self._safeRequest(url, urlencode(data), headers)
+        if DEBUG:
+            return resp
+        resp = resp.lower()
+        if resp == 'true':
+            return True
+        elif resp == 'false':
+            return False
+        else:
+            # NOTE: Happens when you get a 'howdy wilbur' response !
+            raise AkismetError('missing required argument.')
+
+
+    def submit_spam(self, comment, data=None, build_data=True):
+        """
+        This function is used to tell akismet that a comment it marked as ham,
+        is really spam.
+        
+        It takes all the same arguments as ``comment_check``, except for
+        *DEBUG*.
+        """
+        if self.key is None:
+            raise APIKeyError("Your have not set an API key.")
+        if data is None:
+            data = {}
+        if build_data:
+            self._build_data(comment, data)
+        url = '%ssubmit-spam' % self._getURL()
+        # we *don't* trap the error here
+        # so if akismet is down it will raise an HTTPError or URLError
+        headers = {'User-Agent' : self.user_agent}
+        self._safeRequest(url, urlencode(data), headers)
+
+
+    def submit_ham(self, comment, data=None, build_data=True):
+        """
+        This function is used to tell akismet that a comment it marked as spam,
+        is really ham.
+        
+        It takes all the same arguments as ``comment_check``, except for
+        *DEBUG*.
+        """
+        if self.key is None:
+            raise APIKeyError("Your have not set an API key.")
+        if data is None:
+            data = {}
+        if build_data:
+            self._build_data(comment, data)
+        url = '%ssubmit-ham' % self._getURL()
+        # we *don't* trap the error here
+        # so if akismet is down it will raise an HTTPError or URLError
+        headers = {'User-Agent' : self.user_agent}
+        self._safeRequest(url, urlencode(data), headers)

=== added file 'akismet-0.2.0/apikey.txt'
--- akismet-0.2.0/apikey.txt	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/apikey.txt	2016-10-06 17:53:22 +0000
@@ -0,0 +1,7 @@
+# Lines starting with '#' are comments
+# The first non-blank, non-comment, line should be your api key
+# The second your blog URL
+#
+# You can get a wordpress API key from http://wordpress.com/
+SOME KEY
+SOME URL
\ No newline at end of file

=== added directory 'akismet-0.2.0/docs'
=== added file 'akismet-0.2.0/docs/Akismet API Docs.html'
--- akismet-0.2.0/docs/Akismet API Docs.html	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/Akismet API Docs.html	2016-10-06 17:53:22 +0000
@@ -0,0 +1,171 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd";>
+<!-- saved from url=(0035)http://akismet.com/development/api/ -->
+<HTML 
+xmlns="http://www.w3.org/1999/xhtml";><HEAD><TITLE>Development « Akismet</TITLE>
+<META http-equiv=Content-Type content="text/html; charset=utf-8">
+<STYLE type=text/css>@import url( /style.css );
+#promo {
+	BACKGROUND: url(i/days-1.jpg)
+}
+</STYLE>
+<LINK title="Akismet Blog and Updates" href="http://akismet.com/blog/feed/"; 
+type=application/rss+xml rel=alternate>
+<SCRIPT src="Development « Akismet_files/urchin.js" 
+type=text/javascript></SCRIPT>
+
+<SCRIPT type=text/javascript>
+_uacct = "UA-52447-4";
+urchinTracker();
+</SCRIPT>
+
+<META content="MSHTML 6.00.2900.2769" name=GENERATOR></HEAD>
+<BODY>
+<DIV id=rap>
+<H1 id=logo><A href="http://akismet.com/";>Akismet</A></H1>
+<UL id=menu>
+  <LI><A href="http://akismet.com/";>About Akismet</A> </LI>
+  <LI><A href="http://akismet.com/download/";>Download</A> </LI>
+  <LI><A href="http://akismet.com/faq/";>FAQ</A> </LI>
+  <LI><A href="http://akismet.com/commercial/";>Commercial Use</A> </LI>
+  <LI><A href="http://akismet.com/blog/";>Blog</A> </LI>
+  <LI><A href="http://akismet.com/contact/";>Contact Us</A> </LI></UL>
+<H1>Akismet API Documentation Version 1.1 </H1>
+<H2>About the Akismet Service</H2>
+<P>Akismet is basically a big machine that sucks up all the data it possibly 
+can, looks for patterns, and learns from its mistakes. Thus far it has been 
+highly effective at stopping spam and adapting to new techniques and attempts to 
+evade it, and time will tell how it stands up. I've tried to keep the API 
+interaction as simple as possible.</P>
+<H3>A Good Consumer</H3>
+<P>To interact fully with the Akismet API your program really should be putting 
+data back into the system as well as just taking it out. If it is at all 
+possible within the framework of your application you should have a way for your 
+users to submit missed spam and false positives, otherwise Akismet will never 
+learn from its mistakes.</P>
+<H2>User Agent</H2>
+<P>If it is at all possible, please modify the user agent string you request 
+with to be of the following format:</P><PRE>Application Name/Version | Plugin Name/Version</PRE>
+<P>So in the WordPress plugin this looks like:</P><PRE>$ksd_user_agent = "WordPress/$wp_version | Akismet/1.11";
+</PRE>
+<H2>Call Structure</H2>
+<P>All calls to Akismet are POST requests much like a web form would send. The 
+request variables should be constructed like a query string, 
+<CODE>key=value</CODE> and multiple variables separated by ampersands. Don't 
+forget to URL escape the values. </P>
+<P>In the WordPress plugin the POST part of things is abstracted out in this 
+function:</P><PRE>function ksd_http_post($request, $host, $path, $port = 80) {
+	global $ksd_user_agent;
+
+	$http_request  = "POST $path HTTP/1.0\r\n";
+	$http_request .= "Host: $host\r\n";
+	$http_request .= "Content-Type: application/x-www-form-urlencoded; charset=" . get_settings('blog_charset') . "\r\n";
+	$http_request .= "Content-Length: " . strlen($request) . "\r\n";
+	$http_request .= "User-Agent: $ksd_user_agent\r\n";
+	$http_request .= "\r\n";
+	$http_request .= $request;
+
+	$response = '';
+	if( false !== ( $fs = @fsockopen($host, $port, $errno, $errstr, 3) ) ) {
+		fwrite($fs, $http_request);
+		while ( !feof($fs) )
+			$response .= fgets($fs, 1160); // One TCP-IP packet
+		fclose($fs);
+		$response = explode("\r\n\r\n", $response, 2);
+	}
+	return $response;
+}  </PRE>
+<P>This sends a POST request to the specified host and port with a timeout of 3 
+seconds. The HTTP request is constructed with full headers. The response headers 
+are discarded and the function returns the body of the response. </P>
+<H2>API Key</H2>
+<P>Use of the Akismet API requires an API key, which are currently only being 
+provided along with accounts to <A 
+href="http://wordpress.com/";>WordPress.com</A>. The API key is used as a 
+subdomain in the call, for example if you had the API key <CODE>aoeu1aoue</CODE> 
+you would make all API calls to <CODE>aoeu1aoue.rest.akismet.com</CODE>. The 
+only exception to this is the <A 
+href="http://akismet.com/development/api/#verify-key";>verify-key</A> call, which 
+may be made to <CODE>rest.akismet.com</CODE> without an API key subdomain. </P>
+<H2 id=verify-key>Key Verification — <CODE>rest.akismet.com/1.1/verify 
+key</CODE> </H2>
+<P>The key verification call should be made before beginning to use the service. 
+It requires two variables, key and blog.</P>
+<DL>
+  <DT><CODE>key</CODE> (required) 
+  <DD>The API key being verified for use with the API 
+  <DT><CODE>blog</CODE> (required) 
+  <DD>The front page or home URL of the instance making the request. For a blog 
+  or wiki this would be the front page. </DD></DL>
+<P>The call returns "<CODE>valid</CODE>" if the key is valid. This is the one 
+call that can be made without the API key subdomain. Using our example function 
+from above, this is how the API key is verified in the WP plugin: <PRE>function akismet_verify_key( $key ) {
+	global $ksd_api_host, $ksd_api_port;
+	$blog = urlencode( get_option('home') );
+	$response = ksd_http_post("key=$key&amp;blog=$blog", 'rest.akismet.com', '/1.1/verify-key', $ksd_api_port);
+	if ( 'valid' == $response[1] )
+		return true;
+	else
+		return false;
+}</PRE>
+<H2 id=comment-check>Comment Check — 
+<CODE>api-key.rest.akismet.com/1.1/comment-check</CODE></H2>
+<P>This is basically the core of everything. This call takes a number of 
+arguments and characteristics about the submitted content and then returns a 
+thumbs up or thumbs down. Almost everything is optional, but performance can 
+drop dramatically if you exclude certain elements. I would recommend erring on 
+the side of too much data, as everything is used as part of the Akismet 
+signature.</P>
+<DL>
+  <DT><CODE>blog </CODE>(required) 
+  <DD>The front page or home URL of the instance making the request. For a blog 
+  or wiki this would be the front page. 
+  <DT><CODE>user_ip</CODE> (required) 
+  <DD>IP address of the comment submitter. 
+  <DT><CODE>user_agent</CODE> (required) 
+  <DD>User agent information. 
+  <DT><CODE>referrer</CODE> (note spelling) 
+  <DD>The content of the HTTP_REFERER header should be sent here. 
+  <DT><CODE>permalink</CODE> 
+  <DD>The permanent location of the entry the comment was submitted to. 
+  <DT><CODE>comment_type</CODE> 
+  <DD>May be blank, comment, trackback, pingback, or a made up value like 
+  "registration". 
+  <DT><CODE>comment_author</CODE> 
+  <DD>Submitted name with the comment 
+  <DT><CODE>comment_author_email</CODE> 
+  <DD>Submitted email address 
+  <DT><CODE>comment_author_url</CODE> 
+  <DD>Commenter URL. 
+  <DT><CODE>comment_content</CODE> 
+  <DD>The content that was submitted. 
+  <DT>Other server enviroment variables 
+  <DD>In PHP there is an array of enviroment variables called 
+  <CODE>$_SERVER</CODE> which contains information about the web server itself 
+  as well as a key/value for every HTTP header sent with the request. This data 
+  is highly useful to Akismet as how the submited content interacts with the 
+  server can be very telling, so please include as much information as possible. 
+  </DD></DL>
+<P>This call returns either "true" or "false" as the body content. True means 
+that the comment is spam and false means that it isn't spam. If you are having 
+trouble triggering you can send "viagra-test-123" as the author and it will 
+trigger a true response, always. </P>
+<H2 id=submit-spam>Submit Spam — 
+<CODE>api-key.rest.akismet.com/1.1/submit-spam</CODE></H2>
+<P>This call is for submitting comments that weren't marked as spam but should 
+have been. It takes identical arguments as comment check.</P>
+<H2 id=submit-ham>Submit Ham — 
+<CODE>api-key.rest.akismet.com/1.1/submit-ham</CODE></H2>
+<P>This call is intended for the marking of false positives, things that were 
+incorrectly marked as spam. It takes identical arguments as <A 
+href="http://akismet.com/development/api/#comment-check";>comment check</A> and 
+submit spam.</P>
+<DL></DL>
+<DIV id=zeitgeist>
+<H2>Live Spam Zeitgeist</H2>
+<P>477,826 spams caught so far</P>
+<P>2,099 so far today</P>
+<P>81% of all comments are spam</P><!--  --></DIV>
+<DIV id=footer><A id=ap href="http://automattic.com/";>An Automattic 
+Production</A> 
+<P><A href="http://akismet.com/privacy/";>Privacy Policy</A> 
+</P></DIV></DIV></BODY></HTML>

=== added file 'akismet-0.2.0/docs/BSD-LICENSE.txt'
--- akismet-0.2.0/docs/BSD-LICENSE.txt	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/BSD-LICENSE.txt	2016-10-06 17:53:22 +0000
@@ -0,0 +1,67 @@
+===================================
+ The Voidspace Open Source License
+===================================
+
+.. note::
+
+    See this document online at http://www.voidspace.org.uk/python/license.shtml
+
+This is the OSI_ Approved license that the Voidspace modules and programs are
+available under [#]_. It's often reffered to as the *BSD License*.
+
+It is a very unrestrictive license but it comes with the usual disclaimer. 
+This is free software: test it, break it, just don't blame me if it eats your 
+data ! Of course if it does, let me know and I'll fix the problem so that it 
+doesn't happen to anyone else {sm;:-)}.
+
+.. _osi: http://www.opensource.org/
+
+
+.. note::
+
+    `ConfigObj <configobj.html>`_ and `Odict <odict.html>`_ are also
+    copyright Nicola Larosa.
+
+
+::
+
+    Copyright (c) 2003-2009, Michael Foord & Nicola Larosa
+    All rights reserved.
+    E-mail : fuzzyman AT voidspace DOT org DOT uk
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are
+    met:
+    
+    
+        * Redistributions of source code must retain the above copyright
+          notice, this list of conditions and the following disclaimer.
+    
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials provided
+          with the distribution.
+    
+        * Neither the name of Michael Foord nor the name of Nicola Larosa 
+          may be used to endorse or promote products derived from this
+          software without specific prior written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+    "AS IS" AND ANY EXPRESS 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
+    OWNER OR CONTRIBUTORS 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.
+
+If you use any of my code in your projects, then a link back would be nice. If
+you let me know about any of your projects that use them - then I can link to
+you as examples.
+
+-----------
+
+.. [#] Unless specifically stated otherwise of course.

=== added file 'akismet-0.2.0/docs/akismet_python.html'
--- akismet-0.2.0/docs/akismet_python.html	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/akismet_python.html	2016-10-06 17:53:22 +0000
@@ -0,0 +1,451 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";>
+<html xmlns="http://www.w3.org/1999/xhtml"; xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/"; />
+<title>Akismet - The Python API</title>
+<meta name="author" content="Michael Foord" />
+<meta name="date" content="2009/06/18" />
+<link rel="stylesheet" href="stylesheets/voidspace_docutils.css" type="text/css" />
+</head>
+<body>
+<div class="document" id="akismet-the-python-api">
+<h1 class="title">Akismet - The Python API</h1>
+<h2 class="subtitle" id="stopping-comment-spam-with-akismet">Stopping Comment Spam with Akismet</h2>
+<table class="docinfo" frame="void" rules="none">
+<col class="docinfo-name" />
+<col class="docinfo-content" />
+<tbody valign="top">
+<tr><th class="docinfo-name">Author:</th>
+<td><a class="first last reference external" href="http://www.voidspace.org.uk/python/index.shtml";>Michael Foord</a></td></tr>
+<tr><th class="docinfo-name">Contact:</th>
+<td><a class="first last reference external" href="mailto:fuzzyman&#37;&#52;&#48;voidspace&#46;org&#46;uk";>fuzzyman<span>&#64;</span>voidspace<span>&#46;</span>org<span>&#46;</span>uk</a></td></tr>
+<tr><th class="docinfo-name">Version:</th>
+<td>0.2.0</td></tr>
+<tr><th class="docinfo-name">Date:</th>
+<td>2009/06/18</td></tr>
+<tr class="field"><th class="docinfo-name">License:</th><td class="field-body"><a class="reference external" href="BSD-LICENSE.txt">BSD License</a> <a class="footnote-reference" href="#id5" id="id1">[1]</a></td>
+</tr>
+<tr class="field"><th class="docinfo-name">Online Docs:</th><td class="field-body"><a class="reference external" href="http://www.voidspace.org.uk/python/akismet_python.html";>akismet.py online</a></td>
+</tr>
+</tbody>
+</table>
+<div class="contents topic" id="the-akismet-api">
+<p class="topic-title first">The Akismet API</p>
+<ul class="simple">
+<li><a class="reference internal" href="#introduction" id="id9">Introduction</a><ul>
+<li><a class="reference internal" href="#downloading" id="id10">Downloading</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#apikey-txt" id="id11">apikey.txt</a></li>
+<li><a class="reference internal" href="#the-akismet-class" id="id12">The Akismet Class</a><ul>
+<li><a class="reference internal" href="#creating-an-instance" id="id13">Creating an Instance</a><ul>
+<li><a class="reference internal" href="#user-agent" id="id14">User-Agent</a></li>
+<li><a class="reference internal" href="#example-1" id="id15">Example 1</a></li>
+<li><a class="reference internal" href="#example-2" id="id16">Example 2</a></li>
+<li><a class="reference internal" href="#example-3" id="id17">Example 3</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#setapikey" id="id18">setAPIKey</a></li>
+<li><a class="reference internal" href="#akismet-methods" id="id19">Akismet Methods</a><ul>
+<li><a class="reference internal" href="#verify-key" id="id20">verify-key</a></li>
+<li><a class="reference internal" href="#comment-check" id="id21">comment-check</a></li>
+<li><a class="reference internal" href="#submit-spam" id="id22">submit-spam</a></li>
+<li><a class="reference internal" href="#submit-ham" id="id23">submit-ham</a></li>
+</ul>
+</li>
+</ul>
+</li>
+<li><a class="reference internal" href="#error-classes" id="id24">Error Classes</a><ul>
+<li><a class="reference internal" href="#akismeterror" id="id25">AkismetError</a></li>
+<li><a class="reference internal" href="#apikeyerror" id="id26">APIKeyError</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#usage-example" id="id27">Usage Example</a></li>
+<li><a class="reference internal" href="#akismet-test-cgi" id="id28">Akismet Test CGI</a></li>
+<li><a class="reference internal" href="#todo" id="id29">TODO</a></li>
+<li><a class="reference internal" href="#changelog" id="id30">CHANGELOG</a><ul>
+<li><a class="reference internal" href="#version-0-2-0" id="id31">2009/06/18      Version 0.2.0</a></li>
+<li><a class="reference internal" href="#version-0-1-5" id="id32">2007/02/05      Version 0.1.5</a></li>
+<li><a class="reference internal" href="#version-0-1-4" id="id33">2006/12/13      Version 0.1.4</a></li>
+<li><a class="reference internal" href="#version-0-1-3" id="id34">2006/07/18      Version 0.1.3</a></li>
+<li><a class="reference internal" href="#version-0-1-2" id="id35">2005/12/04      Version 0.1.2</a></li>
+<li><a class="reference internal" href="#version-0-1-1" id="id36">2005/12/02      Version 0.1.1</a></li>
+<li><a class="reference internal" href="#version-0-1-0" id="id37">2005/12/01      Version 0.1.0</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#footnotes" id="id38">Footnotes</a></li>
+</ul>
+</div>
+<div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">As of version 0.2.0 akismet.py can be used with Google AppEngine.</p>
+</div>
+<div class="section" id="introduction">
+<h1><a class="toc-backref" href="#id9">Introduction</a></h1>
+<p><a class="reference external" href="http://www.akismet.com";>Akismet</a> is a web service for recognising spam
+comments. It promises to be almost 100% effective at catching comment spam.
+They say that currently 81% of all comments submitted to them are spam.</p>
+<p>It's designed to work with the <a class="reference external" href="http://wordpress.org/";>Wordpress Blog Tool</a>,
+but it's not restricted to that - so this is a Python interface to the
+<a class="reference external" href="http://akismet.com/development/api/";>Akismet API</a>.</p>
+<p>You'll need a <a class="reference external" href="http://wordpress.com";>Wordpress Key</a> to use it. This script
+will allow you to plug akismet into any CGI script or web application, and
+there are full docs in the code. It's extremely easy to use, because the folks
+at  akismet have implemented a nice and straightforward
+<acronym title="REpresentational State Transfer">REST</acronym> API.</p>
+<div class="note">
+<p class="first admonition-title">Note</p>
+<p>If possible your program should inform Akismet of false positives and false
+negatives.</p>
+<p>Informing Akismet helps makes the service more reliable.  <img src="/smilies/smile.gif" alt="Smile" height="15" width="15" /> </p>
+<p class="last">To do this, use the <a class="reference internal" href="#submit-spam">submit-spam</a> and <a class="reference internal" href="#submit-ham">submit-ham</a> functionality.</p>
+</div>
+<p>Most of the work is done by the <a class="reference internal" href="#comment-check">comment-check</a> function.</p>
+<div class="section" id="downloading">
+<h2><a class="toc-backref" href="#id10">Downloading</a></h2>
+<p>You can download <strong>akismet.py</strong> from :</p>
+<ul class="simple">
+<li><a class="reference external" href="http://www.voidspace.org.uk/downloads/akismet.py";>akismet.py</a></li>
+<li><a class="reference external" href="http://www.voidspace.org.uk/downloads/akismet-0.2.0.zip";>akismet.zip (48k)</a></li>
+</ul>
+<p>This contains the docs, <strong>akismet.py</strong>, and a test CGI called <em>test_akismet.py</em>.</p>
+</div>
+</div>
+<div class="section" id="apikey-txt">
+<h1><a class="toc-backref" href="#id11">apikey.txt</a></h1>
+<p>The easiest way to use <em>akismet.py</em> is to provide the wordpress key and blog
+URL in a text file called <tt class="docutils literal"><span class="pre">apikey.txt</span></tt>.</p>
+<p>This should be in the current directory when you create your <tt class="docutils literal"><span class="pre">Akismet</span></tt>
+instance (or call <a class="reference internal" href="#setapikey">setAPIKey</a> with no arguments).</p>
+<p>The format for <tt class="docutils literal"><span class="pre">apikey.txt</span></tt> is simple (see the example one in the
+distribution.</p>
+<p>Lines that start with a <tt class="docutils literal"><span class="pre">#</span></tt> are comments. The first non-blank, non-comment
+line should be the API key. The second line should be the blog URL (or
+application URL) to use.</p>
+<pre class="literal-block">
+# Lines starting with '#' are comments
+# The first non-blank, non-comment, line should be your api key
+# The second your blog URL
+#
+# You can get a wordpress API key from http://wordpress.com/
+some_key
+some_blog_url
+</pre>
+</div>
+<div class="section" id="the-akismet-class">
+<h1><a class="toc-backref" href="#id12">The Akismet Class</a></h1>
+<p>The <a class="reference external" href="http://www.akismet.com";>akismet</a> API provides four functions. <em>akismet.py</em> gives you access to
+all of these through a single class.</p>
+<p>The four akismet functions are :</p>
+<ul class="simple">
+<li><a class="reference internal" href="#verify-key">verify-key</a>     - the <tt class="docutils literal"><span class="pre">verify_key</span></tt> method</li>
+<li><a class="reference internal" href="#comment-check">comment-check</a>  - the <tt class="docutils literal"><span class="pre">comment_check</span></tt> method</li>
+<li><a class="reference internal" href="#submit-spam">submit-spam</a>   - the <tt class="docutils literal"><span class="pre">submit_spam</span></tt> method</li>
+<li><a class="reference internal" href="#submit-ham">submit-ham</a>   - the <tt class="docutils literal"><span class="pre">submit_ham</span></tt> method</li>
+</ul>
+<p>In addition to these, the Akismet class has the following user methods and
+attributes :</p>
+<ul class="simple">
+<li><a class="reference internal" href="#setapikey">setAPIKey</a>    - method</li>
+<li>key           - attribute</li>
+<li>blog_url      - attribute</li>
+</ul>
+<div class="section" id="creating-an-instance">
+<h2><a class="toc-backref" href="#id13">Creating an Instance</a></h2>
+<pre class="literal-block">
+Akismet(key=None, blog_url=None, agent=None)
+</pre>
+<p>To use the akismet web service you <em>need</em> an API key. There are three ways of
+telling the <tt class="docutils literal"><span class="pre">Akismet</span></tt> class what this is.</p>
+<ol class="arabic simple">
+<li>When you create a new <tt class="docutils literal"><span class="pre">Akismet</span></tt> instance you can pass in the API key and
+blog url.</li>
+<li>If you don't pass in a key, it will automatically look for <a class="reference internal" href="#apikey-txt">apikey.txt</a> in
+the current directory, and attempt to load it.</li>
+<li>You can set the <tt class="docutils literal"><span class="pre">key</span></tt> and <tt class="docutils literal"><span class="pre">blog_url</span></tt> Attributes manually, after creating
+your instance.</li>
+</ol>
+<div class="section" id="user-agent">
+<h3><a class="toc-backref" href="#id14">User-Agent</a></h3>
+<p>As well as setting your key, you <em>ought</em> to pass in a string for <tt class="docutils literal"><span class="pre">Akismet</span></tt> to
+create a User-Agent header with. This is the <tt class="docutils literal"><span class="pre">agent</span></tt> argument.</p>
+<p>According to the <a class="reference external" href="http://akismet.com/development/api/";>API docs</a>, this ought
+to be in the form :</p>
+<pre class="literal-block">
+Program Name/Version
+</pre>
+<p><em>akismet.py</em> adds it's version number to this, to create a User-Agent in the
+form liked by akismet.</p>
+<p>The default User-Agent (if you don't pass in a values to <tt class="docutils literal"><span class="pre">agent</span></tt>) is:</p>
+<pre class="literal-block">
+Python Interface by Fuzzyman/0.2.0 | akismet.py/0.2.0
+</pre>
+</div>
+<div class="section" id="example-1">
+<h3><a class="toc-backref" href="#id15">Example 1</a></h3>
+<div class="pysrc"><span class="pycomment">#example 1<br />
+</span><span class="pytext">api</span> <span class="pyoperator">=</span> <span class="pytext">Akismet</span><span class="pyoperator">(</span><span class="pytext">api_key</span><span class="pyoperator">,</span> <span class="pytext">url</span><span class="pyoperator">,</span> <span class="pytext">agent</span><span class="pyoperator">=</span><span class="pystring">'Example/0.1'</span><span class="pyoperator">)</span><span class="pytext"></span></div></div>
+<div class="section" id="example-2">
+<h3><a class="toc-backref" href="#id16">Example 2</a></h3>
+<div class="pysrc"><span class="pycomment">#example 2<br />
+</span><span class="pykeyword">if</span> <span class="pytext">os</span><span class="pyoperator">.</span><span class="pytext">path</span><span class="pyoperator">.</span><span class="pytext">isfile</span><span class="pyoperator">(</span><span class="pystring">'apikey.txt'</span><span class="pyoperator">)</span><span class="pyoperator">:</span><br />
+&nbsp;&nbsp;&nbsp;&nbsp;<span class="pytext">api</span> <span class="pyoperator">=</span> <span class="pytext">Akismet</span><span class="pyoperator">(</span><span class="pytext">agent</span><span class="pyoperator">=</span><span class="pystring">'Example/0.2'</span><span class="pyoperator">)</span><br />
+<br />
+<span class="pycomment"># The key and URL are loaded from<br />
+</span><span class="pycomment"># 'apikey.txt'</span><span class="pytext"></span></div></div>
+<div class="section" id="example-3">
+<h3><a class="toc-backref" href="#id17">Example 3</a></h3>
+<div class="pysrc"><span class="pycomment">#example 3<br />
+</span><span class="pytext">url</span> <span class="pyoperator">=</span> <span class="pystring">'http://www.voidspace.org.uk/cgi-bin/voidspace/guestbook.py'</span><br />
+<span class="pytext">api_key</span> <span class="pyoperator">=</span> <span class="pystring">'0acdfg1fr'</span><br />
+<span class="pykeyword">if</span> <span class="pykeyword">not</span> <span class="pytext">os</span><span class="pyoperator">.</span><span class="pytext">path</span><span class="pyoperator">.</span><span class="pytext">isfile</span><span class="pyoperator">(</span><span class="pystring">'apikey.txt'</span><span class="pyoperator">)</span><span class="pyoperator">:</span><br />
+&nbsp;&nbsp;&nbsp;&nbsp;<span class="pytext">api</span> <span class="pyoperator">=</span> <span class="pytext">Akismet</span><span class="pyoperator">(</span><span class="pytext">agent</span><span class="pyoperator">=</span><span class="pystring">'Example/0.3'</span><span class="pyoperator">)</span><br />
+&nbsp;&nbsp;&nbsp;&nbsp;<span class="pytext">api</span><span class="pyoperator">.</span><span class="pytext">key</span> <span class="pyoperator">=</span> <span class="pytext">api_key</span><br />
+&nbsp;&nbsp;&nbsp;&nbsp;<span class="pytext">api</span><span class="pyoperator">.</span><span class="pytext">blog_url</span> <span class="pyoperator">=</span> <span class="pytext">url</span><br />
+<br />
+<span class="pycomment"># The key and URL are set manually</span><span class="pytext"></span></div></div>
+</div>
+<div class="section" id="setapikey">
+<h2><a class="toc-backref" href="#id18">setAPIKey</a></h2>
+<pre class="literal-block">
+setAPIKey(key=None, blog_url=None)
+</pre>
+<p>Set the wordpress API key for all transactions.</p>
+<p>If you don't specify an explicit API <tt class="docutils literal"><span class="pre">key</span></tt> and <tt class="docutils literal"><span class="pre">blog_url</span></tt> it will
+attempt to load them from a file called <tt class="docutils literal"><span class="pre">apikey.txt</span></tt> in the current
+directory.</p>
+<p>This method is <em>usually</em> called automatically when you create a new <tt class="docutils literal"><span class="pre">Akismet</span></tt>
+instance.</p>
+</div>
+<div class="section" id="akismet-methods">
+<h2><a class="toc-backref" href="#id19">Akismet Methods</a></h2>
+<p>These four methods equate to the four functions of the <a class="reference external" href="http://akismet.com/development/api/";>Akismet API</a>.</p>
+<div class="section" id="verify-key">
+<h3><a class="toc-backref" href="#id20">verify-key</a></h3>
+<pre class="literal-block">
+verify_key()
+</pre>
+<p>This equates to the <tt class="docutils literal"><span class="pre">verify-key</span></tt> call against the akismet API.</p>
+<p>It returns <tt class="docutils literal"><span class="pre">True</span></tt> if the key is valid.</p>
+<p>The docs state that your program <em>ought</em> to call this at the start of the
+transaction.</p>
+<p>It raises <tt class="docutils literal"><span class="pre">APIKeyError</span></tt> if you have not yet set an API key.</p>
+<p>If the connection to akismet fails, it allows the normal <tt class="docutils literal"><span class="pre">HTTPError</span></tt>
+or <tt class="docutils literal"><span class="pre">URLError</span></tt> to be raised. (<em>akismet.py</em> uses
+<a class="reference external" href="http://docs.python.org/lib/module-urllib2.html";>urllib2</a>)</p>
+</div>
+<div class="section" id="comment-check">
+<h3><a class="toc-backref" href="#id21">comment-check</a></h3>
+<pre class="literal-block">
+comment_check(comment, data=None, build_data=True, DEBUG=False)
+</pre>
+<p>This is the main function in the Akismet API. It checks comments.</p>
+<p>It returns <tt class="docutils literal"><span class="pre">True</span></tt> for spam and <tt class="docutils literal"><span class="pre">False</span></tt> for ham.</p>
+<p>If you set <tt class="docutils literal"><span class="pre">DEBUG=True</span></tt> then it will return the text of the response,
+instead of the <tt class="docutils literal"><span class="pre">True</span></tt> or <tt class="docutils literal"><span class="pre">False</span></tt> object.</p>
+<p>It raises <tt class="docutils literal"><span class="pre">APIKeyError</span></tt> if you have not yet set an API key.</p>
+<p>If the connection to Akismet fails then the <tt class="docutils literal"><span class="pre">HTTPError</span></tt> or
+<tt class="docutils literal"><span class="pre">URLError</span></tt> will be propogated.</p>
+<p>As a minimum it requires the body of the comment. This is the
+<tt class="docutils literal"><span class="pre">comment</span></tt> argument.</p>
+<p>Akismet requires some other arguments, and allows some optional ones.
+The more information you give it, the more likely it is to be able to
+make an accurate diagnosise.</p>
+<p>You supply these values using a mapping object (dictionary) as the
+<tt class="docutils literal"><span class="pre">data</span></tt> argument.</p>
+<p>If <tt class="docutils literal"><span class="pre">build_data</span></tt> is <tt class="docutils literal"><span class="pre">True</span></tt> (the default), then <em>akismet.py</em> will
+attempt to fill in as much information as possible, using default
+values where necessary. This is particularly useful for programs
+running in a CGI environment. A lot of useful information
+can be supplied from evironment variables (<tt class="docutils literal"><span class="pre">os.environ</span></tt>). See below.</p>
+<p>You <em>only</em> need supply values for which you don't want defaults filled
+in for. All values must be strings.</p>
+<p>There are a few required values. If they are not supplied, and
+defaults can't be worked out, then an <tt class="docutils literal"><span class="pre">AkismetError</span></tt> is raised.</p>
+<p>If you set <tt class="docutils literal"><span class="pre">build_data=False</span></tt> and a required value is missing an
+<tt class="docutils literal"><span class="pre">AkismetError</span></tt> will also be raised.</p>
+<p>The normal values (and defaults) are as follows :</p>
+<ul class="simple">
+<li>'user_ip':          <tt class="docutils literal"><span class="pre">os.environ['REMOTE_ADDR']</span></tt>       (*)</li>
+<li>'user_agent':       <tt class="docutils literal"><span class="pre">os.environ['HTTP_USER_AGENT']</span></tt>   (*)</li>
+<li>'referrer':         <tt class="docutils literal"><span class="pre">os.environ.get('HTTP_REFERER',</span> <span class="pre">'unknown')</span></tt> <a class="footnote-reference" href="#id6" id="id3">[2]</a></li>
+<li>'permalink':        ''</li>
+<li>'comment_type':     'comment' <a class="footnote-reference" href="#id7" id="id4">[3]</a></li>
+<li>'comment_author':   ''</li>
+<li>'comment_author_email': ''</li>
+<li>'comment_author_url': ''</li>
+<li>'SERVER_ADDR':      <tt class="docutils literal"><span class="pre">os.environ.get('SERVER_ADDR',</span> <span class="pre">'')</span></tt></li>
+<li>'SERVER_ADMIN':     <tt class="docutils literal"><span class="pre">os.environ.get('SERVER_ADMIN',</span> <span class="pre">'')</span></tt></li>
+<li>'SERVER_NAME':      <tt class="docutils literal"><span class="pre">os.environ.get('SERVER_NAME',</span> <span class="pre">'')</span></tt></li>
+<li>'SERVER_PORT':      <tt class="docutils literal"><span class="pre">os.environ.get('SERVER_PORT',</span> <span class="pre">'')</span></tt></li>
+<li>'SERVER_SIGNATURE': <tt class="docutils literal"><span class="pre">os.environ.get('SERVER_SIGNATURE',</span> <span class="pre">'')</span></tt></li>
+<li>'SERVER_SOFTWARE':  <tt class="docutils literal"><span class="pre">os.environ.get('SERVER_SOFTWARE',</span> <span class="pre">'')</span></tt></li>
+<li>'HTTP_ACCEPT':      <tt class="docutils literal"><span class="pre">os.environ.get('HTTP_ACCEPT',</span> <span class="pre">'')</span></tt></li>
+</ul>
+<p>(*) Required values</p>
+<p>You may supply as many additional <strong>'HTTP_*'</strong> type values as you wish.
+These should correspond to the http headers sent with the request.</p>
+</div>
+<div class="section" id="submit-spam">
+<h3><a class="toc-backref" href="#id22">submit-spam</a></h3>
+<pre class="literal-block">
+submit_spam(comment, data=None, build_data=True)
+</pre>
+<p>This function is used to tell akismet that a comment it marked as ham,
+is really spam.</p>
+<p>It takes all the same arguments as <tt class="docutils literal"><span class="pre">comment_check</span></tt>, except for
+<em>DEBUG</em>.</p>
+</div>
+<div class="section" id="submit-ham">
+<h3><a class="toc-backref" href="#id23">submit-ham</a></h3>
+<pre class="literal-block">
+submit_ham(self, comment, data=None, build_data=True)
+</pre>
+<p>This function is used to tell akismet that a comment it marked as spam,
+is really ham.</p>
+<p>It takes all the same arguments as <tt class="docutils literal"><span class="pre">comment_check</span></tt>, except for
+<em>DEBUG</em>.</p>
+</div>
+</div>
+</div>
+<div class="section" id="error-classes">
+<h1><a class="toc-backref" href="#id24">Error Classes</a></h1>
+<p>In the course of using <em>akismet.py</em>, there are two possible errors you could
+see.</p>
+<div class="section" id="akismeterror">
+<h2><a class="toc-backref" href="#id25">AkismetError</a></h2>
+<p>This is for general Akismet errors. For example, if you didn't supply some of
+the required information.</p>
+<p>This error is a subclass of <tt class="docutils literal"><span class="pre">Exception</span></tt>.</p>
+<p>This error is also raised if there is a network connection error. This can happen when the Akismet
+service or domain goes down temporarily.</p>
+<p>Your code should trap this and handle it appropriately (either let the comment through or push it
+onto a moderation queue).</p>
+</div>
+<div class="section" id="apikeyerror">
+<h2><a class="toc-backref" href="#id26">APIKeyError</a></h2>
+<p>If <em>apikey.txt</em> is invalid, or you attempt to call one of the <a class="reference internal" href="#akismet-methods">akismet methods</a>
+without setting a key, you will get an <tt class="docutils literal"><span class="pre">APIKeyError</span></tt>.</p>
+<p>This error is a subclass of <tt class="docutils literal"><span class="pre">AkismetError</span></tt>.</p>
+</div>
+</div>
+<div class="section" id="usage-example">
+<h1><a class="toc-backref" href="#id27">Usage Example</a></h1>
+<p>A simple example that loads the key automatically, verifies the key, and then
+checks a comment.</p>
+<div class="pysrc"><span class="pytext">api</span> <span class="pyoperator">=</span> <span class="pytext">Akismet</span><span class="pyoperator">(</span><span class="pytext">agent</span><span class="pyoperator">=</span><span class="pystring">'Test Script'</span><span class="pyoperator">)</span><br />
+<span class="pycomment"># if apikey.txt is in place,<br />
+</span><span class="pycomment"># the key will automatically be set<br />
+</span><span class="pycomment"># or you can call ``api.setAPIKey()``<br />
+</span><span class="pycomment">#<br />
+</span><span class="pykeyword">if</span> <span class="pytext">api</span><span class="pyoperator">.</span><span class="pytext">key</span> <span class="pykeyword">is</span> <span class="pytext">None</span><span class="pyoperator">:</span><br />
+&nbsp;&nbsp;&nbsp;&nbsp;<span class="pykeyword">print</span> <span class="pystring">"No 'apikey.txt' file."</span><br />
+<span class="pykeyword">elif</span> <span class="pykeyword">not</span> <span class="pytext">api</span><span class="pyoperator">.</span><span class="pytext">verify_key</span><span class="pyoperator">(</span><span class="pyoperator">)</span><span class="pyoperator">:</span><br />
+&nbsp;&nbsp;&nbsp;&nbsp;<span class="pykeyword">print</span> <span class="pystring">"The API key is invalid."</span><br />
+<span class="pykeyword">else</span><span class="pyoperator">:</span><br />
+&nbsp;&nbsp;&nbsp;&nbsp;<span class="pycomment"># data should be a dictionary of values<br />
+</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="pycomment"># They can all be filled in with defaults<br />
+</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="pycomment"># from a CGI environment<br />
+</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="pykeyword">if</span> <span class="pytext">api</span><span class="pyoperator">.</span><span class="pytext">comment_check</span><span class="pyoperator">(</span><span class="pytext">comment</span><span class="pyoperator">,</span> <span class="pytext">data</span><span class="pyoperator">)</span><span class="pyoperator">:</span><br />
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="pykeyword">print</span> <span class="pystring">'This comment is spam.'</span><br />
+&nbsp;&nbsp;&nbsp;&nbsp;<span class="pykeyword">else</span><span class="pyoperator">:</span><br />
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="pykeyword">print</span> <span class="pystring">'This comment is ham.'</span><span class="pytext"></span></div></div>
+<div class="section" id="akismet-test-cgi">
+<h1><a class="toc-backref" href="#id28">Akismet Test CGI</a></h1>
+<p>Included in the distribution is a file called <tt class="docutils literal"><span class="pre">test_akismet.py</span></tt>.</p>
+<p>This is a simple test CGI. It needs <a class="reference external" href="http://www.voidspace.org.uk/python/recipebook.shtml#util";>cgiutils</a>
+to run.</p>
+<p>When activated, it allows you to put a comment in and test it with akismet. It
+will tell you if the comment is marked as <em>ham</em>, or <em>spam</em>.</p>
+<p>To confirm that your setup is working; any post with <strong>viagra-test-123</strong> as the
+name, should be marked as spam.</p>
+<p>Obviously you will need an API key for this to work.</p>
+<p>You can try this online at :</p>
+<ul class="simple">
+<li><a class="reference external" href="http://www.voidspace.org.uk/cgi-bin/akismet/test_akismet.py";>Akismet Example CGI</a></li>
+</ul>
+</div>
+<hr class="docutils" />
+<div class="section" id="todo">
+<h1><a class="toc-backref" href="#id29">TODO</a></h1>
+<p>Make the timeout adjustable ?</p>
+<p>Should we fill in a default value for permalink ?</p>
+<p>What about automatically filling in the 'HTTP_*' values from os.environ ?</p>
+</div>
+<div class="section" id="changelog">
+<h1><a class="toc-backref" href="#id30">CHANGELOG</a></h1>
+<div class="section" id="version-0-2-0">
+<h2><a class="toc-backref" href="#id31">2009/06/18      Version 0.2.0</a></h2>
+<p>If 'blog' is not in the data dictionary passed to <tt class="docutils literal"><span class="pre">comment_check</span></tt> it will be
+added even if <tt class="docutils literal"><span class="pre">build_data</span></tt> is False. Thanks to Mark Walling.</p>
+<p>Fix for compatibility with Google AppEngine. Thanks to Matt King.</p>
+<p>Added a setup.py.</p>
+</div>
+<div class="section" id="version-0-1-5">
+<h2><a class="toc-backref" href="#id32">2007/02/05      Version 0.1.5</a></h2>
+<p>Fixed a typo/bug in <tt class="docutils literal"><span class="pre">submit_ham</span></tt>. Thanks to Ian Ozsvald for pointing this out.</p>
+</div>
+<div class="section" id="version-0-1-4">
+<h2><a class="toc-backref" href="#id33">2006/12/13      Version 0.1.4</a></h2>
+<p>Akismet now traps errors in connections. If there is a network error it raises an <tt class="docutils literal"><span class="pre">AkismetError</span></tt>.</p>
+<p>This can happen when the Akismet service or domain goes down temporarily.</p>
+<p>Your code should trap this and handle it appropriately (either let the comment through or push it onto a moderation
+queue).</p>
+</div>
+<div class="section" id="version-0-1-3">
+<h2><a class="toc-backref" href="#id34">2006/07/18      Version 0.1.3</a></h2>
+<p>Add the blog url to the data. Bugfix thanks to James Bennett.</p>
+</div>
+<div class="section" id="version-0-1-2">
+<h2><a class="toc-backref" href="#id35">2005/12/04      Version 0.1.2</a></h2>
+<p>Added the <tt class="docutils literal"><span class="pre">build_data</span></tt> argument to <tt class="docutils literal"><span class="pre">comment_check</span></tt>, <tt class="docutils literal"><span class="pre">submit_spam</span></tt>, and
+<tt class="docutils literal"><span class="pre">submit_ham</span></tt>.</p>
+</div>
+<div class="section" id="version-0-1-1">
+<h2><a class="toc-backref" href="#id36">2005/12/02      Version 0.1.1</a></h2>
+<p>Corrected so that ham and spam are the right way round  <img src="/smilies/smile.gif" alt="Smile" height="15" width="15" /> </p>
+</div>
+<div class="section" id="version-0-1-0">
+<h2><a class="toc-backref" href="#id37">2005/12/01      Version 0.1.0</a></h2>
+<p>Test version.</p>
+</div>
+</div>
+<div class="section" id="footnotes">
+<h1><a class="toc-backref" href="#id38">Footnotes</a></h1>
+<table class="docutils footnote" frame="void" id="id5" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id1">[1]</a></td><td>Online at <a class="reference external" href="http://www.voidspace.org.uk/python/license.shtml";>http://www.voidspace.org.uk/python/license.shtml</a></td></tr>
+</tbody>
+</table>
+<table class="docutils footnote" frame="void" id="id6" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id3">[2]</a></td><td>Note the spelling &quot;referrer&quot;. This is a required value by the
+akismet api - however, referrer information is not always
+supplied by the browser or server. In fact the HTTP protocol
+forbids relying on referrer information for functionality in
+programs.</td></tr>
+</tbody>
+</table>
+<table class="docutils footnote" frame="void" id="id7" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id4">[3]</a></td><td>The <a class="reference external" href="http://akismet.com/development/api/";>API docs</a> state that this value
+can be &quot; <em>blank, comment, trackback, pingback, or a made up value</em>
+<em>like 'registration'</em> &quot;.</td></tr>
+</tbody>
+</table>
+</div>
+</div>
+<div class="footer">
+<hr class="footer" />
+<a class="reference external" href="akismet_python.txt">View document source</a>.
+Generated on: 2009-06-18 23:45 UTC.
+Generated by <a class="reference external" href="http://docutils.sourceforge.net/";>Docutils</a> from <a class="reference external" href="http://docutils.sourceforge.net/rst.html";>reStructuredText</a> source.
+
+</div>
+</body>
+</html>

=== added file 'akismet-0.2.0/docs/akismet_python.txt'
--- akismet-0.2.0/docs/akismet_python.txt	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/akismet_python.txt	2016-10-06 17:53:22 +0000
@@ -0,0 +1,494 @@
+==========================
+ Akismet - The Python API
+==========================
+------------------------------------
+ Stopping Comment Spam with Akismet
+------------------------------------
+
+:Author: `Michael Foord`_
+:Contact: fuzzyman@xxxxxxxxxxxxxxxx
+:Version: 0.2.0
+:Date: 2009/06/18
+:License: `BSD License`_ [#]_
+:Online Docs: `akismet.py online`_
+
+.. _`akismet.py online`: http://www.voidspace.org.uk/python/akismet_python.html
+.. _BSD License: BSD-LICENSE.txt
+
+.. contents:: The Akismet API
+
+.. note::
+
+    As of version 0.2.0 akismet.py can be used with Google AppEngine.
+
+
+Introduction
+============
+
+`Akismet <http://www.akismet.com>`_ is a web service for recognising spam
+comments. It promises to be almost 100% effective at catching comment spam. 
+They say that currently 81% of all comments submitted to them are spam.
+
+It's designed to work with the `Wordpress Blog Tool <http://wordpress.org/>`_,
+but it's not restricted to that - so this is a Python interface to the 
+`Akismet API <http://akismet.com/development/api/>`_.
+
+You'll need a `Wordpress Key <http://wordpress.com>`_ to use it. This script 
+will allow you to plug akismet into any CGI script or web application, and 
+there are full docs in the code. It's extremely easy to use, because the folks 
+at  akismet have implemented a nice and straightforward 
+{acro;REST;REpresentational State Transfer} API.
+
+.. note::
+
+    If possible your program should inform Akismet of false positives and false
+    negatives.
+    
+    Informing Akismet helps makes the service more reliable. {sm;:-)}
+    
+    To do this, use the `submit-spam`_ and `submit-ham`_ functionality.
+
+Most of the work is done by the `comment-check`_ function.
+
+
+Downloading
+-----------
+
+You can download **akismet.py** from :
+
+* `akismet.py <http://www.voidspace.org.uk/downloads/akismet.py>`_
+* `akismet.zip (48k) <http://www.voidspace.org.uk/downloads/akismet-0.2.0.zip>`_
+
+This contains the docs, **akismet.py**, and a test CGI called *test_akismet.py*.
+
+
+apikey.txt
+==========
+
+The easiest way to use *akismet.py* is to provide the wordpress key and blog
+URL in a text file called ``apikey.txt``.
+
+This should be in the current directory when you create your ``Akismet``
+instance (or call setAPIKey_ with no arguments).
+
+The format for ``apikey.txt`` is simple (see the example one in the
+distribution.
+
+Lines that start with a ``#`` are comments. The first non-blank, non-comment
+line should be the API key. The second line should be the blog URL (or 
+application URL) to use.
+
+::
+
+    # Lines starting with '#' are comments
+    # The first non-blank, non-comment, line should be your api key
+    # The second your blog URL
+    #
+    # You can get a wordpress API key from http://wordpress.com/
+    some_key
+    some_blog_url
+
+
+The Akismet Class
+=================
+
+The akismet_ API provides four functions. *akismet.py* gives you access to
+all of these through a single class.
+
+The four akismet functions are :
+
+* `verify-key`_     - the ``verify_key`` method
+* `comment-check`_  - the ``comment_check`` method
+* `submit-spam`_   - the ``submit_spam`` method
+* `submit-ham`_   - the ``submit_ham`` method
+
+In addition to these, the Akismet class has the following user methods and
+attributes :
+
+* setAPIKey_    - method
+* key           - attribute
+* blog_url      - attribute
+
+
+Creating an Instance
+--------------------
+
+::
+
+    Akismet(key=None, blog_url=None, agent=None)
+
+To use the akismet web service you *need* an API key. There are three ways of
+telling the ``Akismet`` class what this is.
+
+1) When you create a new ``Akismet`` instance you can pass in the API key and
+   blog url.
+2) If you don't pass in a key, it will automatically look for apikey.txt_ in
+   the current directory, and attempt to load it.
+3) You can set the ``key`` and ``blog_url`` Attributes manually, after creating
+   your instance.
+
+
+User-Agent
+~~~~~~~~~~
+
+As well as setting your key, you *ought* to pass in a string for ``Akismet`` to
+create a User-Agent header with. This is the ``agent`` argument.
+
+According to the `API docs <http://akismet.com/development/api/>`_, this ought
+to be in the form : ::
+
+    Program Name/Version
+
+*akismet.py* adds it's version number to this, to create a User-Agent in the
+form liked by akismet.
+
+The default User-Agent (if you don't pass in a values to ``agent``) is::
+
+    Python Interface by Fuzzyman/0.2.0 | akismet.py/0.2.0
+
+
+Example 1
+~~~~~~~~~
+
+.. raw:: html
+
+    {+coloring}
+    #example 1
+    api = Akismet(api_key, url, agent='Example/0.1') 
+    {-coloring}
+
+
+Example 2
+~~~~~~~~~
+
+.. raw:: html
+
+    {+coloring}
+    #example 2
+    if os.path.isfile('apikey.txt'):
+        api = Akismet(agent='Example/0.2') 
+    
+    # The key and URL are loaded from
+    # 'apikey.txt'
+    {-coloring}
+
+
+Example 3
+~~~~~~~~~
+
+.. raw:: html
+
+    {+coloring}
+    #example 3
+    url = 'http://www.voidspace.org.uk/cgi-bin/voidspace/guestbook.py'
+    api_key = '0acdfg1fr'
+    if not os.path.isfile('apikey.txt'):
+        api = Akismet(agent='Example/0.3') 
+        api.key = api_key
+        api.blog_url = url
+    
+    # The key and URL are set manually
+    {-coloring}
+
+
+setAPIKey
+---------
+
+::
+
+    setAPIKey(key=None, blog_url=None)
+
+Set the wordpress API key for all transactions.
+
+If you don't specify an explicit API ``key`` and ``blog_url`` it will
+attempt to load them from a file called ``apikey.txt`` in the current
+directory.
+
+This method is *usually* called automatically when you create a new ``Akismet``
+instance.
+
+
+Akismet Methods
+---------------
+
+These four methods equate to the four functions of the `Akismet API <http://akismet.com/development/api/>`_.
+
+
+verify-key
+~~~~~~~~~~
+
+::
+
+    verify_key()
+
+This equates to the ``verify-key`` call against the akismet API.
+
+It returns ``True`` if the key is valid.
+
+The docs state that your program *ought* to call this at the start of the
+transaction.
+
+It raises ``APIKeyError`` if you have not yet set an API key.
+
+If the connection to akismet fails, it allows the normal ``HTTPError``
+or ``URLError`` to be raised. (*akismet.py* uses 
+`urllib2 <http://docs.python.org/lib/module-urllib2.html>`_)
+
+
+comment-check
+~~~~~~~~~~~~~
+
+::
+
+    comment_check(comment, data=None, build_data=True, DEBUG=False)
+
+This is the main function in the Akismet API. It checks comments.
+
+It returns ``True`` for spam and ``False`` for ham.
+
+If you set ``DEBUG=True`` then it will return the text of the response,
+instead of the ``True`` or ``False`` object.
+
+It raises ``APIKeyError`` if you have not yet set an API key.
+
+If the connection to Akismet fails then the ``HTTPError`` or
+``URLError`` will be propogated.
+
+As a minimum it requires the body of the comment. This is the
+``comment`` argument.
+
+Akismet requires some other arguments, and allows some optional ones.
+The more information you give it, the more likely it is to be able to
+make an accurate diagnosise.
+
+You supply these values using a mapping object (dictionary) as the
+``data`` argument.
+
+If ``build_data`` is ``True`` (the default), then *akismet.py* will
+attempt to fill in as much information as possible, using default
+values where necessary. This is particularly useful for programs
+running in a CGI environment. A lot of useful information
+can be supplied from evironment variables (``os.environ``). See below.
+
+You *only* need supply values for which you don't want defaults filled
+in for. All values must be strings.
+
+There are a few required values. If they are not supplied, and
+defaults can't be worked out, then an ``AkismetError`` is raised.
+
+If you set ``build_data=False`` and a required value is missing an
+``AkismetError`` will also be raised.
+
+The normal values (and defaults) are as follows :
+
+*    'user_ip':          ``os.environ['REMOTE_ADDR']``       (*)
+*    'user_agent':       ``os.environ['HTTP_USER_AGENT']``   (*)
+*    'referrer':         ``os.environ.get('HTTP_REFERER', 'unknown')`` [#]_
+*    'permalink':        ''
+*    'comment_type':     'comment' [#]_
+*    'comment_author':   ''
+*    'comment_author_email': ''
+*    'comment_author_url': ''
+*    'SERVER_ADDR':      ``os.environ.get('SERVER_ADDR', '')``
+*    'SERVER_ADMIN':     ``os.environ.get('SERVER_ADMIN', '')``
+*    'SERVER_NAME':      ``os.environ.get('SERVER_NAME', '')``
+*    'SERVER_PORT':      ``os.environ.get('SERVER_PORT', '')``
+*    'SERVER_SIGNATURE': ``os.environ.get('SERVER_SIGNATURE', '')``
+*    'SERVER_SOFTWARE':  ``os.environ.get('SERVER_SOFTWARE', '')``
+*    'HTTP_ACCEPT':      ``os.environ.get('HTTP_ACCEPT', '')``
+
+(*) Required values
+
+You may supply as many additional **'HTTP_*'** type values as you wish.
+These should correspond to the http headers sent with the request.
+
+
+submit-spam
+~~~~~~~~~~~
+
+::
+
+    submit_spam(comment, data=None, build_data=True)
+
+This function is used to tell akismet that a comment it marked as ham,
+is really spam.
+
+It takes all the same arguments as ``comment_check``, except for
+*DEBUG*.
+
+
+submit-ham
+~~~~~~~~~~
+
+::
+
+    submit_ham(self, comment, data=None, build_data=True)
+
+This function is used to tell akismet that a comment it marked as spam,
+is really ham.
+
+It takes all the same arguments as ``comment_check``, except for
+*DEBUG*.
+
+
+Error Classes
+=============
+
+In the course of using *akismet.py*, there are two possible errors you could
+see.
+
+
+AkismetError
+------------
+
+This is for general Akismet errors. For example, if you didn't supply some of
+the required information.
+
+This error is a subclass of ``Exception``.
+
+This error is also raised if there is a network connection error. This can happen when the Akismet
+service or domain goes down temporarily.
+
+Your code should trap this and handle it appropriately (either let the comment through or push it
+onto a moderation queue).
+
+
+APIKeyError
+-----------
+
+If *apikey.txt* is invalid, or you attempt to call one of the `akismet methods`_
+without setting a key, you will get an ``APIKeyError``.
+
+This error is a subclass of ``AkismetError``.
+
+
+Usage Example
+=============
+
+A simple example that loads the key automatically, verifies the key, and then
+checks a comment.
+
+.. raw:: html
+
+    {+coloring}
+    api = Akismet(agent='Test Script')
+    # if apikey.txt is in place,
+    # the key will automatically be set
+    # or you can call ``api.setAPIKey()``
+    #
+    if api.key is None:
+        print "No 'apikey.txt' file."
+    elif not api.verify_key():
+        print "The API key is invalid."
+    else:
+        # data should be a dictionary of values
+        # They can all be filled in with defaults
+        # from a CGI environment
+        if api.comment_check(comment, data):
+            print 'This comment is spam.'
+        else:
+            print 'This comment is ham.'
+    {-coloring}
+
+
+Akismet Test CGI
+================
+
+Included in the distribution is a file called ``test_akismet.py``.
+
+This is a simple test CGI. It needs `cgiutils <http://www.voidspace.org.uk/python/recipebook.shtml#util>`_
+to run.
+
+When activated, it allows you to put a comment in and test it with akismet. It
+will tell you if the comment is marked as *ham*, or *spam*.
+
+To confirm that your setup is working; any post with **viagra-test-123** as the
+name, should be marked as spam.
+
+Obviously you will need an API key for this to work.
+
+You can try this online at :
+
+* `Akismet Example CGI <http://www.voidspace.org.uk/cgi-bin/akismet/test_akismet.py>`_
+
+
+---------------------
+
+
+TODO
+====
+
+Make the timeout adjustable ?
+
+Should we fill in a default value for permalink ?
+
+What about automatically filling in the 'HTTP_*' values from os.environ ?
+
+
+CHANGELOG
+=========
+
+2009/06/18      Version 0.2.0
+-----------------------------
+
+If 'blog' is not in the data dictionary passed to ``comment_check`` it will be
+added even if ``build_data`` is False. Thanks to Mark Walling.
+
+Fix for compatibility with Google AppEngine. Thanks to Matt King.
+
+Added a setup.py.
+
+
+2007/02/05      Version 0.1.5
+-----------------------------
+
+Fixed a typo/bug in ``submit_ham``. Thanks to Ian Ozsvald for pointing this out.
+
+2006/12/13      Version 0.1.4
+-----------------------------
+
+Akismet now traps errors in connections. If there is a network error it raises an ``AkismetError``.
+
+This can happen when the Akismet service or domain goes down temporarily.
+
+Your code should trap this and handle it appropriately (either let the comment through or push it onto a moderation
+queue).
+
+2006/07/18      Version 0.1.3
+-----------------------------
+
+Add the blog url to the data. Bugfix thanks to James Bennett.
+
+2005/12/04      Version 0.1.2
+-----------------------------
+
+Added the ``build_data`` argument to ``comment_check``, ``submit_spam``, and
+``submit_ham``.
+
+2005/12/02      Version 0.1.1
+-----------------------------
+
+Corrected so that ham and spam are the right way round {sm;:-)}
+
+2005/12/01      Version 0.1.0
+-----------------------------
+
+Test version.
+
+
+Footnotes
+=========
+
+.. [#] Online at http://www.voidspace.org.uk/python/license.shtml
+.. [#] Note the spelling "referrer". This is a required value by the
+    akismet api - however, referrer information is not always
+    supplied by the browser or server. In fact the HTTP protocol
+    forbids relying on referrer information for functionality in 
+    programs.
+.. [#] The `API docs <http://akismet.com/development/api/>`_ state that this value
+    can be " *blank, comment, trackback, pingback, or a made up value*
+    *like 'registration'* ".
+
+.. _Michael Foord: http://www.voidspace.org.uk/python/index.shtml
+.. _let me know: fuzzyman@xxxxxxxxxxxxxxxx
+

=== added directory 'akismet-0.2.0/docs/images'
=== added directory 'akismet-0.2.0/docs/images/.svn'
=== added file 'akismet-0.2.0/docs/images/.svn/all-wcprops'
--- akismet-0.2.0/docs/images/.svn/all-wcprops	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/images/.svn/all-wcprops	2016-10-06 17:53:22 +0000
@@ -0,0 +1,35 @@
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svn/!svn/ver/2/trunk/akismet/docs/images
+END
+powered_by_python.jpg
+K 25
+svn:wc:ra_dav:version-url
+V 63
+/svn/!svn/ver/2/trunk/akismet/docs/images/powered_by_python.jpg
+END
+osi-certified-120x100.gif
+K 25
+svn:wc:ra_dav:version-url
+V 67
+/svn/!svn/ver/2/trunk/akismet/docs/images/osi-certified-120x100.gif
+END
+PythonPowered.png
+K 25
+svn:wc:ra_dav:version-url
+V 59
+/svn/!svn/ver/2/trunk/akismet/docs/images/PythonPowered.png
+END
+pythonbanner.gif
+K 25
+svn:wc:ra_dav:version-url
+V 58
+/svn/!svn/ver/2/trunk/akismet/docs/images/pythonbanner.gif
+END
+new_python.gif
+K 25
+svn:wc:ra_dav:version-url
+V 56
+/svn/!svn/ver/2/trunk/akismet/docs/images/new_python.gif
+END

=== added file 'akismet-0.2.0/docs/images/.svn/entries'
--- akismet-0.2.0/docs/images/.svn/entries	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/images/.svn/entries	2016-10-06 17:53:22 +0000
@@ -0,0 +1,81 @@
+8
+
+dir
+2
+https://mfoord.googlecode.com/svn/trunk/akismet/docs/images
+https://mfoord.googlecode.com/svn
+
+
+
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+
+
+svn:special svn:externals svn:needs-lock
+
+powered_by_python.jpg
+file
+
+
+
+
+2005-06-29T19:01:46.000000Z
+a9feae5c4778756a0383caeb8847e6f6
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+osi-certified-120x100.gif
+file
+
+
+
+
+2005-06-29T19:01:46.000000Z
+e53ed0e0678da8099bae8c743f118f39
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+PythonPowered.png
+file
+
+
+
+
+2005-06-29T19:01:46.000000Z
+f24139c6c5077677d1d9e8da1b86d68f
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+pythonbanner.gif
+file
+
+
+
+
+2006-04-01T10:01:20.000000Z
+2c4ddbbca1accedb13f6c94e99d1771f
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+new_python.gif
+file
+
+
+
+
+2006-04-01T08:36:14.000000Z
+eeb5fab16eed5a6f245ea2404c36d5cd
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+

=== added file 'akismet-0.2.0/docs/images/.svn/format'
--- akismet-0.2.0/docs/images/.svn/format	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/images/.svn/format	2016-10-06 17:53:22 +0000
@@ -0,0 +1,1 @@
+8

=== added directory 'akismet-0.2.0/docs/images/.svn/prop-base'
=== added file 'akismet-0.2.0/docs/images/.svn/prop-base/PythonPowered.png.svn-base'
--- akismet-0.2.0/docs/images/.svn/prop-base/PythonPowered.png.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/images/.svn/prop-base/PythonPowered.png.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/images/.svn/prop-base/new_python.gif.svn-base'
--- akismet-0.2.0/docs/images/.svn/prop-base/new_python.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/images/.svn/prop-base/new_python.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/images/.svn/prop-base/osi-certified-120x100.gif.svn-base'
--- akismet-0.2.0/docs/images/.svn/prop-base/osi-certified-120x100.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/images/.svn/prop-base/osi-certified-120x100.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/images/.svn/prop-base/powered_by_python.jpg.svn-base'
--- akismet-0.2.0/docs/images/.svn/prop-base/powered_by_python.jpg.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/images/.svn/prop-base/powered_by_python.jpg.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/images/.svn/prop-base/pythonbanner.gif.svn-base'
--- akismet-0.2.0/docs/images/.svn/prop-base/pythonbanner.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/images/.svn/prop-base/pythonbanner.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added directory 'akismet-0.2.0/docs/images/.svn/props'
=== added directory 'akismet-0.2.0/docs/images/.svn/text-base'
=== added file 'akismet-0.2.0/docs/images/.svn/text-base/PythonPowered.png.svn-base'
Binary files akismet-0.2.0/docs/images/.svn/text-base/PythonPowered.png.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/images/.svn/text-base/PythonPowered.png.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/images/.svn/text-base/new_python.gif.svn-base'
Binary files akismet-0.2.0/docs/images/.svn/text-base/new_python.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/images/.svn/text-base/new_python.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/images/.svn/text-base/osi-certified-120x100.gif.svn-base'
Binary files akismet-0.2.0/docs/images/.svn/text-base/osi-certified-120x100.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/images/.svn/text-base/osi-certified-120x100.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/images/.svn/text-base/powered_by_python.jpg.svn-base'
Binary files akismet-0.2.0/docs/images/.svn/text-base/powered_by_python.jpg.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/images/.svn/text-base/powered_by_python.jpg.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/images/.svn/text-base/pythonbanner.gif.svn-base'
Binary files akismet-0.2.0/docs/images/.svn/text-base/pythonbanner.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/images/.svn/text-base/pythonbanner.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added directory 'akismet-0.2.0/docs/images/.svn/tmp'
=== added directory 'akismet-0.2.0/docs/images/.svn/tmp/prop-base'
=== added directory 'akismet-0.2.0/docs/images/.svn/tmp/props'
=== added directory 'akismet-0.2.0/docs/images/.svn/tmp/text-base'
=== added file 'akismet-0.2.0/docs/images/PythonPowered.png'
Binary files akismet-0.2.0/docs/images/PythonPowered.png	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/images/PythonPowered.png	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/images/new_python.gif'
Binary files akismet-0.2.0/docs/images/new_python.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/images/new_python.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/images/osi-certified-120x100.gif'
Binary files akismet-0.2.0/docs/images/osi-certified-120x100.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/images/osi-certified-120x100.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/images/powered_by_python.jpg'
Binary files akismet-0.2.0/docs/images/powered_by_python.jpg	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/images/powered_by_python.jpg	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/images/pythonbanner.gif'
Binary files akismet-0.2.0/docs/images/pythonbanner.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/images/pythonbanner.gif	2016-10-06 17:53:22 +0000 differ
=== added directory 'akismet-0.2.0/docs/smilies'
=== added directory 'akismet-0.2.0/docs/smilies/.svn'
=== added file 'akismet-0.2.0/docs/smilies/.svn/all-wcprops'
--- akismet-0.2.0/docs/smilies/.svn/all-wcprops	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/all-wcprops	2016-10-06 17:53:22 +0000
@@ -0,0 +1,143 @@
+K 25
+svn:wc:ra_dav:version-url
+V 42
+/svn/!svn/ver/2/trunk/akismet/docs/smilies
+END
+doubt.gif
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/doubt.gif
+END
+surprised.gif
+K 25
+svn:wc:ra_dav:version-url
+V 56
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/surprised.gif
+END
+biggrin.gif
+K 25
+svn:wc:ra_dav:version-url
+V 54
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/biggrin.gif
+END
+exclaim.gif
+K 25
+svn:wc:ra_dav:version-url
+V 54
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/exclaim.gif
+END
+razz.gif
+K 25
+svn:wc:ra_dav:version-url
+V 51
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/razz.gif
+END
+lol.gif
+K 25
+svn:wc:ra_dav:version-url
+V 50
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/lol.gif
+END
+redface.gif
+K 25
+svn:wc:ra_dav:version-url
+V 54
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/redface.gif
+END
+arrow.gif
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/arrow.gif
+END
+cool.gif
+K 25
+svn:wc:ra_dav:version-url
+V 51
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/cool.gif
+END
+cry.gif
+K 25
+svn:wc:ra_dav:version-url
+V 50
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/cry.gif
+END
+rolleyes.gif
+K 25
+svn:wc:ra_dav:version-url
+V 55
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/rolleyes.gif
+END
+evil.gif
+K 25
+svn:wc:ra_dav:version-url
+V 51
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/evil.gif
+END
+sc_smilies.pak
+K 25
+svn:wc:ra_dav:version-url
+V 57
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/sc_smilies.pak
+END
+mad.gif
+K 25
+svn:wc:ra_dav:version-url
+V 50
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/mad.gif
+END
+idea.gif
+K 25
+svn:wc:ra_dav:version-url
+V 51
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/idea.gif
+END
+confused.gif
+K 25
+svn:wc:ra_dav:version-url
+V 55
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/confused.gif
+END
+badgrin.gif
+K 25
+svn:wc:ra_dav:version-url
+V 54
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/badgrin.gif
+END
+question.gif
+K 25
+svn:wc:ra_dav:version-url
+V 55
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/question.gif
+END
+sad.gif
+K 25
+svn:wc:ra_dav:version-url
+V 50
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/sad.gif
+END
+shock.gif
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/shock.gif
+END
+wink.gif
+K 25
+svn:wc:ra_dav:version-url
+V 51
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/wink.gif
+END
+smile.gif
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/smile.gif
+END
+neutral.gif
+K 25
+svn:wc:ra_dav:version-url
+V 54
+/svn/!svn/ver/2/trunk/akismet/docs/smilies/neutral.gif
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/entries'
--- akismet-0.2.0/docs/smilies/.svn/entries	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/entries	2016-10-06 17:53:22 +0000
@@ -0,0 +1,315 @@
+8
+
+dir
+2
+https://mfoord.googlecode.com/svn/trunk/akismet/docs/smilies
+https://mfoord.googlecode.com/svn
+
+
+
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+
+
+svn:special svn:externals svn:needs-lock
+
+doubt.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+429dfdc20ca8968e9eab1e82480a4397
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+surprised.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+bd906e86fc0736802bb00ee00bf60c73
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+biggrin.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+293a751c19878bb77838a7beed09c465
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+exclaim.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+32e9d2d45d75dd2678ae2e3222cd17a6
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+lol.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+017280bf45cf307e1b56ea6ca25a39d9
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+razz.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+be4933cb8ca17d67082fb4b8136133c8
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+redface.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+f41c1b80a3699ccfc4c77bb3eac69148
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+arrow.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+03a895606f0eee702b1689ce85089f98
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+cool.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+a5578420eaa425ab56499d5298c23247
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+cry.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+a7d5e05e24884909cabf3cf371cc79d7
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+rolleyes.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+7bc83ba0773c84a6631d0af7b76c876a
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+evil.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+d247568c69a1ebd3593a91dd9a334794
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+sc_smilies.pak
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+0ca4767642193b33288e6305474cd763
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+mad.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+31707546eca577e089b36dcf99af8bc8
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+idea.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+a62075169e2a3748947fa9b1553a494e
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+confused.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+90fc5b8617e35818167b11cfbfaba8bf
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+badgrin.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+c260d55cdc98541b06f0dbeaad12e7ef
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+question.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+9281759c5fdd439d9e5723756f632110
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+sad.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+7cb777647bf4dae0d217ff60a898ec3a
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+shock.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+a9ceeefe2a6a0985c0229175310efa56
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+wink.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+cba538cc2ceb84abb75adb996283e682
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+smile.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+2640818f553e34978736225e1e18fbd2
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+neutral.gif
+file
+
+
+
+
+2005-06-29T19:02:20.000000Z
+9568907cef379dd4cbc60359639a02e5
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+

=== added file 'akismet-0.2.0/docs/smilies/.svn/format'
--- akismet-0.2.0/docs/smilies/.svn/format	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/format	2016-10-06 17:53:22 +0000
@@ -0,0 +1,1 @@
+8

=== added directory 'akismet-0.2.0/docs/smilies/.svn/prop-base'
=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/arrow.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/arrow.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/arrow.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/badgrin.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/badgrin.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/badgrin.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/biggrin.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/biggrin.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/biggrin.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/confused.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/confused.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/confused.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/cool.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/cool.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/cool.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/cry.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/cry.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/cry.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/doubt.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/doubt.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/doubt.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/evil.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/evil.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/evil.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/exclaim.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/exclaim.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/exclaim.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/idea.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/idea.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/idea.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/lol.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/lol.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/lol.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/mad.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/mad.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/mad.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/neutral.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/neutral.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/neutral.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/question.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/question.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/question.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/razz.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/razz.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/razz.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/redface.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/redface.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/redface.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/rolleyes.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/rolleyes.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/rolleyes.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/sad.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/sad.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/sad.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/sc_smilies.pak.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/sc_smilies.pak.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/sc_smilies.pak.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/shock.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/shock.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/shock.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/smile.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/smile.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/smile.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/surprised.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/surprised.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/surprised.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added file 'akismet-0.2.0/docs/smilies/.svn/prop-base/wink.gif.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/prop-base/wink.gif.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/prop-base/wink.gif.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,9 @@
+K 14
+svn:executable
+V 1
+*
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END

=== added directory 'akismet-0.2.0/docs/smilies/.svn/props'
=== added directory 'akismet-0.2.0/docs/smilies/.svn/text-base'
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/arrow.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/arrow.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/arrow.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/badgrin.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/badgrin.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/badgrin.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/biggrin.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/biggrin.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/biggrin.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/confused.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/confused.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/confused.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/cool.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/cool.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/cool.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/cry.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/cry.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/cry.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/doubt.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/doubt.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/doubt.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/evil.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/evil.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/evil.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/exclaim.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/exclaim.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/exclaim.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/idea.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/idea.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/idea.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/lol.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/lol.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/lol.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/mad.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/mad.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/mad.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/neutral.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/neutral.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/neutral.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/question.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/question.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/question.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/razz.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/razz.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/razz.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/redface.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/redface.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/redface.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/rolleyes.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/rolleyes.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/rolleyes.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/sad.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/sad.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/sad.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/sc_smilies.pak.svn-base'
--- akismet-0.2.0/docs/smilies/.svn/text-base/sc_smilies.pak.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/.svn/text-base/sc_smilies.pak.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,43 @@
+biggrin.gif=+:Very Happy=+::D
+biggrin.gif=+:Very Happy=+::-D
+biggrin.gif=+:Very Happy=+::grin:
+biggrin.gif=+:Very Happy=+::biggrin:
+smile.gif=+:Smile=+::)
+smile.gif=+:Smile=+::-)
+smile.gif=+:Smile=+::smile:
+sad.gif=+:Sad=+::(
+sad.gif=+:Sad=+::-(
+sad.gif=+:Sad=+::sad:
+surprised.gif=+:Surprised=+::o
+surprised.gif=+:Surprised=+::-o
+surprised.gif=+:Surprised=+::eek:
+shock.gif=+:Shock=+::shock:
+confused.gif=+:Confused=+::?
+confused.gif=+:Confused=+::-?
+confused.gif=+:Confused=+::???:
+cool.gif=+:Cool=+:8)
+cool.gif=+:Cool=+:8-)
+cool.gif=+:Cool=+::cool:
+lol.gif=+:Laughing=+::lol:
+mad.gif=+:Mad=+::x
+mad.gif=+:Mad=+::-X
+mad.gif=+:Mad=+::mad:
+razz.gif=+:Razz=+::p
+razz.gif=+:Razz=+::-p
+razz.gif=+:Razz=+::razz:
+redface.gif=+:Embarassed=+::oops:
+cry.gif=+:Crying or Very sad=+::cry:
+evil.gif=+:Evil or Very Mad=+::evil:
+badgrin.gif=+:Bad Grin=+::badgrin:
+rolleyes.gif=+:Rolling Eyes=+::roll:
+wink.gif=+:Wink=+:;)
+wink.gif=+:Wink=+:;-)
+wink.gif=+:Wink=+::wink:
+exclaim.gif=+:Exclamation=+::!:
+question.gif=+:Question=+::?:
+idea.gif=+:Idea=+::idea:
+arrow.gif=+:Arrow=+::arrow:
+neutral.gif=+:Neutral=+::|
+neutral.gif=+:Neutral=+::-|
+neutral.gif=+:Neutral=+::neutral:
+doubt.gif=+:Doubt=+::doubt:
\ No newline at end of file

=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/shock.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/shock.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/shock.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/smile.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/smile.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/smile.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/surprised.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/surprised.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/surprised.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/.svn/text-base/wink.gif.svn-base'
Binary files akismet-0.2.0/docs/smilies/.svn/text-base/wink.gif.svn-base	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/.svn/text-base/wink.gif.svn-base	2016-10-06 17:53:22 +0000 differ
=== added directory 'akismet-0.2.0/docs/smilies/.svn/tmp'
=== added directory 'akismet-0.2.0/docs/smilies/.svn/tmp/prop-base'
=== added directory 'akismet-0.2.0/docs/smilies/.svn/tmp/props'
=== added directory 'akismet-0.2.0/docs/smilies/.svn/tmp/text-base'
=== added file 'akismet-0.2.0/docs/smilies/arrow.gif'
Binary files akismet-0.2.0/docs/smilies/arrow.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/arrow.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/badgrin.gif'
Binary files akismet-0.2.0/docs/smilies/badgrin.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/badgrin.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/biggrin.gif'
Binary files akismet-0.2.0/docs/smilies/biggrin.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/biggrin.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/confused.gif'
Binary files akismet-0.2.0/docs/smilies/confused.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/confused.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/cool.gif'
Binary files akismet-0.2.0/docs/smilies/cool.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/cool.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/cry.gif'
Binary files akismet-0.2.0/docs/smilies/cry.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/cry.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/doubt.gif'
Binary files akismet-0.2.0/docs/smilies/doubt.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/doubt.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/evil.gif'
Binary files akismet-0.2.0/docs/smilies/evil.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/evil.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/exclaim.gif'
Binary files akismet-0.2.0/docs/smilies/exclaim.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/exclaim.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/idea.gif'
Binary files akismet-0.2.0/docs/smilies/idea.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/idea.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/lol.gif'
Binary files akismet-0.2.0/docs/smilies/lol.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/lol.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/mad.gif'
Binary files akismet-0.2.0/docs/smilies/mad.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/mad.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/neutral.gif'
Binary files akismet-0.2.0/docs/smilies/neutral.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/neutral.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/question.gif'
Binary files akismet-0.2.0/docs/smilies/question.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/question.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/razz.gif'
Binary files akismet-0.2.0/docs/smilies/razz.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/razz.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/redface.gif'
Binary files akismet-0.2.0/docs/smilies/redface.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/redface.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/rolleyes.gif'
Binary files akismet-0.2.0/docs/smilies/rolleyes.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/rolleyes.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/sad.gif'
Binary files akismet-0.2.0/docs/smilies/sad.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/sad.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/sc_smilies.pak'
--- akismet-0.2.0/docs/smilies/sc_smilies.pak	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/smilies/sc_smilies.pak	2016-10-06 17:53:22 +0000
@@ -0,0 +1,43 @@
+biggrin.gif=+:Very Happy=+::D
+biggrin.gif=+:Very Happy=+::-D
+biggrin.gif=+:Very Happy=+::grin:
+biggrin.gif=+:Very Happy=+::biggrin:
+smile.gif=+:Smile=+::)
+smile.gif=+:Smile=+::-)
+smile.gif=+:Smile=+::smile:
+sad.gif=+:Sad=+::(
+sad.gif=+:Sad=+::-(
+sad.gif=+:Sad=+::sad:
+surprised.gif=+:Surprised=+::o
+surprised.gif=+:Surprised=+::-o
+surprised.gif=+:Surprised=+::eek:
+shock.gif=+:Shock=+::shock:
+confused.gif=+:Confused=+::?
+confused.gif=+:Confused=+::-?
+confused.gif=+:Confused=+::???:
+cool.gif=+:Cool=+:8)
+cool.gif=+:Cool=+:8-)
+cool.gif=+:Cool=+::cool:
+lol.gif=+:Laughing=+::lol:
+mad.gif=+:Mad=+::x
+mad.gif=+:Mad=+::-X
+mad.gif=+:Mad=+::mad:
+razz.gif=+:Razz=+::p
+razz.gif=+:Razz=+::-p
+razz.gif=+:Razz=+::razz:
+redface.gif=+:Embarassed=+::oops:
+cry.gif=+:Crying or Very sad=+::cry:
+evil.gif=+:Evil or Very Mad=+::evil:
+badgrin.gif=+:Bad Grin=+::badgrin:
+rolleyes.gif=+:Rolling Eyes=+::roll:
+wink.gif=+:Wink=+:;)
+wink.gif=+:Wink=+:;-)
+wink.gif=+:Wink=+::wink:
+exclaim.gif=+:Exclamation=+::!:
+question.gif=+:Question=+::?:
+idea.gif=+:Idea=+::idea:
+arrow.gif=+:Arrow=+::arrow:
+neutral.gif=+:Neutral=+::|
+neutral.gif=+:Neutral=+::-|
+neutral.gif=+:Neutral=+::neutral:
+doubt.gif=+:Doubt=+::doubt:
\ No newline at end of file

=== added file 'akismet-0.2.0/docs/smilies/shock.gif'
Binary files akismet-0.2.0/docs/smilies/shock.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/shock.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/smile.gif'
Binary files akismet-0.2.0/docs/smilies/smile.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/smile.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/surprised.gif'
Binary files akismet-0.2.0/docs/smilies/surprised.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/surprised.gif	2016-10-06 17:53:22 +0000 differ
=== added file 'akismet-0.2.0/docs/smilies/wink.gif'
Binary files akismet-0.2.0/docs/smilies/wink.gif	1970-01-01 00:00:00 +0000 and akismet-0.2.0/docs/smilies/wink.gif	2016-10-06 17:53:22 +0000 differ
=== added directory 'akismet-0.2.0/docs/stylesheets'
=== added directory 'akismet-0.2.0/docs/stylesheets/.svn'
=== added file 'akismet-0.2.0/docs/stylesheets/.svn/all-wcprops'
--- akismet-0.2.0/docs/stylesheets/.svn/all-wcprops	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/stylesheets/.svn/all-wcprops	2016-10-06 17:53:22 +0000
@@ -0,0 +1,29 @@
+K 25
+svn:wc:ra_dav:version-url
+V 46
+/svn/!svn/ver/2/trunk/akismet/docs/stylesheets
+END
+pysrc.css
+K 25
+svn:wc:ra_dav:version-url
+V 56
+/svn/!svn/ver/2/trunk/akismet/docs/stylesheets/pysrc.css
+END
+voidspace_docutils.css
+K 25
+svn:wc:ra_dav:version-url
+V 69
+/svn/!svn/ver/2/trunk/akismet/docs/stylesheets/voidspace_docutils.css
+END
+default.css
+K 25
+svn:wc:ra_dav:version-url
+V 58
+/svn/!svn/ver/2/trunk/akismet/docs/stylesheets/default.css
+END
+pep.css
+K 25
+svn:wc:ra_dav:version-url
+V 54
+/svn/!svn/ver/2/trunk/akismet/docs/stylesheets/pep.css
+END

=== added file 'akismet-0.2.0/docs/stylesheets/.svn/entries'
--- akismet-0.2.0/docs/stylesheets/.svn/entries	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/stylesheets/.svn/entries	2016-10-06 17:53:22 +0000
@@ -0,0 +1,68 @@
+8
+
+dir
+2
+https://mfoord.googlecode.com/svn/trunk/akismet/docs/stylesheets
+https://mfoord.googlecode.com/svn
+
+
+
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+
+
+svn:special svn:externals svn:needs-lock
+
+pysrc.css
+file
+
+
+
+
+2005-08-26T17:57:02.000000Z
+fc37699fc65d57ee407b4d6987c3330e
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+voidspace_docutils.css
+file
+
+
+
+
+2005-10-28T19:17:32.000000Z
+4532ba5f1e85a1cbf24a6f37a629ad7b
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+default.css
+file
+
+
+
+
+2006-01-04T20:27:42.000000Z
+a4ac76699b87ba40aa201cf9f64fdcc3
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+
+pep.css
+file
+
+
+
+
+2005-09-25T14:52:16.000000Z
+50f264243a603bde9ceaf9f30ec916e7
+2009-06-18T18:58:24.300424Z
+2
+fuzzyman
+has-props
+

=== added file 'akismet-0.2.0/docs/stylesheets/.svn/format'
--- akismet-0.2.0/docs/stylesheets/.svn/format	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/stylesheets/.svn/format	2016-10-06 17:53:22 +0000
@@ -0,0 +1,1 @@
+8

=== added directory 'akismet-0.2.0/docs/stylesheets/.svn/prop-base'
=== added file 'akismet-0.2.0/docs/stylesheets/.svn/prop-base/default.css.svn-base'
--- akismet-0.2.0/docs/stylesheets/.svn/prop-base/default.css.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/stylesheets/.svn/prop-base/default.css.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END

=== added file 'akismet-0.2.0/docs/stylesheets/.svn/prop-base/pep.css.svn-base'
--- akismet-0.2.0/docs/stylesheets/.svn/prop-base/pep.css.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/stylesheets/.svn/prop-base/pep.css.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END

=== added file 'akismet-0.2.0/docs/stylesheets/.svn/prop-base/pysrc.css.svn-base'
--- akismet-0.2.0/docs/stylesheets/.svn/prop-base/pysrc.css.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/stylesheets/.svn/prop-base/pysrc.css.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END

=== added file 'akismet-0.2.0/docs/stylesheets/.svn/prop-base/voidspace_docutils.css.svn-base'
--- akismet-0.2.0/docs/stylesheets/.svn/prop-base/voidspace_docutils.css.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/stylesheets/.svn/prop-base/voidspace_docutils.css.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END

=== added directory 'akismet-0.2.0/docs/stylesheets/.svn/props'
=== added directory 'akismet-0.2.0/docs/stylesheets/.svn/text-base'
=== added file 'akismet-0.2.0/docs/stylesheets/.svn/text-base/default.css.svn-base'
--- akismet-0.2.0/docs/stylesheets/.svn/text-base/default.css.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/stylesheets/.svn/text-base/default.css.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,278 @@
+/*
+:Author: David Goodger
+:Contact: goodger@xxxxxxxxxxxxxxxxxxxxx
+:Date: $Date: 2005-09-25 17:49:54 +0200 (Sun, 25 Sep 2005) $
+:Revision: $Revision: 3901 $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+
+See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
+customize this style sheet.
+*/
+
+/* "! important" is used here to override other ``margin-top`` and
+   ``margin-bottom`` styles that are later in the stylesheet or 
+   more specific.  See http://www.w3.org/TR/CSS1#the-cascade */
+.first {
+  margin-top: 0 ! important }
+
+.last, .with-subtitle {
+  margin-bottom: 0 ! important }
+
+.hidden {
+  display: none }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+blockquote.epigraph {
+  margin: 2em 5em ; }
+
+dl.docutils dd {
+  margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+  font-weight: bold }
+*/
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+   compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+*/
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em }
+
+div.footer, div.header {
+  clear: both;
+  font-size: smaller }
+
+div.line-block {
+  display: block ;
+  margin-top: 1em ;
+  margin-bottom: 1em }
+
+div.line-block div.line-block {
+  margin-top: 0 ;
+  margin-bottom: 0 ;
+  margin-left: 1.5em }
+
+div.sidebar {
+  margin-left: 1em ;
+  border: medium outset ;
+  padding: 1em ;
+  background-color: #ffffee ;
+  width: 40% ;
+  float: right ;
+  clear: right }
+
+div.sidebar p.rubric {
+  font-family: sans-serif ;
+  font-size: medium }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+  margin-top: 0.4em }
+
+h1.title {
+  text-align: center }
+
+h2.subtitle {
+  text-align: center }
+
+hr.docutils {
+  width: 75% }
+
+img.align-left {
+  clear: left }
+
+img.align-right {
+  clear: right }
+
+img.borderless {
+  border: 0 }
+
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.attribution {
+  text-align: right ;
+  margin-left: 50% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.rubric {
+  font-weight: bold ;
+  font-size: larger ;
+  color: maroon ;
+  text-align: center }
+
+p.sidebar-title {
+  font-family: sans-serif ;
+  font-weight: bold ;
+  font-size: larger }
+
+p.sidebar-subtitle {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font-family: serif ;
+  font-size: 100% }
+
+pre.line-block {
+  font-family: serif ;
+  font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em ;
+  background-color: #eeeeee }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+ /* 
+span.pre {
+  white-space: pre }
+*/
+
+span.problematic {
+  color: red }
+
+span.section-subtitle {
+  /* font-size relative to parent (h1..h6 element) */
+  font-size: 80% }
+
+table.citation {
+  border-left: solid thin gray }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.docutils {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.footnote {
+  border-left: solid thin black }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+  font-weight: bold ;
+  text-align: left ;
+  white-space: nowrap ;
+  padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100% }
+
+tt.docutils {
+  background-color: #eeeeee }
+
+ul.auto-toc {
+  list-style-type: none }

=== added file 'akismet-0.2.0/docs/stylesheets/.svn/text-base/pep.css.svn-base'
--- akismet-0.2.0/docs/stylesheets/.svn/text-base/pep.css.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/stylesheets/.svn/text-base/pep.css.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,349 @@
+/*
+:Author: David Goodger
+:Contact: goodger@xxxxxxxxxxxxxxxxxxxxx
+:date: $Date: 2005-09-25 17:49:54 +0200 (Sun, 25 Sep 2005) $
+:version: $Revision: 3901 $
+:copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the PEP HTML output of Docutils.
+*/
+
+/* "! important" is used here to override other ``margin-top`` and
+   ``margin-bottom`` styles that are later in the stylesheet or 
+   more specific.  See http://www.w3.org/TR/CSS1#the-cascade */
+.first {
+  margin-top: 0 ! important }
+
+.last, .with-subtitle {
+  margin-bottom: 0 ! important }
+
+.hidden {
+  display: none }
+
+.navigation {
+  width: 100% ;
+  background: #99ccff ;
+  margin-top: 0px ;
+  margin-bottom: 0px }
+
+.navigation .navicon {
+  width: 150px ;
+  height: 35px }
+
+.navigation .textlinks {
+  padding-left: 1em ;
+  text-align: left }
+
+.navigation td, .navigation th {
+  padding-left: 0em ;
+  padding-right: 0em ;
+  vertical-align: middle }
+
+.rfc2822 {
+  margin-top: 0.5em ;
+  margin-left: 0.5em ;
+  margin-right: 0.5em ;
+  margin-bottom: 0em }
+
+.rfc2822 td {
+  text-align: left }
+
+.rfc2822 th.field-name {
+  text-align: right ;
+  font-family: sans-serif ;
+  padding-right: 0.5em ;
+  font-weight: bold ;
+  margin-bottom: 0em }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+blockquote.epigraph {
+  margin: 2em 5em ; }
+
+body {
+  margin: 0px ;
+  margin-bottom: 1em ;
+  padding: 0px }
+
+dl.docutils dd {
+  margin-bottom: 0.5em }
+
+div.section {
+  margin-left: 1em ;
+  margin-right: 1em ;
+  margin-bottom: 1.5em }
+
+div.section div.section {
+  margin-left: 0em ;
+  margin-right: 0em ;
+  margin-top: 1.5em }
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+   compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+*/
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em }
+
+div.footer, div.header {
+  clear: both;
+  font-size: smaller }
+
+div.footer {
+  margin-left: 1em ;
+  margin-right: 1em }
+
+div.line-block {
+  display: block ;
+  margin-top: 1em ;
+  margin-bottom: 1em }
+
+div.line-block div.line-block {
+  margin-top: 0 ;
+  margin-bottom: 0 ;
+  margin-left: 1.5em }
+
+div.sidebar {
+  margin-left: 1em ;
+  border: medium outset ;
+  padding: 1em ;
+  background-color: #ffffee ;
+  width: 40% ;
+  float: right ;
+  clear: right }
+
+div.sidebar p.rubric {
+  font-family: sans-serif ;
+  font-size: medium }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+  margin-top: 0.4em }
+
+h1 {
+  font-family: sans-serif ;
+  font-size: large }
+
+h2 {
+  font-family: sans-serif ;
+  font-size: medium }
+
+h3 {
+  font-family: sans-serif ;
+  font-size: small }
+
+h4 {
+  font-family: sans-serif ;
+  font-style: italic ;
+  font-size: small }
+
+h5 {
+  font-family: sans-serif;
+  font-size: x-small }
+
+h6 {
+  font-family: sans-serif;
+  font-style: italic ;
+  font-size: x-small }
+
+hr.docutils {
+  width: 75% }
+
+img.align-left {
+  clear: left }
+
+img.align-right {
+  clear: right }
+
+img.borderless {
+  border: 0 }
+
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.attribution {
+  text-align: right ;
+  margin-left: 50% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.rubric {
+  font-weight: bold ;
+  font-size: larger ;
+  color: maroon ;
+  text-align: center }
+
+p.sidebar-title {
+  font-family: sans-serif ;
+  font-weight: bold ;
+  font-size: larger }
+
+p.sidebar-subtitle {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+p.topic-title {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font-family: serif ;
+  font-size: 100% }
+
+pre.line-block {
+  font-family: serif ;
+  font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em ;
+  background-color: #eeeeee }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+span.option-argument {
+  font-style: italic }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+span.section-subtitle {
+  /* font-size relative to parent (h1..h6 element) */
+  font-size: 80% }
+
+table.citation {
+  border-left: solid thin gray }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.docutils {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.footnote {
+  border-left: solid thin black }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+td.num {
+  text-align: right }
+
+th.field-name {
+  font-weight: bold ;
+  text-align: left ;
+  white-space: nowrap ;
+  padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100% }
+
+tt.docutils {
+  background-color: #eeeeee }
+
+ul.auto-toc {
+  list-style-type: none }

=== added file 'akismet-0.2.0/docs/stylesheets/.svn/text-base/pysrc.css.svn-base'
--- akismet-0.2.0/docs/stylesheets/.svn/text-base/pysrc.css.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/stylesheets/.svn/text-base/pysrc.css.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,29 @@
+.pysrc {
+    border: #c0c0ff 2px dotted;  padding:10px;
+    font-weight: normal; background: #e0e0ff; margin: 20px;  
+    padding:10px; 
+}
+
+.pykeyword {
+    font-weight: bold;
+    color: orange;
+}
+.pystring {
+	color: green
+}
+.pycomment {
+	color: red
+}
+.pynumber {
+    color:purple;
+}
+.pyoperator {
+    color:purple;
+}
+.pytext {
+    color:black;
+}
+.pyerror {
+    font-wieght: bold;
+    color: red;
+}
\ No newline at end of file

=== added file 'akismet-0.2.0/docs/stylesheets/.svn/text-base/voidspace_docutils.css.svn-base'
--- akismet-0.2.0/docs/stylesheets/.svn/text-base/voidspace_docutils.css.svn-base	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/stylesheets/.svn/text-base/voidspace_docutils.css.svn-base	2016-10-06 17:53:22 +0000
@@ -0,0 +1,141 @@
+/*
+:Authors: Ian Bicking, Michael Foord
+:Contact: fuzzyman@xxxxxxxxxxxxxxxx
+:Date: 2005/08/26 
+:Version: 0.1.0
+:Copyright: This stylesheet has been placed in the public domain.
+
+Stylesheet for Docutils.
+Based on ``blue_box.css`` by Ian Bicking
+and ``default.css`` revision 3442
+*/
+
+@import url(default.css);
+@import url(pysrc.css);
+
+body {
+  font-family: Arial, sans-serif;
+}
+
+em, i {
+  /* Typically serif fonts have much nicer italics */
+  font-family: Times New Roman, Times, serif;
+}
+
+
+a.target {
+  color: blue;
+}
+
+a.toc-backref {
+  text-decoration: none;
+  color: black;
+}
+
+a.toc-backref:hover {
+  background-color: inherit;
+}
+
+a:hover {
+  background-color: #cccccc;
+}
+
+div.attention, div.caution, div.danger, div.error, div.hint,
+div.important, div.note, div.tip, div.warning {
+  background-color: #cccccc;
+  padding: 3px;
+  width: 80%;
+}
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title  {
+  text-align: center;
+  background-color: #999999;
+  display: block;
+  margin: 0;
+}
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: #cc0000;
+  font-family: sans-serif;
+  text-align: center;
+  background-color: #999999;
+  display: block;
+  margin: 0;
+}
+
+h1, h2, h3, h4, h5, h6 {
+  font-family: Helvetica, Arial, sans-serif;
+  border: thin solid black;
+  /* This makes the borders rounded on Mozilla, which pleases me */
+  -moz-border-radius: 8px;
+  padding: 4px;
+}
+
+h1 {
+  background-color: #444499;
+  color: #ffffff;
+  border: medium solid black;
+}
+
+h1 a.toc-backref, h2 a.toc-backref { 
+  color: #ffffff;
+}
+
+h2 {
+  background-color: #666666;
+  color: #ffffff;
+  border: medium solid black;
+}
+
+h3, h4, h5, h6 {
+  background-color: #cccccc;
+  color: #000000;
+}
+
+h3 a.toc-backref, h4 a.toc-backref, h5 a.toc-backref, 
+h6 a.toc-backref { 
+  color: #000000;
+}
+
+h1.title {
+  text-align: center;
+  background-color: #444499;
+  color: #eeeeee;
+  border: thick solid black;
+  -moz-border-radius: 20px;
+}
+
+table.footnote {
+  padding-left: 0.5ex;
+}
+
+table.citation {
+  padding-left: 0.5ex
+}
+
+pre.literal-block, pre.doctest-block {
+  border: thin black solid;
+  padding: 5px;
+}
+
+.image img { border-style : solid;
+            border-width : 2px;
+}
+
+img.align-center {
+    display: block;
+    margin: auto; 
+    text-align: center;
+}
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+  font-size: 100%;
+}
+
+code, tt {
+  color: #000066;
+}

=== added directory 'akismet-0.2.0/docs/stylesheets/.svn/tmp'
=== added directory 'akismet-0.2.0/docs/stylesheets/.svn/tmp/prop-base'
=== added directory 'akismet-0.2.0/docs/stylesheets/.svn/tmp/props'
=== added directory 'akismet-0.2.0/docs/stylesheets/.svn/tmp/text-base'
=== added file 'akismet-0.2.0/docs/stylesheets/default.css'
--- akismet-0.2.0/docs/stylesheets/default.css	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/stylesheets/default.css	2016-10-06 17:53:22 +0000
@@ -0,0 +1,278 @@
+/*
+:Author: David Goodger
+:Contact: goodger@xxxxxxxxxxxxxxxxxxxxx
+:Date: $Date: 2005-09-25 17:49:54 +0200 (Sun, 25 Sep 2005) $
+:Revision: $Revision: 3901 $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+
+See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
+customize this style sheet.
+*/
+
+/* "! important" is used here to override other ``margin-top`` and
+   ``margin-bottom`` styles that are later in the stylesheet or 
+   more specific.  See http://www.w3.org/TR/CSS1#the-cascade */
+.first {
+  margin-top: 0 ! important }
+
+.last, .with-subtitle {
+  margin-bottom: 0 ! important }
+
+.hidden {
+  display: none }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+blockquote.epigraph {
+  margin: 2em 5em ; }
+
+dl.docutils dd {
+  margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+  font-weight: bold }
+*/
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+   compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+*/
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em }
+
+div.footer, div.header {
+  clear: both;
+  font-size: smaller }
+
+div.line-block {
+  display: block ;
+  margin-top: 1em ;
+  margin-bottom: 1em }
+
+div.line-block div.line-block {
+  margin-top: 0 ;
+  margin-bottom: 0 ;
+  margin-left: 1.5em }
+
+div.sidebar {
+  margin-left: 1em ;
+  border: medium outset ;
+  padding: 1em ;
+  background-color: #ffffee ;
+  width: 40% ;
+  float: right ;
+  clear: right }
+
+div.sidebar p.rubric {
+  font-family: sans-serif ;
+  font-size: medium }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+  margin-top: 0.4em }
+
+h1.title {
+  text-align: center }
+
+h2.subtitle {
+  text-align: center }
+
+hr.docutils {
+  width: 75% }
+
+img.align-left {
+  clear: left }
+
+img.align-right {
+  clear: right }
+
+img.borderless {
+  border: 0 }
+
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.attribution {
+  text-align: right ;
+  margin-left: 50% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.rubric {
+  font-weight: bold ;
+  font-size: larger ;
+  color: maroon ;
+  text-align: center }
+
+p.sidebar-title {
+  font-family: sans-serif ;
+  font-weight: bold ;
+  font-size: larger }
+
+p.sidebar-subtitle {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font-family: serif ;
+  font-size: 100% }
+
+pre.line-block {
+  font-family: serif ;
+  font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em ;
+  background-color: #eeeeee }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+ /* 
+span.pre {
+  white-space: pre }
+*/
+
+span.problematic {
+  color: red }
+
+span.section-subtitle {
+  /* font-size relative to parent (h1..h6 element) */
+  font-size: 80% }
+
+table.citation {
+  border-left: solid thin gray }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.docutils {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.footnote {
+  border-left: solid thin black }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+  font-weight: bold ;
+  text-align: left ;
+  white-space: nowrap ;
+  padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100% }
+
+tt.docutils {
+  background-color: #eeeeee }
+
+ul.auto-toc {
+  list-style-type: none }

=== added file 'akismet-0.2.0/docs/stylesheets/pep.css'
--- akismet-0.2.0/docs/stylesheets/pep.css	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/stylesheets/pep.css	2016-10-06 17:53:22 +0000
@@ -0,0 +1,349 @@
+/*
+:Author: David Goodger
+:Contact: goodger@xxxxxxxxxxxxxxxxxxxxx
+:date: $Date: 2005-09-25 17:49:54 +0200 (Sun, 25 Sep 2005) $
+:version: $Revision: 3901 $
+:copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the PEP HTML output of Docutils.
+*/
+
+/* "! important" is used here to override other ``margin-top`` and
+   ``margin-bottom`` styles that are later in the stylesheet or 
+   more specific.  See http://www.w3.org/TR/CSS1#the-cascade */
+.first {
+  margin-top: 0 ! important }
+
+.last, .with-subtitle {
+  margin-bottom: 0 ! important }
+
+.hidden {
+  display: none }
+
+.navigation {
+  width: 100% ;
+  background: #99ccff ;
+  margin-top: 0px ;
+  margin-bottom: 0px }
+
+.navigation .navicon {
+  width: 150px ;
+  height: 35px }
+
+.navigation .textlinks {
+  padding-left: 1em ;
+  text-align: left }
+
+.navigation td, .navigation th {
+  padding-left: 0em ;
+  padding-right: 0em ;
+  vertical-align: middle }
+
+.rfc2822 {
+  margin-top: 0.5em ;
+  margin-left: 0.5em ;
+  margin-right: 0.5em ;
+  margin-bottom: 0em }
+
+.rfc2822 td {
+  text-align: left }
+
+.rfc2822 th.field-name {
+  text-align: right ;
+  font-family: sans-serif ;
+  padding-right: 0.5em ;
+  font-weight: bold ;
+  margin-bottom: 0em }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+blockquote.epigraph {
+  margin: 2em 5em ; }
+
+body {
+  margin: 0px ;
+  margin-bottom: 1em ;
+  padding: 0px }
+
+dl.docutils dd {
+  margin-bottom: 0.5em }
+
+div.section {
+  margin-left: 1em ;
+  margin-right: 1em ;
+  margin-bottom: 1.5em }
+
+div.section div.section {
+  margin-left: 0em ;
+  margin-right: 0em ;
+  margin-top: 1.5em }
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+   compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+*/
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em }
+
+div.footer, div.header {
+  clear: both;
+  font-size: smaller }
+
+div.footer {
+  margin-left: 1em ;
+  margin-right: 1em }
+
+div.line-block {
+  display: block ;
+  margin-top: 1em ;
+  margin-bottom: 1em }
+
+div.line-block div.line-block {
+  margin-top: 0 ;
+  margin-bottom: 0 ;
+  margin-left: 1.5em }
+
+div.sidebar {
+  margin-left: 1em ;
+  border: medium outset ;
+  padding: 1em ;
+  background-color: #ffffee ;
+  width: 40% ;
+  float: right ;
+  clear: right }
+
+div.sidebar p.rubric {
+  font-family: sans-serif ;
+  font-size: medium }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+  margin-top: 0.4em }
+
+h1 {
+  font-family: sans-serif ;
+  font-size: large }
+
+h2 {
+  font-family: sans-serif ;
+  font-size: medium }
+
+h3 {
+  font-family: sans-serif ;
+  font-size: small }
+
+h4 {
+  font-family: sans-serif ;
+  font-style: italic ;
+  font-size: small }
+
+h5 {
+  font-family: sans-serif;
+  font-size: x-small }
+
+h6 {
+  font-family: sans-serif;
+  font-style: italic ;
+  font-size: x-small }
+
+hr.docutils {
+  width: 75% }
+
+img.align-left {
+  clear: left }
+
+img.align-right {
+  clear: right }
+
+img.borderless {
+  border: 0 }
+
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.attribution {
+  text-align: right ;
+  margin-left: 50% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.rubric {
+  font-weight: bold ;
+  font-size: larger ;
+  color: maroon ;
+  text-align: center }
+
+p.sidebar-title {
+  font-family: sans-serif ;
+  font-weight: bold ;
+  font-size: larger }
+
+p.sidebar-subtitle {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+p.topic-title {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font-family: serif ;
+  font-size: 100% }
+
+pre.line-block {
+  font-family: serif ;
+  font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em ;
+  background-color: #eeeeee }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+span.option-argument {
+  font-style: italic }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+span.section-subtitle {
+  /* font-size relative to parent (h1..h6 element) */
+  font-size: 80% }
+
+table.citation {
+  border-left: solid thin gray }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.docutils {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.footnote {
+  border-left: solid thin black }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+td.num {
+  text-align: right }
+
+th.field-name {
+  font-weight: bold ;
+  text-align: left ;
+  white-space: nowrap ;
+  padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100% }
+
+tt.docutils {
+  background-color: #eeeeee }
+
+ul.auto-toc {
+  list-style-type: none }

=== added file 'akismet-0.2.0/docs/stylesheets/pysrc.css'
--- akismet-0.2.0/docs/stylesheets/pysrc.css	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/stylesheets/pysrc.css	2016-10-06 17:53:22 +0000
@@ -0,0 +1,29 @@
+.pysrc {
+    border: #c0c0ff 2px dotted;  padding:10px;
+    font-weight: normal; background: #e0e0ff; margin: 20px;  
+    padding:10px; 
+}
+
+.pykeyword {
+    font-weight: bold;
+    color: orange;
+}
+.pystring {
+	color: green
+}
+.pycomment {
+	color: red
+}
+.pynumber {
+    color:purple;
+}
+.pyoperator {
+    color:purple;
+}
+.pytext {
+    color:black;
+}
+.pyerror {
+    font-wieght: bold;
+    color: red;
+}
\ No newline at end of file

=== added file 'akismet-0.2.0/docs/stylesheets/voidspace_docutils.css'
--- akismet-0.2.0/docs/stylesheets/voidspace_docutils.css	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/docs/stylesheets/voidspace_docutils.css	2016-10-06 17:53:22 +0000
@@ -0,0 +1,141 @@
+/*
+:Authors: Ian Bicking, Michael Foord
+:Contact: fuzzyman@xxxxxxxxxxxxxxxx
+:Date: 2005/08/26 
+:Version: 0.1.0
+:Copyright: This stylesheet has been placed in the public domain.
+
+Stylesheet for Docutils.
+Based on ``blue_box.css`` by Ian Bicking
+and ``default.css`` revision 3442
+*/
+
+@import url(default.css);
+@import url(pysrc.css);
+
+body {
+  font-family: Arial, sans-serif;
+}
+
+em, i {
+  /* Typically serif fonts have much nicer italics */
+  font-family: Times New Roman, Times, serif;
+}
+
+
+a.target {
+  color: blue;
+}
+
+a.toc-backref {
+  text-decoration: none;
+  color: black;
+}
+
+a.toc-backref:hover {
+  background-color: inherit;
+}
+
+a:hover {
+  background-color: #cccccc;
+}
+
+div.attention, div.caution, div.danger, div.error, div.hint,
+div.important, div.note, div.tip, div.warning {
+  background-color: #cccccc;
+  padding: 3px;
+  width: 80%;
+}
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title  {
+  text-align: center;
+  background-color: #999999;
+  display: block;
+  margin: 0;
+}
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: #cc0000;
+  font-family: sans-serif;
+  text-align: center;
+  background-color: #999999;
+  display: block;
+  margin: 0;
+}
+
+h1, h2, h3, h4, h5, h6 {
+  font-family: Helvetica, Arial, sans-serif;
+  border: thin solid black;
+  /* This makes the borders rounded on Mozilla, which pleases me */
+  -moz-border-radius: 8px;
+  padding: 4px;
+}
+
+h1 {
+  background-color: #444499;
+  color: #ffffff;
+  border: medium solid black;
+}
+
+h1 a.toc-backref, h2 a.toc-backref { 
+  color: #ffffff;
+}
+
+h2 {
+  background-color: #666666;
+  color: #ffffff;
+  border: medium solid black;
+}
+
+h3, h4, h5, h6 {
+  background-color: #cccccc;
+  color: #000000;
+}
+
+h3 a.toc-backref, h4 a.toc-backref, h5 a.toc-backref, 
+h6 a.toc-backref { 
+  color: #000000;
+}
+
+h1.title {
+  text-align: center;
+  background-color: #444499;
+  color: #eeeeee;
+  border: thick solid black;
+  -moz-border-radius: 20px;
+}
+
+table.footnote {
+  padding-left: 0.5ex;
+}
+
+table.citation {
+  padding-left: 0.5ex
+}
+
+pre.literal-block, pre.doctest-block {
+  border: thin black solid;
+  padding: 5px;
+}
+
+.image img { border-style : solid;
+            border-width : 2px;
+}
+
+img.align-center {
+    display: block;
+    margin: auto; 
+    text-align: center;
+}
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+  font-size: 100%;
+}
+
+code, tt {
+  color: #000066;
+}

=== added file 'akismet-0.2.0/setup.py'
--- akismet-0.2.0/setup.py	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/setup.py	2016-10-06 17:53:22 +0000
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+
+from distutils.core import setup
+
+import akismet
+
+description = 'A Python interface to the Akismet anti comment-spam API.'
+setup(name='akismet',
+      version=akismet.__version__,
+      description=description,
+      author='Michael Foord',
+      author_email='michael@xxxxxxxxxxxxxxxx',
+      url='http://www.voidspace.org.uk/python/modules.shtml#akismet',
+      py_modules=['akismet'],
+     )

=== added directory 'akismet-0.2.0/test'
=== added file 'akismet-0.2.0/test/cgiutils.py'
--- akismet-0.2.0/test/cgiutils.py	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/test/cgiutils.py	2016-10-06 17:53:22 +0000
@@ -0,0 +1,603 @@
+# Version 0.3.5
+# 2005/11/26
+
+# Copyright Michael Foord 2004 & 2005
+# cgiutils.py
+# Functions and constants useful for working with CGIs
+
+# http://www.voidspace.org.uk/python/modules.shtml
+
+# Released subject to the BSD License
+# Please see http://www.voidspace.org.uk/python/license.shtml
+
+# For information about bugfixes, updates and support, please join the Pythonutils mailing list.
+# http://groups.google.com/group/pythonutils/
+# Comments, suggestions and bug reports welcome.
+# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
+# E-mail fuzzyman@xxxxxxxxxxxxxxxx
+
+import os
+import sys
+
+__version__ = '0.3.5'
+
+__all__ = (
+    'serverline',
+    'SENDMAIL',
+    'validchars',
+    'alphanums',
+    'getrequest',
+    'getform',
+    'getall',
+    'isblank',
+    'formencode',
+    'formdecode',
+    'mailme',
+    'sendmailme',
+    'createhtmlmail',
+    'environdata',
+    'validemail',
+    'cgiprint',
+    'ucgiprint',
+    'replace',
+    'error',
+    'makeindexline',
+    'istrue',
+    'randomstring',
+    'blacklisted',
+    '__version__',
+    )
+
+serverline = "Content-Type: text/html"
+
+# A common location of sendmail on servers
+SENDMAIL = "/usr/sbin/sendmail"
+validchars = 'abcdefghijklmnopqrstuvwxyz0123456789!-_*'
+alphanums = 'abcdefghijklmnopqrstuvwxyz0123456789'
+
+#######################################################
+# Some functions for dealing with CGI forms (instances of FieldStorage)
+
+def getrequest(valuelist=None, nolist=False):
+    """
+    Initialise the ``FieldStorage`` and return the specified list of values as 
+    a dictionary.
+    
+    If you don't specify a list of values, then *all* values will be returned.
+    
+    If you set ``nolist`` to ``True`` then any parameters supplied as lists 
+    will only have their first entry returned.
+    """
+    import cgi
+    form = cgi.FieldStorage()
+    if valuelist is not None:
+        return getform(valuelist, form, nolist=nolist)
+    else:
+        return getall(form, nolist=nolist)
+
+def getform(valuelist, theform, notpresent='', nolist=False):
+    """
+    This function, given a CGI form, extracts the data from it, based on
+    valuelist passed in. Any non-present values are set to '' - although this 
+    can be changed.
+    
+    It also takes a keyword argument 'nolist'. If this is True list values only 
+    return their first value.
+    
+    Returns a dictionary.
+    """
+    data = {}
+    for field in valuelist:
+        if not theform.has_key(field):
+            data[field] = notpresent
+        else:
+            if not isinstance(theform[field], list):
+                data[field] = theform[field].value
+            else:
+                if not nolist:
+                    # allows for list type values
+                    data[field] = [x.value for x in theform[field]]
+                else:
+                    # just fetch the first item
+                    data[field] = theform[field][0].value
+    return data
+
+def getall(theform, nolist=False):
+    """
+    Passed a form (FieldStorage instance) return all the values.
+    This doesn't take into account file uploads.
+    
+    Also accepts the 'nolist' keyword argument as ``getform``.
+    
+    Returns a dictionary.
+    """
+    data = {}
+    for field in theform.keys():
+        if not isinstance(theform[field], list):
+            data[field] = theform[field].value
+        else:
+            if not nolist:
+                # allows for list type values
+                data[field] = [x.value for x in theform[field]]
+            else:
+                # just fetch the first item
+                data[field] = theform[field][0].value
+    return data
+
+def isblank(indict):
+    """
+    Passed an indict of values it checks if any of the values are set.
+    
+    Returns ``True`` if every member of the indict is empty (evaluates as False).
+    
+    I use it on a form processed with getform to tell if my CGI has been 
+    activated without any values.
+    """
+    return not [val for val in indict.values() if val]
+
+def formencode(theform):
+    """
+    A version that turns a cgi form into a single string.
+    It only handles single and list values, not multipart.
+    This allows the contents of a form requested to be encoded into a single value as part of another request.
+    """
+    from urllib import urlencode, quote_plus
+    return quote_plus(urlencode(getall(theform)))
+
+def formdecode(thestring):
+    """Decode a single string back into a form like dictionary."""
+    from cgi import parse_qs
+    from urllib import unquote_plus 
+    return parse_qs(unquote_plus(thestring), True)
+
+
+#############################################################
+# Functions for handling emails
+#
+# Use mailme for sending email - specify a path to sendmail *or* a host, port etc (optionally username)
+
+
+def mailme(to_email, msg, email_subject=None, from_email=None,
+            host='localhost', port=25, username=None, password=None,
+            html=True, sendmail=None):
+    """
+    This function will send an email using ``sendmail`` or ``smtplib``, depending 
+    on what parameters you pass it.
+    
+    If you want to use ``sendmail`` to send the email then set 
+    ``sendmail='/path/to/sendmail'``. (The ``SENDMAIL`` value from Constants_ often 
+    works).
+    
+    If you aren't using sendmail then you will need to set ``host`` and ``port`` to 
+    the correct values. If your server requires authentication then you'll need to 
+    supply the correct ``username`` and ``password``. 
+    
+    ``to_email`` can be a single email address, *or* a list of addresses.
+    
+    ``mailme`` *assumes* you are sending an html email created by 
+    ``createhtmlmail``. If this isn't the case then set ``html=False``.
+    
+    Some servers won't let you send a message without supplying a ``from_email``.
+    """
+    if sendmail is not None:
+        # use sendmailme if specified
+        return sendmailme(to_email, msg, email_subject, from_email, 
+                            html, sendmail)
+    if not isinstance(to_email, list):
+        # if we have a single email then change it into a list
+        to_email = [to_email]
+    #
+    import smtplib
+    #
+    head = "To: %s\r\n" % ','.join(to_email) 
+    if from_email is not None:
+        head += ('From: %s\r\n' % from_email)
+    # subject is in the body of an html email
+    if not html and email_subject is not None:
+        head += ("Subject: %s\r\n\r\n" % email_subject)
+    msg = head + msg
+    #
+    server = smtplib.SMTP(host, port)
+    if username:
+        server.login(username, password)
+    server.sendmail(from_email, to_email, msg)
+    server.quit()
+
+ 
+def sendmailme(to_email, msg, email_subject=None, from_email=None, 
+                html=True, sendmail=SENDMAIL):
+    """
+    Quick and dirty, pipe a message to sendmail. Can only work on UNIX type systems 
+    with sendmail.
+    
+    Will need the path to sendmail - defaults to the 'SENDMAIL' constant.
+    
+    ``to_email`` can be a single email address, *or* a list of addresses.
+    
+    *Assumes* you are sending an html email created by ``createhtmlmail``. If this 
+    isn't the case then set ``html=False``.
+    """
+    if not isinstance(to_email, list):
+        to_email = [to_email]
+    o = os.popen("%s -t" %  sendmail,"w")
+    o.write("To: %s\r\n" %  ','.join(to_email))
+    if from_email:
+        o.write("From: %s\r\n" %  from_email)
+    if not html and email_subject:
+        o.write("Subject: %s\r\n" %  email_subject)
+    o.write("\r\n")
+    o.write("%s\r\n" % msg)
+    o.close()
+
+def createhtmlmail(subject, html, text=None):
+    """
+    Create a mime-message that will render as HTML or text as appropriate.
+    If no text is supplied we use htmllib to guess a text rendering. 
+    (so html needs to be well formed) 
+    
+    Adapted from recipe 13.5 from Python Cookbook 2
+    """
+    import MimeWriter, mimetools, StringIO
+    if text is None:
+        # produce an approximate text from the HTML input
+        import htmllib
+        import formatter
+        textout = StringIO.StringIO()
+        formtext = formatter.AbstractFormatter(formatter.DumbWriter(textout))
+        parser = htmllib.HTMLParser(formtext)
+        parser.feed(html)
+        parser.close()
+        text = textout.getvalue()
+        del textout, formtext, parser
+    out = StringIO.StringIO()       # output buffer for our message
+    htmlin = StringIO.StringIO(html)  # input buffer for the HTML
+    txtin = StringIO.StringIO(text)   # input buffer for the plain text
+    writer = MimeWriter.MimeWriter(out)
+    # Set up some basic headers. Place subject here because smtplib.sendmail
+    # expects it to be in the message, as relevant RFCs prescribe.
+    writer.addheader("Subject", subject)
+    writer.addheader("MIME-Version", "1.0")
+    # Start the multipart section of the message. Multipart/alternative seems
+    # to work better on some MUAs than multipart/mixed.
+    writer.startmultipartbody("alternative")
+    writer.flushheaders()
+    # the plain-text section: just copied through, assuming iso-8859-1  # XXXX always true ?
+    subpart = writer.nextpart()
+    pout = subpart.startbody("text/plain", [("charset", 'iso-8859-l')]) 
+    pout.write(txtin.read())
+    txtin.close()
+    # the HTML subpart of the message: quoted-printable, just in case
+    subpart = writer.nextpart()
+    subpart.addheader("Content-Transfer-Encoding", "quoted-printable")
+    pout = subpart.startbody("text/html", [("charset", 'us-ascii')])
+    mimetools.encode(htmlin, pout, 'quoted-printable')
+    htmlin.close()
+    # You're done; close your writer and return the message as a string
+    writer.lastpart()
+    msg = out.getvalue()
+    out.close()
+    return msg    
+
+def environdata():
+    """Returns some data about the CGI environment, in a way that can be mailed."""
+    ENVIRONLIST = [ 'REQUEST_URI','HTTP_USER_AGENT','REMOTE_ADDR','HTTP_FROM','REMOTE_HOST','REMOTE_PORT','SERVER_SOFTWARE','HTTP_REFERER','REMOTE_IDENT','REMOTE_USER','QUERY_STRING','DATE_LOCAL' ]  # XXX put this in template ??
+    environs = []
+    environs.append("\n\n---------------------------------------\n")
+    for x in ENVIRONLIST:
+        if os.environ.has_key(x):
+            environs.append("%s: %s\n" % (x, os.environ[x]))
+    environs.append("---------------------------------------\n")
+    return ''.join(environs)
+
+def validemail(email):
+    """
+    A quick function to do a basic email validation.
+    Returns False or the email address.
+    """
+    if ' ' in email:
+        return False
+    dot = email.rfind('.')
+    at = email.find('@')
+    if dot == -1 or at < 1 or at > dot:
+        return False
+    return email
+
+##########################################################
+
+def error(errorval=''):
+    """The generic error function."""
+    print serverline
+    print
+    print '''<html><head><title>An Error Has Occurred</title>
+    <body><center>
+    <h1>Very Sorry</h1>
+    <h2>An Error Has Occurred</h2>'''
+    if errorval:
+        print '<h3>%s</h3>' % errorval
+    print '</center></body></html>'
+    sys.exit()
+    
+#########################################################
+
+def makeindexline(url, startpage, total, numonpage=10, pagesonscreen=5):
+    """
+    Make a menu line for a given number of inputs, with a certain number per page.
+    Will look something like : ::
+    
+        First  Previous  22 23 24 25 26 27 28 29 30 31 32  Next  Last
+    
+    Each number or word will be a link to the relevant page.
+    
+    url should be in the format : ``'<a href="script.py?startpage=%s">%s</a>'`` - 
+    it will have the two ``%s`` values filled in by the function.
+    
+    The url will automatically be put between ``<strong></strong>`` tags. Your 
+    script needs to accepts a parameter ``start`` telling it which page to display.
+    
+    ``startpage`` is the page actually being viewed - which won't be a link.
+    
+    ``total`` is the number of total inputs.
+    
+    ``numonpage`` is the number of inputs per page - this tells makeindexline how 
+    many pages to divide the total into.
+    
+    The links shown will be some before startpage and some after. The amount of 
+    pages links are shown for is ``pagesonscreen``. (The actual total number shown 
+    will be *2 \* pagesonscreen + 1*).
+    
+    The indexes generated are *a bit* like the ones created by google. Unlike 
+    google however, next and previous jump you into the *middle* of the next set of 
+    links. i.e. If you are on page 27 next will take you to 33 and previous to 21. 
+    (assuming pagesonscreen is 5). This makes it possible to jump more quickly 
+    through a lot of links. Also - the current page will always be in the center of 
+    the index. (So you never *need* Next just to get to the next page).
+    """
+    b = '<strong>%s</strong>'
+    url = b % url
+    outlist = []
+    last = ''
+    next = ''
+    numpages = total//numonpage
+    if total%numonpage:
+        numpages += 1
+    if startpage - pagesonscreen > 1:
+        outlist.append(url % (1, 'First'))
+        outlist.append('&nbsp;')
+        outlist.append(url % (startpage-pagesonscreen-1, 'Previous'))
+        outlist.append('&nbsp;')
+    index = max(startpage - pagesonscreen, 1)
+    end = min(startpage+pagesonscreen, numpages)
+    while index <= end:
+        if index == startpage:
+            outlist.append(b % startpage)
+        else:
+            outlist.append(url % (index, index))
+        index += 1
+    outlist.append('&nbsp;')
+    if (startpage+pagesonscreen) < numpages:
+        outlist.append(url % (startpage+pagesonscreen+1, 'Next'))
+        outlist.append('&nbsp;')
+        outlist.append(url % (numpages, 'Last'))
+
+    return '&nbsp;'.join(outlist)    
+
+######################################
+
+def istrue(value):
+    """
+    Accepts a string as input.
+    
+    If the string is one of  ``True``, ``On``, ``Yes``, or ``1`` it returns 
+    ``True``.
+    
+    If the string is one of  ``False``, ``Off``, ``No``, or ``0`` it returns 
+    ``False``.
+    
+    ``istrue`` is not case sensitive.
+    
+    Any other input will raise a ``KeyError``. 
+    """
+    return {
+        'yes': True, 'no': False,
+        'on': True, 'off': False, 
+        '1': True, '0': False,
+        'true': True, 'false': False,
+        }[value.lower()]
+
+def randomstring(length):
+    """
+    Return a random string of length 'length'.
+    
+    The string is comprised only of numbers and lowercase letters.
+    """ 
+    import random
+    outstring = []
+    while length > 0:
+        length -= 1
+        outstring.append(alphanums[int(random.random()*36)])
+    return ''.join(outstring)
+
+##################################
+
+def cgiprint(inline='', unbuff=False, line_end='\r\n'):
+    """
+    Print to the ``stdout``.
+    
+    Set ``unbuff=True`` to flush the buffer after every write.
+    
+    It prints the inline you send it, followed by the ``line_end``. By default this 
+    is ``\r\n`` - which is the standard specified by the RFC for http headers.
+    """
+    sys.stdout.write(inline)
+    sys.stdout.write(line_end)
+    if unbuff:
+        sys.stdout.flush()
+
+def ucgiprint(inline='', unbuff=False, encoding='UTF-8', line_end='\r\n'):
+    """
+    A unicode version of ``cgiprint``. It allows you to store everything in your 
+    script as unicode and just do your encoding in one place.
+    
+    Print to the ``stdout``.
+    
+    Set ``unbuff=True`` to flush the buffer after every write.
+    
+    It prints the inline you send it, followed by the ``line_end``. By default this 
+    is ``\r\n`` - which is the standard specified by the RFC for http headers.
+    
+    ``inline`` should be a unicode string.
+    
+    ``encoding`` is the encoding used to encode ``inline`` to a byte-string. It 
+    defaults to ``UTF-8``, set it to ``None`` if you pass in ``inline`` as a byte 
+    string rather than a unicode string.
+    """
+    if encoding:
+        inline = inline.encode(encoding)
+        # don't need to encode the line endings
+    sys.stdout.write(inline)
+    sys.stdout.write(line_end)
+    if unbuff:
+        sys.stdout.flush()
+
+def replace(instring, indict):
+    """
+    This function provides a simple but effective template system for your html 
+    pages. Effectively it is a convenient way of doing multiple replaces in a 
+    single string.
+    
+    Takes a string and a dictionary of replacements. 
+    
+    This function goes through the string and replaces every occurrence of every 
+    dicitionary key with it's value.
+    
+    ``indict`` can also be a list of tuples instead of a dictionary (or anything 
+    accepted by the dict function).
+    """
+    indict = dict(indict)
+    if len(indict) > 40:
+        regex = re.compile("(%s)" % "|".join(map(re.escape, indict.keys())))
+        # For each match, look-up corresponding value in dictionary
+        return regex.sub(lambda mo: indict[mo.string[mo.start():mo.end()]],
+                                                                    instring)
+    for key in indict:
+        instring = instring.replace(key, indict[key])
+    return instring
+
+############################
+
+def blacklisted(ip, DNSBL_HOST='sbl-xbl.spamhaus.org'):
+    """
+    Returns ``True`` if ip address is a blacklisted IP (i.e. from a spammer).
+    
+    ip can also be a domain name - this raises ``socket.gaierror`` if the ip is
+    a domain name that cannot be resolved.
+    
+    The DNS blacklist host (``DNSBL_HOST``) defaults to *sbl-xbl.spamhaus.org*.
+    
+    Other ones you could use include :
+    
+    - 'relays.ordb.org'
+    - 'dns.rfc-ignorant.org'
+    - 'postmaster.rfc-ignorant.org'
+    - 'http.dnsbl.sorbs.net'
+    - 'misc.dnsbl.sorbs.net'
+    - 'spam.dnsbl.sorbs.net'
+    - 'bl.spamcop.net'
+    
+    Useful for vetting user added information posted to web applications.
+    """
+    # turn '1.2.3.4' into '4.3.2.1.sbl-xbl.spamhaus.org'
+    import socket
+    # convert domain name to IP
+    # raises an error if domain name can't be resolved
+    ip = socket.gethostbyname(ip)
+    iplist = ip.split('.')
+    iplist.reverse()
+    ip = '%s.%s' % ('.'.join(iplist), DNSBL_HOST)
+    try:
+        socket.gethostbyname(ip)
+        return True
+    except socket.gaierror:
+        return False
+
+############################
+
+if __name__ == '__main__':
+    print 'No tests yet - sorry'
+
+"""
+TODO/ISSUES
+===========
+
+The indexes generated by makeindexline use next to jump 10 pages. This is
+different to what people will expect if they are used to the 'Google' type
+index lines.
+
+createhtmlmail assumes iso-8859-1 input encoding for the html
+
+email functions to support 'cc' and 'bcc'
+
+Need doctests
+
+Changelog
+=========
+
+2005/11/26      Version 0.3.5
+-----------------------------
+
+Add the ``blacklisted`` function.
+
+Added ``__version__``
+
+
+2005/10/29      Version 0.3.4
+-----------------------------
+
+Shortened ``isblank``.
+
+
+2005/09/21      Version 0.3.3
+-----------------------------
+
+Fixed bug in ``getall`.
+
+Fixed bug in ``getrequest``.
+
+
+2005/08/27      Version 0.3.2
+-----------------------------
+
+Large dictionary replaces use a regex approach.
+
+
+2005/08/20      Version 0.3.1
+-----------------------------
+
+Improved istrue function.
+
+Added __all__.
+
+Various other code/doc improvements.
+
+
+2005/04/07      Version 0.3.0
+-----------------------------
+
+Changed the email functions, this may break things (but it's better this way)
+
+Added createhtmlemail, removed loginmailme
+
+mailme is now a wrapper for sendmailme, mailme, *and* the old loginmailme
+
+
+2005/03/20      Version 0.2.0
+-----------------------------
+
+Added ucgiprint and replace.
+
+
+2005/02/18      Version 0.1.0
+-----------------------------
+
+The first numbered version.
+"""

=== added file 'akismet-0.2.0/test/test_akismet.py'
--- akismet-0.2.0/test/test_akismet.py	1970-01-01 00:00:00 +0000
+++ akismet-0.2.0/test/test_akismet.py	2016-10-06 17:53:22 +0000
@@ -0,0 +1,163 @@
+#!/usr/bin/python
+# Version 0.1.2
+# 2005/12/05
+
+# Copyright Michael Foord 2005
+# test_akismet.py
+# Test CGI for akismet.py - the Python interface to the akismet API
+
+# http://www.voidspace.org.uk/python/modules.shtml
+# http://akismet.com
+
+# Released subject to the BSD License
+# Please see http://www.voidspace.org.uk/python/license.shtml
+
+# For information about bugfixes, updates and support, please join the Pythonutils mailing list.
+# http://groups.google.com/group/pythonutils/
+# Comments, suggestions and bug reports welcome.
+# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
+# E-mail fuzzyman@xxxxxxxxxxxxxxxx
+
+"""
+A simple test CGI for akismet.py
+
+Requires cgiutils and a file called apikey.txt
+"""
+
+import cgi
+import os
+import sys
+import cgitb
+cgitb.enable()
+
+sys.path.append('../modules')
+sys.path.append('modules')
+
+from cgiutils import *
+import akismet
+from akismet import Akismet
+
+__version__ = '0.1.2'
+
+DEBUG = False
+
+valuelist = ['comment', 'comment_author_email', 'comment_author',
+    'comment_author_url', ]
+
+header = '''<html><head><title>Akismet Test CGI</title></head><body>
+<center><h1>Testing the Python Interface to Akismet</h1>
+By 
+<em><a href="http://www.voidspace.org.uk/python/index.shtml";>Fuzzyman</a></em>
+<br><br>
+<h2>Combatting Comment Spam</h2>
+<h2>Akismet Test Version %s</h2>
+<a href="http://www.voidspace.org.uk/python/modules.shtml#akismet";>
+<h2>Python API Version %s</h2></a>
+''' % (__version__, akismet.__version__)
+
+form = '''
+**result**
+<em>Posts With the Name set as </em><strong>viagra-test-123</strong>
+<em>Should Always be Marked as Spam</em><br>
+<strong>Enter a comment to test :</strong>
+<form method="post" action="**scriptname**">
+    <table>
+        <tr><td align="right"><small><strong><label for="comment_author">Your Name:</label></strong></small></td>
+            <td><input type="text" name="comment_author" value ="**comment_author**" ></td></tr>
+        <tr><td align="right"><small><strong><label for="comment_author_email">Your E-Mail Address:</label></strong></small></td>
+            <td><input type="text" name="comment_author_email" size="40" value="**comment_author_email**" ></td></tr>
+
+        <tr><td align="right"><small><strong><label for="comment_author_url">Homepage:</label></strong></small></td>
+            <td><input type="text" name="comment_author_url" value="**comment_author_url**" size="40"></td></tr>
+    </table><br>
+    <small><strong><label for="comment">Please make your comments below</label></strong></small><br>
+    <textarea name="comment" cols="60" rows="6" wrap="hard">**comment**</textarea>
+    <br><br>
+    <input type="submit" value="Go For It"><input type="reset">
+</form>
+'''
+
+footer = '</center></body></html>'
+
+no_key = '''<h1>This script needs a %sWordpress API Key</h1>
+<h2><a href="http://wordpress.com";>Vist Wordpress</a></h2>
+'''
+
+res_line = '<h1>Akismet Says the Comment is %s</h1>'
+
+def results(req):
+    #
+    # FIXME: could break here if apikey.txt exists, but has no key/blog_url
+    api = Akismet()
+    if api.key is None:
+        # apikey.txt file
+        return no_key % ''
+    if not api.verify_key():
+        # invalid key
+        return no_key % 'Valid '
+    # check the form - it contains some relevant data
+    # the rest will be filled in with defaults
+    for entry, val in os.environ.items():
+        if entry.startswith('HTTP'):
+            req[entry] = val
+    result = api.comment_check(req['comment'], req, DEBUG=DEBUG)
+    if DEBUG:
+        return res_line % result
+    elif result:
+        return res_line % 'Spam'
+    else:
+        return res_line % 'Ham'
+
+def main():
+    # getrequest, serverline, cgiprint, replace - all come from cgituils
+    req = getrequest(valuelist)
+    cgiprint(serverline)
+    cgiprint()
+    print header
+    #
+    if req['comment'].strip():
+        result = '<br><br>%s<br><br>' % results(req)
+    else:
+        req['comment_author'] = 'viagra-test-123'
+        result = ''
+    rep = {'**result**': result }
+    for key, val in req.items():
+        rep['**%s**' % key] = val.strip()
+    rep['**scriptname**'] = os.environ['SCRIPT_NAME']
+    print replace(form, rep)
+    print footer
+
+
+if __name__ == '__main__':
+    if not 'SCRIPT_NAME' in os.environ:
+        print 'This script must be run as a CGI'
+    else:
+        main()
+
+"""
+
+CHANGELOG
+=========
+
+2005/12/05      Version 0.1.2
+-----------------------------
+
+Added DEBUG mode
+
+
+2005/12/04      Version 0.1.1
+-----------------------------
+
+Added the version numbers
+
+Added default name 'viagra-test-123'
+
+
+2005/12/02      Version 0.1.0
+-----------------------------
+
+A simple test script for akismet.py
+
+It tests ``verify_key`` and ``comment_check`` in 80 lines of code
+
+"""
\ No newline at end of file

=== modified file 'pybb/admin.py'
--- pybb/admin.py	2012-03-18 21:06:49 +0000
+++ pybb/admin.py	2016-10-06 17:53:22 +0000
@@ -39,7 +39,7 @@
          ),
         (_('Additional options'), {
                 'classes': ('collapse',),
-                'fields': (('views',), ('sticky', 'closed'), 'subscribers')
+                'fields': (('views',), ('sticky', 'closed', 'hided'), 'subscribers')
                 }
          ),
         )
@@ -57,7 +57,7 @@
          ),
         (_('Additional options'), {
                 'classes': ('collapse',),
-                'fields' : (('created', 'updated'), 'user_ip')
+                'fields' : (('created', 'updated'), 'user_ip', 'hided')
                 }
          ),
         (_('Message'), {

=== modified file 'pybb/forms.py'
--- pybb/forms.py	2016-06-22 21:02:53 +0000
+++ pybb/forms.py	2016-10-06 17:53:22 +0000
@@ -66,7 +66,6 @@
         post = Post(topic=topic, user=self.user, user_ip=self.ip,
                     markup=self.cleaned_data['markup'],
                     body=self.cleaned_data['body'])
-
         post.save(*args, **kwargs)
 
         if pybb_settings.ATTACHMENT_ENABLE:

=== added file 'pybb/migrations/0002_auto_20161001_2046.py'
--- pybb/migrations/0002_auto_20161001_2046.py	1970-01-01 00:00:00 +0000
+++ pybb/migrations/0002_auto_20161001_2046.py	2016-10-06 17:53:22 +0000
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('pybb', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='post',
+            name='hided',
+            field=models.BooleanField(default=False, verbose_name='Hided'),
+        ),
+    ]

=== modified file 'pybb/models.py'
--- pybb/models.py	2016-06-22 21:02:53 +0000
+++ pybb/models.py	2016-10-06 17:53:22 +0000
@@ -95,6 +95,13 @@
         except IndexError:
             return None
 
+    @property
+    def last_unhided_post(self):
+        posts = self.posts.order_by('-created').filter(hided=False).select_related()
+        try:
+            return posts[0]
+        except IndexError:
+            return None
 
 class Topic(models.Model):
     forum = models.ForeignKey(Forum, related_name='topics', verbose_name=_('Forum'))
@@ -130,7 +137,24 @@
     @property
     def last_post(self):
         return self.posts.all().order_by('-created').select_related()[0]
-
+    
+    @property
+    def last_unhided_post(self):
+        try:
+            p = self.posts.all().order_by('-created').filter(hided=False).select_related()[0]
+        except IndexError:
+            return self.posts.all().order_by('-created').select_related()[0]
+        return p
+    
+    # If the first post of this topic is hided, the topic is hided
+    @property
+    def is_hided(self):
+        try:
+            p = self.posts.all().order_by('created').filter(hided=False).select_related()[0]
+        except IndexError:
+            return True
+        return False
+    
     @property
     def post_count(self):
         return Post.objects.filter(topic=self).count()
@@ -193,6 +217,7 @@
     body_html = models.TextField(_('HTML version'))
     body_text = models.TextField(_('Text version'))
     user_ip = models.GenericIPAddressField(_('User IP'), default='')
+    hided = models.BooleanField(_('Hided'), blank=True, default=False)
 
     # Django sphinx
     if settings.USE_SPHINX:

=== modified file 'pybb/urls.py'
--- pybb/urls.py	2016-06-04 14:17:40 +0000
+++ pybb/urls.py	2016-10-06 17:53:22 +0000
@@ -30,7 +30,8 @@
     url('^post/(?P<post_id>\d+)/$', views.show_post, name='pybb_post'),
     url('^post/(?P<post_id>\d+)/edit/$', views.edit_post, name='pybb_edit_post'),
     url('^post/(?P<post_id>\d+)/delete/$', views.delete_post, name='pybb_delete_post'),
-
+    url('pybb_moderate_info/$', views.pybb_moderate_info),
+    
     # Attachment
     url('^attachment/(?P<hash>\w+)/$', views.show_attachment, name='pybb_attachment'),
 

=== modified file 'pybb/views.py'
--- pybb/views.py	2016-06-15 19:20:24 +0000
+++ pybb/views.py	2016-10-06 17:53:22 +0000
@@ -10,6 +10,7 @@
 from django.core.urlresolvers import reverse
 from django.db import connection
 from django.utils import translation
+from django.shortcuts import render
 
 from pybb.util import render_to, paged, build_form, quote_text, paginate, set_language, ajax, urlize
 from pybb.models import Category, Forum, Topic, Post, PrivateMessage, Attachment,\
@@ -65,7 +66,7 @@
 
     topics = forum.topics.order_by('-sticky', '-updated').select_related()
     page, paginator = paginate(topics, request, pybb_settings.FORUM_PAGE_SIZE)
-
+    
     return {'forum': forum,
             'topics': page.object_list,
             'quick': quick,
@@ -159,7 +160,28 @@
                       initial={'markup': "markdown", 'body': quote})
 
     if form.is_valid():
-        post = form.save();
+        # Add akismet check here
+        spam = False
+        
+        # Check in post text
+        text = form.cleaned_data['body']
+        if all(x in text.lower() for x in ['vashikaran', 'baba']):
+            spam = True
+            
+        # Check in topic name ('name' is empty if this a post to an existing topic)
+        text = form.cleaned_data['name']
+        if text != '':
+            if any(x in text.lower() for x in [' baba ', 'ji']):
+                spam = True
+        
+        post = form.save()
+        if spam:
+            # Hide the post against normal users
+            post.hided = True
+            post.save()
+            # Redirect to an info page to inform the user
+            return HttpResponseRedirect('pybb_moderate_info')
+        
         if not topic:
             post.topic.subscribers.add(request.user)
         return HttpResponseRedirect(post.get_absolute_url())
@@ -353,3 +375,6 @@
 
     html = urlize(html)
     return {'content': html}
+
+def pybb_moderate_info(request):
+    return render(request, 'pybb/pybb_moderate_info.html')

=== modified file 'templates/pybb/forum.html'
--- templates/pybb/forum.html	2016-04-29 07:28:16 +0000
+++ templates/pybb/forum.html	2016-10-06 17:53:22 +0000
@@ -40,7 +40,8 @@
 			</tr>
 		</thead>
 		<tbody>
-	{% for topic in topics %}
+		{% for topic in topics %}
+		{% if not topic.is_hided %}
 		<tr class="{% cycle 'odd' 'even' %}">
 			<td class="forumIcon center">
 				{% if topic|pybb_has_unreads:user %}
@@ -60,13 +61,43 @@
 				Views: {{ topic.views }}
 			</td>
 			<td class="lastPost">
-				{%if topic.last_post %}
+				{% if user.is_superuser %}
+					{% if topic.last_post %}
+						{{ topic.last_post.user|user_link }} <a href="{{ topic.last_post.get_absolute_url }}">&#187;</a><br />
+						<span class="small">on {{ topic.last_post.created|custom_date:user }}</span>
+					{% endif %}
+				{% else %}
+					{{ topic.last_unhided_post.user|user_link }} <a href="{{ topic.last_unhided_post.get_absolute_url }}">&#187;</a><br />
+					<span class="small">on {{ topic.last_unhided_post.created|custom_date:user }}</span>
+				{% endif %}
+			</td>
+		</tr>
+		{% elif user.is_superuser %}
+		<tr class="{% cycle 'odd' 'even' %}">
+			<td class="forumIcon center">
+				{% if topic|pybb_has_unreads:user %}
+				<img src="{{ MEDIA_URL }}forum/img/doc_big_work_star.png" style="margin: 0px;" alt="" class="middle" />
+				{% else %}
+					<img src="{{ MEDIA_URL }}forum/img/doc_big_work.png" style="margin: 0px;" alt="" class="middle" />
+				{% endif %}
+			</td>
+			<td class="forumTitle">
+				{% if topic.sticky %}<img src="{{ MEDIA_URL }}forum/img/sticky.png" alt="Sticky" title="Sticky" />{% endif %}
+				{% if topic.closed %}<img src="{{ MEDIA_URL }}forum/img/closed.png" alt="Closed" title="Closed" />{% endif %}
+				<a href="{{ topic.get_absolute_url }}">{{ topic.name }}</a><br />
+				<span class="small">Created by {{ topic.user|user_link }} on {{ topic.created|custom_date:user }}</span>
+			</td>
+			<td class="forumCount center small" style="width: 120px;">
+				Posts: {{ topic.post_count }}<br/>
+				Views: {{ topic.views }}
+			</td>
+			<td class="lastPost">
 				{{ topic.last_post.user|user_link }} <a href="{{ topic.last_post.get_absolute_url }}">&#187;</a><br />
 				<span class="small">on {{ topic.last_post.created|custom_date:user }}</span>
-				{% endif %}
 			</td>
 		</tr>
-	{% endfor %}
+		{% endif %} {# topic.is_hided #}
+		{% endfor %} {# topic #}
 		</tbody>
 	</table>
 

=== modified file 'templates/pybb/inlines/display_category.html'
--- templates/pybb/inlines/display_category.html	2016-03-02 21:02:38 +0000
+++ templates/pybb/inlines/display_category.html	2016-10-06 17:53:22 +0000
@@ -29,13 +29,22 @@
 			Topics: {{ forum.topics.count }}<br/>
 			Posts: {{ forum.posts.count }}
 		</td>
-		<td class="lastPost">
-		{%if forum.last_post %}
-			<a href="{{forum.last_post.get_absolute_url}}">{{ forum.last_post.topic.name }}</a><br />
-			<span class="small">by {{ forum.last_post.user|user_link }}<br />
-			on {{ forum.last_post.created|custom_date:user}}</span>
-		{% else %}
-			&nbsp;
+		{% if user.is_superuser %} {# Show all to superuser #}
+			{% if forum.last_post %}
+			<td class="lastPost">
+				<a href="{{forum.last_post.get_absolute_url}}">{{ forum.last_post.topic.name }}</a><br />
+				<span class="small">by {{ forum.last_post.user|user_link }}<br />
+				on {{ forum.last_post.created|custom_date:user}}</span>
+			</td>
+			{% endif %}
+		{% else %} {# no super_user: Show only unhided posts#}
+			{% if forum.last_unhided_post %}
+			<td class="lastPost">
+				<a href="{{forum.last_unhided_post.get_absolute_url}}">{{ forum.last_unhided_post.topic.name }}</a><br />
+				<span class="small">by {{ forum.last_unhided_post.user|user_link }}<br />
+				on {{ forum.last_unhided_post.created|custom_date:user}}</span>
+			</td>
+			{% endif %}
 		{% endif %}
 		</td>
 	</tr>

=== modified file 'templates/pybb/last_posts.html'
--- templates/pybb/last_posts.html	2016-03-02 21:02:38 +0000
+++ templates/pybb/last_posts.html	2016-10-06 17:53:22 +0000
@@ -9,11 +9,13 @@
 	<div class="columnModuleBox">
 		<ul>
 			{% for post in posts %}
-			<li>
-				{{ post.topic.forum.name }}<br />
-				<a href="{{ post.get_absolute_url }}" title="{{ post.topic.name }}">{{ post.topic.name|pybb_cut_string:30 }}</a><br />
-				by <a href="{% url 'profile_view' post.user %}">{{post.user.username}}</a> {{ post.created|minutes }} ago
-			</li>
+				{% if not post.hided %}
+				<li>
+					{{ post.topic.forum.name }}<br />
+					<a href="{{ post.get_absolute_url }}" title="{{ post.topic.name }}">{{ post.topic.name|pybb_cut_string:30 }}</a><br />
+					by <a href="{% url 'profile_view' post.user %}">{{post.user.username}}</a> {{ post.created|minutes }} ago
+				</li>
+				{% endif %}
 			{% endfor %}
 		</ul>
 	</div>

=== added file 'templates/pybb/pybb_moderate_info.html'
--- templates/pybb/pybb_moderate_info.html	1970-01-01 00:00:00 +0000
+++ templates/pybb/pybb_moderate_info.html	2016-10-06 17:53:22 +0000
@@ -0,0 +1,12 @@
+{% extends 'pybb/base.html' %}
+
+{% block content %}
+
+<h1>Your comment has to be moderated</h1>
+
+<div class="blogEntry">
+	<p>Your comment is saved but hided to normal users. As soon as possible a
+	moderator takes a look at it and unhide it.</p>
+</div>
+	
+{% endblock %}

=== modified file 'templates/pybb/topic.html'
--- templates/pybb/topic.html	2016-07-31 08:44:48 +0000
+++ templates/pybb/topic.html	2016-10-06 17:53:22 +0000
@@ -157,6 +157,7 @@
 	<table class="forum">
 		<tbody>
 	{% for post in posts %}
+		{% if not post.hided or user.is_superuser %}
 		<tr class="{% cycle 'odd' 'even' %}">
 			<td class="author">
 				{{ post.user|user_link }}<br />
@@ -228,6 +229,7 @@
 				{% endif %}
 			</td>
 		</tr>
+		{% endif %}
 		<tr class="spacer">
 			<td></td>
 			<td></td>


Follow ups