Syntax Highlighting, ReST, Pygments, and Django

Some of you regulars out there may have noticed an interesting change in the presentation of some of my articles: source code highlighting. I've been interested in doing this for quite some time, I just never really got around to implementing it until last night.

I found this implementation process to be a bit more complicatd than I had anticipated. For my own benefit as well as for anyone else who wants to do the same thing, I thought I'd document my findings in a thorough article for how to add syntax highlighting to an existing Django- and reStructuredText-powered Web site.

The power behind the syntax highlighting is:

Python is a huge player in this feature because reStructuredText (ReST) was built for Python, Pygments is the source highlighter (written in Python), and Django is written in Python (and my site is powered by Django). Some of you may recall that I converted all of my articles to ReST not too long ago because it suited my needs better than Textile, my previous markup processor. At the time, I was not aware that the conversion to ReST would make it all the easier for me to implement the syntax highlighting, but last night I figured out that that conversion probably saved me a lot of frustration. Cascading Stylesheets (CSS) are responsible for making the source code actually look good, while Pygments takes care of assigning classes to various parts of the designated source code and generating the CSS.

So, the first set of requirements, which I will not document in this article, are that you already have a Django site up and running and that you're familiar with ReST syntax. If you have the django.contrib.flatpages application installed already, you can type up some ReST documents there and apply the concepts discussed in this article.

Next, you should ensure that you have Pygments installed. There are a variety of ways to install this. Perhaps the easiest and most platform-independent method is to use easy_install:

$ easy_install pygments

This command should work essentially the same on Windows, Linux, and Macintosh computers. If you don't have it installed, you can get it from its website. If you're using a Debian-based distribution of Linux, such as Ubuntu, you could do something like this:

$ sudo apt-get install python-pygments

...and it should take care of downloading and installing Pygments. Alternatively, you can download it straight from the PyPI page and install it manually.

Now we need to install the Pygments ReST directive. A ReST directive is basically like a special command to the ReST processor. I think this part was the most difficult aspect of the implementation, simply because I didn't know where to find the Pygments directive or how to write my own. Eventually, I ended up downloading the Pygments-1.0.tar.gz file from PyPI, opening the Pygments-1.0/external/rst-directive.py file from the archive, and copying the stuff in there into a new file within my site.

For my own purposes, I made some small adjustments to the directive over what come with the Pygments distribution. I think it would save us all a lot of hassle if I just copied and pasted the directive, as I currently have it, so you can see it first-hand.

"""
    The Pygments reStructuredText directive
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    This fragment is a Docutils_ 0.4 directive that renders source code
    (to HTML only, currently) via Pygments.

    To use it, adjust the options below and copy the code into a module
    that you import on initialization.  The code then automatically
    registers a ``code-block`` directive that you can use instead of
    normal code blocks like this::

    .. code:: python

            My code goes here.

    If you want to have different code styles, e.g. one with line numbers
    and one without, add formatters with their names in the VARIANTS dict
    below.  You can invoke them instead of the DEFAULT one by using a
    directive option::

    .. code:: python
       :number-lines:

            My code goes here.

    Look at the `directive documentation`_ to get all the gory details.

    .. _Docutils: http://docutils.sf.net/
    .. _directive documentation:
       http://docutils.sourceforge.net/docs/howto/rst-directives.html

    :copyright: 2007 by Georg Brandl.
    :license: BSD, see LICENSE for more details.
"""

# Options
# ~~~~~~~

# Set to True if you want inline CSS styles instead of classes
INLINESTYLES = False

from pygments.formatters import HtmlFormatter

# The default formatter
DEFAULT = HtmlFormatter(noclasses=INLINESTYLES)

# Add name -> formatter pairs for every variant you want to use
VARIANTS = {
    'linenos': HtmlFormatter(noclasses=INLINESTYLES, linenos=True),
}


from docutils import nodes
from docutils.parsers.rst import directives

from pygments import highlight
from pygments.lexers import get_lexer_by_name, TextLexer

def pygments_directive(name, arguments, options, content, lineno,
                       content_offset, block_text, state, state_machine):
    try:
        lexer = get_lexer_by_name(arguments[0])
    except ValueError:
        # no lexer found - use the text one instead of an exception
        lexer = TextLexer()
    # take an arbitrary option if more than one is given
    formatter = options and VARIANTS[options.keys()[0]] or DEFAULT
    parsed = highlight(u'\n'.join(content), lexer, formatter)
    parsed = '<div class="codeblock">%s</div>' % parsed
    return [nodes.raw('', parsed, format='html')]

