TheJoyOfHack

For people who like to make things

Switching to Octopress

Over this past weekend I switched my blog over from WordPress to Octopress. In this post I write about why I did it, what exactly I did to get the blog just the way I wanted, and what I plan to do in the future.

If you were to ask me what’s the difference between the two, the first thing I would tell you is that Octopress serves static HTML. The blog is generated on my local machine (usually my laptop) and then the static files are uploaded to the server. This is also called ‘baking the site.’

While I’m not an ‘A-list’ blogger and don’t have to worry about my site being Fireballed or Slashdotted (or JessicaHisched or SwissMissed) it’s comforting to know that my blog is being served as efficiently as it can be.

A lot has been said about the virtues of baking your own blogs, so I’m not gonna repeat them here. You can read what Matt Gemmell had to say about it and also what Brent Simmons wrote about it in these three articles.

For me, though, the biggest motivating factor was that I didn’t like using the Wordpress website to create and edit blog posts. The web interface is just not natural. Yes, there are apps like MarsEdit that simplify the process, but that’s still one more layer of abstraction than I care to interact with. I want the experience of writing to be as close to the metal as possible: I use a text editor to edit text - I should be able to use any text editor to edit my blog.

Enter Octopress and its support of Markdown. I set up Octopress per Matt’s recommendations and with some minor hacking I was able to migrate the blog over the course of one weekend. In what’s left of this post I’ll write about what changes I made to the system to get the blog ‘just right’ and what changes I would like to make in the future.

Floating Images

Octopress has a nice shorthand for specifying images:

1
{% img [class names] /path/to/image [width] [height] [title text [alt text]] %}

Using the proper class names one can have the image float left or right or otherwise set its alignment. However, I like having captions under my images. This requires a floating div that would contain both the image and the caption under it. For best results, the div would have to be about as wide as the image.

Octopress is based on Jekyll that supports the Liquid template engine written in ruby.
I could probably have written a Liquid plugin to do this, but I don’t know Ruby (yet) and so I had to come up with another solution.

To get this to work I created my own markup that would be inserted into the markdown text as an HTML comment. Markdown would preserve the HTML comment, and it would show up in the HTML file after rake generate was called. I wrote a small shell script call generate that calls rake generate and then invokes the perl script imageCaption.pl on every generated html file:

(generate) download
1
2
3
4
5
6
7
8
#!/bin/bash

rake generate

find /Users/aijaz/octopress/public \
     -type f \
     -name '*.html' \
     -exec /Users/aijaz/octopress/imageCaption.pl '{}' ';'

And, here’s imageCaption.pl. It searches for the markup and replaces it with the appropriate HTML.

(imageCaption.pl) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#!/usr/bin/perl

use strict;
use warnings;

# The file that was specified on the command line
#
my $file = shift;

# Read all lines from the file into a list named 'lines'
#
open (I, $file) || die;
my @lines = <I>;
close I;

