4ac1bf2cbaa2

Add the project content.
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Wed, 23 Dec 2009 20:59:20 -0500
parents cf38a58b1927
children 8a15a71f3376
branches/tags (none)
files content/projects/django-hoptoad.html content/projects/fuego.html content/projects/grabtweets.html content/projects/hg-paste.html content/projects/hg-prompt.html content/projects/hgtab.html content/projects/index.html content/projects/lindyjam-com.html content/projects/stevelosh-com.html content/projects/t.html content/projects/women-in-water.html

Changes

--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/content/projects/django-hoptoad.html	Wed Dec 23 20:59:20 2009 -0500
@@ -0,0 +1,211 @@
+{% extends "_post.html" %}
+
+{% hyde
+    title: "django-hoptoad"
+    snip: "Now ponies can ride the toad too."
+    created: 2009-07-25 01:16:40
+%}
+
+{% block article %}
+
+django-hoptoad is some simple Middleware for letting [Django][]-driven
+websites report their errors to [Hoptoad][]. Now [ponies][] can ride the toad
+too.
+
+You can get it from [the repository on BitBucket][repo].
+
+[Django]: http://djangoproject.com/
+[Hoptoad]: http://hoptoadapp.com/
+[ponies]: http://djangopony.com/
+[repo]: http://bitbucket.org/sjl/django-hoptoad/
+
+[TOC]
+
+Requirements
+------------
+
+django-hoptoad requires:
+
+* [Python][] 2.5+ (preferably 2.6+ as that's what I've tested it with)
+* [PyYAML][] (`pip install pyyaml` or `easy_install pyyaml`)
+* [Django][] 1.0+
+* A [Hoptoad][] account
+
+[Python]: http://python.org/
+[PyYAML]: http://pyyaml.org/
+
+Installation
+------------
+
+Grab the the django-hoptoad code by cloning the [Mercurial][] repository (or
+just [download the latest version][tip-dl] and unzip it somewhere):
+
+    hg clone http://bitbucket.org/sjl/django-hoptoad/
+
+There's a git mirror too if you *really* want it.
+
+    git clone git://github.com/sjl/django-hoptoad.git
+
+Once you download it, you can install it in the usual manner:
+
+    cd django-hoptoad
+    python setup.py install
+
+If you'd prefer to be able to update at any time by pulling down changes with
+Mercurial or git, you can symlink the module into your `site-packages`
+directory instead of using `python setup.py install`:
+
+    ln -s /full/path/to/django-hoptoad/hoptoad /full/path/to/site-packages/
+
+To make sure it works you can run:
+
+    python -c 'import hoptoad'
+
+[Mercurial]: http://mercurial.selenic.com/
+[tip-dl]: http://bitbucket.org/sjl/django-hoptoad/get/tip.zip
+
+Usage
+-----
+
+To set up a Django project to notify Hoptoad of its errors, you need to do two
+things in the `settings.py` file.
+
+First, add the `HoptoadNotifierMiddleware` as the last item in your
+`MIDDLEWARE_CLASSES` setting:
+
+    MIDDLEWARE_CLASSES = (
+        # ... other middleware classes ...
+        'hoptoad.middleware.HoptoadNotifierMiddleware',
+    )
+
+Next, you'll need to add a `HOPTOAD_API_KEY` setting. You can get the key from
+the Hoptoad project page.
+
+    HOPTOAD_API_KEY = 'Your Hoptoad API key.'
+
+Optional Settings
+-----------------
+
+There are a few extra things you can configure if you'd like to tweak the
+notification process a bit.
+
+### Notify Hoptoad While in DEBUG Mode
+
+By default the Middleware will **not** report errors to Hoptoad when your
+project is in `DEBUG` mode. The idea behind this is that if you can already
+see the error information right in the browser you probably don't need to see
+it in Hoptoad too. If you want to always notify Hoptoad of errors, even while
+in `DEBUG` mode, add the following setting:
+
+    HOPTOAD_NOTIFY_WHILE_DEBUG = True
+
+### Specify a Default Timeout
+
+The notification middleware will make sure the error notification gets to
+Hoptoad before the response gets sent back to the user. If it takes a while to
+contact Hoptoad the user will notice a delay.
+
+By default, the amount of time the notifier will wait before giving up is
+Python's "global default timeout setting". I have no idea what that is because
+the [documentation][urllib2docs] does not see fit to explain that to me.
+
+If you'd like to change that amount you can use the `HOPTOAD_TIMEOUT` setting.
+You **must** be running Python 2.6+ to use this.
+
+    HOPTOAD_TIMEOUT = 5
+
+The number is the number of seconds the notifier will wait before timing out.
+Yes, you can use a float like `0.5` to specify fractions of a second.
+
+[urllib2docs]: http://docs.python.org/library/urllib2.html
+
+### Track 404 Errors
+
+By default Hoptoad will **not** be notified of 404 (page not found) errors. If
+you'd like to change this you'll need to add the following setting:
+
+    HOPTOAD_NOTIFY_404 = True
+
+**IMPORTANT**: If you are using Django's `flatpages` app and want to track 404
+errors, you need to make sure the `FlatpageFallbackMiddleware` comes *after*
+the `HoptoadNotifierMiddleware`. If you don't do this Hoptoad will be notified
+of 404 errors even if the user actually sees a Flatpage.
+
+To track 404s while using the `flatpages` app your `MIDDLEWARE_CLASSES`
+setting should look like this:
+
+    MIDDLEWARE_CLASSES = (
+        # ... other middleware classes ...
+        'hoptoad.middleware.HoptoadNotifierMiddleware',
+        'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
+    )
+
+A couple of things to note:
+
+* If your website doesn't have a favicon specified most browsers will request it each time.  This will result in one (or possibly two, if it tries to append a slash) 404 errors for every page view.
+* At the moment all 404 errors are grouped together as "similar" errors in Hoptoad.  I am trying to figure out what causes this.
+
+### Track 403 Errors
+
+By default Hoptoad will **not** be notified of 403 (forbidden) errors. If
+you'd like to change this you'll need to add the following setting:
+
+    HOPTOAD_NOTIFY_403 = True
+
+Note:
+
+* At the moment all 403 errors are grouped together as "similar" errors in
+  Hoptoad. I am trying to figure out what causes this.
+
+### Ignore Specific User Agents
+
+If you'd like to ignore all errors from certain User Agents you can use the
+following setting:
+
+    HOPTOAD_IGNORE_AGENTS = ['MSIE 6.0', 'Trident']
+
+If any of the strings in the list appear *anywhere* in the User Agent string,
+Hoptoad will not be notified of the error.
+
+The strings are actually regular expressions, so you can be more specific if
+you like:
+
+    HOPTOAD_IGNORE_AGENTS = [r'^Mozilla.*compatible; MSIE \d+\.\d+.*$']
+
+One thing this is useful for (aside from hating on IE) is ignoring errors from
+web crawlers. Often bots will mangle URLs and if you're tracking 404 errors
+you'll see a *lot* of errors that you probably don't care about.
+
+This would probably be a good starting point for ignoring crawlers:
+
+    HOPTOAD_IGNORE_AGENTS = ['Googlebot', 'Yahoo! Slurp', 'YahooSeeker']
+
+Troubleshooting
+---------------
+
+If things don't go smoothly, the first thing to do is run the tests to see if
+they can determine what's wrong. To enable the tests you'll need to add
+django-hoptoad to your `INSTALLED_APPS` setting:
+
+    INSTALLED_APPS = (
+        # ... other apps ...
+        'hoptoad',
+        # ... other apps ...
+    )
+
+Once you've done that you can run the unit tests:
+
+    python manage.py test hoptoad
+
+**NOTE**: The unit tests are very simple at the moment. I'm working on more,
+but please feel free to submit ideas (or better yet: patches).
+
+Suggestions
+-----------
+
+This Middleware is a work in progress. If you have a suggestion or find a bug
+please [add an issue][issues] or post a comment and let me know.
+
+[issues]: http://bitbucket.org/sjl/django-hoptoad/issues/?status=new&status=open
+
+{% endblock %}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/content/projects/fuego.html	Wed Dec 23 20:59:20 2009 -0500
@@ -0,0 +1,22 @@
+{% extends "_post.html" %}
+
+{% hyde
+    title: "Fuego"
+    snip: "Photographs of Alex. Studio."
+    created: 2009-01-19 01:25:20
+%}
+
+{% block article %}
+
+<div class="gallery">
+	<img src="/site-media/storage/projects/2009-01-19-fuego/Fuego-4852.jpg" />
+	<img src="/site-media/storage/projects/2009-01-19-fuego/Fuego-4887.jpg" />
+	<img src="/site-media/storage/projects/2009-01-19-fuego/Fuego-4919.jpg" />
+	<img src="/site-media/storage/projects/2009-01-19-fuego/Fuego-4941.jpg" />
+	<img src="/site-media/storage/projects/2009-01-19-fuego/Fuego-4985.jpg" />
+	<img src="/site-media/storage/projects/2009-01-19-fuego/Fuego-5133.jpg" />
+</div>
+
+I really like how these turned out.  One of them is hanging in my apartment.
+
+{% endblock %}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/content/projects/grabtweets.html	Wed Dec 23 20:59:20 2009 -0500
@@ -0,0 +1,77 @@
+{% extends "_post.html" %}
+
+{% hyde
+    title: "grabtweets"
+    snip: "A simple tool for backing up your tweets."
+    created: 2009-09-12 11:02:46
+%}
+
+{% block article %}
+
+`grabtweets` is a simple tool to backup your tweets.
+
+The code is in a [Mercurial repository][repository] on [BitBucket][].
+
+[BitBucket]: http://bitbucket.org/
+
+[TOC]
+
+Installing
+----------
+
+`grabtweets` requires [Python][] 2.6 or later.
+
+To install it, you can [download][] the latest version, or clone the Mercurial
+repository:
+
+    hg clone http://bitbucket.org/sjl/grabtweets/
+
+You can put it anywhere you like.
+
+Using
+-----
+
+`grabtweets` can back up your tweets and print tweets that it has already
+archived.
+
+### Backing Up Tweets
+
+To back up your tweets, run `grabtweets` like this:
+
+    $ grabtweets.py -u USERNAME FILE
+
+`grabtweets` will pull down the 200 newest tweets from USERNAME and store them in FILE.
+
+You probably have more than 200 tweets. However, Twitter will only let you
+pull down 200 at a time and hitting the server too fast will result in Twitter
+cutting off your access for a while.
+
+To deal with this, it's best to set up `grabtweets` as a cron/launchd job that
+runs every couple of hours. Each time it runs, it will pull down the newest
+200 tweets, plus 200 older tweets if there are any available.
+
+It will take about `NUMBER_OF_TWEETS_YOU_HAVE/200` runs to finish archiving
+your tweets. Just set it up and forget about it.
+
+### Printing Backed Up Tweets
+
+To print the tweets that `grabtweets` has already backed up, run it like this:
+
+    $ grabtweets.py -p FILE
+
+[Python]: http://python.org/
+[download]: http://bitbucket.org/sjl/grabtweets/get/tip.zip
+
+Problems, Contributing, etc
+---------------------------
+
+`grabtweets` was hacked together in an hour. There are probably bugs. If you
+find any, go ahead and create an issue in the [issue tracker][].
+
+Want to fix something or add a feature? Great! Fork the [repository][] and
+send me a pull request.
+
+[issue tracker]: http://bitbucket.org/sjl/grabtweets/issues/?status=new&status=open
+[repository]: http://bitbucket.org/sjl/grabtweets/
+
+{% endblock %}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/content/projects/hg-paste.html	Wed Dec 23 20:59:20 2009 -0500
@@ -0,0 +1,73 @@
+{% extends "_post.html" %}
+
+{% hyde
+    title: "hg-paste"
+    snip: "Send diffs from Mercurial to various pastebin websites."
+    created: 2009-09-16 17:52:55
+%}
+
+{% block article %}
+
+hg-paste adds an `hg paste` command to Mercurial which can send diffs to
+various pastebin websites for easy sharing. You can grab the code from the
+[repository][] on BitBucket.
+
+It was inspired by [Pocoo][]'s [hgpaste][pocoopaste] extension, but is
+designed to work with public pastebin websites instead of private
+installations of [LodgeIt][].
+
+[Pocoo]: http://www.pocoo.org/
+[pocoopaste]: http://dev.pocoo.org/hg/hgpaste/
+[LodgeIt]: http://dev.pocoo.org/projects/lodgeit/
+
+[TOC]
+
+Installing
+----------
+
+Clone the repository:
+
+    hg clone http://bitbucket.org/sjl/hg-paste/
+
+Edit the `[extensions]` section in your `~/.hgrc` file:
+
+    [extensions]
+    paste = (path to)/hg-paste/paste.py
+
+Using the Command
+-----------------
+
+To paste a diff of all uncommitted changes in the working directory:
+
+    hg paste
+
+To paste the changes that revision `REV` made:
+
+    hg paste -r REV
+
+To paste the changes between revisions `REV1` and `REV2`:
+
+    hg paste -r REV1:REV2
+
+If any files are specified only those files will be included in the diffs.
+
+Several options can be used to specify more metadata about the paste:
+
+    hg paste --user Steve --title 'Progress on feature X' --keep
+
+The pastebin website to use can be specified with `--dest`. Currently only
+[dpaste.com](http://dpaste.com/) and [dpaste.org](http://dpaste.org) are
+supported.
+
+Questions, Comments, Suggestions
+--------------------------------
+
+If you find any bugs, please create an issue in the [issue tracker][issues].
+
+If you want to contribute (support for more pastebin websites would be great),
+fork the [repository][] on BitBucket and send a pull request.
+
+[issues]: http://bitbucket.org/sjl/hg-paste/issues/?status=new&status=open
+[repository]: http://bitbucket.org/sjl/hg-paste
+
+{% endblock %}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/content/projects/hg-prompt.html	Wed Dec 23 20:59:20 2009 -0500
@@ -0,0 +1,167 @@
+{% extends "_post.html" %}
+
+{% hyde
+    title: "hg-prompt"
+    snip: "A Mercurial extension for adding repository info to your shell prompt."
+    created: 2009-06-19 22:25:17
+%}
+
+{% block article %}
+
+hg-prompt adds an 'hg prompt' command to Mercurial for viewing repository
+information. It's designed to be used in a shell prompt. You can grab the code
+from [the repository on BitBucket](http://bitbucket.org/sjl/hg-prompt/).
+
+Here's what it looks like:
+
+![My bash prompt while using hg-prompt.](http://stevelosh.com/site-media/storage/projects/2009-06-19-hg-prompt/hg-prompt.png "My bash prompt while using hg-prompt.")
+
+[TOC]
+
+Requirements
+------------
+
+hg-prompt requires Python 2.5+ and (obviously) Mercurial.
+
+Installing
+----------
+
+Clone the repository:
+
+    :::text
+    $ hg clone http://bitbucket.org/sjl/hg-prompt/
+
+Edit the `[extensions]` section in your `~/.hgrc` file:
+
+    :::text
+    [extensions]
+    prompt = (path to)/hg-prompt/prompt.py
+
+Using the Command
+-----------------
+
+The `hg prompt` command takes a single string as an argument and outputs it.
+Here's a simple (and useless) example:
+
+    :::text
+    $ hg prompt "test"
+    test
+
+Keywords in curly braces can be used to output repository information:
+
+    :::text
+    $ hg prompt "currently on {branch}"
+    currently on default
+
+Keywords also have an extended form:
+
+    :::text
+    {optional text{branch}more optional text}
+
+This form will output the text and the expanded keyword **only** if the
+keyword successfully expands. This can be useful for displaying extra text
+only if it's applicable:
+
+    :::text
+    $ hg prompt "currently on {branch} and at {bookmark}"
+    currently on branch default and at 
+    
+    $ hg prompt "currently on {branch} {and at {bookmark}}"
+    currently on branch default 
+    
+    $ hg bookmark my-book
+    
+    $ hg prompt "currently on {branch} {and at {bookmark}}"
+    currently on branch default and at my-book
+
+Available Keywords
+------------------
+
+There a number of keywords available. If you have any suggestions for more
+please let me know.
+
+* **bookmark:** the current bookmark (requires the [bookmarks][] extension)
+* **branch:** the current branch
+* **node:** the (full) changeset hash of the current parent
+* **node|short:** a short form of the changeset hash of the current parent
+* **node|merge:** the (full) changeset hash of the changeset you're merging with if you're currently merging, otherwise nothing.
+* **node|merge|short:** a short form of the changeset hash of the changeset you're merging with if you're currently merging, otherwise nothing
+* **patch:** the topmost currently-applied patch (requires the mq extension)
+* **patch|count:** the number of patches in the queue
+* **patch|applied:** the number of currently applied patches
+* **patch|unapplied:** the number of unapplied patches in the queue
+* **rev:** the repository-local changeset number of the current parent
+* **rev|merge:** the repository-local changeset number of the changeset you're merging with if you're currently merging, otherwise nothing
+* **root:** the full path to the root of the current repository, without a trailing slash
+* **root|basename:** the directory name of the root of the current repository.  For example, if the repository is in `/home/u/myrepo` then this keyword would expand to `myrepo`.
+* **status:**  `!` if the repository has any changed/added/removed files, otherwise `?` if it has any untracked (but not ignored) files, otherwise nothing
+* **status|modified:** `!` if the current repository contains files that have been modified, added, removed, or deleted, otherwise nothing
+* **status|unknown:** `?` if the current repository contains untracked files, otherwise nothing
+* **status|modified|unknown:** `!` if the current repository contains files that have been modified, added, removed, or deleted, *and* `?` if it contains untracked (and not ignored) files, otherwise nothing
+* **tags:** the tags of the current parent, separated by a space
+* **tags|SEP:** the tags of the current parent, separated by `SEP`
+* **task:** the current task (requires the [tasks][] extension)
+* **tip:** the repository-local changeset number of the current tip
+* **tip|node:** the (full) changeset hash of the current tip
+* **tip|node|short:** a short form of the changeset hash of the current tip
+* **update:** `^` if the current parent is not the tip of the current branch, otherwise nothing.  In effect, this lets you see if running `hg update` would do something.
+
+[bookmarks]: http://mercurial.selenic.com/wiki/BookmarksExtension
+[tasks]: http://bitbucket.org/alu/hgtasks/wiki/Home
+
+Remote Status Keywords
+----------------------
+
+There are several keywords available to monitor the status of remote
+repositories. Because this can be an expensive operation if the remote
+repository is across a network, they cache their results in
+`.hg/prompt/cache/`. The cache is updated roughly every fifteen minutes.
+
+* **incoming:** this keyword prints nothing on its own.  If the default path contains incoming changesets the extra text will be expanded. For example: `{incoming changes{incoming}}` will expand to `incoming changes` if there are changes, or nothing otherwise.
+* **incoming|count:** the number of incoming changesets if greater than 0
+* **outgoing:** this keyword prints nothing on its own.  If the current repository contains outgoing changesets (to default) the extra text will be expanded. For example: `{outgoing changes{outgoing}}` will expand to `outgoing changes` if there are changes, or nothing otherwise.
+* **outgoing|count:** the number of outgoing changesets if greater than 0
+
+Putting it in a Bash Prompt
+---------------------------
+
+To put it in your bash prompt, edit your `~/.bashrc` file to include something
+like this:
+
+    #!bash
+    hg_ps1() {
+        hg prompt "{ on {branch}}{ at {bookmark}}{status}" 2> /dev/null
+    }
+    
+    export PS1='\u at \h in \w$(hg_ps1)\n$ '
+
+`source ~/.bashrc` after to test it out. Make sure you're in a Mercurial
+repository or you won't see anything. This little prompt will give you
+something like this:
+
+    steve at myhost in ~/src/hg-prompt on default at feature-bookmark?
+    $
+
+How about something a little more interesting?
+
+    hg_ps1() {
+        hg prompt "{[+{incoming|count}]-->}{root|basename}{/{branch}}{-->[+{outgoing|count}]}{ at {bookmark}}{status}" 2> /dev/null
+    }
+    
+    export PS1='$(hg_ps1)\n\u at \h in \w\n$ '
+
+And the result (this example assumes one incoming changeset and two outgoing):
+
+    [+1]-->hg-prompt/default-->[+2] at feature-bookmark
+    steve at myhost in ~/src/hg-prompt
+    $
+
+Questions, Comments, Suggestions
+--------------------------------
+
+The code was kind of thrown together in one night after I got tired of
+chaining three or four hg runs together to get what I wanted. I'm sure it's
+not perfect, so if you've got a way to improve it please [add an
+issue](http://bitbucket.org/sjl/hg-prompt/issues/) and let me know.
+
+{% endblock %}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/content/projects/hgtab.html	Wed Dec 23 20:59:20 2009 -0500
@@ -0,0 +1,114 @@
+{% extends "_post.html" %}
+
+{% hyde
+    title: "hgtab"
+    snip: "Smarter tab completion for Mercurial in bash."
+    created: 2009-03-10 20:22:44
+%}
+
+{% block article %}
+
+hgtab was created to provide smarter tab completion for Mercurial in bash.
+
+**UPDATE**: Apparently there's already [tab completion in
+Mercurial](http://www.selenic.com/hg/file/11efa41037e2/contrib/bash_completion)!
+It's way better than this, *use that*! It should probably be better documented
+though &ndash; I posted this yesterday and it's already the top four results
+for "mercurial tab completion" on Google...
+
+If I've missed something you'd really like tab completed, post an issue on the
+issue tracker and I'll do my best to implement it. My bash scripting skills
+are almost non-existent, so if you improve this (or port it to another shell)
+feel free to send a pull request!
+
+You can download hgtab from its [BitBucket
+repository](http://source.stevelosh.com/hgtab/).
+
+## Installing
+
+All you need to do to use hgtab is source it. There are three ways to do this,
+ranging from easy and ugly to slightly less easy and more elegant.
+
+### OPTION 1: Easy, Ugly
+
+Copy the contents of hgtab-bash.sh into your ~/.bashrc file.
+
+### OPTION 2: Harder, Less Ugly
+
+Download hgtab-bash.sh and place the following line somewhere in your
+~/.bashrc file:
+
+    source ~/path/to/hgtab/hgtab-bash.sh
+
+### OPTION 3: Hardest, Elegant
+
+Clone this repository somewhere with this command:
+
+    hg clone http://bitbucket.org/sjl/hgtab/
+
+Add the following line to your ~/.bashrc file:
+
+    source ~/path/to/hgtab/hgtab-bash.sh
+
+If you use this method you can update the file by pulling down the changes
+from this repository:
+
+    cd ~/path/to/hgtab
+    hg pull
+
+## Using
+
+Once hgtab is sourced it'll add some nifty tab completion features in your
+shell. For example, you can tab complete Mercurial commands:
+
+    #!console
+    sjl at grendel in test $  hg re<tab(s)>
+    recover  remove   rename   resolve  revert
+    sjl at grendel in test $  hg re
+
+When you're using a command that wants a revision as a parameter, hitting tab
+will complete on tags (and bookmarks) and branches.
+
+    #!console
+    sjl at grendel in test $  hg branches
+    blue                          20:f05ca6eb51a1
+    red                           16:8262f0345f41 (inactive)
+    default                       15:67f959b8deb8 (inactive)
+    sjl at grendel in test $  hg book
+     * dev-1.0                   20:f05ca6eb51a1
+    sjl at grendel in test $  hg tags
+    tip                               20:f05ca6eb51a1
+    dev-1.0                           20:f05ca6eb51a1
+    beta                              18:f3ab9bf730f7
+    alpha                             17:ca802019f04f
+    
+    sjl at grendel in test $  hg update <tab(s)>
+    alpha    beta     blue     default  dev-1.0  red      tip
+    sjl at grendel in test $  hg update b<tab(s)>
+    beta  blue  
+    sjl at grendel in test $  hg update b
+    
+    sjl at grendel in test $  hg diff -r b<tab(s)>
+    beta  blue  
+    sjl at grendel in test $  hg diff -r b
+
+It will also complete remote paths when you're pushing or pulling.
+
+    #!console
+    sjl at grendel in test $  hg paths
+    alice-dev = http://alice-dev
+    alice-stable = http://alice-stable
+    bob = http://bob
+    default = ssh://hg@bitbucket.org/sjl/hgtag/
+    
+    sjl at grendel in test $  hg push <tab(s)>
+    alice-dev     alice-stable  bob           default
+    sjl at grendel in test $  hg push
+    
+    sjl at grendel in test $  hg pull alice-<tab(s)>
+    alice-dev     alice-stable  
+    sjl at grendel in test $  hg pull alice-
+
+Enjoy!
+
+{% endblock %}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/content/projects/index.html	Wed Dec 23 20:59:20 2009 -0500
@@ -0,0 +1,6 @@
+{% extends "skeleton/_listing.html" %}
+
+{% hyde
+    title: "Projects"
+    exclude: True
+%}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/content/projects/lindyjam-com.html	Wed Dec 23 20:59:20 2009 -0500
@@ -0,0 +1,152 @@
+{% extends "_post.html" %}
+
+{% hyde
+    title: "lindyjam.com"
+    snip: "A page for a local weekly swing dance event (and more)."
+    created: 2009-01-21 18:28:35
+%}
+
+{% block article %}
+
+A few days ago I released the new [Lindy Jam][] website. Lindy Jam is a weekly
+swing dance in Rochester, NY. I wanted to create a site that was useful for
+those that attend the event but also more than just a "here's when it is and
+how to get there" page.
+
+[Lindy Jam]: http://lindyjam.com/
+
+![lindyjam.com screenshot](/site-media/storage/projects/2009-01-21-lindyjam/lindyjamcom-splash.png "Screenshot of the Lindy Jam site.")
+
+Design
+------
+
+Let me preface this section by saying: "I'm not a graphic designer." Yes, I
+appreciate good design and typography, but I simply haven't studied it as much
+as I'd like. That might change in the future, but for now I'll make due with
+the knowledge I have.
+
+There are very few images used on the site; the background stripes and the
+splash page photo(s) comprise all of them. I did this for a few reasons:
+
+* It saved me time.
+* The site loads faster.
+* The site scales to larger or smaller sizes very gracefully.
+
+I tried to keep things as clean as possible while still being useful. Comments
+and error messages are displayed immediately, without reloading the page. This
+makes it easier to see what you've done (or what went wrong) right off the
+bat.
+
+I'm not 100% pleased with how it came out, but it will do until I learn more
+about design. If you have advice or suggestions about the design, please
+[email me][]!
+
+[email me]: mailto:steve@stevelosh.com
+
+Pages
+-----
+
+### About
+
+The most important part of the site is probably the [About][] page, because it
+tells people when and where the event happens. It's as simple and to the point
+as I could make it so people can get the information they're looking for right
+away. It's linked right from the splash page so it's easier to find.
+
+[About]: http://lindyjam.com/about/
+
+### DJ Schedule
+
+Another important piece of the site is the [DJ Schedule][] page. Every week
+someone can sign up to DJ the event. They get in for free, and we get to hear
+a wider variety of music. The schedule page makes it easy to sign up for a
+week in the near future.
+
+When you sign up to DJ you can also enter your email address or cell phone
+number (or both) if you'd like to be reminded. I know that sometimes I've
+almost forgotten to bring my laptop (and arrive right on time), so I hope that
+this feature will be useful to other DJs too.
+
+[DJ Schedule]: http://lindyjam.com/schedule/
+
+### Blog
+
+One thing I believe our Lindy Hop scene lacks is a place for people to write
+thoughtful, well-crafted articles about the scene. I hope the Lindy Jam
+[Blog][] can become such a place.
+
+It's a fairly simple blog; entries and comments are written in [Markdown][] so
+authors don't need to know HTML to make their articles look nice. Anyone can
+comment without signing up for anything, so I hope people will take advantage
+of that and discuss the articles.
+
+[Blog]: http://lindyjam.com/blog/
+[Markdown]: http://daringfireball.net/projects/markdown/
+
+### Links
+
+Most sites like this have a list of links to other sites that their viewers
+might be interested in, and this site is no different. The [Links][] page is a
+simple, clean list of links that anyone can contribute to. If someone knows of
+a great page we haven't listed, they can submit it and it will appear on the
+page as soon as it's been approved.
+
+[Links]: http://lindyjam.com/links/
+
+### Quotes
+
+Along the top of every page is a random quote. Right now there aren't very
+many, but I hope that people will submit some more by going to the [Quotes][]
+page or by text messaging them to <quotes@lindyjam.com>.
+
+I think the quotes add a more personal touch and allowing anyone to add one
+can really make it a "community" site.
+
+[Quotes]: http://lindyjam.com/quotes/
+
+### RSS
+
+We nerds love our [RSS][] feeds, so I've implemented a couple of different
+feeds that people can use to stay up to date.
+
+[RSS]: http://lindyjam.com/rss/
+
+Implementation
+--------------
+
+The site was built with [Django][] because it makes it very, very easy to get
+a dynamic site like this up and running quickly. I use [Fabric][] to deploy it
+(check out [this
+entry](http://stevelosh.com/blog/entry/2009/1/15/deploying-site-fabric-and-mercurial/)
+on my personal blog for more information about that). All of the fancy effects
+use [jQuery][] so I can avoid programming them from scratch in javascript (and
+tearing my hair out).
+
+One thing I would do differently if I were to design the site all over again
+is use a CSS framework like [Blueprint][]. I used Blueprint for my personal
+site and it made things far, far easier than writing the layout in CSS from
+scratch. I definitely recommend it if you want to keep your sanity.
+
+The site itself is hosted on [WebFaction][]. I use them to host my own site
+too and they're fantastic. Setting up a Django or Rails (or any other type) of
+site is quick and easy, and they're very cheap. If you're looking for a web
+host you should check them out.
+
+The site is open source if you'd like to take a look at what makes it tick.
+You can browse or download the code from the [Mercurial repository][] on
+BitBucket.
+
+[Django]: http://djangoproject.com/
+[Fabric]: http://www.nongnu.org/fab/
+[jQuery]: http://jquery.com/
+[Blueprint]: http://www.blueprintcss.org/
+[WebFaction]: http://www.webfaction.com/signup?affiliate=sjl
+[Mercurial repository]: http://bitbucket.org/sjl/lindyjam/
+
+Feedback
+--------
+
+If you have any comments or questions about the site please let me know! You
+can post them here or [email me][].
+
+{% endblock %}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/content/projects/stevelosh-com.html	Wed Dec 23 20:59:20 2009 -0500
@@ -0,0 +1,101 @@
+{% extends "_post.html" %}
+
+{% hyde
+    title: "stevelosh.com"
+    snip: "This website."
+    created: 2009-01-11 15:40:26
+%}
+
+{% block article %}
+
+For a long time I used [Squarespace][] to create and host my personal website.
+It's a great service, and I highly recommend it to anyone that needs a simple,
+easy, beautiful site.
+
+Recently, however, I've started learning more and more about web design and I
+decided to completely revamp my website and build it myself from the ground
+up. This is the result.
+
+Design
+------
+
+I like simplicity. In all areas of my life (music, dancing, photography,
+programming, design, etc) I'm striving to make everything I do as simple,
+clean, and elegant as possible. That's why I went with such a minimal design
+for the site.
+
+I haven't used any graphics in the layout for a few reasons. First, I'm not
+very good at making them. Second, I want the site to load quickly, even on
+phones, and scale gracefully for accessibility. Third, I wanted the interface
+to be as uncluttered as possible so the content of the site would be front and
+center.
+
+I also stuck to a minimum of color. The only items that have any color on the
+site are any photographs that I post and the links. I did this because I'm not
+a graphic designer and so I haven't studied color enough to know how to use it
+well.
+
+One last thing I tried to keep in mind was sticking to a baseline rhythm for
+some elements of the site. The home page, blog entry list, and project list
+all line up with the links in the right sidebar. I think it gives the layout a
+more stable feel.
+
+Implementation
+------------
+
+This website was written in [Python][] using the [Django][] framework. Django
+makes it really easy to write useful web apps quickly and cleanly. I love it.
+
+[Blueprint][] kept me sane while writing the CSS. Grid layouts are no longer a
+nightmare!
+
+I rely pretty heavily on [Markdown][] throughout the site. The blog entries
+and static pages are all written in Markdown and parsed to XHTML later. This
+might not be the fastest way to do things but processor time is cheap and my
+time isn't.
+
+The Markdown-based editor and preview for commenting is the wonderful [WMD][].
+It's clean, simple, and does exactly what I want it to do. Most of the other
+Javascript magic comes from [jQuery][]. I use the [jQuery form validation
+plugin][form validation] in a couple of places to make checking input easier.
+
+For site statistics I'm relying on the fantastic [Mint][]. It's got a gorgeous
+interface and is absurdly simple to install. Plus it's hosted on my own host
+so I have control. It's also just a one time fee, unlike some other site stat
+packages that charge monthly.
+
+My development process is pretty simple. I use [TextMate][] to edit the code
+and a [Mercurial][] repository to store it and protect against accidents. To
+deploy, I push my local changes to a private repository on [Bitbucket.org][],
+and then use [Fabric][] to pull those changes down to the server and restart
+if necessary.
+
+The site is hosted by [WebFaction][]. If you're looking for a web host for
+Django or Rails sites (or any other kind, really) you should definitely
+consider them. Not only do they make installing Django or Rails very easy,
+they're absurdly cheap: 10gb disk space and 600gb/month bandwidth is less than
+$10 a month. I'd recommend them to anyone.
+
+It's Open Source, Too!
+----------------------
+
+Want to see what makes this site tick? Want to make it tick more smoothly?
+Feel free to head over to <http://bitbucket.org/sjl/stevelosh> and take a look
+at the code.
+
+[Squarespace]: http://www.squarespace.com/
+[Python]: http://python.org
+[Django]: http://djangoproject.com
+[Blueprint]: http://www.blueprintcss.org/
+[Markdown]: http://daringfireball.net/projects/markdown/
+[WMD]: http://wmd-editor.com/
+[jQuery]: http://jquery.com
+[form validation]: http://bassistance.de/jquery-plugins/jquery-plugin-validation/
+[TextMate]: http://macromates.com/
+[Mercurial]: http://www.selenic.com/mercurial/wiki/
+[Bitbucket.org]: http://www.bitbucket.org/
+[Fabric]: http://www.nongnu.org/fab/
+[Mint]: http://haveamint.com/
+[WebFaction]: http://www.webfaction.com/signup?affiliate=sjl
+
+{% endblock %}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/content/projects/t.html	Wed Dec 23 20:59:20 2009 -0500
@@ -0,0 +1,233 @@
+{% extends "_post.html" %}
+
+{% hyde
+    title: "t"
+    snip: "A command-line todo list manager for people that want to <em>finish</em> tasks, not organize them."
+    created: 2009-09-11 19:03:29
+%}
+
+{% block article %}
+
+`t` is a command-line todo list manager for people that want to *finish*
+tasks, not organize them.
+
+The code is in a [Mercurial repository][] on [BitBucket][].
+
+[BitBucket]: http://bitbucket.org/
+
+[TOC]
+
+Why t?
+------
+
+Yeah, I know, *another* command-line todo list manager. Several others already
+exist ([todo.txt][] and [TaskWarrior][] come to mind), so why make another
+one?
+
+[todo.txt]: http://ginatrapani.github.com/todo.txt-cli/
+[TaskWarrior]: http://taskwarrior.org/projects/show/taskwarrior/
+
+### It Does the Simplest Thing That Could Possibly Work
+
+Todo.txt and TaskWarrior are feature-packed. They let you tag tasks, split
+them into projects, set priorities, order them, color-code them, and much
+more.
+
+**That's the problem.**
+
+It's easy to say "I'll just organize my todo list a bit" and spend 15 minutes
+tagging your tasks. In those 15 minutes you probably could have *finished* a
+couple of them.
+
+`t` was inspired by [j][]. It's simple, messy, has almost no features, and is
+extremely effective at the one thing it does. With `t` the only way to make
+your todo list prettier is to **finish some damn tasks**.
+
+[j]: http://github.com/rupa/j2/
+
+### It's Flexible
+
+`t`'s simplicity makes it extremely flexible.
+
+Want to edit a bunch of tasks at once? Open the list in a text editor.
+
+Want to view the lists on a computer that doesn't have `t` installed? Open the
+list in a text editor.
+
+Want to synchronize the list across a couple of computers? Keep your task
+lists in a [Dropbox][] folder.
+
+Want to use it as a distributed bug tracking system like [BugsEverywhere][]?
+Make the task list a `bugs` file in the project repository.
+
+[Dropbox]: https://www.getdropbox.com/
+[BugsEverywhere]: http://bugseverywhere.org/
+
+### It Plays Nice with Version Control
+
+Other systems keep your tasks in a plain text file. This is a good thing, and
+`t` follows their lead.
+
+However, some of them append new tasks to the end of the file when you create
+them. This is not good if you're using a version control system to let more
+than one person edit a todo list. If two people add a task and then try to
+merge, they'll get a conflict and have to resolve it manually.
+
+`t` uses random IDs (actually SHA1 hashes) to order the todo list files. Once
+the list has a couple of tasks in it, adding more is far less likely to cause
+a merge conflict because the list is sorted.
+
+Installing t
+------------
+
+`t` requires [Python][] 2.5 or newer, and some form of UNIX-like shell (bash
+works well). It works on Linux, OS X, and Windows (with [Cygwin][]).
+
+[Python]: http://python.org/
+[Cygwin]: http://www.cygwin.com/
+
+Installing and setting up `t` will take about one minute.
+
+First, [download][] the newest version or clone the Mercurial repository ( `hg
+clone http://bitbucket.org/sjl/t/` ). Put it anywhere you like.
+
+[download]: http://bitbucket.org/sjl/t/get/tip.zip
+
+Next, decide where you want to keep your todo lists. I put mine in `~/tasks`.
+Create that directory:
+
+    mkdir ~/tasks
+
+Finally, set up an alias to run `t`. Put something like this in your
+`~/.bashrc` file:
+
+    alias t='python ~/path/to/t.py --task-dir ~/tasks --list tasks'
+
+Make sure you run `source ~/.bashrc` or restart your terminal window to make
+the alias take effect.
+
+Using t
+-------
+
+`t` is quick and easy to use.
+
+### Add a Task
+
+To add a task, use `t [task description]`:
+
+    $ t Clean the apartment.
+    $ t Write chapter 10 of the novel.
+    $ t Buy more beer.
+    $
+
+### List Your Tasks
+
+Listing your tasks is even easier -- just use `t`:
+
+    $ t
+    9  - Buy more beer.
+    30 - Clean the apartment.
+    31 - Write chapter 10 of the novel.
+    $
+
+`t` will list all of your unfinished tasks and their IDs.
+
+### Finish a Task
+
+After you're done with something, use `t -f ID` to finish it:
+
+    $ t -f 31
+    $ t
+    9  - Buy more beer.
+    30 - Clean the apartment.
+    $
+
+### Edit a Task
+
+Sometimes you might want to change the wording of a task. You can use `t -e ID
+[new description]` to do that:
+
+    $ t -e 30 Clean the entire apartment.
+    $ t
+    9  - Buy more beer.
+    30 - Clean the entire apartment.
+    $
+
+Yes, nerds, you can use sed-style substitution strings:
+
+    $ t -e 9 /more/a lot more/
+    $ t
+    9  - Buy a lot more beer.
+    30 - Clean the entire apartment.
+    $
+
+Tips and Tricks
+---------------
+
+`t` might be simple, but it can do a lot of interesting things.
+
+### Count Your Tasks
+
+Counting your tasks is simple using the `wc` program:
+
+    $ t | wc -l
+          2
+    $
+
+### Put Your Task Count in Your Bash Prompt
+
+Want a count of your tasks right in your prompt?  Edit your `~/.bashrc` file:
+
+    export PS1="[$(t | wc -l | sed -e's/ *//')] $PS1"
+
+Now you've got a prompt that looks something like this:
+
+    [2] $ t -f 30
+    [1] $ t Feed the cat.
+    [2] $
+
+### Multiple Lists
+
+`t` is for people that want to *do* tasks, not organize them. With that said,
+sometimes it's useful to be able to have at least *one* level of organization.
+To split up your tasks into different lists you can add a few more aliases:
+
+    alias g='python ~/path/to/t.py --task-dir ~/tasks --list groceries'
+    alias m='python ~/path/to/t.py --task-dir ~/tasks --list music-to-buy'
+    alias w='python ~/path/to/t.py --task-dir ~/tasks --list wines-to-try'
+
+### Distributed Bugtracking
+
+Like the idea of distributed bug trackers like [BugsEverywhere][], but don't
+want to use such a heavyweight system? You can use `t` instead.
+
+Add another alias to your `~/.bashrc` file:
+
+    alias b='python ~/path/to/t.py --task-dir . --list bugs'
+
+Now when you're in your project directory you can use `b` to manage the list
+of bugs/tasks for that project. Add the `bugs` file to version control and
+you're all set.
+
+Even people without `t` installed can view the bug list, because it's plain
+text.
+
+Problems, Contributions, Etc
+----------------------------
+
+`t` was hacked together in a couple of nights to fit my needs. If you use it
+and find a bug, please let me know.
+
+If you want to request a feature feel free, but remember that `t` is meant to
+be simple. If you need anything beyond the basics you might want to look at
+[todo.txt][] or [TaskWarrior][] instead. They're great tools with lots of
+bells and whistles.
+
+If you want to contribute code to `t`, that's great! Fork the [Mercurial
+repository][] on BitBucket or the [git mirror][] on GitHub and send me a pull
+request.
+
+[Mercurial repository]: http://bitbucket.org/sjl/t/
+[git mirror]: http://github.com/sjl/t/
+
+{% endblock %}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/content/projects/women-in-water.html	Wed Dec 23 20:59:20 2009 -0500
@@ -0,0 +1,26 @@
+{% extends "_post.html" %}
+
+{% hyde
+    title: "Women in Water"
+    snip: "Photographs of women in Lake Ontario."
+    created: 2009-08-04 18:57:36
+%}
+
+{% block article %}
+
+<div class="gallery">
+    <img src="/site-media/storage/projects/2009-08-04-women-in-water/erin-tele.jpg" />
+    <img src="/site-media/storage/projects/2009-08-04-women-in-water/alex-tele.jpg" />
+    <img src="/site-media/storage/projects/2009-08-04-women-in-water/lizza-tele.jpg" />
+    <img src="/site-media/storage/projects/2009-08-04-women-in-water/leah-tele.jpg" />
+    <img src="/site-media/storage/projects/2009-08-04-women-in-water/anna-tele.jpg" />
+    <img src="/site-media/storage/projects/2009-08-04-women-in-water/erin-wide.jpg" />
+    <img src="/site-media/storage/projects/2009-08-04-women-in-water/alex-wide.jpg" />
+    <img src="/site-media/storage/projects/2009-08-04-women-in-water/lizza-wide.jpg" />
+    <img src="/site-media/storage/projects/2009-08-04-women-in-water/leah-wide.jpg" />
+    <img src="/site-media/storage/projects/2009-08-04-women-in-water/anna-wide.jpg" />
+</div>
+
+This is still a work in progress.
+
+{% endblock %}
\ No newline at end of file