pygments_directive.arguments = (1, 0, 1)
pygments_directive.content = 1
pygments_directive.options = dict([(key, directives.flag) for key in VARIANTS])

directives.register_directive('code-block', pygments_directive)

I won't explain what that code means, because, quite frankly, I'm still a little hazy on the inner workings of ReST directives myself. Suffice it to say that this snippet allows you to easily highlight blocks of code on ReST-powered pages.

The question now is: where do I put this snippet? As far as I'm aware, this code can be located anywhere so long as it is loaded at one point or another before you start your ReST processing. For the sake of simplicity, I just stuffed it in the __init__.py file of my Django site. This is the __init__.py file that lives in the same directory as manage.py and settings.py. Putting it in that file just makes sure it's loaded each time you start your Django site.

To make Pygments highlight a block of code, all you need to do is something like this:

.. code:: python

    print 'Hello world!'

...which would look like...

print 'Hello world!'

If you have a longer block of code and would like line numbers, use the :number-lines: option:

.. code:: python
    :number-lines:

    for i in range(100):
        print i

...which should look like this...

for i in range(100):
    print i

That's all fine and dandy, but it probably doesn't look like the code is highlighted at all just yet (on your site, not mine). It's just been marked up by Pygments to have some pretty CSS styles applied to it. But how do you know which styles mean what?

Luckily enough, Pygments takes care of generating the CSS files for you as well. There are several attractive styles that come with Pygments. I would recommend going to the Pygments demo to see which one suits you best. You can also roll your own styles, but I haven't braved that yet so I'll leave that for another day.

Once you choose a style (I chose native for Code Koala), you can run the following commands:

$ pygmentize -S native -f html > native.css
$ cp native.css /path/to/site/media/css