# Scan each line for our special markup: 
# a comment that starts with ai and then has upto 6
# space-separated components
#
# For each such line, call makeDiv on the components and 
# replace the markup with the output of that function
#
foreach my $line (@lines) {
    $line =~ s^<!-- ai\s+(\S+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s+(.*?)\s*-->^makeDiv($1, $2, $3, $4, $5, $6)^ge;
}

# Save the possibly modified contents of the 'lines' array
# back to the original file
#
open (O, ">$file") || die;
print O join("", @lines);
close O;


sub makeDiv {

    # The enclosing div should be this much bigger
    # than the image.  This accounts for the white margin
    # that octopress puts around the image
    #
    my $width_inc = 20;

    # The 6 components in our markup are
    # align:   'l', 'c' or 'r'.  Used to specify the
    #          css class
    # target:  The href of the a tag that's put around
    #          the image
    # image:   The URL of the image 
    # width:   The width of the image
    # height:  The height of the image
    # caption: This is used as the alt tag of the image, 
    #          the title of the a tag as well as the 
    #          caption that's displayed under the image.
    #          This field may be blank, but don't do that 
    #          because really, that's the whole point of 
    #          this exercise.
    #
    my ($align, $target, $image,
        $width, $height, $caption) = @_;

    my $div_width = $width + $width_inc;

    # Construct the html.  Note that the css class is
    # 'ai' followed by the value of the 'align' component.
    #
    return join("",
        qq^<div class="ai$align" style="width:${div_width}px">^,
            qq^<a href="$target" title="$caption">^,
                qq^<img src="$image" ^,
                    qq^width="$width" ^,
                    qq^height="$height" ^,
                    qq^alt="$caption" ^,
                    qq^border=0></a><br>^,
            qq^$caption</div>^);
}

In order to tie this all together, I had to define the css classes for the various ‘ai…’ classes. I added the following code to sass/custom/_styles.scss:

(_styles.scss) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// This File is imported last, and will override other styles in the cascade
// Add styles here to make changes without digging in too much

div.ail {
    max-width: 100%;
    float: left;
    font-size: 12pt;
    color: #808080;
    padding-right: 1em;
    font-style: italic;
    text-align: center;
    margin-bottom: 1em;
    line-height: 16pt;
}

div.air {
    max-width: 100%;
    float: right;
    font-size: 12pt;
    color: #808080;
    padding-left: 1em;
    font-style: italic;
    text-align: center;
    margin-bottom: 1em;
    line-height: 16pt;
}

div.aic {
    max-width: 100%;
    font-size: 12pt;
    color: #808080;
    font-style: italic;
    text-align: center;
    margin-bottom: 2em;
    margin-left: auto;
    margin-right: auto;
    line-height: 16pt;
}

div.air img {
    max-width: 100%;
}


div.ail img {
    max-width: 100%;
}


div.aic img {
    max-width: 100%;
}

Note that I added max-width:100% for all the divs and images - this ensures that the images won’t get cropped when the page is displayed on a smaller, mobile display.

You can see an example of these aligned images in my post on how lenses work.

Web Server Optimizations

I host my site on an Apache 2 web server. As I had done with my taskforest website , I decided to optimize the site and get a high score from PageSpeed. I enabled compression of html files, and turned on KeepAlive.

I also had to change my site redirections. Originally, I was redirecting aijazansari.com to www.aijazansari.com. However, I noticed that my site was not being displayed correctly on Windows Internet Explorer Version 8. As this page shows, it’s probably due to poorly-implemented restrictions to prevent cross-site scripting. I changed the redirections to be the other way around, and then the site worked fine on IE8. I’ve included the relevant part of my httpd.conf file below:

(httpd.conf) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<VirtualHost 216.139.228.44>
    ServerName        aijazansari.com
    DocumentRoot      "/home/aijaz/aijazansari.com"
    FileEtag          None
    ExpiresActive     On
    ExpiresDefault    A3600
    CustomLog        logs/access_log_blog combined
    KeepAlive        On
    ErrorDocument    404 /404.html

    # 1 Week
    <FilesMatch "\.(ico|gif|jpe?g|png|flv|pdf|swf|mov|mp3|wmv|ppt)$">
        ExpiresDefault A604800
        Header append  Cache-Control "public"
    </FilesMatch>

    # 1 Day
    <FilesMatch "\.(xml|txt|html|htm|js|css)$">
        SetOutputFilter DEFLATE
        BrowserMatch    ^Mozilla/4         gzip-only-text/html
        BrowserMatch    ^Mozilla/4\.0[678] no-gzip
        BrowserMatch    \bMSIE            !no-gzip !gzip-only-text/html
        ExpiresDefault  A86400
        Header append   Cache-Control "private, must-revalidate"
    </FilesMatch>

    # Never cache
    <FilesMatch "\.(pl)$">
        ExpiresDefault A0
        Header set     Cache-Control "no-store, no-cache, must-revalidate, max-age=0"
        Header set     Pragma "no-cache"
    </FilesMatch>
</VirtualHost>

<VirtualHost 216.139.228.44>
    ServerName    www.aijazansari.com
    RedirectMatch (.*) http://aijazansari.com$1
</VirtualHost>

Excluding Myself From Google Analytics Reports

While I tweak this blog, I’ll be accessing it very often. I don’t want my accesses to influence the Google Analytics reports. I followed the advice on this page and set up Analytics to ignore the cookie that only I would have set.

Update 2011/12/20 - These instructions didn’t work. Read my next post to see how I got it to work.

Can’t Forget The FavIcon

Finally, I overwrote the default favicon.png with my own version. It was the fininshing touch to get the blog ‘just right’ (for now).

Plans For The Future

The first thing I want to change about my blog is the theme. I think the default Octopress theme is very good, but I personally prefer the more minimalistic themes. I used to use Basic Maths on my WordPress site. I might have to learn some Ruby, and also learn about Liquid and Jekyll, but I would like to make a theme that’s somewhere between Minimal Mac and Basic Maths. I’m also gonna have to replace my Perl image alignment hack to a Liquid plugin soon.