(obviously, you'd want to replace native with the name of the style you like the most) Finally, add a line to your HTML templates to load the newly created CSS file. In my case, it's something like this:

<link rel="stylesheet" type="text/css" href="/static/styles/native.css" />

Now you should be able to see nicely-formatted source code on your Web pages (assuming you've already got ReST processing your content).

If you haven't been using ReST to generate nicely-formatted pages, you should make sure a couple of things are in place. First, you must have the django.contrib.markup application installed. Second, your templates should be setup to process ReST markup into HTML. Here's a sample templates/flatpages/default.html:

{% extends 'base.html' %}
{% load markup %}

{% block title %}{{ flatpage.title }}{% endblock %}

{% block content %}
<h2>{{ flatpage.title }}</h2>

{{ flatpage.content|restructuredtext }}
{% endblock %}

So that short template should allow you to use ReST markup for your flatpages, and it should also take care of the magic behind the .. code:: python directive.

I should also note that Pygments can handle a TON of languages. Check out the Pygments demo for a list of languages it knows how to highlight.

I think that about does it. Hopefully this article will help some other poor chap who is currently in the same situation as I was last night, and hopefully it will save you a lot more time than it took me to figure out all this junk. If it looks like I've missed something, or maybe that something needs further clarification, please comment and I'll see what I can do.

Installing Python 3.0 Alongside an Existing Python

With the recent release of Python 3.0 final, I've had a crazy itch that needed to be scratched. That itch, my friends, was to do a write-up of how to install Python 3.0 alongside my existing Python 2.5.2 installation without borking things up. The reason I thought it would be useful is that I'm running a Debian-based distribution of Linux called sidux right now, and neither Python 2.6 nor Python 3.0 are in the package repositories. I assume that Ubuntu and other Debian-based distributions might be the same way, and that there are others like me who would like to tinker with these new releases.

Just before attempting to install Python 3.0 on my computer, I started getting ready to write this article. Before I knew it, Python 3.0 was installed on my system, and I had no notes to share with you! That is how stinkin easy it is to install Python 3.0 without interfering with an existing install. I mentioned to a good friend that I wasn't sure the process was worth writing an article because it was so simple, but he encouraged me to carry on. Thanks bro.

So, without any further ado, here is what I did to install Python 3.0 from source alongside my Python 2.5 installation:

Note: If you're using a Mac or Windows, you should be able to simply install the packages for your platform to accomplish this same feat. Once the packages are in the repositories it will be just as easy for Linux.

$ wget http://python.org/ftp/python/3.0/Python-3.0.tar.bz2
  • Unpack the archive:
$ tar jxf Python-3.0.tar.bz2
  • Descend into the newly extracted Python-3.0 directory:
$ cd Python-3.0
  • Install libreadline-dev. This step is necessary for the arrow keys to work, as pointed out by jazevec below in the comments. If you are on a Debian-based system, you can execute a command such as this:
  $ sudo apt-get install libreadline-dev

Other distributions may have different package names, such as ``readline-dev``.  If neither one of those package names work for your distribution, try searching your package manager for ``readline`` and install the development files.  Alternatively, you should be able to manually install what you need by installing `readline itself <http://directory.fsf.org/project/readline/>`_.
  • Configure Python 3.0 for your computer:
$ ./configure
  • Compile Python 3.0:
  $ make


**UPDATE** (9 Dec): Depending on your setup, you may or may not see a message such as this after executing the ``make`` command (thanks again to ``jazevec`` for pointing out that this can happen)::

  Failed to find the necessary bits to build these modules:
  _dbm               _gdbm              _hashlib
  _sqlite3           _ssl               _tkinter
  bz2                zlib
  To find the necessary bits, look in setup.py in detect_modules() for the module's name.

If you need any of those capabilities, you should install the appropriate development files for the missing module(s).  For example, above, we installed the ``libreadline-dev`` package.  To resolve the missing module problem for each one listed above (except ``_dbm`` because it's apparently borked on Debian right now... possibly other distros too), install these packages:

  * ``tk-dev`` to satisfy ``_tkinter``
  * ``libsqlite3-dev`` to satisfy ``_sqlite3``
  * ``libbz2-dev`` to satisfy ``bz2``
  * ``zlib1g-dev`` to satisfy ``zlib``
  * ``libssl-dev`` to satisfy ``_ssl`` and ``_hashlib``
  * ``libgdbm-dev`` to satisfy ``_gdbm``
  • Install Python 3.0:
  $ sudo make install

or:
# make install
  • Test Python 3.0:
$ python3.0
Python 3.0 (r30:67503, Dec  5 2008, 11:05:45)
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print 'Hi'
File "<stdin>", line 1
    print 'Hi'
            ^
SyntaxError: invalid syntax
>>> print('Hi')
Hi
>>>
  • Make sure that your old version of Python is still around:
$ python
Python 2.5.2 (r252:60911, Sep 29 2008, 21:15:13)
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print 'Hi'
Hi
>>>
  • Rejoice

That's about it folks! Extremely simple and fast, compared to what it could have been.

If you find yourself in a situation where you don't have access to sudo or straight root-level access, you can install Python 3.0 locally by doing something like this:

  • Configure Python 3.0 for your computer:
$ ./configure --prefix=$HOME/local/
  • Compile Python 3.0:
$ make
  • Install Python 3.0:
  $ make install

Not that I omitted the ``sudo`` part of the command here.
  • Symlink to Python 3.0, assuming you have a bin/ directory in your home directory (i.e. /home/[yourusername]/bin), and that said bin directory is on your PATH:
$ ln -s ~/local/bin/python3.0 ~/bin
  • Test your locally installed Python 3.0:
  $ python3.0

or, if your local ``bin`` directory isn't on your ``PATH``:
$ ~/bin/python3.0
  • Do the dance.

Please comment with any problems you find with this process, or any additional advice you can offer to newbies!

Project Release: django-watermark 0.1.0-pre1

I've found myself in many situations where I have several images that need a watermark applied to them. Applying a watermark to more than 5 images at a time is annoying at best, even if you do have macros to do the mundane stuff for you. I don't like to do things that annoy me.

Recently, I found myself yet again confronted with a "please watermark these images" sort of situation, and I decided to take a more logical approach to the problem: program it. The result of my efforts is called django-watermark and is available on Google Code and PyPI. To be perfectly honest, I actually ganked most of the useful code for this application from a generous soul on the Internet.

This seems to be working fine for me. I think the positioning for watermarks might need more work, but there are several options to hold people over for the time being. Please let me know what your thoughts are.

Project Release: django-reploc 0.1.0-pre1

Here's yet another application to help you make your site more useful to your users. django-reploc is a "representative locator" for Django-powered Web sites. It uses the Google Maps API to offer your users an interactive map of your representatives, vendors, friends, houses, etc.

I built this application to be a dealer locator for one of my clients. The application provides a way for you to create "representatives," and each representative may have one or more locations. For example, say you are a producer of clothing and apparel, ranging from shoes to pants to t-shirts to sweaters to hats to bags and so on. Perhaps your bigger representatives (or vendors) carry your products in all of their retail branches. reploc gives you a way to display each of these locations for the one vendor on a map for your users.

In addition to that, while the bigger vendors might carry your products in all locations, perhaps some locations only carry particular lines of your products. For example, a vendor location in Miami, Florida might carry a good deal of your sandals and none of your sweatshirts, while a vendor location in Bangor, Maine might not bother with any sandals but keeps sweatshirts in stock year-round. reploc offers a way for you to describe which product lines each location carries by the use of "attributes".

However, it can be used for much more than just that. Pretty much any location that you can show on Google Maps (is there anything that can't be shown on Google Maps anymore?) can be displayed with this application.

Furthermore, you can search for locations within a certain radius of an address that your users specify! A nice circle is drawn on the map, making it visually easier to understand what is and isn't within range. To make things even easier, the locations that do not fall within the radius of the given address are hidden from the map.

Finally, once a user finds a location within the radius of the address they specify, they are able to get driving directions to help them get right where they need to go!

w00t!

To learn more, go to the project page: http://code.google.com/p/django-reploc/

Downtime...

As some of you may have noticed, my Web host is having brain farts all over the place lately. None of my sites are very usable thanks to the poor quality of service and support on the part of my host right now. The problems seem to have begun around noon on Friday, September 19th. The symptoms include random HTTP 500 (internal server error) messages or extremely long load times.

I'm in the process of switching to a host that is more reliable. This new host is perhaps one of the best in the industry according to all of the reviews that I've read. Let's hope I have better luck there.

Project Release: Seasonal Stylesheets

The other day at work I was involved in a humorous discussion about having our organization's Web site change colors depending on what day of the year it was. We threw around all sorts of fun ideas, knowing full well that it would never happen for our organization. It would be too unprofessional.

That night my allergies were bothering me to the point where I couldn't sleep, so I decided to see what I could do about making our discussion more possible, at least for others who can take a little more creative license than us. By morning, I had a working application that could effectively change the colors on a Web page depending on the date.

Today I released the source code on Google Code, hoping that someone more creative than me might take it and experiment to make something both attractive and useful.

You can learn more at the project's homepage: http://code.google.com/p/django-seasonal-stylesheets/

Installing Django on Shared Hosting (Site5)

This article is a related to my previously posted article about installing Django, an advanced Web framework for perfectionists, on your own computer. Now we will learn how to install Django on a shared hosting account, using Site5 and fastcgi as an example. Depending on your host, you may or may not have to request additional privileges from the support team in order to execute some of these commands.

Note: Django requires at least Python 2.3. Newer versions of Python are preferred.

Note: This HOWTO assumes familiarity with the UNIX/Linux command line.

Note: If the wget command doesn't work for you (as in you don't have permission to run it), you might try curl [url] -O instead. That's a -O as in upper-case o.

Install Python

Site5 (and many other shared hosting providers that offer SSH access) already has Python installed, but you will want to have your own copy so you can install various tools without affecting other users. So go ahead and download virtual python:

mkdir ~/downloads
cd ~/downloads
wget http://peak.telecommunity.com/dist/virtual-python.py

Virtual Python will make a local copy of the installed Python in your home directory. Now you want to make sure you execute this next command with the newest version of Python available on your host. For example, Site5 offers both Python 2.3.4 and Python 2.4.3. We want to use Python 2.4.3. To verify the version of your Python, execute the following command:

python -V

If that displays Python 2.3.x or anything earlier, try using python2.4 -V or python2.5 -V instead. Whichever command renders the most recent version of Python is the one you should use in place of python in the next command. Since python -V currently displays Python 2.4.3 on my Site5 sandbox, I will execute the following command:

python ~/downloads/virtual-python.py

Again, this is just making a local copy of the Python installation that you used to run the virtual-python.py script. Your local installation is likely in ~/lib/python2.4/ (version could vary).

Make Your Local Python Be Default

To reduce confusion and hassle, let's give our new local installation of Python precedence over the system-wide Python. To do that, open up your ~/.bashrc and make sure it contains a line similar to this:

export PATH=$HOME/bin:$PATH

If you're unfamiliar with UNIX-based text editors such as vi, here is what you would type to use vi to make the appropriate changes:

  • vi ~/.bashrc to edit the file
  • go to the end of the file by using the down arrow key or the j key
  • hit o (the letter) to tell vi you want to start typing stuff on the next line
  • type export PATH=$HOME/bin:$PATH
  • hit the escape key
  • type :x to save the changes and quit. Don't forget the : at the beginning. Alternatively, you can type :wq, which works exactly the same as :x.

Once you've made the appropriate changes to ~/.bashrc, you need to make those changes take effect in your current SSH session:

source ~/.bashrc

Now we should verify that our changes actually took place. Type the following command:

which python

If they output of that command is not something like ~/bin/python or /home/[your username]/bin/python, something probably didn't work. If that's the case, you can try again, or simply remember to use ~/bin/python instead of python throughout the rest of this HOWTO.

Install Python's setuptools

Now we should install Python's setuptools to make our lives easier down the road.

cd ~/downloads
wget http://peak.telecommunity.com/dist/ez_setup.py
python ez_setup.py

This gives us access to a script called easy_install, which makes it easy to install many useful Python tools. We will use this a bit later.

Download Django

Let's now download the most recent development version of Django. SSH into your account and execute the following commands (all commands shall be executed on your host).

svn co http://code.djangoproject.com/svn/django/trunk ~/downloads/django-trunk

Now we should make a symlink (or shortcut) to Django and put it somewhere on the Python Path. A sure-fire place is your ~/lib/python2.4/site-packages/ directory (again, that location could vary from host to host):

ln -s ~/downloads/django-trunk/django ~/lib/python2.4/site-packages
ln -s ~/downloads/django-trunk/django/bin/django-admin.py ~/bin

Now verify that Django is installed and working by executing the following command:

python -c "import django; print django.get_version()"

That command should return something like 1.0-final-SVN-8964. If you got something like that, you're good to move onto the next section. If, however, you get something more along the lines of...

Traceback (most recent call last):
    File "<string>", line 1, in ?
ImportError: No module named django

...then your Django installation didn't work. If this is the case, make sure that you have a ~/downloads/django-trunk/django directory, and also verify that ~/lib/python2.4/site-packages actually exists.

Installing Dependencies

In order for your Django projects to become useful, we need to install some other packages: PIL (Python Imaging Library, required if you want to use Django's ImageField), MySQL-python (a MySQL database driver for Python), and flup (a utility for fastcgi-powered sites).

easy_install -f http://www.pythonware.com/products/pil/ Imaging
easy_install mysql-python
easy_install flup

Sometimes, using easy_install to install PIL doesn't go over too well because of your (lack of) permissions. To circumvent this situation, you can always download the actual PIL source code and install it manually.

cd ~/downloads
wget http://effbot.org/downloads/Imaging-1.1.6.tar.gz
tar zxf Imaging-1.1.6.tar.gz
cd Imaging-1.1.6
ln -s ~/downloads/Imaging-1.1.6/PIL ~/lib/python2.4/site-packages

And to verify, you can try this command:

python -c "import PIL"

If that doesn't return anything, you're good to go. If it says something about "ImportError: No module named PIL", it didn't work. In that case, you have to come up with some other way of installing PIL.

Setting Up A Django Project

Let's attempt to setup a sample Django project.

mkdir -p ~/projects/django
cd ~/projects/django
django-admin.py startproject mysite
cd mysite
mkdir media templates

If that works, then you should be good to do the rest of your Django development on your server. If not, make sure that ~/downloads/django-trunk/django/bin/django-admin.py exists and that it has a functioning symlink (shortcut) in ~/bin. If not, you'll have to make adjustments according to your setup. Your directory structure should look something like:

  • projects
    • django
      • mysite
        • media
        • templates
        • __init__.py
        • manage.py
        • settings.py
        • urls.py

Making A Django Project Live

Now we need to make your Django project accessible from the Web. On Site5, I generally use either a subdomain or a brand new domain when setting up a Django project. If you plan on having other projects accessible on the same hosting account, I recommend you do the same. Let's assume you setup a subdomain such as mysite.mydomain.com. On Site5, you would go to ~/public_html/mysite for the next few commands. This could differ from host to host, so I won't go into much more detail than that.

Once you're in the proper place, you need to setup a few things: two symlinks, a django.fcgi, and a custom .htaccess file. Let's begin with the symlinks.

ln -s ~/projects/django/mysite/media ~/public_html/mysite/static
ln -s ~/lib/python2.4/site-packages/django/contrib/admin/media ~/public_html/mysite/media

This just makes it so you can have your media files (CSS, images, javascripts, etc) in a different location than in your public_html.

Now for the django.fcgi. This file is what tells the webserver to execute your Django project.

#!/home/[your username]/bin/python
import sys, os

# Add a custom Python path.
sys.path.insert(0, "/home/[your username]/projects/django")

# Switch to the directory of your project. (Optional.)
os.chdir("/home/[your username]/projects/django/mysite")

# Set the DJANGO_SETTINGS_MODULE environment variable.
os.environ['DJANGO_SETTINGS_MODULE'] = "mysite.settings"

from django.core.servers.fastcgi import runfastcgi
runfastcgi(method="threaded", daemonize="false")

And finally, the .htaccess file:

1
2
3
4
5
6
RewriteEngine On
RewriteBase /
RewriteRule ^(media/.*)$ - [L]
RewriteRule ^(static/.*)$ - [L]
RewriteCond %{REQUEST_URI} !(django.fcgi)
RewriteRule ^(.*)$ django.fcgi/$1 [L]

The .htaccess file makes it so that requests to http://mysite.mydomain.com/ are properly directed to your Django project. So, now you should have a directory structure that something that looks like this:

  • public_html
    • mysite
      • media
      • static
      • .htaccess
      • django.fcgi

If that looks good, go ahead and make the django.fcgi executable and non-writable by others:

chmod 755 ~/public_html/mysite/django.fcgi

After that, head over to http://mysite.mydomain.com/ (obviously, replace the mydomain accordingly). If you see a page that says you've successfully setup your Django site, you're good to go!

Afterthoughts

I've noticed that I need to "restart" my Django sites on Site5 any time I change the .py files. There are a couple methods of doing this. One includes killing off all of your python processes (killall ~/bin/python) and the other simply updates the timestamp on your django.fcgi (touch ~/public_html/mysite/django.fcgi). I find the former to be more destructive and unreliable than the latter. So, my advice is to use the touch method unless it doesn't work, in which case you can try the killall method.

Good luck!

Django 1.0 Final!!

That's right folks! The amazing Django team has announced the immediate availability of Django 1.0 final!

This release is perhaps one of the most highly anticipated events in the Python community. More than three years in the making, the Django Web framework is something that perfectionist developers love and enjoy using. I've been using it for just over a year now, and I can't even remember doing things any other way! It's absolutely amazing!!!

So go ahead and download and install it today! What are you waiting for?!

My First Firefox Extension

Last November, a former co-worker and I began brainstorming for a particular site. This site was intended to give people a way to remember quotes that they heard/read/smelled/absorbed/etc without much effort. Soon thereafter, QuoteBoards.org was born.

The site has been pretty boring until recently, though it has been performing its purpose since its first launch. Up until a couple weeks ago, we only had one truly "faithful" member. This member, dirid51, added quotes to his QuoteBoard regularly. He held the site record of 52 quotes until one day another member (Puck) blew is 52 quotes out of the water with nearly 150 (genuine, I might add) quotes in one day.

I got in touch with Puck, and he shared some invaluable feedback with me concerning QuoteBoards.org. With this feedback, I was able to make several improvements that helped Puck along the way as he added his collection of quotes. Currently, he as 1,002 quotes. Most of these were added within a two or three day window. The reason he's stopped adding quotes is because he's tired of transcribing them from printed documents.

With that in mind, I decided it was finally time to begin working on the Firefox extension that I had originally planned to build for QuoteBoards.org when my co-worker and I were initially brainstorming. The purpose of this extension was to make adding quotes from the Web even easier. So, with a few minutes here and there between laundry and such, I was able to build my very first Firefox extension: Quote Grabber.

Right now, the extension is marked as "experimental" and requires people to log into the Mozilla Add-ons site in order to install and use it. However, if you're feeling adventurous, you can bypass that requirement by installing it directly from QuoteBoards.org. There are also directions for using it there.

I hope that those of you who are reading this find the extension to be beneficial and useful. I had a good time developing it nonetheless.

Project Release: django-tracking 0.1

I'm proud to announce the official release of yet another one of my side projects. I call it django-tracking, and it is a simple project capable of telling you how many users are currently on your site. If you look at the bottom of any page on codekoala.com, you will see a demonstration of what this project can be used for.

django-tracking also offers basic blacklisting capabilities. I had a chap who apparently setup a script to spam my blog with rubbish comments every 11 minutes recently. I devised a way to stop the comments from being posted, but I noticed from my logs that the script was still hitting my website consistently over the following days. As a result, I implemented the "Banned IP" feature in django-tracking, and any visitor (or script) accessing my site from that IP address receives an error page. Yay!

If you have "Big Brother"-like tendencies when it comes to your visitors, there is also a way for you to have a "live feed" of active users on your site. Works pretty well, if I do say so myself :)

For more information, hop on over to django-tracking's homepage. There you will also find installation instructions and details for configuration and usage.

Have fun!